Skip to content

fix(ios): widget status derives from the issue list; readable light-mode green (#73, #74)#75

Merged
psimaker merged 1 commit into
mainfrom
fix/issue-73-74-widget-status-contrast
Jul 7, 2026
Merged

fix(ios): widget status derives from the issue list; readable light-mode green (#73, #74)#75
psimaker merged 1 commit into
mainfrom
fix/issue-73-74-widget-status-contrast

Conversation

@psimaker

@psimaker psimaker commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Ships in the not-yet-archived 1.8.0 (build 33 unchanged, never uploaded).

#73: the widget snapshot only knew idle/syncing/error, so a parked share or
a required peer offline beyond its grace period left a green "All Synced"
on the home screen - the same lie-class #66 fixed for the in-app header.
The snapshot tier now comes from SyncHeaderModel.deriveWidgetStatus: the
header's own cascade (decision 012) with the vault-setup tiers pinned
"armed", fed by the same unresolvedIssues list plus the freshly polled
folder statuses (they arrive before folderStatuses is published). The
private WidgetSnapshotStatus enum is gone; the snapshot persists
SyncStatus.wireValue. Wire compatibility holds both ways: a stale "idle"
snapshot still decodes to synced, and fromWire maps anything unknown to
attention, so no combination can decode into a false green. Two visible
tier changes, both deliberate and matching the header: folder errors now
show amber "Needs Attention" (was red "Sync Error"), and a snapshot
written while the engine is down shows "Starting" (was green idle). The
new suite pins every tier, asserts widget == header across the full input
matrix, and round-trips the wire encoding.

#74: light-mode statusSuccess measured 3.38:1 on white (WCAG wants 4.5:1
for text) and colors the "N of M devices connected" line; now (26,120,78)
= 5.47:1, with the Increase Contrast variant deepened to (17,95,60) =
7.70:1 so it still increases contrast over the darker base. Dark mode
unchanged. Same class and remedy as #68's amber.

No strings added (the widget's "Needs Attention" labels shipped with #66).
No Go changes - the earlier-1.8.0 xcframework rebuild note still applies
before archiving.

Verified: full Xcode test plan green (iPhone 17 Pro simulator, 237/237
incl. the new #73 suite), design-token lint green, Localizable key counts
identical (632 x 4 app, 16 x 4 widget), WCAG ratios computed for old and
new values.

Fixes #73
Fixes #74

This PR fixes two iOS issues in the widget:

  • The widget now derives its sync status from the same unresolved-issue and folder-state logic used by the in-app header, so it no longer shows a false green “All Synced” state when there are warnings, unreachable folders, or other unresolved sync problems. The widget snapshot format now persists SyncStatus.wireValue and keeps older snapshots fail-safe.
  • The light-mode statusSuccess color used for the widget’s device-count text was darkened to meet WCAG contrast requirements, with the Increase Contrast variant updated as well. Dark mode is unchanged.

No privacy/security or background-execution behavior changed. Test coverage was added for widget status precedence and wire-value round trips, and the Xcode test plan, design-token lint, and localization checks passed.

…ode green (#73, #74)

Ships in the not-yet-archived 1.8.0 (build 33 unchanged, never uploaded).

#73: the widget snapshot only knew idle/syncing/error, so a parked share or
a required peer offline beyond its grace period left a green "All Synced"
on the home screen - the same lie-class #66 fixed for the in-app header.
The snapshot tier now comes from SyncHeaderModel.deriveWidgetStatus: the
header's own cascade (decision 012) with the vault-setup tiers pinned
"armed", fed by the same unresolvedIssues list plus the freshly polled
folder statuses (they arrive before folderStatuses is published). The
private WidgetSnapshotStatus enum is gone; the snapshot persists
SyncStatus.wireValue. Wire compatibility holds both ways: a stale "idle"
snapshot still decodes to synced, and fromWire maps anything unknown to
attention, so no combination can decode into a false green. Two visible
tier changes, both deliberate and matching the header: folder errors now
show amber "Needs Attention" (was red "Sync Error"), and a snapshot
written while the engine is down shows "Starting" (was green idle). The
new suite pins every tier, asserts widget == header across the full input
matrix, and round-trips the wire encoding.

#74: light-mode statusSuccess measured 3.38:1 on white (WCAG wants 4.5:1
for text) and colors the "N of M devices connected" line; now (26,120,78)
= 5.47:1, with the Increase Contrast variant deepened to (17,95,60) =
7.70:1 so it still increases contrast over the darker base. Dark mode
unchanged. Same class and remedy as #68's amber.

No strings added (the widget's "Needs Attention" labels shipped with #66).
No Go changes - the earlier-1.8.0 xcframework rebuild note still applies
before archiving.

Verified: full Xcode test plan green (iPhone 17 Pro simulator, 237/237
incl. the new #73 suite), design-token lint green, Localizable key counts
identical (632 x 4 app, 16 x 4 widget), WCAG ratios computed for old and
new values.

Fixes #73
Fixes #74
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c46192b8-f182-400e-86f0-2451f7989f20

📥 Commits

Reviewing files that changed from the base of the PR and between 39f6ddc and f650d0e.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Go Tests
⚠️ CI failures not shown inline (2)

GitHub Actions: Security / 0_Go Lint.txt: fix(ios): widget status derives from the issue list; readable light-mode green (#73, #74)

Conclusion: failure

View job details

##[group]Run unformatted="$(gofmt -l go/bridge notify)"
 �[36;1munformatted="$(gofmt -l go/bridge notify)"�[0m
 �[36;1mif [ -n "$unformatted" ]; then�[0m
 �[36;1m  echo "::error::These files need gofmt:"�[0m

GitHub Actions: Security / Go Lint: fix(ios): widget status derives from the issue list; readable light-mode green (#73, #74)

Conclusion: failure

View job details

##[group]Run unformatted="$(gofmt -l go/bridge notify)"
 �[36;1munformatted="$(gofmt -l go/bridge notify)"�[0m
 �[36;1mif [ -n "$unformatted" ]; then�[0m
 �[36;1m  echo "::error::These files need gofmt:"�[0m
🧰 Additional context used
📓 Path-based instructions (7)
**/*.swift

📄 CodeRabbit inference engine (Custom checks)

For Swift background execution changes, pass if work is bounded, cancellation-aware, handles expiration callbacks, and records errors without leaking private vault data. Fail only when background work can continue unbounded, miss cleanup, or violate iOS background execution constraints.

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
ios/**/*.swift

📄 CodeRabbit inference engine (README.md)

ios/**/*.swift: Use Swift 6 and SwiftUI for iOS app development
Implement VoiceOver and Dynamic Type accessibility support throughout the app
Use BGAppRefreshTask and BGContinuedProcessingTask (iOS 26+ when available) for background sync operations
Use APNs silent push notifications via Cloud Relay for server-to-iPhone wake-ups
Implement side-by-side diff resolution for Markdown file conflicts
Provide an activity timeline and diagnostics interface showing exactly what synced and when
Implement QR code pairing for Syncthing Device ID connection setup
Detect and list available Obsidian vaults automatically upon connection

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift

⚙️ CodeRabbit configuration file

ios/**/*.swift: Focus on Swift 6 strict concurrency, Sendable/MainActor correctness, Task cancellation,
retain cycles, memory pressure, SwiftUI observation state, StoreKit/APNs flows, and iOS background execution limits.
Pay special attention to BGAppRefreshTask and BGContinuedProcessingTask behavior, expiration handling,
bounded work, and cleanup when the app is suspended or terminated.

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
ios/**/*.{swift,pbxproj}

📄 CodeRabbit inference engine (README.md)

Target iOS / iPadOS 18 or later as the minimum deployment target

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
ios/**/*.{swift,strings,stringsdict}

📄 CodeRabbit inference engine (README.md)

Support localization in English, German, Spanish, and Simplified Chinese

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
**

⚙️ CodeRabbit configuration file

**:

VaultSync

VaultSync

Self-hosted Obsidian vault sync for iPhone and iPad.

Your notes sync peer-to-peer over Syncthing, straight into Obsidian's iOS sandbox — no note cloud, no account, no tracking.

Download on the App Store



Stars
License: MPL-2.0
iOS 18+
CI

VaultSync welcome screen VaultSync home screen

🔭 Why VaultSync

  • Peer-to-peer & private — syncs directly between your own devices over Syncthing. No note cloud, no account, no tracking.
  • Lands in Obsidian — files sync into Obsidian's iOS sandbox, where the app already looks for them.
  • Pair by QR, resolve conflicts — connect your server in seconds; settle Markdown conflicts with side-by-side diffs.
  • Server changes wake your iPhone — optional Cloud Relay nudges the app the moment your server updates, so incoming notes land eve...

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • CHANGELOG.md
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
**/*

⚙️ CodeRabbit configuration file

**/*: VaultSync syncs private Obsidian notes through Syncthing. Treat data loss,
privacy leaks, security regressions, and broken sync behavior as high priority.
Do not nitpick formatting unless it affects maintainability, correctness, or public API clarity.
Flag any accidental logging, telemetry, crash reporting, or network transfer of note contents,
vault paths, filenames with private context, API keys, APNs tokens, relay keys, or security-scoped bookmark data.

Files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • CHANGELOG.md
  • ios/VaultSync/Services/SyncthingManager.swift
  • ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: Review public documentation for technical accuracy, privacy/security claims, App Store-facing wording,
setup correctness, and consistency with the free app plus optional Cloud Relay subscription model.

Files:

  • CHANGELOG.md
🧠 Learnings (1)
📚 Learning: 2026-06-10T18:47:10.724Z
Learnt from: psimaker
Repo: psimaker/vaultsync PR: 38
File: ios/VaultSync/Views/ContentView.swift:605-611
Timestamp: 2026-06-10T18:47:10.724Z
Learning: In the SwiftUI codebase under ios/VaultSync, do not flag missing localization for SwiftUI string literals used as Text("…") or DisclosureGroup("…") titles/labels. In SwiftUI, these string literals are treated as LocalizedStringKey and resolve via the app’s Localizable.strings automatically—so they only need attention if the corresponding key is actually missing. Only require an explicit localization helper (e.g., L10n.tr(…)) when the string is not being passed through SwiftUI’s LocalizedStringKey path (e.g., plain String values provided to non-SwiftUI APIs).

Applied to files:

  • ios/VaultSync/ViewModels/SyncHeaderModel.swift
  • ios/VaultSync/Resources/Theme.swift
  • ios/VaultSync/Services/SyncthingManager.swift
🔇 Additional comments (6)
ios/VaultSync/Resources/Theme.swift (1)

149-158: LGTM!

ios/VaultSync/ViewModels/SyncHeaderModel.swift (1)

82-109: LGTM!

ios/VaultSync/Services/SyncthingManager.swift (2)

1860-1871: LGTM!


1873-1913: LGTM!

ios/VaultSyncTests/WidgetSnapshotStatusTests.swift (1)

1-123: LGTM!

CHANGELOG.md (1)

24-26: LGTM!


📝 Walkthrough

Walkthrough

This PR refactors the iOS widget's sync status computation to derive from the shared issue-severity model instead of a separate idle/syncing/error enum, adds a SyncHeaderModel helper for widget status derivation, adjusts the statusSuccess theme color for light-mode contrast, adds tests, and updates the changelog.

Changes

Widget status derivation fix

Layer / File(s) Summary
SyncHeaderModel widget status helper
ios/VaultSync/ViewModels/SyncHeaderModel.swift
Adds deriveWidgetStatus(...) mapping widget inputs to the existing header precedence cascade, hard-coding vault-related fields.
SyncthingManager widget snapshot refactor
ios/VaultSync/Services/SyncthingManager.swift
Removes WidgetSnapshotStatus enum; derives SyncStatus from issue severities, engine/user errors, unreachable folders, and syncing state; persists via wireValue.
Widget status test coverage
ios/VaultSyncTests/WidgetSnapshotStatusTests.swift
New test suite covering tier precedence, syncing precedence, clean/non-running states, an exhaustive input matrix, and wire-value round-trip.
Changelog entry
CHANGELOG.md
Documents the widget status fix (no more misleading green check).

statusSuccess light-mode color fix

Layer / File(s) Summary
statusSuccess RGB values
ios/VaultSync/Resources/Theme.swift
Updates light and lightHC RGB values for statusSuccess for better contrast; dark values unchanged.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Poem

A widget once winked green, all clear,
while a peer sat offline, out of ear.
Now it checks the issue list too,
and paints its greens a darker hue.
🐰 No more false calm — status is true!

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise, conventional-commit style, and accurately summarizes the widget status and light-mode green fixes.
Linked Issues check ✅ Passed The PR satisfies #73 by deriving widget status from the issue list and #74 by darkening statusSuccess in light mode.
Out of Scope Changes check ✅ Passed The changes stay within the two linked fixes, with only related tests and changelog updates added.
No Private Note Leakage ✅ Passed The new widget snapshot only stores status, counts, and timestamps; the derivation reduces issues to severities/booleans and adds no sensitive logging or network paths.
Bounded Ios Background Work ✅ Passed No background-execution logic changed; this commit only updates widget status derivation, colors, and tests, so the background-work constraints aren’t implicated.
Bridge Contract Compatibility ✅ Passed Only widget/status UI logic changed; no Go bridge or SyncBridgeService API/JSON/empty-string conventions changed, and wire decoding still fails safe.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-73-74-widget-status-contrast

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@psimaker psimaker merged commit 7290afc into main Jul 7, 2026
14 checks passed
@psimaker psimaker deleted the fix/issue-73-74-widget-status-contrast branch July 7, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant