Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,51 @@ jobs:
name: boost-focus-timer-extension
path: dist/*.zip
if-no-files-found: error

desktop:
# windows-2025 images break WebView2 WebDriver sessions (actions/runner-images#14738).
runs-on: windows-2022
timeout-minutes: 60
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm

- run: npm ci
- run: npm test
- run: npm run build:extension

- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
with:
workspaces: desktop

- run: cargo test --manifest-path desktop/Cargo.toml
- run: cargo clippy --manifest-path desktop/Cargo.toml --all-targets -- -D warnings
- run: npx tauri build --no-bundle

- name: Install tauri-driver and Edge driver
shell: pwsh
run: |
cargo install tauri-driver --locked
cargo install --git https://github.com/chippers/msedgedriver-tool
& "$HOME\.cargo\bin\msedgedriver-tool.exe"

- name: End-to-end tests
shell: pwsh
env:
BOOST_APP: ${{ github.workspace }}\desktop\target\release\boost-focus-timer.exe
run: |
$driver = Start-Process tauri-driver -ArgumentList '--native-driver', "$PWD\msedgedriver.exe" -PassThru
$deadline = (Get-Date).AddSeconds(30)
while (-not (Test-NetConnection 127.0.0.1 -Port 4444 -InformationLevel Quiet)) {
if ((Get-Date) -gt $deadline) { throw "tauri-driver did not start" }
Start-Sleep -Seconds 1
}
try { npm run test:e2e } finally { Stop-Process -Id $driver.Id -ErrorAction SilentlyContinue }
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
72 changes: 72 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Release

on:
push:
tags: ["v*"]

jobs:
windows:
runs-on: windows-latest
timeout-minutes: 60
permissions:
contents: write
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm

- run: npm ci

- name: Refuse to release without the updater public key
shell: bash
run: |
if grep -q SET_IN_RELEASE_SETUP desktop/tauri.conf.json; then
echo "::error::desktop/tauri.conf.json still has the placeholder updater pubkey; installs from this release could never update."
exit 1
fi

- run: npm test
- run: npm run build:extension

- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: desktop

- run: cargo test --manifest-path desktop/Cargo.toml

- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: ${{ github.ref_name }}
releaseName: Boost Focus Timer ${{ github.ref_name }}
releaseBody: See the README for install and update steps.
releaseDraft: false
includeUpdaterJson: true
tauriScript: npx tauri

extension:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: windows
permissions:
contents: write
steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm

- run: npm ci
- run: npm run build:extension
- run: gh release upload "$GITHUB_REF_NAME" dist/*.zip --clobber
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ node_modules/
out/
build/
dist/
desktop/target/
desktop/gen/

# Environment
.env
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Boost Focus Timer

A calm, keyboard-friendly focus timer with to-dos, habits, goals and session history.
Runs as a web app or as a browser extension, and keeps every bit of data in your own browser.
Runs as a Windows desktop app, a web app or a browser extension, and keeps every bit of data on your own device.

[![CI](https://github.com/ttncode/boost-focus-timer/actions/workflows/ci.yml/badge.svg)](https://github.com/ttncode/boost-focus-timer/actions/workflows/ci.yml)
![Node 24+](https://img.shields.io/badge/node-%E2%89%A524-339933?logo=node.js&logoColor=white)
Expand Down Expand Up @@ -47,6 +47,18 @@ npm run dev

Open <http://localhost:3000>. To serve an optimized build instead, run `npm run build && npm start`.

## Install the Windows desktop app

1. Download `Boost.Focus.Timer_<version>_x64-setup.exe` from [Releases](https://github.com/ttncode/boost-focus-timer/releases/latest).
2. Run it. Windows may warn about an unknown publisher the first time, because the installer is not code-signed: click **More info**, then **Run anyway**. It installs for your account only, so no admin rights are needed.
3. The app opens, adds an icon to the system tray and starts with Windows from then on.

Press <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>B</kbd> in any program to show or hide it. Closing the window (X) only hides it, so a running session and its notification carry on; to quit, right-click the tray icon → **Quit**. Turn off **Start with Windows** in the same menu if you don't want it at sign-in.

The app updates itself: each time it starts it checks for a new version and installs it, unless a session is running. To check now, right-click the tray icon → **Check for updates**.

The desktop app starts with empty data; it cannot read what the browser extension or web app stored.

## Install as a browser extension

The extension is the same app packaged for Chromium-based browsers (Chrome, Edge, Brave, Opera).
Expand Down
2 changes: 2 additions & 0 deletions desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target/
/gen/
38 changes: 38 additions & 0 deletions desktop/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "boost-focus-timer"
# The app's version comes from package.json through tauri.conf.json.
version = "0.0.0"
description = "A calm focus timer with to-dos, habits, goals and session history"
edition = "2021"
publish = false

[lib]
name = "boost_focus_timer_lib"
crate-type = ["staticlib", "cdylib", "rlib"]

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "~2.12", features = ["tray-icon"] }
tauri-plugin-single-instance = "2"
tauri-plugin-global-shortcut = "2"
tauri-plugin-autostart = "2"
tauri-plugin-window-state = "2"
tauri-plugin-updater = "2"
tauri-plugin-dialog = "2"
tauri-plugin-notification = "2"
tauri-plugin-opener = "2"
serde_json = "1"

# Must match the versions Tauri's WebView2 runtime uses, since with_webview hands over its types.
[target.'cfg(windows)'.dependencies]
webview2-com = "0.39"
windows-core = "0.62"

[profile.release]
codegen-units = 1
lto = true
opt-level = "s"
panic = "abort"
strip = true
3 changes: 3 additions & 0 deletions desktop/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}
7 changes: 7 additions & 0 deletions desktop/capabilities/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "What the window may call: core APIs only; plugins are driven from Rust.",
"windows": ["main"],
"permissions": ["core:default"]
}
Binary file added desktop/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/icons/128x128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktop/icons/icon.ico
Binary file not shown.
Binary file added desktop/icons/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading