Add distinct expanded (big) notification layouts with visual battery
progress bars for dual pods, single pods, and unknown devices.
Collapsed views remain unchanged. Status icon containers use fixed
width to ensure uniform progress bar lengths across rows.
The widget configuration activity used enableEdgeToEdge() but never synced the Android window background with the Compose Material theme. When the system dark/light mode disagreed with the app's theme setting, text became invisible (dark on dark). Also extend the bottom bar Surface under the navigation bar to eliminate the white gap.
- Add CasePopUp as screenshot 3 (popup shown on case open)
- Reorder: WidgetConfiguration moves to 4, app screens follow at 5-8
- Add Widget Configuration screen title heading
- Fix appearance card reset button to always wrap below title
- Balance padding on requires-Pro notice in widget config bottom bar
Monitor mode and scanner mode are functional settings, not appearance
settings. Give them their own "Monitoring" category header and place
them at the top of the general settings screen.
When two popup triggers fire in rapid succession (e.g. connection + case open),
the overlay is now updated via Compose MutableState rather than torn down and
recreated, eliminating the visual flicker.
Add card-based section grouping, animated transitions for custom mode,
animated color swatch selection, preset chip color indicators, and
Surface-based bottom bar and preview wrapper.
Use profile-based identity matching and cooldown keys so two BLE
signals for the same AirPods share one cooldown timer. Revert
connection monitor to show-once-per-connection behavior.
Navigation 3 doesn't auto-populate SavedStateHandle from NavKey args
like Navigation 2.x did. Pass profileId explicitly from the entry
lambda through the ScreenHost to the ViewModel via initialize().
Reset initialized flag on every exit path so re-entering a profile
reloads fresh data from the repository.
In create mode, the init block pre-filled _currentState with a default
name but left _initialState empty. The hasUnsavedChanges() check saw
the non-blank name as a change, triggering the dialog on back press
even without user edits.
Set _initialState to match _currentState defaults in create mode and
unify the comparison logic to always use current != initial.
Navigation 3 doesn't auto-populate SavedStateHandle from NavKey args
like Navigation 2.x did. Pass profileId explicitly from the entry
lambda through the ScreenHost to the ViewModel via initialize().
Reset initialized flag on every exit path so re-entering a profile
reloads fresh data from the repository.
In create mode, the init block pre-filled _currentState with a default
name but left _initialState empty. The hasUnsavedChanges() check saw
the non-blank name as a change, triggering the dialog on back press
even without user edits.
Set _initialState to match _currentState defaults in create mode and
unify the comparison logic to always use current != initial.
Delete dead XML layouts, unused drawable icons, the orphaned
RecyclerView adapter infrastructure, and Fragment-specific
extension functions left behind by the Compose migration.
Add user-facing theme preferences with three independent axes:
- Theme mode (System/Dark/Light)
- Theme style (Default/Material You/Medium Contrast/High Contrast)
- Theme color (Blue/Green/Amber)
Includes safe Moshi enum fallback for corrupted preference values,
color palettes for all combinations, and window background sync
to prevent flash during navigation transitions.
Add @Preview2 multi-preview annotation (light/dark), mock data provider
with realistic device scenarios, and ~45 preview functions across cards,
screens, popup, and settings components.
Check onboarding state in MainActivity before creating the NavBackStack,
so the correct screen is shown from the first frame. Removes the
redundant async check from OverviewViewModel that caused the dashboard
to briefly flash before redirecting to onboarding on fresh installs.
Switch all Compose screens from Icons.Default/Filled and painterResource
drawable references to Icons.TwoTone for a consistent two-tone icon style.
Delete 24 drawable XML files that are no longer referenced.
Replace shared NotificationCompat.Builder + Mutex with a stateless
design where each method builds a fresh notification. Introduces a
baseBuilder() helper to deduplicate common setup. Removes builderLock
and suspend modifiers from getNotification/getNotificationConnected.
Add promoteToForeground() helper that catches ForegroundServiceStartNotAllowedException
(Android 12+) and SecurityException, allowing graceful service exit instead of crashing.
Always show signal quality when available instead of gating on debug
mode. Position icon + percentage text in the top-right corner of the
card, aligned with the title. Remove unused DebugSettings dependency.
Replace vector silhouette placeholders with actual product photo PNGs
for 14 device families across 5 DPI buckets. Fix drawable naming prefix
(devic_ -> device_), add per-model icon overrides for popup left/right/case
views, disable image tinting for color PNGs, fix inverted signal visibility
logic, and use monochrome icon for notification small icon.
Add missing test cases for single-pod one-pod-mode pause direction,
EarDetectionState single-pod properties, and normal-mode steady-state.
Fix stale test comments that incorrectly claimed tests would fail.
Clarify onePodMode flow combine pattern and isWorn field semantics.
Fix edge case where removing a pod while both were in ears didn't trigger pause in one-pod mode. The aggregate boolean (isEitherPodInEar) stayed true, masking the individual pod removal.
See thread by `ZV`:
https://discord.com/channels/548521543039189022/1437499888068726814
Add color presets, custom color picker, transparency slider, and device
label toggle to the widget configuration screen. Widget preview updates
in real-time. Use profile label as device name in both preview and
actual widget.
Updated fastlane (2.232.1), aws-sdk, and google-cloud gems. Added several standard library shims (csv, logger, mutex_m, etc.) to support newer Ruby environments.