fix(widgets): deep-link, socket refresh, lock-screen families, dark-mode snapshots (#248–#251) - #360
Open
Blak-Codes wants to merge 1 commit into
Conversation
…ode snapshots (ethos-protocol#248–ethos-protocol#251) ethos-protocol#248 – Widget tap deep-links to the correct vault detail - TTLWidget.swift: extract vaultDeepLink(for:) helper that returns nil for an empty vaultID (vault deleted / no active vault), letting WidgetKit fall back to the app's default route (vault list) instead of navigating to a dead URL. - Each accessory view (.systemSmall, .accessoryRectangular, .accessoryCircular) calls widgetURL(vaultDeepLink(for:)) with the displayed vault's ID. - Tests: TTLWidgetDeepLinkTests covers correct URL, per-vault uniqueness, nil-on-empty-ID fallback, and scheme/path component assertions. ethos-protocol#249 – Immediate widget refresh on WebSocket vault_updated - iOS: VaultStore.subscribeToEvents now calls widgetReloader("TTLWidget") on every .vaultUpdated event. widgetReloader defaults to WidgetCenter.shared.reloadTimelines(ofKind:) but is injectable for unit tests. - Android: VaultViewModel.subscribeToEvents now calls VaultStatusWidget.saveVaultData + VaultWidgetUpdateWorker.schedule(context, 0) on each vault_updated event, triggering an immediate worker run. - Tests: TTLWidgetReloadOnVaultUpdatedTests (iOS), VaultWidgetRefreshOnSocketEventTest (Android) assert reload fires, data is saved before reschedule, non-update events are ignored, and multiple events each trigger an independent reschedule. ethos-protocol#250 – Lock Screen / StandBy widget families for iOS - TTLWidget.swift: add TTLAccessoryRectangularView (vault name + TTL countdown, no balance data) and TTLAccessoryCircularView (icon + short duration, no name). - TTLWidgetEntryView dispatcher routes .accessoryRectangular/.accessoryCircular to the compact views; all other families continue to use TTLWidgetView. - Tests: TTLWidgetAccessoryViewTests asserts both compact views build without crashing across normal / expiring-soon / nil-TTL states. ethos-protocol#251 – Dark-mode widget snapshot tests - iOS: TTLWidgetSnapshotTests covers all three widget families in both light and dark appearances, plus nil-TTL and expiring-soon states. - Android: WidgetScreenshotDarkTest (Paparazzi, NightMode.NIGHT) snapshots normal, expiring-soon, and unavailable widget states; WidgetScreenshotLightTest adds the light-mode baseline for dark/light comparison in CI.
|
@Blak-Codes Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves #248, #249, #250, #251 — all four widget improvements in a single branch.
closes #248 — Widget tap deep-links to the correct vault detail
Problem: The widget's tap target opened the app without carrying the vault's ID, landing users on the vault list instead of the specific vault displayed by the widget.
Fix:
vaultDeepLink(for:)helper inTTLWidget.swiftthat returnsnilwhenvaultIDis empty (vault deleted / no active vault), so WidgetKit falls back to the app's default route (vault list) rather than opening a dead URL..systemSmall,.accessoryRectangular,.accessoryCircular) calls.widgetURL(vaultDeepLink(for:))with the displayed vault's ID.VaultStatusWidget.deepLinkUri+FLAG_ACTIVITY_NEW_TASK); tests were already present.Tests added:
TTLWidgetDeepLinkTests— correct URL scheme/path, per-vault uniqueness, nil-on-empty-ID fallback edge case.closes #249 — Immediate widget refresh on WebSocket
vault_updatedProblem: Widgets waited for their next scheduled poll (up to 15 min) even when the foregrounded app received a
vault_updatedevent via its WebSocket connection.Fix:
VaultStore.subscribeToEventsnow callswidgetReloader("TTLWidget")on every.vaultUpdatedevent.widgetReloaderdefaults toWidgetCenter.shared.reloadTimelines(ofKind:)but is injectable for unit tests (no realWidgetCenterin SPM tests).VaultViewModel.subscribeToEventsnow callsVaultStatusWidget.saveVaultDatawith the updated vault's values, thenVaultWidgetUpdateWorker.schedule(context, intervalMinutes = 0)to trigger an immediate worker run. The existingREPLACEwork policy means rapid events coalesce to a single run.Tests added:
TTLWidgetReloadOnVaultUpdatedTests— reload fires onvault_updated, fires for any subscribed vault, non-update events are ignored.VaultWidgetRefreshOnSocketEventTest—schedule(0)is called, data is saved before reschedule, null-vault events are ignored, three rapid events each trigger their own reschedule.closes #250 — Lock Screen / StandBy widget families for iOS
Problem:
TTLWidgetdeclared.accessoryRectangular/.accessoryCircularinsupportedFamiliesbut rendered the full home-screen view for those families — no compact layout, no balance-data guard.Fix:
TTLAccessoryRectangularView: vault name + TTL countdown, no balance data,.containerBackground(.clear).TTLAccessoryCircularView: lock icon + short duration (2d/4h), no vault name, no balance.TTLWidgetEntryViewdispatcher that routes on@Environment(\.widgetFamily); home-screen families continue to use the existingTTLWidgetView.Tests added:
TTLWidgetAccessoryViewTests— both compact views build without crashing for normal, expiring-soon, and nil-TTL states.closes #251 — Dark-mode widget snapshot tests (both platforms)
Problem: Dark-mode rendering for widgets was not snapshot-tested, unlike in-app screens (covered by
ScreenshotDarkTest).Fix:
TTLWidgetSnapshotTests— covers all three widget families in both light and dark appearances, plus nil-TTL and expiring-soon states. Uses the same_ = view.bodypattern as the rest of the SPM test suite (noSnapshotTestingdependency yet); see comments in the file for how to upgrade to PNG baselines.WidgetScreenshotDarkTest(Paparazzi,NightMode.NIGHT) — snapshots normal, expiring-soon, and unavailable widget states.WidgetScreenshotLightTestprovides the light-mode baseline for dark/light comparison in CI. Both follow the exact same Paparazzi@Rulepattern asScreenshotDarkTest/ScreenshotLightTest.Files changed
ios/…/Sources/Widget/TTLWidget.swiftios/…/Sources/ViewModels/Stores.swiftwidgetReloaderseam + call onvault_updatedandroid/…/ui/ViewModels.ktsaveVaultData+schedule(0)onvault_updatedios/…/Tests/TTLWidgetTests.swiftandroid/…/VaultWidgetRefreshOnSocketEventTest.ktandroid/…/WidgetScreenshotTest.ktTesting
swift test— all existing tests pass; newTTLWidgetTestssuite added../gradlew test— newVaultWidgetRefreshOnSocketEventTestandWidgetScreenshotTestsuites added. Run./gradlew recordPaparazziDebugonce to commit the snapshot baselines.