From 814e9c3d24ff87079d4c1487fe43d0a7bc0fccbc Mon Sep 17 00:00:00 2001 From: ZacariaXAsh Date: Tue, 3 Mar 2026 11:17:33 +0000 Subject: [PATCH 1/3] feat: add click-through overlay + configurable slideshow --- dist/index.html | 83 ++++++++++++++++++++++++- src-tauri/src/main.rs | 139 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 216 insertions(+), 6 deletions(-) diff --git a/dist/index.html b/dist/index.html index e9df086..accdd3c 100644 --- a/dist/index.html +++ b/dist/index.html @@ -41,6 +41,13 @@
+ +
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a02a7ed..9c42325 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -27,15 +27,34 @@ enum WindowSizeUnits { Physical, } -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(default)] struct PersistedState { last_file: Option, aspect_lock: bool, + click_through: bool, + slideshow_enabled: bool, + slideshow_interval_ms: u64, window_w: Option, window_h: Option, window_size_units: Option, } +impl Default for PersistedState { + fn default() -> Self { + Self { + last_file: None, + aspect_lock: false, + click_through: false, + slideshow_enabled: false, + slideshow_interval_ms: 5000, + window_w: None, + window_h: None, + window_size_units: None, + } + } +} + #[derive(Clone, Debug, Serialize)] struct ActiveFilePayload { path: Option, @@ -66,6 +85,8 @@ struct AppState { aspect_ratio: Mutex>, // per-window aspect ratio adjusting_resize: Mutex>, // per-window resize guard aspect_toggle: Mutex>>, + click_through_toggle: Mutex>>, + slideshow_toggle: Mutex>>, pending_save: Mutex>>, selections: Mutex>, // per-window selections last_focused_window: Mutex>, // label of last focused window @@ -121,6 +142,8 @@ impl Default for AppState { aspect_ratio: Mutex::new(HashMap::new()), adjusting_resize: Mutex::new(HashSet::new()), aspect_toggle: Mutex::new(None), + click_through_toggle: Mutex::new(None), + slideshow_toggle: Mutex::new(None), pending_save: Mutex::new(HashMap::new()), selections: Mutex::new(HashMap::new()), last_focused_window: Mutex::new(None), @@ -249,10 +272,16 @@ fn reset_cache(app: &AppHandle) -> Result<(), Error> { state.adjusting_resize.lock().clear(); state.selections.lock().clear(); state.last_focused_window.lock().take(); - // Sync menu toggle to defaults + // Sync menu toggles to defaults if let Some(toggle) = state.aspect_toggle.lock().clone() { let _ = toggle.set_checked(false); } + if let Some(toggle) = state.click_through_toggle.lock().clone() { + let _ = toggle.set_checked(false); + } + if let Some(toggle) = state.slideshow_toggle.lock().clone() { + let _ = toggle.set_checked(false); + } } if let Ok(path) = config_path(app) { if path.exists() { @@ -393,6 +422,17 @@ fn navigate_selection(app: &AppHandle, window: &WebviewWindow, delta: isize) -> None } +fn apply_click_through_to_window(window: &WebviewWindow, enabled: bool) { + #[allow(deprecated)] + let _ = window.set_ignore_cursor_events(enabled); +} + +fn apply_click_through_to_all_windows(app: &AppHandle, enabled: bool) { + for (_, win) in app.webview_windows() { + apply_click_through_to_window(&win, enabled); + } +} + fn apply_initial_window_state(app: &AppHandle, window: &WebviewWindow, load_last_file: bool) { let _ = window.set_always_on_top(true); @@ -417,6 +457,8 @@ fn apply_initial_window_state(app: &AppHandle, window: &WebviewWindow, load_last } } + apply_click_through_to_window(window, st.click_through); + if load_last_file { if let Some(p) = st.last_file.clone() { if is_image_path(&p) && PathBuf::from(&p).exists() { @@ -605,6 +647,9 @@ fn get_settings(app: AppHandle) -> PersistedState { #[derive(Deserialize)] struct SettingsUpdate { aspect_lock: Option, + click_through: Option, + slideshow_enabled: Option, + slideshow_interval_ms: Option, } #[tauri::command] @@ -623,6 +668,26 @@ fn set_settings(app: AppHandle, update: SettingsUpdate) -> Result() { + if let Some(toggle) = state.click_through_toggle.lock().clone() { + let _ = toggle.set_checked(v); + } + } + } + if let Some(v) = update.slideshow_enabled { + st.slideshow_enabled = v; + if let Some(state) = app.try_state::() { + if let Some(toggle) = state.slideshow_toggle.lock().clone() { + let _ = toggle.set_checked(v); + } + } + } + if let Some(v) = update.slideshow_interval_ms { + st.slideshow_interval_ms = v.clamp(1000, 60000); + } save_state(&app, &win, st.clone()).map_err(|e| e.to_string())?; if let Some(state) = app.try_state::() { *state.settings.lock() = st.clone(); @@ -808,9 +873,28 @@ fn main() { ) .build()?; + let initial_settings = load_state(&app_handle); let aspect_toggle = CheckMenuItemBuilder::with_id("aspect_lock_toggle", "Lock aspect ratio on resize") - .checked(load_state(&app_handle).aspect_lock) + .checked(initial_settings.aspect_lock) + .build(&app_handle)?; + let click_through_toggle = + CheckMenuItemBuilder::with_id("click_through_toggle", "Click-through overlay") + .checked(initial_settings.click_through) + .accelerator(if cfg!(target_os = "macos") { + "Cmd+Shift+X" + } else { + "Ctrl+Shift+X" + }) + .build(&app_handle)?; + let slideshow_toggle = + CheckMenuItemBuilder::with_id("slideshow_toggle", "Slideshow mode") + .checked(initial_settings.slideshow_enabled) + .accelerator(if cfg!(target_os = "macos") { + "Cmd+Shift+S" + } else { + "Ctrl+Shift+S" + }) .build(&app_handle)?; let view_menu = SubmenuBuilder::new(&app_handle, "View") .item( @@ -840,7 +924,9 @@ fn main() { }) .build(&app_handle)?, ) - .item(&aspect_toggle); + .item(&aspect_toggle) + .item(&click_through_toggle) + .item(&slideshow_toggle); let app_menu = MenuBuilder::new(&app_handle) .item(&file_menu) .item(&view_menu.build()?) @@ -848,6 +934,8 @@ fn main() { app.set_menu(app_menu)?; if let Some(state) = app_handle.try_state::() { *state.aspect_toggle.lock() = Some(aspect_toggle.clone()); + *state.click_through_toggle.lock() = Some(click_through_toggle.clone()); + *state.slideshow_toggle.lock() = Some(slideshow_toggle.clone()); } if let Some(state) = app_handle.try_state::() { @@ -939,6 +1027,49 @@ fn main() { *state.settings.lock() = s; } } + "click_through_toggle" => { + if let Some(state) = app.try_state::() { + let mut s = state.settings.lock().clone(); + let new_state = if let Some(toggle) = state.click_through_toggle.lock().clone() { + if let Ok(current) = toggle.is_checked() { + let desired = !current; + let _ = toggle.set_checked(desired); + desired + } else { + !s.click_through + } + } else { + !s.click_through + }; + s.click_through = new_state; + apply_click_through_to_all_windows(app, new_state); + if let Some(win) = focused_window(app) { + let _ = save_state(app, &win, s.clone()); + } + *state.settings.lock() = s; + } + } + "slideshow_toggle" => { + if let Some(state) = app.try_state::() { + let mut s = state.settings.lock().clone(); + let new_state = if let Some(toggle) = state.slideshow_toggle.lock().clone() { + if let Ok(current) = toggle.is_checked() { + let desired = !current; + let _ = toggle.set_checked(desired); + desired + } else { + !s.slideshow_enabled + } + } else { + !s.slideshow_enabled + }; + s.slideshow_enabled = new_state; + if let Some(win) = focused_window(app) { + let _ = save_state(app, &win, s.clone()); + } + *state.settings.lock() = s; + } + } _ => {} }) .invoke_handler(tauri::generate_handler![ From e3d9304701dde710e70d0fc34086efdcc39320bf Mon Sep 17 00:00:00 2001 From: Zacaria Date: Sat, 14 Mar 2026 07:51:35 +0100 Subject: [PATCH 2/3] fix: stabilize ui test workflow --- .github/workflows/ui-tests.yml | 14 ++------- package.json | 3 +- tests/ui-mock.spec.ts | 54 +++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 8182739..6497ffe 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -1,8 +1,8 @@ -name: UI Tests (Playwright + tauri-driver) +name: UI Tests on: push: - branches: [ main ] + branches: [ master ] pull_request: jobs: @@ -16,19 +16,11 @@ jobs: with: node-version: '22' - - name: Set up Rust - uses: dtolnay/rust-toolchain@stable - - name: Install JS deps run: npm install --no-fund - name: Install Playwright browsers run: npx playwright install --with-deps - - name: Install tauri-driver - run: cargo install tauri-driver --locked - - - name: Run Playwright tests - env: - PATH: "$HOME/.cargo/bin:${PATH}" + - name: Run Playwright smoke tests run: npm run test:ui diff --git a/package.json b/package.json index b2162bd..7ba6534 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@playwright/test": "^1.50.0" }, "scripts": { - "test:ui": "playwright test tests/tauri-driver.spec.ts" + "test:ui": "playwright test tests/ui-mock.spec.ts", + "test:ui:tauri": "playwright test tests/tauri-driver.spec.ts" } } diff --git a/tests/ui-mock.spec.ts b/tests/ui-mock.spec.ts index 03c5191..5264c45 100644 --- a/tests/ui-mock.spec.ts +++ b/tests/ui-mock.spec.ts @@ -2,37 +2,49 @@ import { test, expect } from '@playwright/test'; import path from 'path'; /** - * Frontend-only smoke test: load dist/index.html with a mocked TAURI invoke implementation - * to verify the Open flow updates the UI. + * Frontend-only smoke test: load dist/index.html with a mocked Tauri v2 API + * and verify bootstrap renders the selected file state. */ -test('open flow updates UI with mocked tauri', async ({ page }) => { +test('bootstrap renders selected file with mocked tauri', async ({ page }) => { const distPath = path.resolve(__dirname, '..', 'dist', 'index.html'); const mockPath = '/tmp/icon.png'; + const pixelDataUrl = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9sYpWJ0AAAAASUVORK5CYII='; - await page.addInitScript(({ mockPath }) => { - // Minimal __TAURI__ mock to satisfy invoke calls + await page.addInitScript(({ mockPath, pixelDataUrl }) => { + // Minimal __TAURI__ v2 mock to satisfy frontend bootstrap and image fallback calls. // eslint-disable-next-line @typescript-eslint/no-explicit-any (window as any).__TAURI__ = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - invoke: (cmd: string, args: any = {}) => { - if (cmd === 'choose_file') return Promise.resolve(mockPath); - if (cmd === 'fit_now') return Promise.resolve(); - if (cmd === 'quick_look') return Promise.resolve(); - if (cmd === 'get_settings') return Promise.resolve({ aspect_lock: false, fit_window: true }); - if (cmd === 'set_settings') { - return Promise.resolve({ - aspect_lock: !!args.update?.aspect_lock, - fit_window: args.update?.fit_window ?? true, - }); - } - return Promise.resolve(); + core: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + invoke: (cmd: string, _args: any = {}) => { + if (cmd === 'get_settings') { + return Promise.resolve({ + last_file: mockPath, + aspect_lock: false, + fit_window: true, + }); + } + if (cmd === 'load_image_data') { + return Promise.resolve(pixelDataUrl); + } + if (cmd === 'previous_file' || cmd === 'next_file') { + return Promise.resolve(); + } + return Promise.resolve(null); + }, + convertFileSrc: () => 'file:///definitely-missing.png', + }, + event: { + listen: () => Promise.resolve(() => {}), }, }; - }, { mockPath }); + }, { mockPath, pixelDataUrl }); await page.goto(`file://${distPath}`); - await page.click('#openBtn'); - await expect(page.locator('#fileName')).toHaveText('icon.png'); + await expect(page.locator('#fileInfo')).toHaveText('icon.png'); await expect(page.locator('#status')).toHaveText(''); + await expect(page.locator('#placeholder')).toHaveText(''); + await expect(page.locator('#imageContainer')).not.toHaveClass(/placeholder/); }); From 2a06ed37a15c5d7f3e4167624735f5a80aa8d13c Mon Sep 17 00:00:00 2001 From: Zacaria Date: Sun, 15 Mar 2026 07:12:31 +0100 Subject: [PATCH 3/3] Rename app to Float Refresh app icons, update packaging metadata, and remove pre-release legacy settings migration paths. Change-ID: rename-project-to-float --- Cargo.lock | 26 +++++----- Cargo.toml | 2 +- dist/apple-touch-icon.png | Bin 0 -> 18537 bytes dist/favicon.ico | Bin 0 -> 5238 bytes dist/index.html | 2 + justfile | 2 +- .../rename-project-to-float/proposal.md | 4 +- .../specs/app-branding/spec.md | 8 +-- .../changes/rename-project-to-float/tasks.md | 2 +- src-tauri/Cargo.lock | 34 ++++++------- src-tauri/Cargo.toml | 2 +- src-tauri/icons/128x128.png | Bin 0 -> 5344 bytes src-tauri/icons/128x128@2x.png | Bin 0 -> 12100 bytes src-tauri/icons/32x32.png | Bin 0 -> 1234 bytes src-tauri/icons/Square107x107Logo.png | Bin 0 -> 4442 bytes src-tauri/icons/Square142x142Logo.png | Bin 0 -> 5838 bytes src-tauri/icons/Square150x150Logo.png | Bin 0 -> 6232 bytes src-tauri/icons/Square284x284Logo.png | Bin 0 -> 13304 bytes src-tauri/icons/Square30x30Logo.png | Bin 0 -> 1161 bytes src-tauri/icons/Square310x310Logo.png | Bin 0 -> 15330 bytes src-tauri/icons/Square44x44Logo.png | Bin 0 -> 1678 bytes src-tauri/icons/Square71x71Logo.png | Bin 0 -> 2927 bytes src-tauri/icons/Square89x89Logo.png | Bin 0 -> 3651 bytes src-tauri/icons/StoreLogo.png | Bin 0 -> 1964 bytes .../icons/android/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1898 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 6800 bytes .../android/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 1898 bytes .../icons/android/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1871 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 4417 bytes .../android/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1871 bytes .../android/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3881 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 9380 bytes .../mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 3881 bytes .../android/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5969 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 15495 bytes .../mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 5969 bytes .../android/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 8261 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 22285 bytes .../mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 8261 bytes src-tauri/icons/icon.icns | Bin 37283 -> 159186 bytes src-tauri/icons/icon.ico | Bin 5420 -> 22779 bytes src-tauri/icons/icon.png | Bin 10686 -> 28160 bytes src-tauri/icons/icon_base_1024.png | Bin 14346 -> 199515 bytes src-tauri/icons/ios/AppIcon-20x20@1x.png | Bin 0 -> 756 bytes src-tauri/icons/ios/AppIcon-20x20@2x-1.png | Bin 0 -> 1555 bytes src-tauri/icons/ios/AppIcon-20x20@2x.png | Bin 0 -> 1555 bytes src-tauri/icons/ios/AppIcon-20x20@3x.png | Bin 0 -> 2395 bytes src-tauri/icons/ios/AppIcon-29x29@1x.png | Bin 0 -> 1141 bytes src-tauri/icons/ios/AppIcon-29x29@2x-1.png | Bin 0 -> 2251 bytes src-tauri/icons/ios/AppIcon-29x29@2x.png | Bin 0 -> 2251 bytes src-tauri/icons/ios/AppIcon-29x29@3x.png | Bin 0 -> 3520 bytes src-tauri/icons/ios/AppIcon-40x40@1x.png | Bin 0 -> 1555 bytes src-tauri/icons/ios/AppIcon-40x40@2x-1.png | Bin 0 -> 3329 bytes src-tauri/icons/ios/AppIcon-40x40@2x.png | Bin 0 -> 3329 bytes src-tauri/icons/ios/AppIcon-40x40@3x.png | Bin 0 -> 5023 bytes src-tauri/icons/ios/AppIcon-512@2x.png | Bin 0 -> 65235 bytes src-tauri/icons/ios/AppIcon-60x60@2x.png | Bin 0 -> 5023 bytes src-tauri/icons/ios/AppIcon-60x60@3x.png | Bin 0 -> 7458 bytes src-tauri/icons/ios/AppIcon-76x76@1x.png | Bin 0 -> 3059 bytes src-tauri/icons/ios/AppIcon-76x76@2x.png | Bin 0 -> 6513 bytes src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png | Bin 0 -> 7004 bytes src-tauri/src/main.rs | 47 ++---------------- src/main.rs | 40 +-------------- 63 files changed, 47 insertions(+), 122 deletions(-) create mode 100644 dist/apple-touch-icon.png create mode 100644 dist/favicon.ico create mode 100644 src-tauri/icons/128x128.png create mode 100644 src-tauri/icons/128x128@2x.png create mode 100644 src-tauri/icons/32x32.png create mode 100644 src-tauri/icons/Square107x107Logo.png create mode 100644 src-tauri/icons/Square142x142Logo.png create mode 100644 src-tauri/icons/Square150x150Logo.png create mode 100644 src-tauri/icons/Square284x284Logo.png create mode 100644 src-tauri/icons/Square30x30Logo.png create mode 100644 src-tauri/icons/Square310x310Logo.png create mode 100644 src-tauri/icons/Square44x44Logo.png create mode 100644 src-tauri/icons/Square71x71Logo.png create mode 100644 src-tauri/icons/Square89x89Logo.png create mode 100644 src-tauri/icons/StoreLogo.png create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-512@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-60x60@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-60x60@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-76x76@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-76x76@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png diff --git a/Cargo.lock b/Cargo.lock index 64da66f..1c57b52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,19 +24,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "always-on-top" -version = "0.1.0" -dependencies = [ - "cocoa", - "directories", - "objc", - "once_cell", - "serde", - "serde_json", - "winit", -] - [[package]] name = "android-activity" version = "0.4.3" @@ -331,6 +318,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float" +version = "0.1.0" +dependencies = [ + "cocoa", + "directories", + "objc", + "once_cell", + "serde", + "serde_json", + "winit", +] + [[package]] name = "foreign-types" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index a030143..7edb618 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "always-on-top" +name = "float" version = "0.1.0" edition = "2021" description = "Float - minimal utility to keep a window always on top." diff --git a/dist/apple-touch-icon.png b/dist/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..366c60ea99e89ddcecb161ee67a3595d4f177c79 GIT binary patch literal 18537 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 literal 0 HcmV?d00001 diff --git a/dist/index.html b/dist/index.html index accdd3c..2c48e1a 100644 --- a/dist/index.html +++ b/dist/index.html @@ -4,6 +4,8 @@ + + Float