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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ section to the released version and opens a fresh empty one (see `docs/RELEASING
- **Polling session state moves off module statics into `AppState::session` (#758, PARTIAL — polling half).** `SessionState` owns the write-decision clocks (with the D11 generation guard), the quiet/snooze latches, the last-now-playing cache, the preferred-presence session, the exit snapshot, and the #863 failure/gate mirrors; `poll_once`/`loop`/`state`/`sync`/`diagnostics` thread `&session` instead of touching statics. `global_state_lock` is deleted and each test constructs its own `SessionState::new()` (new `test_two_sessions_do_not_share_clocks_latches_or_caches` proves isolation). Tray/config `AppCaches` (slice 2) stay static for now, so `QUARANTINE_TEST_LOCK` and `LOCALE_TEST_LOCK` survive and the issue stays open. No behaviour change in the single-session path.
### Refactor
- **Monolithic `lib.rs` split into `app`/`cli`/`deep_link`/`state` modules (#757).** The ~4.9k-line `lib.rs` is now a 34-line module registry + state re-export shim; the Tauri `run()`/setup wiring lives in `app.rs` (with `setup_*` helpers), CLI parsing/dispatch in `cli.rs`, the Spotify-callback exchange in `deep_link.rs`, and `AppState` + token-commit seams in `state.rs`. Six source-scanner guards retargeted to the new homes (`generate_handler!` → `app.rs`, `handle_spotify_callback` → `deep_link.rs`, `forward_launch_to_running_instance` → `app.rs`, `polling::run_oneshot` call site → `cli.rs`, log-permission setup → `setup_log_permissions` helper, `macos_deeplink` module decl → `lib.rs`), and the redaction-literal sweep now covers the four new modules. No behaviour change.
- **Config split into 7-slice mod with re-exported surface (#755).** `src-tauri/src/config.rs` (8313 ln) becomes `src-tauri/src/config/{schema,clamp,snooze,patch,migrate,io,transfer}.rs` plus a 52-line re-export header in `mod.rs` that keeps every `crate::config::X` path stable. All 121 config tests remain centralized in `config/mod.rs` (identical set, 565 asserts) — the slices carry no `#[test]`; source-scan guards read the slices through one `concat!(include_str!(…))`, `redact.rs` aggregates the 8 slice sources, `LoggingConfig` lives only in `schema.rs`. `cargo check --all-targets` plus `cargo test --lib` (config 121/121, full 910/910) plus `clippy -D warnings` plus `fmt --check` are all clean.
### Fixed
- **Polish CLDR few/many plurals render the real forms (#1154).** `tCount` already resolved any `Intl.PluralRules` category with an `_other` fallback — the gap was data, not logic — so this adds `{key}_few` entries for both plural keys (`logs.count`, `dashboard.snoozeStatusStart`) in all eight dictionaries: real Polish nominative plurals ("2 wpisy", "2 minuty") plus `_other`-mirroring `_few` entries in the seven locales whose CLDR never selects `few`. No distinct `_many`: for the covered nouns CLDR `many` ("5 wpisów", "5 minut") IS the genitive plural `_other` carries, and the fr/es/it/pt `many`-at-10⁶+ magnitudes are unreachable for small UI counts. `tests/i18n.test.ts` asserts the real few/many forms (failing pre-fix with "2 wpisów"), and the key-coverage + placeholder-union scans now cover the `_one`/`_other`/`_few` trio. Provenance: the two Polish `_few` forms are model-written per #984 — human review pending.
- **A deep link arriving before `AppState` is managed is replayed after setup instead of dropped (#1122).** `handle_deep_link`'s unmanaged-state guard now buffers the callback URL in a process-wide single slot (a second early callback overwrites; the slot drains once) and the setup closure re-dispatches it through `handle_deep_link_from_app` immediately after `app.manage(state.clone())`. The early arm returns before the #799 `deep_link_seen` claim, so the replay is the first delivery the dedup gate sees and true duplicates still drop. Both new log lines carry presence only — never the URL, code, verifier, or state contents.
Expand Down
1 change: 1 addition & 0 deletions docs/STATE-OF-FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ end-to-end; the few rows that can't be sourced inline are explicitly flagged
| Tray tooltip + native CheckMenuItems + dock badge (C4) | ✅ | `tray/mod.rs` + `tray/dedup.rs` — live tooltip `Artist — Track (▶|⏸)` on each rebuild; Play/Pause, Shuffle and Repeat as native CheckMenuItems driven by `LAST_PLAYING_STATE` / `LAST_SHUFFLE_STATE` / `LAST_REPEAT_STATE`; macOS-only (`#[cfg]`) presence-gated dock badge wired into the polling loop (`b82f515`). The menu also carries a **Pause / Resume Sync** item (IDs `ID_PAUSE_SYNC` / `ID_RESUME_SYNC`) and, since 4.7.0 (#677), a **Pause sync for…** snooze submenu plus **Resume sync now** while a snooze is active. The tray's own status line is `sync_status_line` ("Syncing — Artist — Track", "Paused — …", "Not syncing", "Syncing — nothing playing"), and the tooltip is `{status_line} · {track_tooltip}`; the words come from the `i18n::Strings` table and a snooze replaces the line with `snooze_status_line` (remaining time + local deadline). |
| Settings dirty-state + clamp feedback + reset (C9) | ✅ | `Settings.svelte` — unsaved-changes banner via BigInt-safe deep compare; inline clamp feedback mirroring Rust `clamp_polling`; per-section Reset-to-default buttons using `defaultConfig`. |
| Settings per-card split, slice 1 (#750-PARTIAL) | ⚠ Partial | `src/lib/components/settings/` holds `SettingsCard` shell + `RulesCard`/`LoggingCard`/`BackupCard`/`ShortcutsCard` (each: `$bindable()` slice + `onreset`/`onchange`); `Settings.svelte` keeps draft state, save/discard, `pendingNav`, footer. Remaining: Spotify, Teams, Presence, StatusFormat, Polling, Notifications, Appearance, Profiles, Updates cards. |
| Config module split, one concern per file (#755) | ✅ | `src-tauri/src/config/mod.rs` re-exports `schema`/`clamp`/`snooze`/`patch`/`migrate`/`io`/`transfer` (one concern per file, every `crate::config::X` path stable); all 121 config tests remain centralized in `mod.rs` (identical set) — the slices carry no `#[test]`; `redact.rs` aggregates the 8 slice sources through one `concat!`; `LoggingConfig` lives only in `schema.rs`; `cargo check --all-targets` plus `cargo test --lib` (config 121/121, full 910/910) plus `clippy -D warnings` plus `fmt --check` all clean. |
| Notification throttle + grouping (C8) | ✅ | `Dashboard.svelte` — max 1 track-change notification per 5s (throttled tracks don't claim `lastNotifiedId`); replace-in-place via stable id + group tag where the platform supports it. 4.6 moved the opt-in into `src/lib/stores/notifications.ts` (#549); 4.7.0 (#675) replaces it with four config-backed classes (see the notification-classes row below), migrating the legacy `localStorage.notificationsEnabled` value into `track_change` exactly once — and only after the write lands, so a rejected save cannot lose an opt-out. Track changes keep the 5 s throttle (`TRACK_NOTIFICATION_THROTTLE_MS`) and the replace-in-place id. |
| WCAG 2.2 AA accessibility pass (C12) | ✅ | Skip link, focus-ring alpha fixes, `prefers-reduced-motion` guards, and darkened status/accent tokens in both themes. The build-version label uses `var(--fg-muted)` at full opacity; `tests/version-contrast.test.ts` mounts the page with production styles, composites effective opacity against the painted background, and requires at least 4.5:1 in both themes. |
| Form-control boundary contrast (#740) | ✅ | A dedicated `--border-input` token paints the shared `input` / `textarea` / `select` rule in `src/app.css`: **3.95:1** against `--bg-surface` and **3.29:1** against the `--bg-elevated` field fill in the dark theme, **3.48:1** / **3.08:1** in the light theme, all at or above the WCAG 1.4.11 3:1 non-text minimum. The decorative `--border` divider colour is unchanged. `tests/form-control-contrast.test.ts` resolves the token each theme actually paints and asserts the computed WCAG ratio, not a hex literal, so a palette revision is judged by the ratio it keeps. |
Expand Down
Loading
Loading