banner



How To Use After Focus App

In this article, I will describe the steps I went through to create a small desktop application to help me focus on my daily tasks.

Preview of the focus popup

The focus problem

One of my goals is to create the ultimate time management tool that will solve all my productivity issues, but let'due south beginning with one small problem for now. When I am working on a chore, I oftentimes become interrupted by other tasks that should exist done (a new job is assigned to me, I remember something that I should do, …), most of the time, the new task is non that urgent and tin expect until I cease my current one. But it gets me distracted and sometimes I find myself prioritizing it over the current job only to non forget about it. Then resuming the original task becomes hard because I lost focus. To solve this problem I needed a way to quickly log interrupting tasks every bit they popup and forget about them until I end my current job.

The idea of the application

  • I am working on something … an interrupting thought/task appears.
  • I hitting a custom shortcut on my keyboard so a text input appears in the middle of the screen.
  • I type a quick description of the interrupting idea/task, hit enter and the text input disappears.
  • I continue my work usually. …
  • When I finish, I open a predefined file and detect all the ideas/tasks I typed written within it.

Setting up the project

What I am trying to build hither is a desktop application, but I want to use web technologies (at least for the UI). The popular tool to practise that is Electron, but I started recently learning Rust and Tauri seems like a good tool to try. And then I will be using information technology with React for the frontend and Tailwind for styling.

I followed the instructions on Tauri's prerequisites page to setup Rust and Node on my system, then I run yarn create tauri-app to create the project. I named the project focus and chose the create-vite receipe for the UI and agreed to install @tauri-apps/api. Then chose the react-ts template of create-vite:

Create Tauri project with Vite react-ts template

Creating the projection

Tauri created the project and installed the dependencies. Allow's take a look at the files structure:

          src/
main.tsx <- entry signal of JS/TS
... other UI files hither
src-tauri/
icons/ <- icons of unlike sizes
src/
main.rs <- entry point for the application
target/ <- the compiled and bundles files
Cargo.toml <- like package.json for Rust
Cargo.lock <- similar yarn.lock
tauri.conf.json <- config file for Tauri
index.html <- entry bespeak of the UI
package.json
yarn.lock
tsconfig.json
vite.config.ts <- config file for Vite

Now running the yarn tauri dev should start the app. This will take some time as Rust compiles the lawmaking for the outset time, the post-obit executions will be fast.

The last footstep of the setup was to add Tailwind to the projection, I did that by following the official docs

Creating the UI

For the UI, all I need is a text input where I will type the task then hitting Enter to save it. So I changed the App component lawmaking to the following:

          office App() {
return <input
type="text"
className="west-[800px] h-[80px] bg-[#222] text-2xl text-white px-half dozen"
/>
}

Annotation that I am using Tailwind's arbitrary values syntax to accept a dark greyness 800px/80px input.

When I blazon some text in this input and then hitting Enter, I want that text to exist appended to a file somewhere. Let'south starting time by saving the text in a country and logging it when Enter is pressed:

          function App() {
const [content, setContent] = React.useState('')
return (
<input
type="text"
value={content}
onChange={e => setContent(eastward.target.value)}
onKeyDown={e => e.cardinal === 'Enter' && panel.log(content)}
className="w-[800px] h-[80px] bg-[#222] text-2xl text-white px-vi"
/>
)
}

Add state for the input content

Showing the input value on the panel

Calling Rust functions from the frontend

The side by side step is to write a Rust function that will receive the input content and suspend it to a file. Afterward reading the Calling Rust from the frontend documentation page, I changed the src-tauri/src/main.rs to the following:

Warning: I am new to Rust, so I may exist doing many things wrong in this code

          #![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use std::fs::OpenOptions;
utilize std::io::prelude::*;
#[tauri::command]
fn add_task(content: Cord) {
permit mut file = OpenOptions::new()
.create(true)
.append(true)
.open("../tasks.txt")
.expect("Error while opening the tasks file");
writeln!(file, "{}", content).expect("Mistake while writing in the tasks file");
}
fn chief() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![add_task])
.run(tauri::generate_context!())
.await("error while running tauri application");
}

Then I modified the App component to phone call that office when Enter is pressed:

          function App() {
const [content, setContent] = React.useState('')
const handleKeyDown = async (e: React.KeyboardEvent) => {
if (e.central === 'Enter') {
await invoke('add_task', { content })
}
}
render (
<input
type="text"
value={content}
onChange={e => setContent(e.target.value)}
onKeyDown={handleKeyDown}
className="w-[800px] h-[80px] bg-[#222] text-2xl text-white px-6"
/>
)
}

Now when typing some text and hiting Enter, the entered text is added to the tasks.txt file.

Append content to file

Adding the typed text to a file

Customizing the tasks file path

Note that this file is created in the root of the project while the path in the Rust code is ../tasks.txt, this is because the app is executed inside the src-tauri directory, and so any relative path will exist relative to that directory. Information technology will be meliorate to use an absolute path and let the user define it. The easiest way I could recall of to define it is via an environment variable, let'due south phone call it FOCUS_TASKS_PATH.

And then I added this variable to my .zshrc then updated the Rust code:

          // ...
employ std::env;
#[tauri::control]
fn add_task(content: Cord) {
permit path = env::var("FOCUS_TASKS_PATH") // read the env var
.expect("The 'FOCUS_TASKS_PATH' env variable was not found!");
let mut file = OpenOptions::new()
.create(true)
.suspend(true)
.open up(path) // <- use it here
.expect("Fault while opening the tasks file");
writeln!(file, "{}", content).expect("Error while writing in the tasks file")
}

Customizing the window

The initial idea was to have a popup, something like Spotlight on macOS, but what we take at present in a browser window! Luckily, Tauri allows us to tweak the window using the src-tauri/tauri.conf.json file. The initial window configuration was:

          {
"fullscreen": false,
"acme": 600,
"resizable": truthful,
"title": "Focus",
"width": 800
}

I replaced it with

          {
"fullscreen": faux,
"width": 800, // the width of the input
"height": 80, // the height of the input
"title": "Focus",
"resizable": imitation,
"centre": truthful, // position it in the center of the screen
"decorations": simulated // remove the title bar
}

The result looks good :)

The application styled as a popup

Preview of the popup

Closing the application after adding the task

At present I want the popup to disappear when I hit Enter, so let'south add together a procedure.leave() in our App component (This could besides be added on the add_task Rust office).

          import { procedure } from '@tauri-apps/api'          function App() {
const [content, setContent] = React.useState('')
const handleKeyDown = async (e: React.KeyboardEvent) => {
if (east.primal === 'Enter') {
await invoke('add_task', { content })
process.exit()
}
}
//...
}

Now the popup is closed when Enter is pressed :)

Compiling, installing and using the application

I think we have the alpha version of the application ready now, let'due south build it

          yarn tauri build        

Starting time the command failed with this message

          Error You must change the bundle identifier in `tauri.conf.json > tauri > bundle > identifier`. The default value `com.tauri.dev` is not immune equally it must be unique across applications.        

Setting the identifier to dev.webneat.focus solved the problem.

The compilation took a while so I had the following files generated (I am using Ubuntu):

          src-tauri/target/release/packet/
deb/focus_0.1.0_amd64.deb
appimage/focus_0.1.0_amd64.AppImage

Since the AppImage is easier to use (no installation needed), I just moved it to my bin directory and named it focus:

          sudo mv src-tauri/target/release/bundle/appimage/focus_0.1.0_amd64.AppImage /usr/bin/focus        

Now running the control focus on the terminal opens the popup :D

On Ubuntu, I tin set a new custom shortcut on the Keyboard settings. At present when I hit that shortcut anywhere, The popup appears, I blazon what I take in mind and hit Enter then continue what I was doing.

Bank check out the side by side function of me working on this project, where I make the app open faster by adding it to the system tray.

Check out the repository hither:

Source: https://betterprogramming.pub/how-i-created-the-focus-app-using-react-and-rust-fd8fd072d1a7

0 Response to "How To Use After Focus App"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel