Adjust rest time from the watch with the same 1-second stepper
A gear on the watch root opens a small Settings sheet whose stepper edits the shared restSeconds default (10-180s, 1s steps). Edits ride a new settingsUpdate message to the phone - debounced per stepper burst, falling back to transferUserInfo when unreachable - which clamps the value, writes the shared default, and re-echoes it to every device through the application context. While an edit is pending on the watch, an in-flight context's stale rest value is skipped so it can't yank the stepper back mid-edit.
This commit is contained in:
@@ -288,8 +288,47 @@ final class WatchConnectivityBridge: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Settings edits (watch → phone)
|
||||
|
||||
/// Debounces the stepper's tick-per-second bursts into one settings message.
|
||||
private var settingsSendTask: Task<Void, Never>?
|
||||
|
||||
/// Forward a rest-time change to the phone, which owns the durable value and echoes
|
||||
/// it back through the application context. The local default was already written by
|
||||
/// the setting's `@AppStorage`; debounced so holding the stepper sends once, and the
|
||||
/// send falls back to `transferUserInfo` so the change survives the phone being
|
||||
/// unreachable right now.
|
||||
func sendRestSeconds(_ seconds: Int) {
|
||||
settingsSendTask?.cancel()
|
||||
settingsSendTask = Task { [weak self] in
|
||||
try? await Task.sleep(for: .seconds(0.6))
|
||||
guard let self, !Task.isCancelled else { return }
|
||||
self.settingsSendTask = nil
|
||||
self.pushSettingsUpdate(restSeconds: seconds)
|
||||
}
|
||||
}
|
||||
|
||||
private func pushSettingsUpdate(restSeconds: Int) {
|
||||
guard let session, session.activationState == .activated else { return }
|
||||
let payload = WCPayload.encodeSettingsUpdate(restSeconds: restSeconds)
|
||||
if session.isReachable {
|
||||
// Re-encode in the fallback rather than capturing the non-Sendable payload
|
||||
// (the error handler runs on WatchConnectivity's background queue).
|
||||
session.sendMessage(payload, replyHandler: nil, errorHandler: { @Sendable [weak self] _ in
|
||||
Task { @MainActor in
|
||||
_ = self?.session?.transferUserInfo(WCPayload.encodeSettingsUpdate(restSeconds: restSeconds))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
session.transferUserInfo(payload)
|
||||
}
|
||||
}
|
||||
|
||||
private func applySettings(_ dict: [String: Any]) {
|
||||
if let rest = WCPayload.decodeRestSeconds(dict) {
|
||||
// Skip the context's rest value while a local edit is still waiting to be sent —
|
||||
// a concurrent push (triggered by anything) would carry the pre-edit value and
|
||||
// yank the stepper back mid-edit. The phone echoes our value right after it lands.
|
||||
if let rest = WCPayload.decodeRestSeconds(dict), settingsSendTask == nil {
|
||||
UserDefaults.standard.set(rest, forKey: WCPayload.restSecondsKey)
|
||||
}
|
||||
if let done = WCPayload.decodeDoneCountdownSeconds(dict) {
|
||||
|
||||
Reference in New Issue
Block a user