Commit Graph
7 Commits
Author SHA1 Message Date
rzuastiandClaude Opus 4.8 ed04a9bc89 Scale duration formatting up to months
formatSeconds previously capped at minutes; extend it to dynamically
show the two largest relevant units up through months for the passive
scanners' "Listening for ..." line and other duration displays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:15:20 -04:00
rzuastiandClaude Opus 4.8 40a7f3a432 Request iOS local-network permission at app launch
The iOS local-network permission prompt fires on the first local-network
access. That used to be the user's "Test" tap in settings, so the prompt
appeared mid-request and the first connection attempt always failed.

Provoke the prompt at launch instead via an mDNS multicast datagram, so the
permission is settled before the user reaches settings. Platform exclusion is
handled with a conditional import: web gets a no-op stub (keeping dart:io out
of web builds) and the native path no-ops off iOS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:33:06 -04:00
rzuastiandClaude Opus 4.8 9efe84c099 Add DeviceChanged and DeviceBackOnline event types
Record what happened on each known-device sighting instead of only
"seen": a baseline DeviceSeen (history heartbeat, no notification) plus
DeviceChanged and DeviceBackOnline events, each deduplicated
independently so a recent routine sighting no longer suppresses a
genuine change or return notification. The frontend chart now trusts the
event type for its marker and tooltip rather than comparing each event's
snapshot against the device's current state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 08:47:56 -04:00
rzuastiandClaude Opus 4.8 b0222445fb Fix API docs link when app is served from the backend
The API docs nav entry uses the origin-relative path "/api/docs", which
Uri.parse left scheme- and host-less, so canLaunchUrl/launchUrl could not
open it (e.g. in Docker). Resolve external links against the current page
so they carry a scheme and host; absolute URLs pass through unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:50:43 -04:00
rzuastiandClaude Opus 4.8 a51b9c06dc Display unknown values as a dash and centralise repeated literals
Backend: notifications now show a plain "-" for an absent name, vendor, or
device type (was empty string / "(unknown)" / "Unknown"), via a single
UNKNOWN_PLACEHOLDER constant.

Frontend:
- Empty/unknown values render as an em dash everywhere, centralised in a new
  Placeholders.emptyValue constant (replaces inline '—' and '(unknown)').
- Route paths moved to a new Routes class, used by the router and every
  navigation call site.
- Device event type modelled as a DeviceEventType enum mirroring the backend
  (NewDevice/DeviceSeen) instead of bare string comparisons.
- Hardcoded EdgeInsets/SizedBox spacing replaced with existing Insets tokens.

Tests and formatting updated; all backend and frontend tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:07:05 -04:00
rzuasti 48d73fb207 Consolidate frontend scanner, pagination, and tick-timer duplication
Collapse the five scanner status models into two shared shapes,
ActiveScannerStatus and PassiveScannerStatus, mirroring the backend's
active/passive vocabulary. Replace the five near-identical per-scanner
detail card files with a single scanner_status_cards.dart (two shared
resolvers plus a config list), and rebuild the combined home card to
iterate a list of scanners with two shape resolvers instead of five
copy-pasted resolve methods.

Extract two reusable mixins:
- PeriodicRebuild: the shared once-a-second "rebuild to refresh elapsed
  text" timer used by the scanner cards and the stale indicator.
- PaginatedListState: the shared pagination state, page-size/page-count
  getters, cancel-token-aware fetch orchestration, and disposal used by
  the device and notification lists.

No behaviour change; ~900 lines removed. Tests and analyzer pass.
2026-06-05 21:57:58 -04:00
rzuastiandClaude Opus 4.8 98b5fa267f Add automated test suite for the Flutter frontend
Introduce a headless `flutter test` suite (83 tests) covering models,
utilities, every API endpoint, and the five screens, with shared helpers
and fixtures so new tests stay terse.

API endpoint methods are statically-dispatched extensions on the
BackendAPI singleton, so they cannot be mocked via `implements`. Mock at
the Dio HTTP-adapter layer (http_mock_adapter) instead, enabled by two
small @visibleForTesting seams: BackendAPI.dioForTesting swaps the
singleton's Dio, and BackendReachability.forceOnlineForTesting() forces a
deterministic online state so polling widgets load.

Add frontend/run_tests.sh and document it in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:41:52 -04:00