From 1f7f7c382d89e89e826f401a11b177a636f3e7b8 Mon Sep 17 00:00:00 2001 From: donny-son Date: Sat, 7 Mar 2026 20:05:17 -0800 Subject: [PATCH 01/11] v1.7: remove gesture control(wrist flick) since it is not 100% production reliable. Instead implemented double tap feature to go to next slide --- CLAUDE.md | 3 +- MacApp/Info.plist | 2 +- WatchApp/ClickerWatchApp.swift | 20 +--- WatchApp/ContentView.swift | 119 ++++--------------- WatchApp/GestureManager.swift | 205 --------------------------------- WatchApp/Info.plist | 6 +- WatchApp/SettingsView.swift | 43 +------ index.html | 2 +- project.yml | 8 +- 9 files changed, 41 insertions(+), 367 deletions(-) delete mode 100644 WatchApp/GestureManager.swift diff --git a/CLAUDE.md b/CLAUDE.md index 42b579e..e88a0a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ This is a SwiftUI-based presentation remote system with three apps: - **Mac App** (`ClickerRemoteReceiver` v1.2): Menu bar app that receives commands and sends keystrokes to presentation software - **iPhone App** (`ClickerRemote` v1.6): Remote control with vertical slide navigation and presentation timer -- **Apple Watch App** (`ClickerWatch` v1.6): Companion watch app with gesture-based slide control using wrist flicks +- **Apple Watch App** (`ClickerWatch` v1.6): Companion watch app with gesture-based slide control using double tap motion for next slide ## Tech Stack @@ -129,6 +129,7 @@ Team ID: `HD35YQ72U4` (DOU Inc.) 1. Edit Swift source files directly 2. If changing build settings, targets, or Info.plist keys, edit `project.yml` 3. Run `just generate` after modifying `project.yml` to regenerate the Xcode project + - Note that this overrides the version information. ## Useful Debugging Commands diff --git a/MacApp/Info.plist b/MacApp/Info.plist index 098422a..0ed3991 100644 --- a/MacApp/Info.plist +++ b/MacApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2 + 1.7 CFBundleVersion 1 LSUIElement diff --git a/WatchApp/ClickerWatchApp.swift b/WatchApp/ClickerWatchApp.swift index 4fd8a36..354b365 100644 --- a/WatchApp/ClickerWatchApp.swift +++ b/WatchApp/ClickerWatchApp.swift @@ -5,7 +5,6 @@ import HealthKit struct ClickerWatchApp: App { @StateObject private var connectionManager = WatchConnectionManager() @StateObject private var sessionManager = ExtendedSessionManager() - @StateObject private var gestureManager = GestureManager() @StateObject private var workoutManager = WorkoutManager() @Environment(\.scenePhase) var scenePhase @@ -14,10 +13,8 @@ struct ClickerWatchApp: App { ContentView() .environmentObject(connectionManager) .environmentObject(sessionManager) - .environmentObject(gestureManager) .environmentObject(workoutManager) .onAppear { - wireGestureCallbacks() workoutManager.start() } .onChange(of: scenePhase) { _, phase in @@ -25,15 +22,9 @@ struct ClickerWatchApp: App { case .active: sessionManager.start() workoutManager.start() - if gestureManager.autoToggleWithWrist { - gestureManager.start() - } case .inactive: - if gestureManager.autoToggleWithWrist { - gestureManager.stop() - } + break case .background: - // User explicitly navigated away — stop workout to save battery workoutManager.stop() @unknown default: break @@ -41,13 +32,4 @@ struct ClickerWatchApp: App { } } } - - private func wireGestureCallbacks() { - gestureManager.onNextSlide = { [weak connectionManager] in - connectionManager?.nextSlide() - } - gestureManager.onPreviousSlide = { [weak connectionManager] in - connectionManager?.previousSlide() - } - } } diff --git a/WatchApp/ContentView.swift b/WatchApp/ContentView.swift index 547a548..0dc7600 100644 --- a/WatchApp/ContentView.swift +++ b/WatchApp/ContentView.swift @@ -3,7 +3,6 @@ import WatchKit struct ContentView: View { @EnvironmentObject var connectionManager: WatchConnectionManager - @EnvironmentObject var gestureManager: GestureManager @Environment(\.isLuminanceReduced) var isLuminanceReduced @State private var timerStartDate: Date? @State private var accumulatedTime: TimeInterval = 0 @@ -27,78 +26,43 @@ struct ContentView: View { var body: some View { TimelineView(.periodic(from: .now, by: 1.0)) { context in GeometryReader { geometry in - VStack(spacing: 6) { - // Previous slide button + VStack(spacing: 2) { Button(action: { - WKInterfaceDevice.current().play(.directionDown) - connectionManager.previousSlide() + WKInterfaceDevice.current().play(.directionUp) + connectionManager.nextSlide() }) { - ZStack { - Image(systemName: "chevron.left") - .font(.system(size: 32, weight: .bold)) - - if gestureManager.lastGesture == .previous { - Image(systemName: gestureManager.isLocked ? "lock.fill" : "hand.wave.fill") - .font(.system(size: 16)) - .foregroundColor(.yellow) - .opacity(gestureManager.gestureLockEnabled ? gestureManager.lockProgress : 1.0) - .offset(x: 40, y: -10) - .transition(.opacity) - } - } - .frame(maxWidth: .infinity) - .frame(height: geometry.size.height * 0.30) - .background( - gestureManager.lastGesture == .previous - ? Color.yellow.opacity(gestureManager.gestureLockEnabled ? 0.3 * gestureManager.lockProgress : 0.3) - : Color.blue.opacity(isLuminanceReduced ? 0.1 : 0.3) - ) - .clipShape(RoundedRectangle(cornerRadius: 12)) - .animation(.easeOut(duration: 0.2), value: gestureManager.lastGesture) - .animation(.linear(duration: 0.05), value: gestureManager.lockProgress) + Image(systemName: "chevron.right") + .font(.system(size: 32, weight: .bold)) + .frame(width: geometry.size.width * 0.45, height: geometry.size.width * 0.45) + .background(Color.blue.opacity(isLuminanceReduced ? 0.15 : 0.35)) + .clipShape(Circle()) } .buttonStyle(.plain) + .modifier(PrimaryGestureShortcut()) - // Timer + gesture toggle + settings row - HStack(spacing: 4) { - // Gesture toggle — tap or hardware double-tap to toggle - Button { - gestureManager.toggle() - WKInterfaceDevice.current().play(gestureManager.isEnabled ? .stop : .start) - } label: { - ZStack { - Image(systemName: gestureManager.isEnabled ? "hand.wave.fill" : "hand.wave") - .font(.system(size: 14, weight: .medium)) - .foregroundColor(gestureManager.isEnabled ? .yellow : .secondary) - - if gestureManager.isLocked { - Image(systemName: "lock.fill") - .font(.system(size: 8, weight: .bold)) - .foregroundColor(.orange) - .offset(x: 8, y: -8) - } - } - .frame(width: 30, height: 30) - .background( - gestureManager.isLocked - ? Color.orange.opacity(0.2 * gestureManager.lockProgress) - : gestureManager.isEnabled - ? Color.yellow.opacity(0.15) - : Color.white.opacity(0.08) - ) - .clipShape(Circle()) - .animation(.easeOut(duration: 0.2), value: gestureManager.isEnabled) - .animation(.linear(duration: 0.05), value: gestureManager.lockProgress) + Spacer() + + // Bottom row: Previous, Timer, Settings + HStack(spacing: 8) { + // Previous slide — small circular button + Button(action: { + WKInterfaceDevice.current().play(.directionDown) + connectionManager.previousSlide() + }) { + Image(systemName: "chevron.left") + .font(.system(size: 16, weight: .bold)) + .frame(width: 36, height: 36) + .background(Color.blue.opacity(isLuminanceReduced ? 0.1 : 0.25)) + .clipShape(Circle()) } .buttonStyle(.plain) - .modifier(PrimaryGestureShortcut()) Spacer() // Timer — tap to start/stop, long press to reset VStack(spacing: 2) { Text(formattedTime(at: context.date)) - .font(.system(size: 22, weight: .medium, design: .monospaced)) + .font(.system(size: 20, weight: .medium, design: .monospaced)) .foregroundColor(timerRunning ? .green : .white) HStack(spacing: 4) { @@ -127,7 +91,7 @@ struct ContentView: View { Image(systemName: "gearshape.fill") .font(.system(size: 14, weight: .medium)) .foregroundColor(.secondary) - .frame(width: 30, height: 30) + .frame(width: 36, height: 36) .background(Color.white.opacity(0.08)) .clipShape(Circle()) } @@ -136,40 +100,8 @@ struct ContentView: View { .sheet(isPresented: $showSettings) { NavigationStack { SettingsView() - .environmentObject(gestureManager) } } - - // Next slide button - Button(action: { - WKInterfaceDevice.current().play(.directionUp) - connectionManager.nextSlide() - }) { - ZStack { - Image(systemName: "chevron.right") - .font(.system(size: 32, weight: .bold)) - - if gestureManager.lastGesture == .next { - Image(systemName: gestureManager.isLocked ? "lock.fill" : "hand.wave.fill") - .font(.system(size: 16)) - .foregroundColor(.yellow) - .opacity(gestureManager.gestureLockEnabled ? gestureManager.lockProgress : 1.0) - .offset(x: 40, y: -10) - .transition(.opacity) - } - } - .frame(maxWidth: .infinity) - .frame(height: geometry.size.height * 0.30) - .background( - gestureManager.lastGesture == .next - ? Color.yellow.opacity(gestureManager.gestureLockEnabled ? 0.3 * gestureManager.lockProgress : 0.3) - : Color.blue.opacity(isLuminanceReduced ? 0.1 : 0.3) - ) - .clipShape(RoundedRectangle(cornerRadius: 12)) - .animation(.easeOut(duration: 0.2), value: gestureManager.lastGesture) - .animation(.linear(duration: 0.05), value: gestureManager.lockProgress) - } - .buttonStyle(.plain) } .padding(.horizontal, 4) .padding(.vertical, 4) @@ -216,5 +148,4 @@ private struct PrimaryGestureShortcut: ViewModifier { #Preview { ContentView() .environmentObject(WatchConnectionManager()) - .environmentObject(GestureManager()) } diff --git a/WatchApp/GestureManager.swift b/WatchApp/GestureManager.swift deleted file mode 100644 index 4af5cc0..0000000 --- a/WatchApp/GestureManager.swift +++ /dev/null @@ -1,205 +0,0 @@ -import Foundation -import CoreMotion -import WatchKit -import Combine - -/// Detects wrist flick gestures using CoreMotion for hands-free slide control. -/// -/// Default gesture mapping: -/// - Flick wrist forward (clockwise, away from body) → Next slide -/// - Flick wrist backward (counterclockwise, toward body) → Previous slide -/// -/// Inverted gesture mapping: -/// - Counterclockwise → Next slide -/// - Clockwise → Previous slide -/// -/// Uses the gyroscope rotation rate around the x-axis, which corresponds -/// to wrist flexion/extension — the natural "flick forward" and "pull back" motion. -class GestureManager: ObservableObject { - - // MARK: - Published State - - @Published var isEnabled = false - @Published var lastGesture: DetectedGesture? - @Published var isInverted: Bool { - didSet { UserDefaults.standard.set(isInverted, forKey: "gestureInverted") } - } - @Published var autoToggleWithWrist: Bool { - didSet { UserDefaults.standard.set(autoToggleWithWrist, forKey: "gestureAutoToggle") } - } - @Published var gestureLockEnabled: Bool { - didSet { UserDefaults.standard.set(gestureLockEnabled, forKey: "gestureLockEnabled") } - } - @Published var isLocked: Bool = false - @Published var lockProgress: CGFloat = 0.0 - - enum DetectedGesture: Equatable { - case next - case previous - } - - // MARK: - Callbacks - - var onNextSlide: (() -> Void)? - var onPreviousSlide: (() -> Void)? - - // MARK: - Configuration - - /// Minimum rotation rate (rad/s) to trigger a gesture. - /// Higher = less sensitive, fewer false positives. - private let rotationThreshold: Double = 3.0 - - /// Minimum time between gesture triggers to prevent double-fires. - private let cooldownInterval: TimeInterval = 0.8 - - /// Duration of the gesture lock period. - private let lockDuration: TimeInterval = 3.0 - - /// Motion update frequency in Hz. - private let updateFrequency: Double = 50.0 - - // MARK: - Private State - - private let motionManager = CMMotionManager() - private var lastTriggerTime: Date = .distantPast - private let motionQueue = OperationQueue() - private var lockTimer: Timer? - - // MARK: - Initialization - - init() { - self.isInverted = UserDefaults.standard.bool(forKey: "gestureInverted") - self.autoToggleWithWrist = UserDefaults.standard.bool(forKey: "gestureAutoToggle") - self.gestureLockEnabled = UserDefaults.standard.bool(forKey: "gestureLockEnabled") - motionQueue.name = "com.dou.clicker.gesture" - motionQueue.maxConcurrentOperationCount = 1 - } - - // MARK: - Start / Stop - - func start() { - guard motionManager.isDeviceMotionAvailable else { - print("⌚ Device motion not available") - return - } - guard !motionManager.isDeviceMotionActive else { return } - - motionManager.deviceMotionUpdateInterval = 1.0 / updateFrequency - - motionManager.startDeviceMotionUpdates(to: motionQueue) { [weak self] motion, error in - guard let self, let motion else { - if let error { - print("⌚ Motion error: \(error.localizedDescription)") - } - return - } - self.processMotion(motion) - } - - DispatchQueue.main.async { - self.isEnabled = true - } - print("⌚ Gesture detection started") - } - - func stop() { - motionManager.stopDeviceMotionUpdates() - DispatchQueue.main.async { - self.isEnabled = false - self.lastGesture = nil - self.lockTimer?.invalidate() - self.lockTimer = nil - self.isLocked = false - self.lockProgress = 0 - } - print("⌚ Gesture detection stopped") - } - - func toggle() { - if isEnabled { - stop() - } else { - start() - } - } - - // MARK: - Motion Processing - - private func processMotion(_ motion: CMDeviceMotion) { - // Use rotation rate around x-axis: wrist flexion (forward flick) / extension (backward flick) - let rotationX = motion.rotationRate.x - - guard abs(rotationX) > rotationThreshold else { return } - - let now = Date() - let effectiveCooldown = gestureLockEnabled ? lockDuration : cooldownInterval - guard now.timeIntervalSince(lastTriggerTime) >= effectiveCooldown else { return } - lastTriggerTime = now - - // Positive x rotation = wrist flick forward, Negative = backward - // When inverted: counterclockwise (negative) = next, clockwise (positive) = previous - let isInverted = self.isInverted - let gesture: DetectedGesture = (rotationX > 0) != isInverted ? .next : .previous - let lockEnabled = self.gestureLockEnabled - - DispatchQueue.main.async { [weak self] in - guard let self else { return } - self.lastGesture = gesture - - // Play strong directional haptic so the user clearly feels the gesture was recognized - let device = WKInterfaceDevice.current() - switch gesture { - case .next: - device.play(.directionUp) - // Follow up with a second tap after a short delay for emphasis - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - device.play(.directionUp) - } - self.onNextSlide?() - case .previous: - device.play(.directionDown) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - device.play(.directionDown) - } - self.onPreviousSlide?() - } - - if lockEnabled { - self.startLockCountdown(for: gesture) - } else { - // Clear visual indicator after a short delay - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - if self.lastGesture == gesture { - self.lastGesture = nil - } - } - } - } - } - - // MARK: - Gesture Lock - - private func startLockCountdown(for gesture: DetectedGesture) { - lockTimer?.invalidate() - isLocked = true - lockProgress = 1.0 - - let startTime = Date() - lockTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 30.0, repeats: true) { [weak self] timer in - guard let self else { - timer.invalidate() - return - } - let elapsed = Date().timeIntervalSince(startTime) - if elapsed >= self.lockDuration { - timer.invalidate() - self.lockTimer = nil - self.isLocked = false - self.lockProgress = 0 - self.lastGesture = nil - } else { - self.lockProgress = CGFloat(1.0 - elapsed / self.lockDuration) - } - } - } -} diff --git a/WatchApp/Info.plist b/WatchApp/Info.plist index 0d94e63..1181501 100644 --- a/WatchApp/Info.plist +++ b/WatchApp/Info.plist @@ -15,15 +15,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.6 + 1.7 CFBundleVersion 1 NSHealthShareUsageDescription Clicker does not read your health data. HealthKit is used solely to maintain an active workout session that keeps the app visible during presentations. NSHealthUpdateUsageDescription - Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible for reliable gesture control. - NSMotionUsageDescription - Clicker uses motion sensors to detect wrist gestures for hands-free slide control during presentations. + Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible during presentations. WKApplication WKBackgroundModes diff --git a/WatchApp/SettingsView.swift b/WatchApp/SettingsView.swift index 765cc75..911aa10 100644 --- a/WatchApp/SettingsView.swift +++ b/WatchApp/SettingsView.swift @@ -1,47 +1,17 @@ import SwiftUI struct SettingsView: View { - @EnvironmentObject var gestureManager: GestureManager - var body: some View { List { Section { - Toggle(isOn: $gestureManager.gestureLockEnabled) { - VStack(alignment: .leading, spacing: 2) { - Text("Gesture Lock") - .font(.system(size: 15)) - } - } - } footer: { - Text("After a gesture, lock out further gestures for 3 seconds to prevent accidental triggers") - .font(.system(size: 11)) - .foregroundColor(.secondary) - } - - Section { - Toggle(isOn: $gestureManager.isInverted) { - VStack(alignment: .leading, spacing: 2) { - Text("Invert Gestures") - .font(.system(size: 15)) - } - } - } footer: { - Text(gestureManager.isInverted - ? "Counterclockwise → Next\nClockwise → Previous" - : "Clockwise → Next\nCounterclockwise → Previous") - .font(.system(size: 11)) - .foregroundColor(.secondary) - } - - Section { - Toggle(isOn: $gestureManager.autoToggleWithWrist) { - VStack(alignment: .leading, spacing: 2) { - Text("Auto-toggle with Wrist") - .font(.system(size: 15)) - } + HStack { + Image(systemName: "info.circle") + .foregroundColor(.secondary) + Text("Clicker Remote v1.6") + .font(.system(size: 15)) } } footer: { - Text("Gestures enable on wrist raise and disable on wrist lower") + Text("Use the large button to advance slides. Double-tap gesture (watchOS 11+) also triggers next slide.") .font(.system(size: 11)) .foregroundColor(.secondary) } @@ -53,6 +23,5 @@ struct SettingsView: View { #Preview { NavigationStack { SettingsView() - .environmentObject(GestureManager()) } } diff --git a/index.html b/index.html index 51cfb5f..4e4aced 100644 --- a/index.html +++ b/index.html @@ -176,7 +176,7 @@

Peer-to-peer reliability

02

Cross-device gesture flow

-

Apple Watch flick gestures trigger the same RemoteCommand used by the iPhone UI, routed through WatchConnectivity with built-in lockout guards.

+

Apple Watch flick trigger the same RemoteCommand used by the iPhone UI, routed through WatchConnectivity with built-in lockout guards.

03 diff --git a/project.yml b/project.yml index efa927f..cb291e7 100644 --- a/project.yml +++ b/project.yml @@ -94,7 +94,7 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios PRODUCT_NAME: ClickerRemote IPHONEOS_DEPLOYMENT_TARGET: "18.0" - MARKETING_VERSION: "1.6" + MARKETING_VERSION: "1.7" CURRENT_PROJECT_VERSION: "1" CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: HD35YQ72U4 @@ -124,22 +124,20 @@ targets: WKCompanionAppBundleIdentifier: com.dou.clicker-ios WKBackgroundModes: - self-care - NSMotionUsageDescription: "Clicker uses motion sensors to detect wrist gestures for hands-free slide control during presentations." NSHealthShareUsageDescription: "Clicker does not read your health data. HealthKit is used solely to maintain an active workout session that keeps the app visible during presentations." - NSHealthUpdateUsageDescription: "Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible for reliable gesture control." + NSHealthUpdateUsageDescription: "Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible during presentations." entitlements: path: WatchApp/ClickerWatch.entitlements properties: com.apple.developer.healthkit: true dependencies: - - sdk: CoreMotion.framework - sdk: HealthKit.framework settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios.watchkitapp PRODUCT_NAME: ClickerWatch WATCHOS_DEPLOYMENT_TARGET: "10.0" - MARKETING_VERSION: "1.6" + MARKETING_VERSION: "1.7" CURRENT_PROJECT_VERSION: "1" CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: HD35YQ72U4 From a1d1c3dac927d35a25d3627054845e26a21e8302 Mon Sep 17 00:00:00 2001 From: donny-son Date: Sat, 7 Mar 2026 21:15:00 -0700 Subject: [PATCH 02/11] add changelog and update docs --- CHANGELOG.md | 7 +++++++ CLAUDE.md | 6 ++---- wiki/API-Reference.md | 24 ++---------------------- wiki/Feature-Ideas.md | 4 ++-- 4 files changed, 13 insertions(+), 28 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9850423 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## v1.7 + +- Removed CoreMotion wrist flick gesture detection from Apple Watch app due to unreliable production behavior +- Added double-tap gesture support (`handGestureShortcut(.primaryAction)`) for advancing slides on watchOS 11+ (Apple Watch Series 9+ / Ultra 2) +- Note: Double-tap requires the watch display to be active (wrist raised); it does not work in always-on / luminance-reduced state diff --git a/CLAUDE.md b/CLAUDE.md index e88a0a5..8cf71af 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -113,10 +113,8 @@ The `update-tap` command triggers a GitHub Action in `douinc/homebrew-tap` that: ### Apple Watch App Specifics - App name: `ClickerWatch` (embedded in iOS app, distributed via App Store) - Bundle ID: `com.dou.clicker-ios.watchkitapp` -- Gesture detection via CoreMotion (wrist flick rotation rate on x-axis) -- Gesture lock: 3-second lockout after gesture to prevent accidental triggers -- Gesture inversion: option to swap flick direction mapping -- Auto-toggle: gesture activation follows wrist raise/lower +- Double-tap gesture via `handGestureShortcut(.primaryAction)` on watchOS 11+ (Apple Watch Series 9+ / Ultra 2) for next slide +- Note: Double-tap requires active display (wrist raised); does not work in always-on / luminance-reduced state - HealthKit workout session keeps app active during presentations - Extended WatchKit session for background operation diff --git a/wiki/API-Reference.md b/wiki/API-Reference.md index acc4446..2263294 100644 --- a/wiki/API-Reference.md +++ b/wiki/API-Reference.md @@ -240,32 +240,12 @@ class WatchConnectionManager: NSObject, ObservableObject { **Retry Logic**: Commands are retried up to 3 times at 0.5s intervals if the iPhone is temporarily unreachable. -### GestureManager - -Handles CoreMotion wrist gesture detection for hands-free slide control. - -```swift -class GestureManager: ObservableObject { - @Published var isGestureEnabled: Bool - @Published var gestureLockEnabled: Bool - @Published var isInverted: Bool - @Published var autoToggleWithWrist: Bool -} -``` - -| Property | Type | Description | -|----------|------|-------------| -| `isGestureEnabled` | `Bool` | Whether gesture detection is active | -| `gestureLockEnabled` | `Bool` | 3-second lockout after gesture to prevent accidental triggers | -| `isInverted` | `Bool` | Swap flick direction mapping | -| `autoToggleWithWrist` | `Bool` | Gestures enable on wrist raise, disable on wrist lower | - ### Watch SwiftUI Views | View | Description | |------|-------------| -| `ContentView` | Previous/next buttons + timer display + gesture toggle | -| `SettingsView` | Gesture lock, inversion, and auto-toggle settings | +| `ContentView` | Next/previous buttons + timer display + double-tap gesture support | +| `SettingsView` | Watch app settings | **Timer Gestures**: - **Tap**: Start/stop timer diff --git a/wiki/Feature-Ideas.md b/wiki/Feature-Ideas.md index 429cac9..88c667c 100644 --- a/wiki/Feature-Ideas.md +++ b/wiki/Feature-Ideas.md @@ -125,7 +125,7 @@ Let users rearrange, resize, or hide buttons on the iPhone remote. Some presente Allow light mode for bright environments or custom accent colors beyond the current dark-only design. Per-user preference with quick toggle. Keep dark mode as default since it's optimized for stage visibility. ### Configurable Haptic Patterns 🟡 -Let users create custom vibration patterns for different events: slide advance, timer milestones, gesture lock, connection lost. Different intensity levels and rhythms to convey information without looking at the screen. +Let users create custom vibration patterns for different events: slide advance, timer milestones, connection lost. Different intensity levels and rhythms to convey information without looking at the screen. --- @@ -141,7 +141,7 @@ A widget in the watchOS Smart Stack showing timer and connection status at a gla Use the Digital Crown rotation to scroll through slides — rotate forward for next, backward for previous. Provides a tactile, precise alternative to wrist gestures or button taps. Configurable sensitivity and detent mapping. ### Expanded Double-Tap Gestures 🟢 -Build on the existing watchOS 11 `handGestureShortcut` support. Map double-tap to configurable actions: next slide, previous slide, start/stop timer, or toggle gesture lock. Let users choose what double-tap does in settings. +Build on the existing watchOS 11 `handGestureShortcut` support. Map double-tap to configurable actions: next slide, previous slide, or start/stop timer. Let users choose what double-tap does in settings. --- From b6b896d7184a25b03b5deba1b966b74cbf7d488d Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 04:23:27 +0900 Subject: [PATCH 03/11] remove healthkit --- CLAUDE.md | 3 +- WatchApp/ClickerWatch.entitlements | 5 +-- WatchApp/ClickerWatchApp.swift | 10 +---- WatchApp/Info.plist | 4 -- WatchApp/WorkoutManager.swift | 61 ------------------------------ iPhoneApp/Info.plist | 2 +- project.yml | 7 +--- 7 files changed, 6 insertions(+), 86 deletions(-) delete mode 100644 WatchApp/WorkoutManager.swift diff --git a/CLAUDE.md b/CLAUDE.md index 8cf71af..02805ec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -115,8 +115,7 @@ The `update-tap` command triggers a GitHub Action in `douinc/homebrew-tap` that: - Bundle ID: `com.dou.clicker-ios.watchkitapp` - Double-tap gesture via `handGestureShortcut(.primaryAction)` on watchOS 11+ (Apple Watch Series 9+ / Ultra 2) for next slide - Note: Double-tap requires active display (wrist raised); does not work in always-on / luminance-reduced state -- HealthKit workout session keeps app active during presentations -- Extended WatchKit session for background operation +- Extended WatchKit runtime session (`WKExtendedRuntimeSession` with `self-care` background mode) keeps app active during presentations ## Development Team diff --git a/WatchApp/ClickerWatch.entitlements b/WatchApp/ClickerWatch.entitlements index e10f430..0c67376 100644 --- a/WatchApp/ClickerWatch.entitlements +++ b/WatchApp/ClickerWatch.entitlements @@ -1,8 +1,5 @@ - - com.apple.developer.healthkit - - + diff --git a/WatchApp/ClickerWatchApp.swift b/WatchApp/ClickerWatchApp.swift index 354b365..1addaf0 100644 --- a/WatchApp/ClickerWatchApp.swift +++ b/WatchApp/ClickerWatchApp.swift @@ -1,11 +1,9 @@ import SwiftUI -import HealthKit @main struct ClickerWatchApp: App { @StateObject private var connectionManager = WatchConnectionManager() @StateObject private var sessionManager = ExtendedSessionManager() - @StateObject private var workoutManager = WorkoutManager() @Environment(\.scenePhase) var scenePhase var body: some Scene { @@ -13,19 +11,15 @@ struct ClickerWatchApp: App { ContentView() .environmentObject(connectionManager) .environmentObject(sessionManager) - .environmentObject(workoutManager) .onAppear { - workoutManager.start() + sessionManager.start() } .onChange(of: scenePhase) { _, phase in switch phase { case .active: sessionManager.start() - workoutManager.start() - case .inactive: + case .inactive, .background: break - case .background: - workoutManager.stop() @unknown default: break } diff --git a/WatchApp/Info.plist b/WatchApp/Info.plist index 1181501..35a88a9 100644 --- a/WatchApp/Info.plist +++ b/WatchApp/Info.plist @@ -18,10 +18,6 @@ 1.7 CFBundleVersion 1 - NSHealthShareUsageDescription - Clicker does not read your health data. HealthKit is used solely to maintain an active workout session that keeps the app visible during presentations. - NSHealthUpdateUsageDescription - Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible during presentations. WKApplication WKBackgroundModes diff --git a/WatchApp/WorkoutManager.swift b/WatchApp/WorkoutManager.swift deleted file mode 100644 index 286eaa3..0000000 --- a/WatchApp/WorkoutManager.swift +++ /dev/null @@ -1,61 +0,0 @@ -import HealthKit - -/// Manages an HKWorkoutSession to keep the app frontmost during presentations. -/// Without an active workout session, watchOS dismisses apps on wrist-down. -class WorkoutManager: NSObject, ObservableObject, HKWorkoutSessionDelegate { - private let healthStore = HKHealthStore() - private var session: HKWorkoutSession? - @Published var isActive = false - - func start() { - guard HKHealthStore.isHealthDataAvailable() else { return } - guard session == nil else { return } - - let typesToShare: Set = [HKObjectType.workoutType()] - healthStore.requestAuthorization(toShare: typesToShare, read: nil) { [weak self] success, _ in - guard success else { return } - DispatchQueue.main.async { - self?.startSession() - } - } - } - - private func startSession() { - guard session == nil else { return } - - let config = HKWorkoutConfiguration() - config.activityType = .other - config.locationType = .indoor - - do { - session = try HKWorkoutSession(healthStore: healthStore, configuration: config) - session?.delegate = self - session?.startActivity(with: Date()) - isActive = true - } catch { - print("⌚ Failed to start workout session: \(error)") - } - } - - func stop() { - session?.end() - session = nil - isActive = false - } - - // MARK: - HKWorkoutSessionDelegate - - func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) { - DispatchQueue.main.async { - self.isActive = toState == .running - } - } - - func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) { - print("⌚ Workout session error: \(error)") - DispatchQueue.main.async { - self.isActive = false - self.session = nil - } - } -} diff --git a/iPhoneApp/Info.plist b/iPhoneApp/Info.plist index 5d6c711..7bb955f 100644 --- a/iPhoneApp/Info.plist +++ b/iPhoneApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.6 + 1.7 CFBundleVersion 1 NSBonjourServices diff --git a/project.yml b/project.yml index cb291e7..f563dc6 100644 --- a/project.yml +++ b/project.yml @@ -124,14 +124,9 @@ targets: WKCompanionAppBundleIdentifier: com.dou.clicker-ios WKBackgroundModes: - self-care - NSHealthShareUsageDescription: "Clicker does not read your health data. HealthKit is used solely to maintain an active workout session that keeps the app visible during presentations." - NSHealthUpdateUsageDescription: "Clicker uses HealthKit to maintain an active session during presentations, keeping the app visible during presentations." entitlements: path: WatchApp/ClickerWatch.entitlements - properties: - com.apple.developer.healthkit: true - dependencies: - - sdk: HealthKit.framework + properties: {} settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios.watchkitapp From 630b65db226e2ef8e07944d5bc712b0b7abd4be3 Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 04:24:30 +0900 Subject: [PATCH 04/11] fix version up --- CLAUDE.md | 4 ++-- WatchApp/SettingsView.swift | 2 +- index.html | 4 ++-- wiki/Home.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 02805ec..4e23421 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,8 +4,8 @@ This is a SwiftUI-based presentation remote system with three apps: - **Mac App** (`ClickerRemoteReceiver` v1.2): Menu bar app that receives commands and sends keystrokes to presentation software -- **iPhone App** (`ClickerRemote` v1.6): Remote control with vertical slide navigation and presentation timer -- **Apple Watch App** (`ClickerWatch` v1.6): Companion watch app with gesture-based slide control using double tap motion for next slide +- **iPhone App** (`ClickerRemote` v1.7): Remote control with vertical slide navigation and presentation timer +- **Apple Watch App** (`ClickerWatch` v1.7): Companion watch app with gesture-based slide control using double tap motion for next slide ## Tech Stack diff --git a/WatchApp/SettingsView.swift b/WatchApp/SettingsView.swift index 911aa10..af1e945 100644 --- a/WatchApp/SettingsView.swift +++ b/WatchApp/SettingsView.swift @@ -7,7 +7,7 @@ struct SettingsView: View { HStack { Image(systemName: "info.circle") .foregroundColor(.secondary) - Text("Clicker Remote v1.6") + Text("Clicker Remote v1.7") .font(.system(size: 15)) } } footer: { diff --git a/index.html b/index.html index 4e4aced..de6adce 100644 --- a/index.html +++ b/index.html @@ -148,8 +148,8 @@

Presentation Remote for Apple Fans

Mac 1.2ClickerRemoteReceiver
-
iOS 1.6ClickerRemote
-
watchOS 1.6ClickerWatch
+
iOS 1.7ClickerRemote
+
watchOS 1.7ClickerWatch
diff --git a/wiki/Home.md b/wiki/Home.md index 25de41e..b986b99 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -17,9 +17,9 @@ Welcome to the ClickerRemote developer documentation. This wiki contains technic ClickerRemote is a presentation remote system consisting of three apps: -- **ClickerRemote** (iOS v1.6) — Remote control app for iPhone +- **ClickerRemote** (iOS v1.7) — Remote control app for iPhone - **ClickerRemoteReceiver** (macOS v1.2) — Menu bar app that receives commands -- **ClickerWatch** (watchOS v1.6) — Apple Watch companion for wrist-based control +- **ClickerWatch** (watchOS v1.7) — Apple Watch companion for wrist-based control ```mermaid %%{init: {'theme': 'dark'}}%% From 4efd666e704ba3ac021910b5a0861fafd9861c76 Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 10:34:19 +0900 Subject: [PATCH 05/11] change icon to match dou color pallete --- .../AppIcon.appiconset/icon-1024.png | Bin 60709 -> 18681 bytes public/logo/ios-logo.png | Bin 15726 -> 18681 bytes public/logo/mac-logo.png | Bin 15534 -> 19644 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/WatchApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/WatchApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png index 04258455411fdc43b89213c72b85e3cb12e52822..a4fcd3480b44393cadec2ed07c8d42e8580bb69f 100644 GIT binary patch literal 18681 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%0A`s7@RTAxVPfu@orh zhXdE)wx1|)wgyHB!1qIM--iRR2PgJ)$2Hgw;*X&2oy9jeNx}9}%^&t-0dG{nO+gGD zrcMG;My=z$b}k<=*19$Z|Fm8SNNl# zQ48APNrhKRI_i4 zxFQc2QKq-TusgLNeO(u@Ja$sjhms$`JS8YrF;0o{{=E&5I2fLx7L<#lKzK_Mff{1= z0Q$ICPE3fS_Ly*lqW%{;w}Ac&cuLciAqjn+K3Vr=;4;)seHX-X37l^wJ z7Lu#n^g~`=}hekeOu7(lT z0|W+ZcZl|PS~55+We|EzsE#-q+`sLfNE)CZ zeHk0ccmY1_atEb&rGr+2%+H2+JagUz*+}8{)!)cKCUuOjn^h)ZMiZlhw}VEWz&4n! z_(?cT6)dM=zSb^~L#a)G_ULKY(%;5;rl~uOj36mT*^`8tXa`Q@r$F1pL60 z6tj#N-{tKc9G>Y}1GNAwX&d(4j`uC0CKBDC7Kx9-U@X?jrcy`{-QB-_bfE$XxhZ;9 z?)|sriDdnlyO~pg|K;s{3CNYbi3Emk%b}f#I5yduSV8jjQMjI}0+j`b@GtcxokxFN zV3eFIiiE&=aao_Rl_z1!#fxdsO3{i>} zp^_3)n!nl{o1xl+oDM9@E5B_1cd?LL%obs+dsf5f2q0?sRB|vSD(vpQgIw`qLtM1C3uyhj|w|Hsh&{@$9ov2k7l5=!gU*aP-A; zp#7J?_P1vz7t27zbpL>{Tk9QgSiMtEuJm#Xdyz4YHJ7=I2mfKczm~Nf;JK|%D@4X= zw4%q-Ty?Iy7PNy|pp8n=o^Fv<0y&YbvIH&YJJ0$^0ejO^a+ZZENrb;uSo%*^QbWT= z&Ya)%yZp4392ainRP4!@xU9I)&`?{HDnsSwP+t;&BD**9yWu>M!V7~KObQb$q4(3i zmaAhJxiYKuXqP_3Z%Z*qm(~Qj^~sL&@8gwN*u0aXg^1Kd%Ju5jkqV!ct^K$o97j-f zL=hUi0NM*8r)?z~l;78-BBfT;_P21)U=B+X`A~s3{=*rhJS)}M)wU~KjR1LjOK*U_ z+NEcx9C$o1TuX04VKq=Tlo2*v2$Y_&A{ zLTvbGd(oPkQl+O;oH+{#P>|eQi7_gu2O?qb+I<&F!q1C40{y#Bmgcojg;DqZtbM;rpm^B3CK`!snws!Do*o6y-@=WeTV`!RFMu|!t8a9 zXxBnacBqLhG%qnujEb-{mBiSFsTYTPfC}t5-PXv4@?Lw%rETNJQxnCs8)Qof{c$2I zq&7PI=5A&+`&3DFs0Jf^CC)+xRI#e-&$`(^^1Uh=+k;R0{sD=@h|MI79C1$rO}k2r z*($tR6|j?z1~)R6pgM#K#K=kuZ3L3(Ij`}=cttJeNp|mwDztvuHcL>6PkM|1wWN_a zd@P^(M#yYg(-BBs)oebw08R}`mnrP;+V0h}~#9ksY zA6~z%KulEFAIba}cpm!3952>{z3=kQ)Dr^Ys1(EcD)kr0C;g4KUsiI;LyFwD!9hf4ogeqAq zSmYEWMw$Z-AreoG^xXKUzgRwKe0O1OO=t2dFFb4Io%1T@8;5Ww8xQ>pnd=at#VaZq zr^>{C`%Px}!e8HvLZ+ouUej8ZoHUp_IV@{qM38kq;iS-K#5Xg&@`vF(TC|h*p@heW zH`eajqo(CLr+m}Cl26pH>kq$~UALxcUboiVTVFMQl`b_)(hPn#`~H#i)Y~^CJ-8v6 z4~jK>eq_uTu|BdpKBD>M3$zX%?9KD(TG9B2-o{908Bur!Qyt?F*NF} zmNIIPD>g-P`^{$hYd7s~3pJtsTTZrjc@ncZ-C#$l;|qFaW!efxS69=IAHG-&Tz+_E zw=aHMdGnbo$o%?(aQxuWzL9|mZd1btJuf4gAk@7qIDEQ4cye;mL?|n{^iRxPKGIpi zXYTrNSj$jncTG5dJ)`r?mER0}nJ-h;J`QHPcUClG#)+=tywq9K;q)y08w=v~WD7=v zKZ;Y{JwVje@F^^U6W`zEYsg>tGQ<}M!do(o$}V1#vP_Pz|6F}$VolB)^{J8GR=CmF zK=8kQdftTV@}qNUD$aa~r!0&L=Gm0{q)$xfvpE_ttl{Ua%PNfL3?2?NP0H9bb-p^3 zb2QCev#YDP?7lx@wbLIT?>E;sFlejrDRO#}mXeYJkst=gY{ph`EKLpFI3ztPn=9u} z3k?>_=w!8)RaK=w^y_ukTk>UMu!F&1G=j}S%9ZYtOXEBa+c;!W!#2yL*_QgmrtO}a zpWn!n2u8(l>xdzvC5Wew`3`xz)RKpWE+R_)6?YcT1_P8=-Dw+eHS|tek=!_)GcztL z@HNTOlzI!9Ye>jU!v^cJt8IC=Pu8-L z*&QWV*!rl?hsSf>S2VA4n)SK|3?R44aQBlK`y8hRD9GC8h_x{x?oU!KT zP0elf#hYsQ>Kr$Vw*AhBUL~&*8V8&kz#E+E@eqH?T8W9X6jQN08}2XUEBaaaPUu}a(z{e?DjkI=9YmT^m0m=UB1jRC4uW)0L`4XQ(xoU^ zkRTvUlqyZ+&jj^VulK#`_pX1fyVjk|Iyq;b=j{FLz0aAM%uIHMcQ61#TU|>XfIt8M zg8cwHF9215h=72Q0H27EkdT;|h=gnpITRz}=&VXd$ra(;@Y|Fy>Y_6ETX^z>vb(?;;C9`3$tWdlXN48bek8vMSlJ2fV0 zKg&DLm|4Iq187*k1m?xMx`sy?Yjev+{@5JSESm%YTRXu0a5|=e<}ZC%bHb zIW4mGj_cHSy#N69^ZNwP+8=6n~N7mj2NM#sF&<}loHGf6|Hnui3val7rJdMNs zITzx_Ea|4b3p_=>lB5+5NxLkl2gROC>yxYl!z%bne-Zhi20MOnsVOHXD<|RZm$^=T zPEMFJ05Z@yw_G+pz}@~iw0}(R>daU$KL(yjz+!`k3+ufd~Nbelm~0CvVc8?TX*_4Isjn#JWhyN~ae#qx&=@mv+!6dK_K zmkxcv?|q8a?bm$8xD8suZhsoX2e!xW&b{NenZsbtF7#SkZo6=daKw)F4)3b{L#6zc z*l5oOLo6P+yy| z0=(a>Zt(c}=TJHXVMqUIssI41FltSE9d=(NWpVZB8})@r+{xvS-Dak^Px%gevO0fK zXngj1SL|44HqN_0b(t_kab^L$yrK(aG19X+4L^oc2mC2PCVz6jZj`Goo%e$yX$&nX zO8+-?fRFrpD>>!`3dPTgAo8m6c}WWuLF8e`qr19)R!U6Y7a*aho26rDQT*{z;7?uq z%g(QoSYtUIJA+!imUsEa<$AHRe<{G#AhHL!i!N~(qo?9-J-~$iNb?(XTwA~Hvn;0D z+d>lCl7e*22duy81glKe(}j*F$!|XsIK|DJHug7{u8@WBVbK?!sBnQx+blGn>Sbp9 z&$S4-eWwpHF~eROsTY1od9{0R{?G{OqULw~-!;~^>}uQ(johTR z+OAn`P-)yBpF2bHp9|8(%^EbyT-vj_D2k$@=YFKV{czk}7Nzg(eAl48Q96_v__W`+ zT!^Rd(RW<{KzRC~@%j5?*ZCd3UU>b0*loh^MNr^-JZU*z7C>L$Rg)>R-Xg}`B_=A| z^{7RRovbV7KUKF`+_X;z3VHZ;%?Y_mi?03D%KwD_EfK)p$l*a?@7%!fU;y~RZ4f97 z4*OPkXWDINeL}qJlHVE%oEO5MYErIvd<#-jbkLuSyXTkJ$?&E(-8pe?X&Ms`W6}oKGtyPgE;CDNb#$hV$@5 zG&(w8m@)Ne^r!Bo0_wCHwt~UiHbxE)s2IXLKE;L=yXlJ29y*PLqMU{i+(&0B_bWqq zHh9Ad4`FhB)Dp8Uk12>Cfdhk-# ze`BG2_`;1z5!yT6aSHXoCW6JbI;r)ooj>icMzPCq&LxFrRY=C~0EFp*=?^ zFV^}j&qV=IwGKq#`B)Qni&H}g2&KbgN>Z~!>igTrd&`kfw!UmOn*P+7V;3J@vsA)6 zn5U#B2wEW~gc@J~HbHtQt2>s#ua&m0L6Ku$Hx0I8;3K#)R!e2NSB9U@*cQp%(w1ufVuzj=ivRCD$*4ff6;rhBTp7E8!sK3f0^g*9L8 zy$TX~@_e%jg9~JO0C;OS%-ILs^*5rMQ;u_nk8(6ayv*$)>*sKu1fQVyZ~Ldqp-!Orin>< znBdoexnPl`VhM)ZbUkagqyfp)B0j*MJH$a5+tX?i>jg8gE<3TlWvcCC#*@A*X3yzn z!Hac!San#|F;|YrlgqA08*@_>YpFi6^6Y?`58}RG7&cs{1J+|a%X-FlO+&jkG{2m!^3|`WU zKSfX|Z{udte(je<(n$vhVkN?0k4-_BdMuM~>v{6HlG8gA5oT9`URi!O&=#B3=h7bJ zk37><-5dr?mE`e3zZ|MVO78Beb_DaDDxVUno{ol03)*7IYjmp>E%c?9Aelp+W8+dM zD-P$d3nqB|Z}KEOy7opmP~I!`Q@{>zm(_a1qRYL}as35-UR}_g>&JUuK5AD@e>q^W3&XI_63v$ix zl`&$<%@kzwG`WAWS-h*{0v9oN_?=Vb$`q=P$WAHTxLFJ{0~%!V_dD7ALN~a zqRO8;13^iC7>F=-{l13NC%Bn4L{XStJhP8xUNh(f8(?iNRak&9+Fu~P*Er!4j{&ep z=10M)biXy1@ z2pbqGp{PXgSlN{0apwjsL=mzBM3<+PX)IB!*JRaPd)^c1EWLeW>cfAoW<^f0tV-J5 zxxfKAoS%AU?%|~qqqRhAd68H2(;iewck0eN-YYv$SNNg!)zhob2mH-XJO3L|k=mQ_ zJ=b6@dYdFC_lR#_qcL^fqHWrYcB@XmPegabiutU;5K$}(Is?h_Fiz@|Fr%C#1+y~+ zHF@a6^p@5Z>z5_vgHM^c7zkdxqUSr3W$AQ;+1$BKBJx5+bM0D0bkfv5`V4mau6bS5 zYgDDny|LT^=?85^1j2Uzzl~_sbqJ^+|PM zmIECjjKh&1$C2<^{@V@){iMsAhtj&YltTDE+s^18P!02-*@I1n6OOgxTMFWCL2)S! zRuqV`!*O}lwD1k^1P%0JG}E84RV+yQ^ovy@#;Y)m(T~R1MaYL;git)}!!^h^7ia(;r5FNS zgjCc@Cs;*L%53ht%Mki`8J2Ylx}|aK0EcYNUyGKx(;3&tlv=7Am9z5=Q6@V_b=0-~ zhYpfN{e_mqPWAqzWO^byGoB5_^RoTzR*$yAIr1OBeJl2YrM}#@Rym7N-T$fBtE#Nk zn6(@B_fE>s(Y-hA^=tc?uqlgCh0Ef&P|Zu0JK|T*m>7OK@v+@xy=d-1N*eDDu=m_a zsgb>digyGW{48j7Z}(>h2U`ng?s<{p9UK~*6_0=OjO9^rA@8r9E?6KM>bSW`kn2^rvAk=nahaS*Ft&`hC_ zL@~0tl4xn=3?w&5rj-_H)rA-45vIW@h7W7&!jpEn z>&jS2Ai~3=W0-BE6j55d;xeMRV9nIdxD2Y$(C`WS#$&d@nJ~Q@+2VnM8bcye(_*x3 zcJ0un_-`ALT4kX z=w^<_KO{5bHaOj}o3s|zs;!Wx2tL%1PDIh?z;HdKNssyhocRn)-m|TeWVCi2Hv{zJ zzJ9r222qkc@8fv*-r+rVsh*v6K}n4q8I<#toX*M%LpNB+3S3Q+C)_vLp`bAo-Fn-q zeY4HIBP+N%R6iAkc^&9(S+aM7Ky#Un)AP4>sOB-3LrAAvK%j%sRa z@l~o$;5(Y?nj^KhBx|=nqU{+J-BX=Y-{0!;e(^?jewpdR#-*)*hvynkHjavnp8oe8 zT@qb($|G$H=a-3cYNMm$GFYbd(6n&Dr*ej0w46?AmDq}O@!ICKYo}+oTa)KBQJ<2vGQRIH9PRtG+hPH5psJI_gimw2O@qeSqzqf89F zUUl}tjXk0|ky{3FuMI~QKSql)D8AsT545;fv(>S`)4NVC_w6nJBR{EDDNN=U%9m=5 znP(ZEHI38F+cH_6k#fiQs23$2yTbUwW%ZN{B~l~Q$@kzhRP4=OaFshTIX(@mxH+PB6LgG(2yoBXtH%zYlC1C9ZvUh>Rf6&%4eDl)yaZc!MwJdnV; zRY_l#tU`E<>Qu{<%0)qt13dB620~`~vMY00WE74=?d8*tf``PB`d8bDAM12gXK9pi}@CdLq~Sdqq|cs1EB9sD^Y@ zqrquW881?Jk(nnk(M=Sb+mzQQ_t}OA$BLUSswG_xj>lBrs5}KmRh-N*_hB?R;Un>r zZ9{PL0drE9M((Q#QZTZVFnWio*B5xXVXQ1~jjljIbr*KkT|7}|O%KMp*f{Um!TWb% zAfEbxy&>%IB`&XXCwIY7uWO2fuWL}t$T(L`C{>b!wiWkgs*!6;rS%OQi(|tN#@VjF zF^hCEZ0)&}{?->EKn?05{i4fj=;WhdYuwz@tXAAyA!QYh&u8{3hfQ?1wLfreROW;@r)=@NO)@GI;vSJGhNmr zQ>~rQsx(b?*^DUJU*}Bg+_2JMNlzFNC!?rIu@Qea6GtkhoS`VXo}81pK_O=_y>ZDb z$3i*BD48}sG(6w(Y^)C3*2{*c8Y{?W4k=8z+-mXZT~yRHTxz(bA+K&DWHR{wVV6kD zltNs1A+vNgQE&qx8vJgZQmrjEu8+60EIG;tc3hxZ8A z8qQr%tlFoqg9#(bHnXs>Wt}&__}0mttsg(%lP00dTtmc>@xeb^C3ofUzhb{4fh^hq zs7ArdS_Jm>G6L|j_OIWTlp@x_3yVlrCG1HG<=&T5)trE+{Bq|}krjJ(vOYbZ^g7@5 z*1q-=xepFTU))Q>CveoXxXSRin-}c^#IugZ#-E-{J(h>D{8U)Ku=FukOOUfD5-;TO z>g9E_#v{~d>FuzIVG5ph=c>_O`bW-pJ{}3+j#9}c@8FQi@L_GTP{ANPHGA1_#5GSZ zabqTq5OuN_5bU#q6!=_+hawDA3Odiocae@gmg25RQQM#r=PD*iIgxy^_+WdsL&z{; z=YcHh1rG=znF0lzLmIW<%f8@8NUC((Zg~b@*4jL(Q*$85MwhLL+R}4h=q;Kd0*J3H zdx9`2QIndfdf0rh3stAL_&V+J&|A}s<;pJ>+-~-7X@ugf1hG`Sq=+!3PJRlP=$Io3 z5LIsOhn~NW%$iMkML>W)ujun3-sQZa@Y$mZm_!G^3}z14`?zH!iz#vNwDohb@#zlA zJOzcA9QuE$%4>aKoc3gUEB%;prPh|HFDrW@waNW{+~R{A3cI+`aV>R&Sh|^yc5&xh zAOs6E;je;5nCMi*?F$#v<+sR$3?-2O;MUid#IEjVMVB{PiN=HKAfePR%@2a8d>jg? z#8C}!IpeLAh=w`zYK)8ff1p(g(y{>#Jtdw=0*zj5b69&T91J8r0@7|!4-{kR%2UMj zy&pzFA)N6LF;nhhL(l{uS}CY7{AKLyQE+Tf7*iuzrCgP*T-J4v>@@M?$zF<>f%)NC zoF0NRTgMU*L}XD?0e071A0EMB%x*wbkO(@2+j_Uc$faB`GJRsE&@d&WC~|Bu{oEZU zd60jeT_rwIkdlpZ%eeT~Ss5pgzh<{J2_+EpC^WLo@xxm$T+ou!oA$6lAPIzUpJV!E zoVWme8QP?L7eB{4`+x>6lFvRH4jd}JioLRvasX2!uOtxs{#N2ixySU>OcRKvh&sYi z)Nbe(SFk=_V*$thqtzKgS!lKA{*W3IYkrr=hG@_;bsd=Y2r7PBv7g3+-{mDt9~Y|O zvzRbt{P1-mvqxn$ZsZcUypG^k-61BG-h0y(Qjo`^9tcZ>6=q^dw-a27`j|_Jv$hqVlnO*P;xvoQ-<~@lbr#8GyIP zD-$22c>Tozh?>BPTP6Z_q{)#7%qg7!Iscgm)oipIfP0k-BaWLYv5~GsY6w%Sps#4$ zEM-@t>vG)zltNU-Ot4D|z=(s1&q^*4KT{$_fNly}Mre|~?d)I$(4y=R4^%qB*q}qs%-Fq$Cr!LtiU=v5*o44$ z>FrrCwpiUlL2D?NQr-NfS}R*u9#Gxd*G4n_X@$l!I}j1HEgX-Bj6|gJt3H#lRSKae z)gaJ>6tut16wBsrNXubEBzjA!!Or7NHGOIh?ND7i{wM+lV}mQkpj$hin^fORep_Md z&;RUr$A@2SByMyGwkZRN9sp~jRm0iP&}4{eO>hEX9D`IEfUwL(lV7sr4W18w7;Ej{ z;${(ZcZ@wDYC*+GvVhxx8qV>~L6drK0WVn$A%s*$c`ku^A)>5niO8g8=J@gC$$zxy zEvU?b@UUDGvBzh=egCxu_Oyt5(HeJC2(jEN_rLwWI07^YodVTg_XwB2&!!Z1!GFIY z2mWRP^lSn!9jWn4Uw5*2;A-ICmxNC%GX@{3jWgq?CZ?@75ws66NUb7c)Z;E9`ai$=vB-Z{Vn~U!C0?< ziT{`A{}2Clo`97&{QWtp^NX8b@S=amzokk4+F#7UA>Ah-UyejyG<*xd{>g@Z>wV+bJq-XXzGmWQ z1B7_Kza+r^E8}Y>eukG@NQ@#AZuzQUsm$dZ$=y#oaM1NVZCHwjtqt0W!9e+&Hp`4<7j z=sIGP$yTpzpe;Opf*~MM*wUefs=0$pJ(O{nfW=^cVEEXb;|z8Gxv15N8?$ef+PEMl z&a)3La9ck^Nv^66Sn82}c#(gttFq_gsipf;2hMeL=xH@)E8g*r`ec1bxuz%cu4C

KhBF)TFWmsg-DvuM`CO?J?<6jKJ&VoEA#6*}*ij>Sg$-@vb!{PB5kL7g6 zt9uf)I1;s3;ne(eC(cSu0szV$&|PKlIGtSw^my!1NXr$B+MQ%{6hoXDZxmnO!cIY6 za0&t>;5$QKoH0-T<)0T zPJXJ-e4z_n6I6L;JrIQ~NU;9%xxL?izQ=_i@#R`BTI(lD9S*E)2({LUr&C zbkD8lw@^*l25oO1W9gs%l%lcHpjgniy+3ZoD^Mrz=R(uC(R@_!$$RVpmUpoCvMy=Q zpW!36u}LnNd%#AruoCP?S6+~Kv##P@Xv7k;bh|GJgSp9SVy#2YiUXnIC{wKyg<=P@ zgv|oRX9+VY{JAtoSbHf4-zaGAKsD8Dz4JPB?YY1XAecaI6jLvKNQ%blTu)NUIfm}1 zhruzX+iNn1kM*2xVmmTqyB~f8jvqPdS-|=7%||Gw{8YnuM_^sMahbtInTx zI%>EPf`bsofx3Ua#E>(X|bB_;!U3)MB?1=#TpMKmL#hwQYSw)ml?h8ok z-~{ZW6@xxReC62Jrz_Z1c)_MGDfJ#}m|Mk1<*eRKJxW=D^KiQ#HsTj2ByTF1)aC?v zDsEn=;g^sQk~Xu^jW80T>bc)K2Bgl^+#`y=QqmpBNQJ!3kgJsME#wz&dA0CQf>vvw;`)tNeBq1UX!v-ISm+dH9-Jd@eJXGNq)Ozw& z6N@oEu_T*+2S5zaohN~6a?W|9!)2G$+l`7GlIKcHp9y=)^e{{5gh{Nr-a0WWI6ahD0TDH7nteu{ z#9&v0QMQGyx+43MFRBU!UYXtjiev7nkUH+W;M>gJB0;quR&Cfi{j8lYOMAVg;p`Z% zMUB?8l)!Evv4%*fW$Z;bm&f^<`n8EG*G%C9z6%&(7nx2Tg?#3eH^J2U=H$mG$?Ca1 zIhgX7C)>qQT$gno;&pNl?vpH<3esXy|L_E3)>2aQck zr#trD*p3qHR?2S@w$KQxduc_wv0-Fudeten@LY|Nk=?BuBt%hNhggkE$!iD4FArSX zdxmWPQnGvh4zRSW*{;?g&~tcV@R~f|EbXyLzVU*O_-Y-ZB7W4?=y*txT*((Hd|QdD zjLm@fWR!!w$!WQ-Xq+5Lcg^5&Px&h!qe0<29Yzmz)|obgbj_8-6moJhkKJ7;Ek=1K zm0n6&kX;4RYlH00sjAA{@f|ZUK)>fTVG_c4&q5>|fv(Mnh%;xG(PfDSXprxpDmZF)4yGX^%e0xTMep_%T@urq?J%Wr^8Qg`c0DFl(z^wW;&-x=4bxW0 z8K>WR&jxciwt(dGB2qm2OT-j{^D>z(Z5wdJN`X;Ka_fKRXQXcbSllzOYP19|p@^h_ zO^YTrQ1(dHlW%o2eH-bLJh5qd>Aqnc!H>z*JdYks>xPmj5oD~FN-JrfKwldam(<;s zxuRsleF0t;pK+3dM*P!#%o3RA@3z##<{Y=n@z`|m@*8Rbnr+%^Z){#cOLM-tUU>3C zZ*=wrBv<8(d{q7XCxfU%2fVBi_lNza>WmL^^yIVQktH-^R9J;a`hu`;ZldP0o*WbH zcR$deu<4eANOhfVVhyZZ?bXf+j;E%Ik+ZA4chn>ARxnXmi?=$2bUU)#&xnjHC^ZQ+ zE>SR>m&|mRNR5l3L72$ut-NP{v9%3eYaRt%nUE1<@%(pIl2u_yE>2pXZb!f3NsZG` zO5%ujG0=Tm6qYL`v~&;=o|ZOeohKT6vOWlqG9JW+RzlQw=BThJ^n_t#%+r*TOGnQx z9P;FpKP4A=-rwlBr6Bs4{N?a;8){c6p(YuXp&@xb4AxQqFg9x45ww=8&BwDk_vK2y zku9d9Ck;Bvo0^)4A*xw>-9XZ4O5(zIV?Ny|k78RBYinz~pqyTkdOV>I%wt4h1Kw_T z?J92{6)mk47KSPrOody5l-ss zY0+hoDuI3512;WN#r*W3TxD-5RyQVI-wFNbX0O6{8I_pqC|*zCXf2bt!qQ8})q2K$ z#m#Qgk(;9vdh9UA1~ZwUs+nZwiNn@T7sQrz*~prRs}!{^SmIYsn>8(It!O4pN^=S| zdBheayhnS7cb(CTixlcc%8BKk37}gj7^X;YemmbT+A1&*RO{bC4IMnrIR(9*$$+L7 zhDeT1YAg*16Jx)PsRO3Hy`h%0v}Jt){35iaCTAuJNNst~np=!UU_8{vqLPADs9bLy zE}AH%x_qXgmJQ26>!fYTT;1ay>hm7qAoV4kT4TfSv#2Cu+V*!Q;vW?0kZd* zyJ>j^mu4kgy&@^Bagdk|)fP5dx~W8rXYi@&-lw*;Er!vzrvv}dYGn>*%nopa^}y_> zmyQRUxXOqUtO?ZP>L#YbBw{ z)}Y@u+T9S)(RpKtjSI!gZazWFm@l=Y%HB_(Ciz@QeYs0!Lgc`8`-$}QXNR|3F(q<>5!HZLCOGW5EvSyrA0ynK@dSiy1PX3 z4Gfs~`pNs&yYJq$?snE;?|<#zKhEA~_8AX891H_E(&AF$00;yCAlN_P;3FUkpdcY3 zBO#(7BO{}tqM%`%!NfpE#~{MP$3AnOn4Ii9F)1kp4Kp1D6%#cnDLp3x6ALRlJ3BcY zH$N8}AM+JU0RaJE90(4~L%*My{~i5@MSy?GFZqs~@RzEw)|u@e zv6Bnv>J8i4h+paaWPH7TY57Oq@BLD~*vs?3k|8S{&kOx?Q-pqH{4hp-v1sNMJ`eB( z=D$vCi!~8I&`w4i!1;@duKOBgsarv1szPF-Rt~+M2RT?F%nE76K#!oq4xs- zSQoiixp^<3XVtBacI|v0G57G#>>o$WHZJFvkt~u7GFpBlANF&)3#v0WK#1;jY~H`} zzK==Nil?T*nrt;b-)Zn3D8rbusg6uuxAm^~ue|T$Pu>VLw1X7i3Gg0zxlGYKp#K~F zyBwz;Z2fRX`A&fMz>9eERRE#nuk`O@%nyKwh<3v_!X_DK)yb&JzlymI3GW;4w+_S! zzN!uHP=Ggu}_=7YL zP*O6Fz&W5~bRod@mFlh#d`w{b$mj#ma6E$3e!g1Qf${JbVJjW1A^BedK#fG2E5{)JKEQWMTD<94JM6y9~n9w8~`|D?`OaBngcSAO_yUp ze)r5Y9L}j?15=@&LYn##{W;z%!IJgW6dcOws~bKyaJtN#C>{P~9$|i60P^=f?EmBT z|Nj;~!FAdYpXmMjI|&(dwB{u@K|JCBx-CjS#ch#X69bHWpHP@WQRE4wTh?GrbTs(WknBrdeIY zMlEvp{$mk^T|Bp1qGg-8$Jf7>Z9}o&T)>3|>%D~6TA#$_{W~@`?)s4eHQYfh+gp>= z)N^BxL&NjK4A_oHUukI-97Dy^vhAp0Nr1l->1MOQ8GGD_6%7p!_oq)qg0hFc)E=?#!`L0n6e8-+LdUr5+QlUr&CFI7 z?d-sKZ`e(UULMYfFC!mre=i8EXb z?UJu>{q;V$B4#nTL2%+;9icFM91%*5QeUu&uB5b%M9F#Y(ATTYtki_!xPJQM=hD)r zF+^5KW+2WIN{!Uma!E?&EusGq>7nnMq%TAD3B@r(Zulr7pP|AUIfOuTGT9dk z_0GFT;X5|j{iQ(U`2p~}_=p-XC7eo7;Rs%zIb32$Ou zYAQFqK6*GehF{*(RV=Wt(>Lm&cevGcrm{4{^cVH-dXElj2KaZtBQc2N-z^9BEjf{8f1P&@$yu!g2oopO+4U_wWlSnLWxoDfeDWk-zQ`%!98KKq!d;c8Yjo zph3(2VXRsJ1igI1>SH#pa=KOFPg>2z1}~Snm50CjSL*5wy5RSN)R2Tbo7H4z)UJU`O}d*RY0KhAgi^YV$OP-Va+}lT%50W7JUm-hQAu zdu}LaK%Sgk`3aiC!-3hFmUsIj!JWj05lolN&inS>O`#MXQ*t7HB9(?WoxmW#Ju?~P0ro#hbT=>rPeRr)p z+KwO~kRS*^{(}Vgn*=`&>`Aw6F_3My81VFkt15o$IO zB|Cim+^bxgHGM=c`kvssHl*Sq)_!p#u>7EQfPkZ1Rfa*1xny~rW zAt!nNit>U%G&H5nA^*b~!R6UZv+DfKH*G2w0?KPPnH$Q9D-EK}(n+h6{Zd(m?Fs6& zDgw?b`+W=_b6@r?_ZTzGZeYJ=m}^wuwS8XgWI_H=rpH_`v<;olv7ESuS*CAlN8IME z)LZBLsenDi^T@F^_S%Bv1J*J%=IQF;WQo#d2C3?N?DQ5G3)35D_GI?5Xcf#iS|L~H zhLX5EV+ys^jT2iX5^hBO zrI^sW^^AuWJ@+M~oACpj#YxWOG*D5PZQpp!y+9UELMlh}iO^E1C@9D$V@9577SSeV z0^eM&*bojzRTvkCeUD)xe$mY%%V1@+DB3ZO2ChYPZbF72{A_e;PQSqs)R-VK zF-$>eR}=SyM8=yhTyoOS8^1Z8n+iTR@8J4ZrKYhaBl@|kE^t5f_N}Hf4uHoA&J{DO z>GzsL+7#bg;c}Tc=od=YEkKl%kgV91N?ecay*svtm4I#K#hw1HOIqd@^f@_W#lSHJ zKU&8M)!MR8zL929J@zsgDbWvGRZIm`?4OIlV}>O%ciRi&Oq8@-YOFT@nY2>rY~j`H z_yl<1ZWa+}Ms4Y(#VR?HcF#|9cfkQQKd2l`Y(%8#j>?>TB!7+JQY7@P z2XxBlIBM7Lz8~KwWVjF=FTq~v#vo-Gqv|)I#(NyOqH*Rjy5)K)_Ow}UsKc_d7e<-% z`>1PS$0_?^=H9Ls=*Jl<{;nkWGSU>3z&|LfdyWepJJVJk>+p;yCGvDZBjp|_C86x4 z^>}cg=2vJdJWk~v@T85b9O0J`*(YGNO{wds`Z@i9YkGA@N4f?T zyjJdiOtj1ORic;7#2(dtA*Uo)&~u-TPALZtRQgqjD{1$_=7G*8O~M-+$wNcP)?hCWP=|amBT?T)!LJNl7Q}u zP9Cj#D+5_lZeQN$Hyk7>7ZzhvbrD4NoW2(!}{#skObD_s41`M{1TO z@3-doithy?Hx1p%l`1$caTXCoMjk(-ys~EXiKkjz0?ca*=CT3DArkq)>gY)QigTic zlI5|BEjT{XVM+ZKxhwBoO$e~C@4eX3h&ovku9t-9(yMLmd}G`?&IzZ`EU|i1qu=O~ z!27h5wcvgiPgt0l?eJDrXGzvoQ@FFYu!gc}m#1d;Y1`SdT&qR9d*b+x7oxX;v#Cp( z3M<<|6VT(E{4a`ku;=3A_S-emsev`R9Ey)iZWGWp)IJMeZ+Am_K7&OzZKE2|?wLQ6 zx@RpNza&zN%;x*rvFhDQqr#jW$1Vp^kaM;90YE@U@l^*S@iXUal1tbDKpn8B5{^4H zY&?!B_e!=Ejkw7&u+b%div48;F>*V%Z6V$s52S^AGIwQ=@vA{Pu~g1rDpqmInp%gQ zJBonz0WfwZ6GwckzCnqB&Q@=e$%FR*7+jio>wud-IjN93M*Zf?&Xh}L{vbyQGZ|u- zbY^KZ&jFw>qlz-j0oD{h?^T|h<+)68Th{0WjoKp5TBg*B+QiPCMRT1h9^sl4j_s(| zL3`Kc)-&Q@TUDC1t;>uunbttGa^a*rGr9Df`f5fTLAb0(g*H%T&Y&Don={I(FFpxkx(W1}o0EfQbZ1Ez2D+0s`N$bYyCc3_5`CbPoscv{ zwSFg6r7spThd( z5uAbtD<>xqf|Q3R5LzGQGClkrXM9>g?w#b_4SQ#)m0Ul~NwF$nRm%M3@svf<8djTj zCr+8W+w+_rA9p!%4E`tbr2?>%Jp$ykBpj6Cddj7mA*#EE_BzN?Cc=X*C{>KYGiAL( z)I3;gEoMN+nlrCk5T^n2nAQ2pP)}MLU&ho0Ov$BI-g@H2TiffT?LW6y?1Qo!cu6(( za$SRM*cR^e&7&G@cN=vInh1r|JuOMMa6Y&Nj*^rNMd@B+R=X`lX;yP@5}ZgNa4qVY z8HTFM#qRS27q+6Xbt?JKosmbHddblu47XV;kkp^

lHUIV<27UU0-|?tcP=fT^zqPWC5Q~#&6Oyr>viI%~@AA&g0tNRxy)I z(@vt>1&=1V8gQNA#VCKqD>t-0%PQY`NBX!9U6boWBCRsdmNtG_ZAmbt`4pmOxP0u@ z@sa$Gh9)*v_|N@wq&l)QHfGjtLw7d|tNm-&VxfnvOzD-jq1WQ=xqN8GgvIT{_aLZ9 z)KpbmDZ>)RsBe}>bU9F@}L!Lo?qN=++dTpRja9hj<@c7THsV5|J20-6Cf$Mn6Q7}`D< zUVn8i4;mpSdx7bJ%xjhkrd?y>aZl7TZATS;i&=v;iboIiZ>w*$ziHXUx2~Lpy7l!m zO$uLTY8WqGc@h_~b>Wj^ukuEI*1dLL9re4dCSzAPsh4Fd=b%}0x;F@(AiO9>kL-M9 zY%MVy=h&xm<9*Gu%WSBw#ssuaBCvKP5xPJJ;-SE0pfcKEZ!CQJA&3s(k6M}rrw4gh3$0*$Hg>ZAhzNfffj3W>aCOLx!Yji-KGK9zQ3aZM#O3wd?X2E?^)nJOGt z#ApFc!|O+4X~WYKsGoc@?7hkHMhVr@k1z?cMVp>leVuqj*;kX|6+N(zYFeizx|_oo zl&#`e{Y@qnq>a5=0Hw-RdA}h^TZCcYjXnG@6wyJjtsyg{L`}1o;$aJG2q5UI!E*NP z0dNs5g|S!LMi~u=9RXu1d#HXF)lvanQA^5j{ZY_fxuaEiRdVU#1#l(#gue1MjqE&V z!1dR|f@n7}U+s83^O;e$9Xczf0Wqk!XqSW zpzvh>d=l_LvY6qq`s?tulqL~2nMfp^2+GLrkU@6j7hLNV4_l+NlX|44`iac>v6yvzT=Am54~_*-bP84 z;&Xp)elEFYaQ>y%lEmP(w&16>8qqoI2SD!S>WN!T^y-M8JUp6fy1dEwk$zsI+uQ4q zuQX2bZ~8{K!h|>-tBntUmu0Y><>=RD00efzfU~ny^WV>ZZUnZIetJV!ham80UxdD& zD#3dcf0PdbM6tNW!oGc6yaD__6wEXL`IQ?4x%|%yZ1{I;nE>`bm!Abb{%Riz$p3Ts zVL-_P2)t$Z7oDne#qfJeTqSA|Jz9b=v47cL2y5n{9MB6>fzWpEM@;gd`@7%lMB1%{b@a)22NmnlZT!Z#y83j zozdU-yQDwuUz6UTH$SMuyqE)k@4o!ZI;8sp7(gQi%eN2g5l{b5@_7{AzdR6pOT_QS z4=LNTKgmZxg6FA2$zyo z7*M2u9c=j|M-(d5FXMDQC>Z&Eu!RFV6U&i|@K0Iu6W_=j$}bHPJe_#d!hO>|O%YB?z&?Uduesyv^$BJl7gb)9>G~xc5<#Oziocg)yB< zLqB?I=;!4eTO$Mq8B^4P=K`B+`Pvk&LW)<*1)I1ul5UIcw2Ub^JefEE_OTVYne^CT zZ?D%jua0EYCkty5ph<^fbSIb=M5H>=H&sL;RM++I--SCtoB3?gTq2 z7!wCnr#Ru)@o>PVlC4(ozNS&^aLev2ghIGbB0!!LqU0b4tV-gwL@W{wyWmi}lGirh zXS{F~*crww(s$3}ra>w6;KIwtS`gZGrJXh#Bn4F4UnH)yA00SUi@kPBl@847TBNt1 z&13{!yiYo{lY|&y1yn6lgeu=%?6=MCwn)Wo zFD3aBTvZT-Xzh~l7SWdlMb9rZ_}FRVZjy12D4zvlUU|!uU#{E3a4ti;#%xt!x%tk; z(NsyfSI7BhrA8g6Y~i_`n{855qAGiY81|J%V1P%qx<1>4OV-3|B^ube1Fw{%@QCxL z>kQ+2e}>W*4}I&l|DG*U@~rh;ec8R$7;1WbX{mY3pD!wS zEW7>`_5uPkK0v;YpV9Z(l#1JzEAE3)`cJM!jG$AOs^X*8MES;mLB$2F+f(TZ%7e4{ zI+Hf;k(O8Ji})ySIkh$Db9UP*B?(=1A`;YEhoZ&BtIQ3)S-LG7V02C*pfl-wphA}~ zuJ&VV2b(EahHuzItKFYeFG>}(r?f0LH9@8mg*(lE#_sic^2Rb)#TF^M@@W|`|JHsK z`gJ`?b#_mE<_=z~ADsnq!;Ay@Sw7i!a`&%0P+A9@@Or&n{oynce%M87jA+b!E}~a% z!{>EKYNl}_DC>ih=5l^ZFY_Bz?WdxRq0RizSY<-3Ygh#iXO$2DAu_>sBpP=4cYVYi zuGe()vjr(TrPEuW{A$xKdaRTwo(bje?b{gl?x=soa#hKd3Km1p3#N-FS#B~fDisfI z1O;Q_uW!66PEb^vo9%3|Z_CA^DnU+iFYb14K@SsaxHaPaG9Y-{ZA`tBK6_)sWSo0K zH4s1wuUP_FPa+5CFKDtIh{{=dQf67Ampi59*%Yu92tY=NmZXh4@?dU}XH{>dQx)|XkBBndgS}a?@RB5QoB(-~ zcV?N*ANmP)a~>HK7UAN6?B%)JA&plc*6)RFdtf9pmZ`<}%7>%IaJ^Ls!xTCIED{EV zE0~3Cy$ov-A@tI@y;F`qPm5zM^FWLI!%{|F8(y}f>nD}hRDg6PvVSCDZNpUAFWeDT z351A;F5W-uOeova6KeWHZfp4t?>FBOKvIa&%1>$e+&KT3OY*@L_YOO93Bw;W7 z5-|X9?&!1+!J-KdZ|Vq*=Wx-d59pTe`XCdr6y1}x27CUnsSDB>*^dRn4fmwdZ0fhJ znXaVOtqPc^^58g(+Dg5&(AO@k>VNl8EGx#9Exj_Z5+gXx>B&73$E)^3qN`|o&kYSM zt;b$q$~Yq5B7{UmKTymrWxJ!*OQ)o5)mgBHDM+r~^GMTq-a|%~o>=<2Ui}xR7fF+< zhWI;HnEnlkg>%*eY-5ZOoa9Xb=c0v3^76tXX$3xyf0Q;cw(}~TV4t)s7BtvvdD}L5 z*@luXl4mXjZ+z+8E{_kB{gNm?4I^@uTK$v^0Zo7)xsj_D>a|E6>FGLN+ppwSq_{-U sJEqrUGGRX?bpEBOYkU$E50iS@#?L--wSHM(pj->FD%We~(n0_K0c7pr$N&HU diff --git a/public/logo/mac-logo.png b/public/logo/mac-logo.png index 833ba5faf6d01e14058638bdaf91b40febfbcebf..632eb72415983b1440e758d11f94b341152c82ff 100644 GIT binary patch literal 19644 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 literal 15534 zcmeHt2V4|Ov+wM(EK6P%M3RIh3zC!MC}GLLKv0mZhy)cSBUy3=ktCud1w;uVNRl8T zND>4jisU3BLEsKz0QDTt`R@DfyWe}Kw|~>sRsX53uCDH$?U}9atw8{(azyzE0D%Ai z1pEP8y?`8mfWvX%*a#dP99&!k9swC40X{wfC5n`o>;M%V?Exwp8hR!!R(doiBMl9k zFgqs?uYiC69qVBU5k7G)egVF1B@kR(TmpOo3PM5(J_Z^FzQ3KessR!N41fVx5HtWK zfnbq9wrT-t(A1p-d`)m1Y#0=R1q#WwyRkQIy#@%dAOIAJg#>%(y;t~8?LW)|o6(PO zAsAJ0$(GbTmeWZ}*(F?WtE2w3eB)E>9?_2#_wgVw5`IWfF|mHr;PD^0yQ_E!ccYg* zaq3Bh1Wu|V%4G2$(EruTlgYQH7uM=7L_Grd+0W%rO2zM1yqCr+=dy^0RLz=N1`Y0& z0CXN$$LCC`8J6MJ8P5|g{~+B}B~0&szXTDB8K~UF+#x&p%7zDtiOWW-f0lg%+g3tR zsM(*Kgx$y7a|z%H|AzaCpw0(;e9C-&_iG6123DUtrh_(JTri!<*As(<2t$NeXE5~pP0;)CRZsE1x(vZGLoH-Uk? zCjdaZqb4Q?EY!Q;J6Wc&|H={ZkC&x^zwSe-+s8^%j6oNDYWUENq5%LLOCzreunyd4 z5*FtH{(1mF%1p%afhZ12kuFL}Feu7=7(gvX{ncO?+~@+isEeKite2|)j&;;Uq-6jY zBnW9?8`evJtWh=669Bkohqx*!)MtD=KWpbn>cs{AM!eZ}t55Hk*Pox%4Z(Fn$byEJ zmHCtbCSpY>h!YsPK(&(%)8Fkp6g8{bY&2BWf8WjcN44s9MnnB&QMsR+0HCv|=`w&q z32gTd5@9zW3w9R(KpUU0gCI~j%pcs%oSd*+x9_QT`g^03^)`9L%HdHe07w!)4k|-| zDlT1oez3chj?NeW4zq@F{Jp>dHl`eKu2da(2XneX(m!@Z8dL~4KXPSwW2g9;eQ{OF z6CD44W;5uQ|G$>3?MT>_e!DK?EERDBIIK~}nL4kk{VSKXeq(?_WsGgpcvrJ~$O|5V zh0Ps%SYInR+?l-hF1?DRng7b!TVl-(H{6}_#2GztcC_I!%Zobr|B?J^s@kotHKydQk3$UwOMqh!&UdsUE69VmSY!Q5^bRl3nDn@p> z0{@dW#Gbpj-^c?YE(Cp*lyzZn*5{IU{EKAg17g#Oz-y9lgH)lSAR<~|0*F6J)s z`)a+5`Hdv(#qIY*#@YGMe`D<-zAejpxL+%~cZILKT_toDTxTIZv)#X5Xm>CFyYBi* z{@?9(%LRJ)zDL9L0bkA8UE<761)ZZuU>+|8?Phj2__!lovrYV<`UTy$% zwQkx|}tH4ooB+T8I0TA?O-{z6X}ph~6iI?Y zGxAF3Gl0hd2oM6nhHe3Ys*!5iCeuv1y16Fp+HgTZge(oG2_mb8>SoSqqMPVy1wrvB zoy1IUi)>jMeRN|T@(?sbv`N=J1>rVgQ&=5+7(Xd_p9zIqdOPQG%e9j#3pT6f6PGkE z?%S}qj;ek*E~;Wllf!s|s-f%1eZh#_5VNy?tCC@_lKI9vJL5X3T-PGe^(V@aN*y<} z2HD=k;V1E=D#tXX1W>#lRy$wXE=21~%r2+FWZf}APO>Q{!R3U&K5}I&+5O;&u}By5 zYWT~gC&UYJZJfFlVjf-AX`HvCP|rrNSWNI@t<<=?RxzW+OP-@E)oX8ZT#wF*HW|Dv zc2kWS#lIy>XXR$7<9@@@;e7iPh1=VSP)Ui>4ntQL$IOzI<#$^43o|cnj*RpsDb&{& ziw1>-*uIPW(xmB9_hso7;ah@KRJ7H&*e zSK3{gJv~9x{V)g`+WR;N3SHi|@bUdkzL}D@8_U#@o4t;hRpn{WWT}OcWrLIvP)^%F z{%n|=&-p!T9-l`}n0e{cn8r!74`UifbvWXRK&V79Z4JoI@9W)0_lB9&-|y?TJ-6+F zbM^TnJ+?N&Lfbwm8tJy5E*7FrJO_HI*M3@L*&vayxd`;z%p31}`d@m!2DY1ALGfWI z>?FkpbE1;Z=q-R6Y++Lf#I839zh&tSJ>P3mDm+&#Fc4hP466HBxDN{LeY6i6+Fi8o zmYD6LE)Gr)I5zIXF`A-7eQeZRwe1+DVodEp%)_&fWpCVX#?9#F8rNKA)0T@}It3Kq!!Z7lhH72y(G$}CwTmx#=opvlTvEv>agSr6r)0osm7 zAo4xE8yYHLsmih{}V)X z+PjY>zU=90oaTwi`GKpQOTq4~LK~dd3VcW!TRFXk_bs0oL2L|7xRcK3w7?{zHS(73 z6)VL^9Xj(!{=}0fa*7>+FM8QNy`sZRq!1FFuC;8EYkP+oDtR9=Avxx3#Nqmi_Vg=* z!ICu*rgh2}!VFtLMU>)VVtlMr@S9Mnxf`|@gy}^4#%(1pmbUh}PC2HPtaiPVvwwg0 zh2O|KgCxTG7saB~VM%`o>v@vc`p5(KMrHJ-sRWIVhty&7tcAXE?h$vv)ga(W%y~@b zsmQl4w6m!6tXuG+H*aZ%Ux$Tg>VL|w(d8;xVxsczx;1}C{jO4H&Wmo9RrnIm!6R*a z{f382rDr;y2bgH%#bvDI1>0VhwLo6iW4?=NU)P%+>I!b|Ar~ol8p>&J8bot^xcBoG;=XX3EGQmI?AI>J|bc1S>vdOU{Ak5Eh2N--kX1p9Ehj$YnP9r;tZx#<+m zbSn{C!1nnz$&csTm7g~>aMzQ9062ewfPO=WfzMh{Y#e-WzXZ?4KPPafgk7y7;TO;} zP9H+iqj`8`v?3yJzGSc`W#rTLk~KMQo zdV+a<4ql+~{MbfJSa{J@!#3^QzOdfo*T)$lj7q|lk3FCS*Ty+hF5_shq-96-%X~!OvQKSFft%UME%nC`|EvfNy47_h- zO&|NzU%?GsBt0<7A{OAcxI&Y@k zTEa|dcs`SFX!sa=M~z*l&+8ogq2*wSeQ5J2B~gYj|cwE z`jPJM?yh3A<+^LP0BhWzF!I+?pPX?uH2=LJ{`Y4G@wG_v2+jnwy%XO&>wZUW=>HQ0 zM9L@9GLEVAC}+3~sWM}qbkrH;+Ott=F{~)~)z7;?ega-oyR$)nQf>yu+48|uDJeUu zFX9|Scz(Gsb6pkcffQ?{*FjzF{Tq2|+HKKK1_iA*i9D!zyg<YG{gGYt#!wv2j7@a%$;Iaw5QeDn+;t87BLHk*%EbESXY~mru6wbw|Y#`v|~aXlPEkY(CQa4y21FL89mnHu*b`#OWu30x=g^o>Hi!5w1?Q;=`dB3llwWrPXi zf9=*|j89SGozGU7EELjg@~6y`KDyH6KwN2vZv2jv7u z&rD)?q3vjpUHcJT$;BT1aYi)Vm1#=6!AG>@_?+rS}Dd2xurOldu`G^d6O_S8SNhZ#YSQZC#po)oL zN>JByLs9@ek60EpJ7TN)jkBl+@asY_BShOmrDy}mo+(jENC{*#yxpT@OL zw>yxJY5@YaY-! z-jSGGcVf8AjozCs$EiK5o5mAe9{V*;r`QrL!MA{i`q_IDJ)q17!RARGc&Kqvr(gG@ zoVcd=qXH9g8G!Z;{HLS2-nQbXn1-mEmj>L5$>m zkyhmNc6#YGkbt*QqtD^Ygv$98M9KlANTjWgnY;{r{hi4G{1dP1^B$L`K_8F;HtUV{ zW~4~Y<-V!|R_=H;cP4$g=*Iwk3DWb8kT+OMV|co}9`Tde+2sq}t*TDC%X$(q8kQ>; zcL;Omk%HmynaxrVuqTzq%k zM}y&5amKAx#+m{csEByv@}Xb@#>1q563--Fs`6o^LYlab`T7@Ab$YgmXnD((Ud4d| zS=z&Q22e<19~jjWUk&peVazt6pvqeO7U{#35VavDsP}W~AEs9;z`?IDYm8!1P2l@& zF}r{?TY-crR8;~*Dt5e16-jxKh&Y#_{`~+i7D;R5uzF-VU(hTv=qPJ#48u6R2X4;@ z3s0d?EX#%?KBM(%q?o-JZ+$ARbP;w2Pq<@a4MUww$g;}4PQBOJWqQZXWY6dsW#>H9 zyOjO!Wo3F(&z1}_nMe64kU~`9H6F#zf%B5{p0xm4SsvQ!D%)WeQBUfu@*a<|ETv6J zM43DFxF-~<1v97?y00_tI^h8*8`DG+8mYL#Jegvl9iuqB=V|gBG`V2C^-Ksr#?DL; zAPx%!!&=5v?87+mQYeb&Y8df=%V-#ow7gknR}86$a4(@a+0g3~Cgm^V8q@q(l!zu% zg0y@+!qe`WzM0yheLG}`pp|${cK5hx5$LZ%nuxC6mNF!s^BKjGGn=naui|vLJYTwQ z>~U;r;*gv=Y4u3mhHHfy5qP>7_V|#!efC-RhLJEIwHvDGmBK?BSSD(05yrgxD|oI} zp4J@j6;~IBH3qX9-{xy+{)Cv3vfo@9GA1Co!KBt*BjfD-k^NA+szdOQogcqC1@WB0 z=9_n|c$`ckN`N$!(09M6i^i~0I$j3ve@U;lN$mwc`EO_7p zT)@635-qp|^whE0UbVU0w2<6@@Qi>NxJ4kLOo^m&)u)0ljmur_A;rkLUPV+B?{BiR zR2ZT;jHMx1PQYh}M%2=qWJHEegkKqSL3o6kuATC(x!m~tsdI(tnhc^QRU(>gJ+9Zx z!5*zNx&90L*wo zT0%uezURY(0Ob512h2Di_oKF4h{hk|CxPA{@f8r_KgJIN20!Anfq(GdeDbgOXZ!mk zo%0pzvtY^7JNH|E-UCAis!_2%xgA1(0iU^z1IK7^yVUu;{!D-v%-eV!F#kL71gSgv z<>>#Ke$Z~Pzr)-1JO19DM<8r_j*JBW0L486anYsPC z6ZzZMojZs_NbqYP2o4r(``e(;Q3WAk0KgZVCiY(Rnh`w4X$4jJL-PyLcB$dtPNI+- zsKg1pyH&<#Z2HC69A3lCu}kGi!%RV%4=**dMvk@u)LXMOs{yty z&Yj7wV@FZsdK-)8mV0A)f92gsasHS7Pv0z6q^2nh8?OtTW;trf7Q6+(3lB65MZm}A z&Bd<|OqXb1J$MqH@y=IalBkB>mi*P|V74t*b+4WADX-;YPCq8c+i10wbJ{-gWQ#=F zRV!wm7ROxX#gI0TYI14*-KGEX+V6y}0Eya)H_|^p3XF%Md_;__z*G!2Bi7d7Nc|jOGCF7Bn5|;AkE+b?$c$!N|!yFYyIEDR0+5%F>#i_7~ zx=i>;N2+8ApBUIR z?tQ1c$zS>59Ye4m^TCR5DLf^1;Z$ z{8gxHd2PYzr$OYL$Nxf+=m?AqJ>1ZYb%PVW^BSsdSTL6*U~KUqeb|n9c~UVVPDw`( z0X(&#DTh_Pw>5s#-KRxridFAOhDFfamq)G{gBn{E)_q;&E6+sOu=I>cTa&d?d~&Wb zJOGHXAwwJ#B!0GV0Dc^G8z|)P(ng+lBQj(xlX=b-!{ZjJYSx6%LR(zG!Nz-5I4_cj zh7mA&56GQIdU;$RayBbb5~N~1XyX()fvcw%@D|>pG`OzkBzRPf7 zCW2#KIO+1-JLG66ql{u`6vFdp-Vo86I!B}Xi^OH>M=e*hHB~J5+bqPY+_!)=iQSW2 zKH(nGb@WZ1kI_Jkv8WcyS?`J$?)i!S>S)NB2*ZGn;ZP-YB!}n8sK{KFssW2(s(ZJ@ zZ@s%6dOFQs%gL+daXNcIv`X4bMWs|fqd?cfihQk-Ob_zt!r)2`|C>(X(nnVWDQu=* z@>(sW1m(}pUQsqZcFVOtB=rDX!9F(UWC-00FYeAl##j@~>Rem4&mk?=Kxzs0^(exk z=k~mBsJWP0hwtBbEv|9#h_!KJ0_B6lK^PkQkYyP!|F~Pkviru9nc(#vs%1*?RPVzO zBF9;xX%r`_c$_uTWl=(80}Xi$D<^tcQqMN_DgLb%a(|w`m-B;b;tUsa>(PPgh*j=bKM z;aGZhdK>K19q=g$;o__BZkcle Date: Fri, 20 Mar 2026 15:43:39 +0900 Subject: [PATCH 06/11] add dynamic island and update logo --- CLAUDE.md | 4 +- LiveActivityWidget/Info.plist | 27 +++ LiveActivityWidget/LiveActivityBundle.swift | 9 + .../PresentationLiveActivity.swift | 208 ++++++++++++++++++ .../AppIcon.appiconset/icon-1024.png | Bin 15534 -> 19644 bytes .../AppIcon.appiconset/icon-128.png | Bin 3410 -> 2756 bytes .../AppIcon.appiconset/icon-16.png | Bin 1150 -> 460 bytes .../AppIcon.appiconset/icon-256.png | Bin 6690 -> 7888 bytes .../AppIcon.appiconset/icon-32.png | Bin 1455 -> 760 bytes .../AppIcon.appiconset/icon-512.png | Bin 12560 -> 25768 bytes .../AppIcon.appiconset/icon-64.png | Bin 2004 -> 1418 bytes MacApp/Info.plist | 2 +- README.md | 8 +- WatchApp/ContentView.swift | 24 ++ WatchApp/Info.plist | 2 +- WatchApp/SettingsView.swift | 4 +- .../AppIcon.appiconset/icon-1024.png | Bin 15726 -> 18681 bytes iPhoneApp/Info.plist | 4 +- iPhoneApp/LiveActivityManager.swift | 84 +++++++ iPhoneApp/PresentationAttributes.swift | 17 ++ iPhoneApp/PresentationTimer.swift | 33 ++- iPhoneApp/iPhoneConnectionManager.swift | 3 + index.html | 19 +- project.yml | 34 ++- wiki/Home.md | 4 +- 25 files changed, 457 insertions(+), 29 deletions(-) create mode 100644 LiveActivityWidget/Info.plist create mode 100644 LiveActivityWidget/LiveActivityBundle.swift create mode 100644 LiveActivityWidget/PresentationLiveActivity.swift create mode 100644 iPhoneApp/LiveActivityManager.swift create mode 100644 iPhoneApp/PresentationAttributes.swift diff --git a/CLAUDE.md b/CLAUDE.md index 4e23421..119c4cb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,8 +4,8 @@ This is a SwiftUI-based presentation remote system with three apps: - **Mac App** (`ClickerRemoteReceiver` v1.2): Menu bar app that receives commands and sends keystrokes to presentation software -- **iPhone App** (`ClickerRemote` v1.7): Remote control with vertical slide navigation and presentation timer -- **Apple Watch App** (`ClickerWatch` v1.7): Companion watch app with gesture-based slide control using double tap motion for next slide +- **iPhone App** (`ClickerRemote` v1.8): Remote control with vertical slide navigation and presentation timer +- **Apple Watch App** (`ClickerWatch` v1.8): Companion watch app with gesture-based slide control using double tap motion for next slide ## Tech Stack diff --git a/LiveActivityWidget/Info.plist b/LiveActivityWidget/Info.plist new file mode 100644 index 0000000..6ef3ac5 --- /dev/null +++ b/LiveActivityWidget/Info.plist @@ -0,0 +1,27 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/LiveActivityWidget/LiveActivityBundle.swift b/LiveActivityWidget/LiveActivityBundle.swift new file mode 100644 index 0000000..3d1147f --- /dev/null +++ b/LiveActivityWidget/LiveActivityBundle.swift @@ -0,0 +1,9 @@ +import SwiftUI +import WidgetKit + +@main +struct LiveActivityBundle: WidgetBundle { + var body: some Widget { + PresentationLiveActivity() + } +} diff --git a/LiveActivityWidget/PresentationLiveActivity.swift b/LiveActivityWidget/PresentationLiveActivity.swift new file mode 100644 index 0000000..8dd98bd --- /dev/null +++ b/LiveActivityWidget/PresentationLiveActivity.swift @@ -0,0 +1,208 @@ +import ActivityKit +import SwiftUI +import WidgetKit + +struct PresentationLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: PresentationAttributes.self) { context in + // Lock Screen banner + LockScreenView(context: context) + } dynamicIsland: { context in + DynamicIsland { + // Expanded regions + DynamicIslandExpandedRegion(.leading) { + Label(context.attributes.macName, systemImage: "desktopcomputer") + .font(.caption2) + .foregroundStyle(.secondary) + } + + DynamicIslandExpandedRegion(.trailing) { + if let total = context.state.totalDuration { + remainingText(state: context.state, total: total) + .font(.caption2) + .foregroundStyle(.secondary) + } + } + + DynamicIslandExpandedRegion(.center) { + timerDisplay(state: context.state) + .font(.system(size: 32, weight: .light, design: .monospaced)) + .foregroundStyle(timerColor(state: context.state)) + } + + DynamicIslandExpandedRegion(.bottom) { + if let progress = progress(state: context.state) { + ProgressView(value: min(progress, 1.0)) + .tint(progressColor(progress)) + } + } + } compactLeading: { + timerDisplay(state: context.state) + .font(.system(.caption, design: .monospaced)) + .foregroundStyle(timerColor(state: context.state)) + } compactTrailing: { + Image(systemName: "circle.fill") + .font(.system(size: 6)) + .foregroundStyle(.green) + } minimal: { + Image(systemName: "play.circle.fill") + .foregroundStyle(context.state.isTimerRunning ? .green : .secondary) + } + } + } + + // MARK: - Timer Display + + @ViewBuilder + private func timerDisplay(state: PresentationAttributes.ContentState) -> some View { + if state.isTimerRunning, let startDate = state.timerStartDate { + // Synthetic start = startDate - accumulatedSeconds + // Text(date, style: .timer) counts up from the given date + let syntheticStart = startDate.addingTimeInterval(-Double(state.accumulatedSeconds)) + Text(syntheticStart, style: .timer) + .multilineTextAlignment(.center) + } else { + // Paused: show static time + Text(formatTime(state.accumulatedSeconds)) + .multilineTextAlignment(.center) + } + } + + @ViewBuilder + private func remainingText(state: PresentationAttributes.ContentState, total: Int) -> some View { + if state.isTimerRunning, let startDate = state.timerStartDate { + let endDate = startDate.addingTimeInterval(Double(total - state.accumulatedSeconds)) + Text(endDate, style: .timer) + .multilineTextAlignment(.trailing) + } else { + let remaining = max(0, total - state.accumulatedSeconds) + Text("-\(formatTime(remaining))") + .multilineTextAlignment(.trailing) + } + } + + // MARK: - Helpers + + private func formatTime(_ seconds: Int) -> String { + let m = seconds / 60 + let s = seconds % 60 + return String(format: "%02d:%02d", m, s) + } + + private func timerColor(state: PresentationAttributes.ContentState) -> Color { + guard let total = state.totalDuration, total > 0 else { return .white } + let elapsed = state.accumulatedSeconds + if elapsed >= total { return .red } + if elapsed >= Int(Double(total) * 0.9) { return .orange } + return .white + } + + private func progress(state: PresentationAttributes.ContentState) -> Double? { + guard let total = state.totalDuration, total > 0 else { return nil } + return Double(state.accumulatedSeconds) / Double(total) + } + + private func progressColor(_ progress: Double) -> Color { + if progress >= 1.0 { return .red } + if progress >= 0.9 { return .orange } + if progress >= 0.75 { return .yellow } + return .green + } +} + +// MARK: - Lock Screen View + +private struct LockScreenView: View { + let context: ActivityViewContext + + var body: some View { + VStack(spacing: 8) { + HStack { + HStack(spacing: 6) { + Image(systemName: "circle.fill") + .font(.system(size: 6)) + .foregroundStyle(.green) + Text(context.attributes.macName) + .font(.caption) + .foregroundStyle(.secondary) + } + + Spacer() + + if let total = context.state.totalDuration { + remainingLabel(total: total) + .font(.caption) + .foregroundStyle(.secondary) + } + } + + // Timer + timerText + .font(.system(size: 36, weight: .light, design: .monospaced)) + .foregroundStyle(timerColor) + .frame(maxWidth: .infinity, alignment: .center) + + // Progress bar + if let total = context.state.totalDuration, total > 0 { + let progress = min(Double(context.state.accumulatedSeconds) / Double(total), 1.0) + GeometryReader { geo in + ZStack(alignment: .leading) { + Capsule() + .fill(.white.opacity(0.15)) + Capsule() + .fill(progressColor(progress)) + .frame(width: geo.size.width * progress) + } + } + .frame(height: 4) + } + } + .padding(16) + .activityBackgroundTint(.black.opacity(0.7)) + } + + @ViewBuilder + private var timerText: some View { + if context.state.isTimerRunning, let startDate = context.state.timerStartDate { + let syntheticStart = startDate.addingTimeInterval(-Double(context.state.accumulatedSeconds)) + Text(syntheticStart, style: .timer) + } else { + Text(formatTime(context.state.accumulatedSeconds)) + } + } + + @ViewBuilder + private func remainingLabel(total: Int) -> some View { + if context.state.isTimerRunning, let startDate = context.state.timerStartDate { + let endDate = startDate.addingTimeInterval(Double(total - context.state.accumulatedSeconds)) + HStack(spacing: 2) { + Text("remaining") + Text(endDate, style: .timer) + } + } else { + let remaining = max(0, total - context.state.accumulatedSeconds) + Text("-\(formatTime(remaining)) remaining") + } + } + + private var timerColor: Color { + guard let total = context.state.totalDuration, total > 0 else { return .white } + let elapsed = context.state.accumulatedSeconds + if elapsed >= total { return .red } + if elapsed >= Int(Double(total) * 0.9) { return .orange } + return .white + } + + private func progressColor(_ progress: Double) -> Color { + if progress >= 1.0 { return .red } + if progress >= 0.9 { return .orange } + if progress >= 0.75 { return .yellow } + return .green + } + + private func formatTime(_ seconds: Int) -> String { + let m = seconds / 60 + let s = seconds % 60 + return String(format: "%02d:%02d", m, s) + } +} diff --git a/MacApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/MacApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png index 833ba5faf6d01e14058638bdaf91b40febfbcebf..632eb72415983b1440e758d11f94b341152c82ff 100644 GIT binary patch literal 19644 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 literal 15534 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 literal 3410 zcmb7G2Ut_d7M?VS=t_cu$|@vuVO0VusH~SJMMb)(D+G33h*&}s6_g7KA{Lq`ZKaBW z4e26EL`1-{(nJj)geo8qiX?<2_uXK7@9p=!?|c8;nLF*Cx&N6n=M3@==>nv!7S+c=`c#1seGn`eu3KWx(Zc(jb`y{PZ2qe#_E48S;xKP zpJiuWczRsJY5l&0fG6%v;n_=lx;3{L{8{9D2#4z|bDcou0+>WR@vvt<*N$ zu+hqTtIMw4d%PI?y^kI{9&{%1Y}C2fD~UQW7zzSVt3D1k`v!qwgEGgg9JGAA)s6cQUnxIL@5b~GQ>H^e8qw} zER;a@I}lU|294G%&PBD4yNa+j;vI$EKi^ zElHKbGev{Y#To&`ar5eP{w(`I93aT?Lx8oAIlbk?%F^|7%er*HOGP@%}_@v%schur=FVQovXmEPD} zeK#iE-=jR`b&y~%3QO2KgucM^LLAj9Un_;IBp z4jDO@s}8ZMTyzw?4v(*S>oN&B1h?~MAEgJkPtPwo>BX;{*sykx+oxLmq?U&cvIy__n3l7mkvD5 z`RGtBqeILKgL_sBy3zkn9Xq)L z0ncoD^7$_+d8c+J33q?4#b?8_osO|vkB(-t-7~ushl;8_tTjw%+p2y0dEI+ui>rjoN%1ZLV&*w0@VM}v99ft>hpHIKilY4e zNefHn#oJaHI`ZM<4{&d%_{=62&l>?4@PhV-=jPgu zv5T?Bca=5E;0MkKkP42O&4IXHm7|FT;cXx4O3eMFGU}YGdq)v4kj0vLInA6gL_j9| zatxYaBEW3L%K{zwtRu0OB-13@O10)zHQ0A{bl6~{9SseXQvf>2zTW%XLetnpDO|yE zEJ}VVO1V9->G|y| zdu4=0NA+q;>m14zOa{AbUm>8l9{K=3KmdDR`WVy!kLcO*(nnd-$(pmTd9KBUhYImo z=5j&DaFfBNgH0Q{Sw>J&aT})g!@jNarlg|+Q~RGL|yK zxs>Kt9V6j=qfIM;AndV7lrL&uQ6>yh75iE9M&X`DcrxDL0bCK&$!;k!d2J;O2t29| zSyZ@(hOFEZB_{L6R-1-gRH(rVor>dxgwb;*xdXW&iYKS)m(^IW!yhL#d-Uk|zOUcphqB(NMXGDHTwP+qwIM#%A1m+|c#ST|!g@ zd{$er4FRs(PCt)WFugV3>$XM+9Rc$PUZ-ooc$cz=Dx0@SlUSV&9Bvc>dWDOYt0?>C z|LyQ_foy2?TLeVRJh2Rq;wA}Llv-kB3rm=b0NFkSaL^Z;`<`kiMJ)T&)ACOLraLV! z`NS^I=|6}R{CI-JRFWx?WYm|s@yw#7_ak4))3j;tYwsgqq8qB_JFDb5nrrMmf*t{) z)lDaR>Lu4su9z;~YwGUN5J8?WFkHMnvVR~v;nXz19pq-kyFFH|`J1pvjbHq@`kKtG zK3I4^M)H9&SF9{{TJh51%<2rmrAhPoyPNFu#aAH#>R1Px5pZJ*w$(>|f4_IJuJ4j| zCF>4oyX>0@j^hY;#x*yw&`p35J|4W&B5IDX62l-%E@3!ykbvGi(Tnmt3?Nf!B-An}zTCL5%!0-$ z&iFqJL*kuD2$=riozd37l@MCuczAluA>l6yyVXLlZKzt(zZ()d<1bVhyAQHF`E*6*+|-fx;>K6RO|EiAuz z>UfvC570#b_s)xybCJr~*nx7VS1v&V z?_l$d9anb<>QeVN7;g`EYKt~>&~^WN#To=;7rie?4x&DO7ZQ8oT_fB7`uIxCFx2KQ zcH9VJ%EcaYdZhbtAH)cOgv=#PT2hP*bI!emmt{{`X^`T(Q6sGh9BC^%9D4kmEG5>Q W>i+an&D6QYDS6H#=+@Bamk86mp> diff --git a/MacApp/Assets.xcassets/AppIcon.appiconset/icon-16.png b/MacApp/Assets.xcassets/AppIcon.appiconset/icon-16.png index 1ee1cfe9f4d0ac50e28d78d61b6db1d0449e8837..978cbcc0e2fa6a1c537318f694059f19b92b8608 100644 GIT binary patch delta 403 zcmV;E0c`&M2+RXEiBL{Q4GJ0x0000DNk~Le0000G0000G2m$~A0FaSrHUIzs0drDE zLIAGL9O(c607PY2NoJ8AM1M3@aq<8F0X9iQK~yLem6FX$!$1(nXY)aeAN8YD0#b#D z7CcnE^ic2tdlA@Z!u7qJL?nbREAOopan`UMn^gwT4RG{9EuU>WkJt@l%YSFW0KO7xc;aA( zfiR*l=J6^s082oW!eu9G?rG+BfZnE1#bW#g!kDi5()}%~~gQ~5tI{ifcK!iW|9SFBf!mH0uX2|bUgS+|r) z{;A{Bm{cpD!FPxgs8p^)`;eb}CK|k>YORm>V--aeuCf|hcfO%#Bri>j4}DE@qR xLwp#a&1-^0IP$FHT`n0wK4w9}=mJr(^#d|caOY1GjiUen002ovPDHLkV1khwt#SYW literal 1150 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 literal 6690 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 literal 1455 zcmb7^c~BEq9LL|Dgn+WkCDJ;E(?pR8mtt+pC16mLE7n@A+*h4)YNd7%45wNNXjGt6 z6M|N#Rf14F=oA8KW2c-}K`oFV2o`1tRD@1v(zoI8kN(x~zTN%J+uu7rzu#}4u1_}v zsGtBr06-7`w!;hP)L^Io(WH0)f`h?&000Xhg-HO17IXpD@CE>rA^?MLgz1x_%U?NC z?5)i>>L!6_NMcH6N=9NzD#y*44?KMZ!8kJ;l-_pGo7AHn# zU;opg7bBxD$HrgH{PlYF&D{Lo3?+>20wjFuIT;9?cuPqG6os4^iV-M*;&>qfV}wzr zHaN${$Bf|Hx`vv2lWulVz7}a=?ztiMr7}N-r9reu_*Az;Wa~C{x^~rxm`$mU{t;#C zs(N7Xtn?h4AxJ*H!$%mV98q5W0@vAdk_9w*^&(vT&4xujW!n;A z?-HVBcoA}XnerL%gA9x?*a*l%kOUOTA{nvREWOx^GS+J)Ba>z6;3No~0mpFz*eD}I zBkF%k_Y@do`tZ@PxaI=8n%|5SG{5Z3E}9=Gp8VEs+@ojil6=1LICNyebRYy86Vr6Y zPVr2&>a)8aoY4&QbjCC_B? z^V!ccrmsgoo6Iuoe7D55nVbGfI;|P5Janlt!+G#<=dP^iEDNFgkCPTE-*h49 zu4|vnvX)D0K8c_}(FrsX1b4T}#){QvAGZss@sJc~;|QF29j8yUGO*wwIsrnyB4@`I!`* zj0}2MUB`FND!N>DaOUf-5BKm)r5bJ(`;)yA0~dlH_G`!3K|2doK0PZuP0x^9Hj23S z+4G|P=i4MIiEwrhuJSgW6d>)Hz0%BogaHI4;Nbz!Izt4|HZBz0EGKQMG*_nRZdGgl zvsWfv)IV#N^R;Bd8N8@l3CG%R#3rzm_nvJ1)Zy4V>y>3*!}rFv?mxf@8jW)LsW9nO zHEYd%hX#$J<(ihYyC%7zRa+6_ePwO!M*dgvVsoD8l|p$fjTczsv|4f7G;o|-vibWF fB-EFPG_HDo;6`3PV2ev#Rh92Z9I_w73hMtC?NA7h diff --git a/MacApp/Assets.xcassets/AppIcon.appiconset/icon-512.png b/MacApp/Assets.xcassets/AppIcon.appiconset/icon-512.png index 1acd28c24975424f5d9de809ce139293e8ec1525..c16946f16013c76016b18f2f25aac609a56ce989 100644 GIT binary patch literal 25768 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 literal 12560 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 bO&@{leM`**l|k=O00000NkvXXu0mjfgFuC| literal 2004 zcmb7_Xg?hS5CnkT@B{Ec@QG7WSTF#4_W}z500khzFhGP690H8s2>@D*02F>Bs=i{v z%3XFb`ZiV##3#Tu_t5C0(Q%>CF%0VuH-T*qE_;cp*`U<1sXD~|Sd;Zg1geQodDOz^ zN{1BuI-pSi8?aHt1Q2KlN<;7#uonI%2~kV^7+ea0h>!qTgF@BRf&*?~06}3NN+c6C z$V3V`4j}-PM$~1JHtU&SWP1;*)q%0=H291h2mKOH>nhe4o8E0c(&d=DC6zMBVVfSL z+sMRmrS3bcPs+`_wg%-Ly&iB+@V!CI(ECodhibgz%kpoeP2YD;;0^EE7hFr#G&EXo zZn16qN4s5IeSAOL9}*gNI5Fwi@pNHE=9k%D7ZiT;ZE^Y8a~0=*xLkMTYJI~`O)af$ z?Kf|AbpFx(;9<|BUg_hJ(Xl5_$6vgBHKS0@&Z#J&yUUR9s^(Nd5J_(-X@Ee0oG1Y$ z5l93gQHVf~P)wIeWNfzABW*IV@>tC#Tdxar(2w=p!gpuolsHzstMP>mN7iK;(7bc- zh@75!aBGa2lUMHhrT3tD25Jsl2;#g8qImC9!2}%&R`J9gjZaW9@lFcTmbt`v`O9eE zm%WCouBm;^cm2j2!uxL!hlXE6POnh*0Y}K75(*CzWFe7BP-F^OC5k3REzQ?jrIxlz zIxE8ABnX^=NF-{&1Jj~vVgFcoFIa`D?W4iuQtpa)AlYqIS!CN89X`5P7g?7~yA%H% z<=XA?@$KWYHzFeIT9Y+~{u~}DEuJZ|d1WyhcYt%s*JpgLQ9S#?r!zUE!|0;rOeLI^ z0^c1%A}obRi9%#kY235(2bWGwh+;({a(ddYqmyYa(s#z1&Mtox7$TM`gFnwmACaR!F>fcZwsZdCKBwZ5B?#Wb!vE-_xXVE{guhgk+ zaM(>>DU6nHeA(A}cP?^hOxg(BG4cj$himOSjyaukSJzy7}P1 z;MajA6bD)UQ8+*bl2UI+J3mUi>MGb>$W1h1b%s4t{MW{a+2?*^+TCl~uT56B zvQBqq=S?rJPtl1G#{Yl#&xG@ba{uk_;@WVg&W=8m$vbB?N=mV;9FR>%Tq-+#_CL8X zF5ZYwGY)F|iWIty^*HE_ygQ%i-=D(VJ5ighzbC>u%)CNVxp>=`)vfC)D9Yhn>r3eC z?%m%@doQ;2UUqgieB_sQW%S~Oes22nnSqX1i3wMO+F3_lvC7JRu2|Pa>!=lF`y@s2 zDow*ax2rxpDtUg*KK$^hjtw3Mj$YC%r*P$Yk&?kiWyjVjS^tj3sf-O#;t=n%mMP_z zyo$BMOU-}ZU*I-jgaaE`^VXPZOI!=CHOsoNK{;a++dUwL zmtB0hsZ;tU#q5|km=?Q9f4ima$^8xoFX=caKCh4k2NfXP-y0XOVEqw>UsfZT;g``! zX8Brc%4l{Ares}hrQ`=QYuV22I&1SehDwvu8lsLo1IqE?6dWw9``^gpz<^;KgztOL zefiu8BrRlcy}fYo*sDo_gZOd|4#XV2ZX;=9n#QxGi}INa=3I^Rv#ORg@;f+q zvJnUNAx$+QypP7dt!cl<5>DZu1FrjR!C`<82xC0G4>I6Br?P>j+VW6<5J+&Jhkr{{ z1kjk9G3Wy$R+hsrsp@JTl>f~JRq|pukS(XODt%#V$ZcrFBiNiSWL;s{v!*!$L3-mY z?uDg2i=NC4Jm5U-$j=w!;JU!s$cQmo;rnU-2{tdcL}K06dU3X$fzZrAu|0-*A`(Iyo-yG_A77%s7_LT+dYM4hmNpsQFdr5$&}0 z%K7=1Opl+m9eWBBaUlKbm>4^gTvkapFhJuh{Zj!n$z`chb-B>mMn+n0-XF}_WAVZ) z@Z&iI2M*NUfD=ES)9?D4e?XuCM4I7n-I8hl$sescEpt*QXd_g1>WrcBv-)-%CFBundlePackageType APPL CFBundleShortVersionString - 1.7 + 1.0 CFBundleVersion 1 LSUIElement diff --git a/README.md b/README.md index c889711..9ee74a0 100644 --- a/README.md +++ b/README.md @@ -133,15 +133,17 @@ Download **ClickerRemote** from the [App Store](https://apps.apple.com/us/app/cl | Feature | Description | |---------|-------------| | **Large Touch Targets** | Easy-to-hit buttons designed for stage use | -| **Apple Watch** | Control slides from your wrist with tap buttons or hands-free wrist gestures | -| **Wrist Gestures** | Flick forward for next slide, flick back for previous — with haptic confirmation | +| **Apple Watch** | Control slides from your wrist with tap buttons, Digital Crown, or double-tap gesture | +| **Digital Crown** | Rotate the crown to navigate slides — clockwise for next, counterclockwise for previous | +| **Live Activities** | See your timer on the Lock Screen and Dynamic Island without opening the app | | **Presentation Timer** | Track time with haptic alerts at custom intervals | | **Always-On Display** | Screen stays on while presenting — no connection drops | | **Dark Mode** | Stage-friendly liquid glass aesthetic | | **Visual Progress** | Color-coded timer bar (green → yellow → orange → red) | | **Duration Presets** | 5, 10, 15, 20, 30 minutes or unlimited | | **Haptic Feedback** | Vibrate every 30s, 1m, 2m, or 5m | -| **Stays Active** | Workout session keeps Watch app visible during presentations | +| **Double-Tap Gesture** | Hands-free next slide on Apple Watch Series 9+ / Ultra 2 (watchOS 11+) | +| **Stays Active** | Extended runtime session keeps Watch app visible during presentations | --- diff --git a/WatchApp/ContentView.swift b/WatchApp/ContentView.swift index 0dc7600..5d0541e 100644 --- a/WatchApp/ContentView.swift +++ b/WatchApp/ContentView.swift @@ -8,6 +8,9 @@ struct ContentView: View { @State private var accumulatedTime: TimeInterval = 0 @State private var timerRunning = false @State private var showSettings = false + @State private var crownOffset: Double = 0 + + private let crownThreshold: Double = 3.0 private func elapsedTime(at date: Date) -> TimeInterval { if timerRunning, let start = timerStartDate { @@ -107,6 +110,27 @@ struct ContentView: View { .padding(.vertical, 4) } } + .focusable() + .digitalCrownRotation( + $crownOffset, + from: -crownThreshold, + through: crownThreshold, + by: 1.0, + sensitivity: .medium, + isContinuous: false, + isHapticFeedbackEnabled: true + ) + .onChange(of: crownOffset) { _, newValue in + if newValue >= crownThreshold { + WKInterfaceDevice.current().play(.directionUp) + connectionManager.nextSlide() + crownOffset = 0 + } else if newValue <= -crownThreshold { + WKInterfaceDevice.current().play(.directionDown) + connectionManager.previousSlide() + crownOffset = 0 + } + } } // MARK: - Timer diff --git a/WatchApp/Info.plist b/WatchApp/Info.plist index 35a88a9..6a27c0e 100644 --- a/WatchApp/Info.plist +++ b/WatchApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7 + 1.0 CFBundleVersion 1 WKApplication diff --git a/WatchApp/SettingsView.swift b/WatchApp/SettingsView.swift index af1e945..b305edd 100644 --- a/WatchApp/SettingsView.swift +++ b/WatchApp/SettingsView.swift @@ -7,11 +7,11 @@ struct SettingsView: View { HStack { Image(systemName: "info.circle") .foregroundColor(.secondary) - Text("Clicker Remote v1.7") + Text("Clicker Remote v1.8") .font(.system(size: 15)) } } footer: { - Text("Use the large button to advance slides. Double-tap gesture (watchOS 11+) also triggers next slide.") + Text("Use the large button, Digital Crown, or double-tap gesture (watchOS 11+) to advance slides. Rotate the crown clockwise for next slide, counterclockwise for previous.") .font(.system(size: 11)) .foregroundColor(.secondary) } diff --git a/iPhoneApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/iPhoneApp/Assets.xcassets/AppIcon.appiconset/icon-1024.png index a28024f2b94cc91349cc86eba53828085d82e28a..a4fcd3480b44393cadec2ed07c8d42e8580bb69f 100644 GIT binary patch literal 18681 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 diff --git a/iPhoneApp/Info.plist b/iPhoneApp/Info.plist index 7bb955f..c2432e3 100644 --- a/iPhoneApp/Info.plist +++ b/iPhoneApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7 + 1.0 CFBundleVersion 1 NSBonjourServices @@ -25,6 +25,8 @@ NSLocalNetworkUsageDescription Clicker needs local network access to find and connect to your Mac. + NSSupportsLiveActivities + UILaunchScreen UISupportedInterfaceOrientations diff --git a/iPhoneApp/LiveActivityManager.swift b/iPhoneApp/LiveActivityManager.swift new file mode 100644 index 0000000..e00edbb --- /dev/null +++ b/iPhoneApp/LiveActivityManager.swift @@ -0,0 +1,84 @@ +import ActivityKit +import Foundation + +class LiveActivityManager { + static let shared = LiveActivityManager() + + private var activity: Activity? + + private init() {} + + // MARK: - Start / End + + func startActivity(macName: String) { + guard ActivityAuthorizationInfo().areActivitiesEnabled else { + print("🔴 Live Activities not enabled") + return + } + + // End any existing activity first + endActivity() + + let attributes = PresentationAttributes(macName: macName) + let initialState = PresentationAttributes.ContentState( + timerStartDate: nil, + accumulatedSeconds: 0, + isTimerRunning: false, + totalDuration: nil + ) + + do { + activity = try Activity.request( + attributes: attributes, + content: .init(state: initialState, staleDate: nil), + pushType: nil + ) + print("🟢 Live Activity started") + } catch { + print("❌ Failed to start Live Activity: \(error)") + } + } + + func endActivity() { + guard let activity = activity else { return } + + let finalState = PresentationAttributes.ContentState( + timerStartDate: nil, + accumulatedSeconds: 0, + isTimerRunning: false, + totalDuration: nil + ) + + Task { + await activity.end( + .init(state: finalState, staleDate: nil), + dismissalPolicy: .immediate + ) + print("🔴 Live Activity ended") + } + + self.activity = nil + } + + // MARK: - Timer Updates + + func updateTimerState( + startDate: Date?, + accumulatedSeconds: Int, + isRunning: Bool, + totalDuration: Int? + ) { + guard let activity = activity else { return } + + let state = PresentationAttributes.ContentState( + timerStartDate: startDate, + accumulatedSeconds: accumulatedSeconds, + isTimerRunning: isRunning, + totalDuration: totalDuration + ) + + Task { + await activity.update(.init(state: state, staleDate: nil)) + } + } +} diff --git a/iPhoneApp/PresentationAttributes.swift b/iPhoneApp/PresentationAttributes.swift new file mode 100644 index 0000000..62a2f4e --- /dev/null +++ b/iPhoneApp/PresentationAttributes.swift @@ -0,0 +1,17 @@ +import ActivityKit +import Foundation + +struct PresentationAttributes: ActivityAttributes { + var macName: String + + struct ContentState: Codable, Hashable { + /// When the current timer run started (nil if paused/stopped) + var timerStartDate: Date? + /// Seconds accumulated from previous runs before the current one + var accumulatedSeconds: Int + /// Whether the timer is currently running + var isTimerRunning: Bool + /// Total presentation duration in seconds (nil = no limit) + var totalDuration: Int? + } +} diff --git a/iPhoneApp/PresentationTimer.swift b/iPhoneApp/PresentationTimer.swift index 47f9147..0d3962c 100644 --- a/iPhoneApp/PresentationTimer.swift +++ b/iPhoneApp/PresentationTimer.swift @@ -32,7 +32,9 @@ class PresentationTimer: ObservableObject { // MARK: - Published Properties @Published var elapsedTime: TimeInterval = 0 @Published var isRunning = false - @Published var config = TimerConfig(vibrationInterval: 60, totalDuration: nil) + @Published var config = TimerConfig(vibrationInterval: 60, totalDuration: nil) { + didSet { updateLiveActivity() } + } @Published var lastVibratedAt: TimeInterval = 0 // MARK: - Private Properties @@ -94,30 +96,49 @@ class PresentationTimer: ObservableObject { } // MARK: - Timer Controls + /// The date when the current timer run started (used for Live Activity) + private var timerStartDate: Date? + func start() { guard !isRunning else { return } - + isRunning = true lastVibratedAt = elapsedTime - + timerStartDate = Date() + timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in self?.tick() } - + // Keep timer running in background RunLoop.current.add(timer!, forMode: .common) + updateLiveActivity() } - + func pause() { isRunning = false + timerStartDate = nil timer?.invalidate() timer = nil + updateLiveActivity() } - + func reset() { pause() elapsedTime = 0 lastVibratedAt = 0 + updateLiveActivity() + } + + // MARK: - Live Activity + + private func updateLiveActivity() { + LiveActivityManager.shared.updateTimerState( + startDate: timerStartDate, + accumulatedSeconds: Int(elapsedTime), + isRunning: isRunning, + totalDuration: config.totalDuration.map { Int($0) } + ) } func toggle() { diff --git a/iPhoneApp/iPhoneConnectionManager.swift b/iPhoneApp/iPhoneConnectionManager.swift index 0e50991..c410d70 100644 --- a/iPhoneApp/iPhoneConnectionManager.swift +++ b/iPhoneApp/iPhoneConnectionManager.swift @@ -246,6 +246,7 @@ class iPhoneConnectionManager: NSObject, ObservableObject { connectedMac = nil isConnected = false statusMessage = "Disconnected" + LiveActivityManager.shared.endActivity() startBrowsing() } @@ -296,6 +297,7 @@ extension iPhoneConnectionManager: MCSessionDelegate { self.updateWatchWithConnectionStatus() self.isSearching = false self.lastError = nil + LiveActivityManager.shared.startActivity(macName: peerID.displayName) case .connecting: self.debugLog("SESSION STATE: Connecting to \(peerID.displayName)", level: .network) @@ -310,6 +312,7 @@ extension iPhoneConnectionManager: MCSessionDelegate { self.isConnected = false self.stopKeepalive() self.updateWatchWithConnectionStatus() + LiveActivityManager.shared.endActivity() if self.lastConnectedMacName != nil { self.statusMessage = "Connection lost, reconnecting..." self.debugLog("Scheduling reconnect attempt...", level: .info) diff --git a/index.html b/index.html index de6adce..dba0f9c 100644 --- a/index.html +++ b/index.html @@ -148,8 +148,8 @@

Presentation Remote for Apple Fans

Mac 1.2ClickerRemoteReceiver
-
iOS 1.7ClickerRemote
-
watchOS 1.7ClickerWatch
+
iOS 1.8ClickerRemote
+
watchOS 1.8ClickerWatch
@@ -175,8 +175,8 @@

Peer-to-peer reliability

02 -

Cross-device gesture flow

-

Apple Watch flick trigger the same RemoteCommand used by the iPhone UI, routed through WatchConnectivity with built-in lockout guards.

+

Cross-device control

+

Apple Watch double-tap gestures and Digital Crown rotation trigger the same RemoteCommand used by the iPhone UI, routed through WatchConnectivity.

03 @@ -205,6 +205,7 @@

ClickerRemote (iPhone)

  • Dark-only UI for backstage visibility
  • Subscription-ready with trials
  • Automatic Mac discovery via MultipeerConnectivity
  • +
  • Live Activities on Lock Screen & Dynamic Island
  • @@ -222,9 +223,9 @@

    ClickerRemoteReceiver (Mac)

    ClickerWatch (Apple Watch)

    • Installed automatically with iOS app
    • -
    • Gesture-based gestures with inversion option
    • -
    • Auto-toggle tied to wrist raise/lower
    • -
    • Workout session keeps app alive
    • +
    • Digital Crown rotation for slide navigation
    • +
    • Double-tap gesture for hands-free next slide
    • +
    • Extended runtime session keeps app alive
    • Relays commands through iPhone instantly
    @@ -247,7 +248,7 @@

    Pair the iPhone remote

    Activate the Watch

    -

    Enable the Watch companion from the iOS app. Wrist flicks become precise previous/next commands with a 3-second lockout.

    +

    The Watch companion installs automatically. Use the Digital Crown, double-tap gesture, or on-screen buttons to control slides from your wrist.

    Present with confidence

    @@ -297,7 +298,7 @@

    Security posture

  • Local only: Commands stay on your network
  • Accessibility: Minimal permissions, once per Mac
  • Hardened Runtime: Required for notarization
  • -
  • Watch lockout: Prevents accidental slide jumps
  • +
  • Crown threshold: 3-detent threshold prevents accidental slide jumps
  • diff --git a/project.yml b/project.yml index f563dc6..c52fc50 100644 --- a/project.yml +++ b/project.yml @@ -88,13 +88,14 @@ targets: NSBonjourServices: - _clickerremote._tcp - _clickerremote._udp + NSSupportsLiveActivities: true NSLocalNetworkUsageDescription: "Clicker needs local network access to find and connect to your Mac." settings: base: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios PRODUCT_NAME: ClickerRemote IPHONEOS_DEPLOYMENT_TARGET: "18.0" - MARKETING_VERSION: "1.7" + MARKETING_VERSION: "1.8" CURRENT_PROJECT_VERSION: "1" CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: HD35YQ72U4 @@ -104,6 +105,34 @@ targets: dependencies: - target: ClickerWatch embed: true + - target: ClickerLiveActivity + embed: true + + # ───────────────────────────────────────────────────────────── + # Live Activity Widget Extension + # ───────────────────────────────────────────────────────────── + ClickerLiveActivity: + type: app-extension + platform: iOS + sources: + - path: LiveActivityWidget + - path: iPhoneApp/PresentationAttributes.swift + info: + path: LiveActivityWidget/Info.plist + properties: + NSExtension: + NSExtensionPointIdentifier: com.apple.widgetkit-extension + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios.LiveActivity + PRODUCT_NAME: ClickerLiveActivity + IPHONEOS_DEPLOYMENT_TARGET: "18.0" + MARKETING_VERSION: "1.8" + CURRENT_PROJECT_VERSION: "1" + CODE_SIGN_STYLE: Automatic + DEVELOPMENT_TEAM: HD35YQ72U4 + TARGETED_DEVICE_FAMILY: "1" + SWIFT_EMIT_LOC_STRINGS: "YES" # ───────────────────────────────────────────────────────────── # Apple Watch App @@ -132,7 +161,7 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-ios.watchkitapp PRODUCT_NAME: ClickerWatch WATCHOS_DEPLOYMENT_TARGET: "10.0" - MARKETING_VERSION: "1.7" + MARKETING_VERSION: "1.8" CURRENT_PROJECT_VERSION: "1" CODE_SIGN_STYLE: Automatic DEVELOPMENT_TEAM: HD35YQ72U4 @@ -155,6 +184,7 @@ schemes: targets: ClickeriOS: all ClickerWatch: all + ClickerLiveActivity: all run: config: Debug executable: ClickeriOS diff --git a/wiki/Home.md b/wiki/Home.md index b986b99..6e139c5 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -17,9 +17,9 @@ Welcome to the ClickerRemote developer documentation. This wiki contains technic ClickerRemote is a presentation remote system consisting of three apps: -- **ClickerRemote** (iOS v1.7) — Remote control app for iPhone +- **ClickerRemote** (iOS v1.8) — Remote control app for iPhone - **ClickerRemoteReceiver** (macOS v1.2) — Menu bar app that receives commands -- **ClickerWatch** (watchOS v1.7) — Apple Watch companion for wrist-based control +- **ClickerWatch** (watchOS v1.8) — Apple Watch companion for wrist-based control ```mermaid %%{init: {'theme': 'dark'}}%% From 9a3772526b46cd961b79c3a9968ad614af331c29 Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 16:19:28 +0900 Subject: [PATCH 07/11] add invert option in apple watch --- WatchApp/ContentView.swift | 25 ++++++++++++------------- WatchApp/SettingsView.swift | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/WatchApp/ContentView.swift b/WatchApp/ContentView.swift index 5d0541e..aeedce6 100644 --- a/WatchApp/ContentView.swift +++ b/WatchApp/ContentView.swift @@ -9,8 +9,8 @@ struct ContentView: View { @State private var timerRunning = false @State private var showSettings = false @State private var crownOffset: Double = 0 - - private let crownThreshold: Double = 3.0 + @State private var lastCrownDetent: Int = 0 + @AppStorage("invertCrown") private var invertCrown = false private func elapsedTime(at date: Date) -> TimeInterval { if timerRunning, let start = timerStartDate { @@ -113,23 +113,22 @@ struct ContentView: View { .focusable() .digitalCrownRotation( $crownOffset, - from: -crownThreshold, - through: crownThreshold, - by: 1.0, + from: -10000.0, + through: 10000.0, sensitivity: .medium, - isContinuous: false, - isHapticFeedbackEnabled: true + isContinuous: true ) .onChange(of: crownOffset) { _, newValue in - if newValue >= crownThreshold { - WKInterfaceDevice.current().play(.directionUp) + let detent = Int(newValue.rounded()) + guard detent != lastCrownDetent else { return } + let isForward = invertCrown ? (detent < lastCrownDetent) : (detent > lastCrownDetent) + WKInterfaceDevice.current().play(.click) + if isForward { connectionManager.nextSlide() - crownOffset = 0 - } else if newValue <= -crownThreshold { - WKInterfaceDevice.current().play(.directionDown) + } else { connectionManager.previousSlide() - crownOffset = 0 } + lastCrownDetent = detent } } diff --git a/WatchApp/SettingsView.swift b/WatchApp/SettingsView.swift index b305edd..9e3cd63 100644 --- a/WatchApp/SettingsView.swift +++ b/WatchApp/SettingsView.swift @@ -1,8 +1,23 @@ import SwiftUI struct SettingsView: View { + @AppStorage("invertCrown") private var invertCrown = false + var body: some View { List { + Section { + Toggle(isOn: $invertCrown) { + Label("Invert Crown", systemImage: "digitalcrown.horizontal.arrow.counterclockwise") + .font(.system(size: 15)) + } + } footer: { + Text(invertCrown + ? "Crown clockwise = previous slide, counterclockwise = next slide." + : "Crown clockwise = next slide, counterclockwise = previous slide.") + .font(.system(size: 11)) + .foregroundColor(.secondary) + } + Section { HStack { Image(systemName: "info.circle") @@ -11,7 +26,7 @@ struct SettingsView: View { .font(.system(size: 15)) } } footer: { - Text("Use the large button, Digital Crown, or double-tap gesture (watchOS 11+) to advance slides. Rotate the crown clockwise for next slide, counterclockwise for previous.") + Text("Use the large button, Digital Crown, or double-tap gesture (watchOS 11+) to advance slides.") .font(.system(size: 11)) .foregroundColor(.secondary) } From 329912b68cb3167b95d7f5bc44c2da5bb8ca3149 Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 16:23:14 +0900 Subject: [PATCH 08/11] modify version --- LiveActivityWidget/Info.plist | 2 +- MacApp/Info.plist | 2 +- WatchApp/SettingsView.swift | 2 +- iPhoneApp/Info.plist | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LiveActivityWidget/Info.plist b/LiveActivityWidget/Info.plist index 6ef3ac5..ab9b6af 100644 --- a/LiveActivityWidget/Info.plist +++ b/LiveActivityWidget/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 1.0 + 1.8 CFBundleVersion 1 NSExtension diff --git a/MacApp/Info.plist b/MacApp/Info.plist index 26b1595..098422a 100644 --- a/MacApp/Info.plist +++ b/MacApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.2 CFBundleVersion 1 LSUIElement diff --git a/WatchApp/SettingsView.swift b/WatchApp/SettingsView.swift index 9e3cd63..81f6953 100644 --- a/WatchApp/SettingsView.swift +++ b/WatchApp/SettingsView.swift @@ -22,7 +22,7 @@ struct SettingsView: View { HStack { Image(systemName: "info.circle") .foregroundColor(.secondary) - Text("Clicker Remote v1.8") + Text("Clicker Remote") .font(.system(size: 15)) } } footer: { diff --git a/iPhoneApp/Info.plist b/iPhoneApp/Info.plist index c2432e3..d7ac169 100644 --- a/iPhoneApp/Info.plist +++ b/iPhoneApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.8 CFBundleVersion 1 NSBonjourServices From 1a88289acb6da0c0d07b30b1e0da9b0d785b5de0 Mon Sep 17 00:00:00 2001 From: donny-son Date: Fri, 20 Mar 2026 16:52:09 +0900 Subject: [PATCH 09/11] add metadata for distribution --- LiveActivityWidget/Info.plist | 2 ++ project.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/LiveActivityWidget/Info.plist b/LiveActivityWidget/Info.plist index ab9b6af..3482a4f 100644 --- a/LiveActivityWidget/Info.plist +++ b/LiveActivityWidget/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + ClickerLiveActivity CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/project.yml b/project.yml index c52fc50..65081f6 100644 --- a/project.yml +++ b/project.yml @@ -120,6 +120,7 @@ targets: info: path: LiveActivityWidget/Info.plist properties: + CFBundleDisplayName: ClickerLiveActivity NSExtension: NSExtensionPointIdentifier: com.apple.widgetkit-extension settings: From dce5f5efd397d807afc7e3e9634982eb4bcd1bec Mon Sep 17 00:00:00 2001 From: donny-son Date: Sat, 21 Mar 2026 12:40:46 +0900 Subject: [PATCH 10/11] Update SubscriptionStoreView to use productIDs instead of groupID Updated the StoreKit 2 subscription configuration to use product IDs directly instead of a subscription group ID, and removed the now-unused group ID constant. - Removed `subscriptionGroupID` constant from SubscriptionManager.swift as it is no longer needed - Updated `PaywallView` to initialize `SubscriptionStoreView` with `productIDs: [subscriptionProductID]` instead of `groupID: subscriptionGroupID` This change simplifies the subscription store configuration by using a more direct approach with explicit product IDs rather than relying on a subscription group identifier. This aligns with modern StoreKit 2 best practices and makes the subscription product configuration more explicit and maintainable. --- iPhoneApp/PaywallView.swift | 4 ++-- iPhoneApp/SubscriptionManager.swift | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/iPhoneApp/PaywallView.swift b/iPhoneApp/PaywallView.swift index 5073844..df7dc58 100644 --- a/iPhoneApp/PaywallView.swift +++ b/iPhoneApp/PaywallView.swift @@ -12,7 +12,7 @@ struct PaywallView: View { @Environment(\.dismiss) private var dismiss var body: some View { - SubscriptionStoreView(groupID: subscriptionGroupID) { + SubscriptionStoreView(productIDs: [subscriptionProductID]) { VStack(spacing: 24) { // Header VStack(spacing: 16) { @@ -45,7 +45,7 @@ struct PaywallView: View { } .padding(.top, 40) } - .subscriptionStoreButtonLabel(.multiline) + .subscriptionStoreButtonLabel(.action) .storeButton(.visible, for: .restorePurchases) .onInAppPurchaseCompletion { _, result in if case .success(.success(_)) = result { diff --git a/iPhoneApp/SubscriptionManager.swift b/iPhoneApp/SubscriptionManager.swift index b0e0bce..0b3130c 100644 --- a/iPhoneApp/SubscriptionManager.swift +++ b/iPhoneApp/SubscriptionManager.swift @@ -4,9 +4,6 @@ import Foundation /// Product ID for the yearly subscription let subscriptionProductID = "com.dou.clicker_ios.subscription.yearly" -/// Subscription group ID for StoreKit configuration -let subscriptionGroupID = "21901349" - /// Manages subscription state, purchases, and trial tracking using StoreKit 2 @MainActor @Observable From 4e7a7ae0547fd77c7fef45b2369ddf805b2092f1 Mon Sep 17 00:00:00 2001 From: donny-son Date: Sun, 22 Mar 2026 13:52:53 +0900 Subject: [PATCH 11/11] update mac app version --- CLAUDE.md | 4 +-- Casks/clicker-remote-receiver.rb | 42 ++++++++++++---------- MacApp/AppCoordinator.swift | 6 +++- MacApp/Info.plist | 2 +- MacApp/PresentationRemoteMacApp.swift | 4 +++ MacApp/Services/PreferencesManager.swift | 16 +++++++++ MacApp/Services/UpdateChecker.swift | 46 ++++++++++++++++++++++++ MacApp/ViewModels/MenuBarViewModel.swift | 11 +++++- MacApp/Views/MenuBarView.swift | 17 +++++---- project.yml | 2 +- wiki/Home.md | 2 +- 11 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 MacApp/Services/UpdateChecker.swift diff --git a/CLAUDE.md b/CLAUDE.md index 119c4cb..08e4531 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,7 +3,7 @@ ## Project Overview This is a SwiftUI-based presentation remote system with three apps: -- **Mac App** (`ClickerRemoteReceiver` v1.2): Menu bar app that receives commands and sends keystrokes to presentation software +- **Mac App** (`ClickerRemoteReceiver` v1.8): Menu bar app that receives commands and sends keystrokes to presentation software - **iPhone App** (`ClickerRemote` v1.8): Remote control with vertical slide navigation and presentation timer - **Apple Watch App** (`ClickerWatch` v1.8): Companion watch app with gesture-based slide control using double tap motion for next slide @@ -64,7 +64,7 @@ The notarized DMG is created at `./build/ClickerRemoteReceiver-{version}.dmg`. **Create GitHub release and update Homebrew tap:** ```bash # Create the release -gh release create v1.2 ./build/ClickerRemoteReceiver-1.2.dmg --title 'Clicker v1.2' --notes 'Release notes' +gh release create v1.8 ./build/ClickerRemoteReceiver-1.8.dmg --title 'Clicker v1.8' --notes 'Release notes' # Trigger homebrew-tap update (auto-calculates SHA256) just update-tap diff --git a/Casks/clicker-remote-receiver.rb b/Casks/clicker-remote-receiver.rb index 2b1159a..5810101 100644 --- a/Casks/clicker-remote-receiver.rb +++ b/Casks/clicker-remote-receiver.rb @@ -1,30 +1,34 @@ -cask "clicker-remote-receiver" do - version "1.2" - sha256 "c93cc1b685318f5fa61d7bfb8f7e5a7896c6400e22268b7097535b5bf8ab3dc3" +cask("clicker-remote-receiver") do + version("1.8") + sha256("c93cc1b685318f5fa61d7bfb8f7e5a7896c6400e22268b7097535b5bf8ab3dc3") - url "https://github.com/douinc/clicker/releases/download/v#{version}/ClickerRemoteReceiver-#{version}.dmg" - name "Clicker Remote Receiver" - desc "Presentation remote control - Mac receiver for iOS ClickerRemote app" - homepage "https://github.com/douinc/clicker" + url("https://github.com/douinc/clicker/releases/download/v#{version}/ClickerRemoteReceiver-#{version}.dmg") + name("Clicker Remote Receiver") + desc("Presentation remote control - Mac receiver for iOS ClickerRemote app") + homepage("https://github.com/douinc/clicker") livecheck do - url :url - strategy :github_latest + url(:url) + strategy(:github_latest) end - depends_on macos: ">= :sonoma" + depends_on(macos: ">= :sonoma") - app "ClickerRemoteReceiver.app" + app("ClickerRemoteReceiver.app") postflight do - # Request accessibility permission on first install - system_command "/usr/bin/osascript", - args: ["-e", 'tell application "System Preferences" to reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"'], - sudo: false + # Open Accessibility privacy pane so user can grant permission + system_command( + "/usr/bin/open", + args: ["x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"], + sudo: false + ) end - zap trash: [ - "~/Library/Preferences/com.dou.clicker-mac.plist", - "~/Library/Application Support/ClickerRemoteReceiver", - ] + zap( + trash: [ + "~/Library/Preferences/com.dou.clicker-mac.plist", + "~/Library/Application Support/ClickerRemoteReceiver" + ] + ) end diff --git a/MacApp/AppCoordinator.swift b/MacApp/AppCoordinator.swift index 9163a51..bf93c3e 100644 --- a/MacApp/AppCoordinator.swift +++ b/MacApp/AppCoordinator.swift @@ -17,6 +17,7 @@ final class AppCoordinator: ObservableObject { let permissionService: PermissionService let keystrokeService: KeystrokeService let connectionManager: MacConnectionManager + let updateChecker = UpdateChecker() // MARK: - View Models @@ -25,7 +26,8 @@ final class AppCoordinator: ObservableObject { connectionManager: connectionManager, preferences: preferences, permissionService: permissionService, - keystrokeService: keystrokeService + keystrokeService: keystrokeService, + updateChecker: updateChecker ) }() @@ -65,6 +67,8 @@ final class AppCoordinator: ObservableObject { // Check permission status permissionService.checkPermissionStatus() + updateChecker.checkIfNeeded() + if !preferences.hasCompletedOnboarding { // First launch - show welcome window showWelcome = true diff --git a/MacApp/Info.plist b/MacApp/Info.plist index 098422a..efb8b96 100644 --- a/MacApp/Info.plist +++ b/MacApp/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2 + 1.8 CFBundleVersion 1 LSUIElement diff --git a/MacApp/PresentationRemoteMacApp.swift b/MacApp/PresentationRemoteMacApp.swift index de8a8f3..dbee395 100644 --- a/MacApp/PresentationRemoteMacApp.swift +++ b/MacApp/PresentationRemoteMacApp.swift @@ -133,6 +133,10 @@ struct SettingsView: View { .padding(.vertical, 8) } + Section("General") { + Toggle("Launch at Login", isOn: $preferences.launchAtLogin) + } + Section("Permissions") { HStack { Text("Accessibility Permission") diff --git a/MacApp/Services/PreferencesManager.swift b/MacApp/Services/PreferencesManager.swift index 65aae41..be63fe2 100644 --- a/MacApp/Services/PreferencesManager.swift +++ b/MacApp/Services/PreferencesManager.swift @@ -1,4 +1,5 @@ import Foundation +import ServiceManagement /// Manages app preferences and first-launch state using UserDefaults /// Provides a centralized, testable interface for all app settings @@ -24,6 +25,20 @@ final class PreferencesManager: ObservableObject { } } + @Published var launchAtLogin: Bool { + didSet { + do { + if launchAtLogin { + try SMAppService.mainApp.register() + } else { + try SMAppService.mainApp.unregister() + } + } catch { + launchAtLogin = oldValue + } + } + } + // MARK: - Private Properties private let defaults: UserDefaults @@ -34,6 +49,7 @@ final class PreferencesManager: ObservableObject { // Load persisted values self.hasCompletedOnboarding = defaults.bool(forKey: Keys.hasCompletedOnboarding) self.debugMenuEnabled = defaults.bool(forKey: Keys.debugMenuEnabled) + self.launchAtLogin = SMAppService.mainApp.status == .enabled } // MARK: - Public Methods diff --git a/MacApp/Services/UpdateChecker.swift b/MacApp/Services/UpdateChecker.swift new file mode 100644 index 0000000..c2addab --- /dev/null +++ b/MacApp/Services/UpdateChecker.swift @@ -0,0 +1,46 @@ +import Foundation + +final class UpdateChecker: ObservableObject { + @Published var availableUpdate: String? + + private let currentVersion: String + private let lastCheckKey = "lastUpdateCheckDate" + private let checkInterval: TimeInterval = 86400 // 24 hours + + init() { + self.currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0" + } + + func checkIfNeeded() { + if let lastCheck = UserDefaults.standard.object(forKey: lastCheckKey) as? Date, + Date().timeIntervalSince(lastCheck) < checkInterval { + return + } + + Task { + await check() + } + } + + private func check() async { + guard let url = URL(string: "https://api.github.com/repos/douinc/clicker/releases/latest") else { return } + + do { + let (data, _) = try await URLSession.shared.data(from: url) + guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any], + let tagName = json["tag_name"] as? String else { return } + + let latestVersion = tagName.hasPrefix("v") ? String(tagName.dropFirst()) : tagName + + UserDefaults.standard.set(Date(), forKey: lastCheckKey) + + if latestVersion.compare(currentVersion, options: .numeric) == .orderedDescending { + await MainActor.run { + self.availableUpdate = latestVersion + } + } + } catch { + print("Update check failed: \(error.localizedDescription)") + } + } +} diff --git a/MacApp/ViewModels/MenuBarViewModel.swift b/MacApp/ViewModels/MenuBarViewModel.swift index 1a5cefc..e652c22 100644 --- a/MacApp/ViewModels/MenuBarViewModel.swift +++ b/MacApp/ViewModels/MenuBarViewModel.swift @@ -14,6 +14,7 @@ final class MenuBarViewModel: ObservableObject { @Published private(set) var isConnected: Bool = false @Published private(set) var isListening: Bool = false @Published private(set) var hasAccessibilityPermission: Bool = false + @Published private(set) var availableUpdate: String? // MARK: - Services @@ -21,6 +22,7 @@ final class MenuBarViewModel: ObservableObject { let preferences: PreferencesManager let permissionService: PermissionService let keystrokeService: KeystrokeService + let updateChecker: UpdateChecker // MARK: - Private Properties @@ -32,12 +34,14 @@ final class MenuBarViewModel: ObservableObject { connectionManager: MacConnectionManager, preferences: PreferencesManager = .shared, permissionService: PermissionService = .shared, - keystrokeService: KeystrokeService = .shared + keystrokeService: KeystrokeService = .shared, + updateChecker: UpdateChecker ) { self.connectionManager = connectionManager self.preferences = preferences self.permissionService = permissionService self.keystrokeService = keystrokeService + self.updateChecker = updateChecker setupBindings() setupCommandHandler() @@ -82,6 +86,11 @@ final class MenuBarViewModel: ObservableObject { permissionService.$hasAccessibilityPermission .receive(on: DispatchQueue.main) .assign(to: &$hasAccessibilityPermission) + + // Available update + updateChecker.$availableUpdate + .receive(on: DispatchQueue.main) + .assign(to: &$availableUpdate) } private func setupCommandHandler() { diff --git a/MacApp/Views/MenuBarView.swift b/MacApp/Views/MenuBarView.swift index 7616f58..ab0ad30 100644 --- a/MacApp/Views/MenuBarView.swift +++ b/MacApp/Views/MenuBarView.swift @@ -50,6 +50,15 @@ struct MenuBarView: View { Divider() + // Update available + if let update = viewModel.availableUpdate { + Button("Update Available (v\(update))") { + NSWorkspace.shared.open(URL(string: "https://github.com/douinc/clicker/releases/latest")!) + } + + Divider() + } + // Debug menu (conditional) if preferences.debugMenuEnabled { Menu("Debug") { @@ -110,12 +119,6 @@ struct MenuBarIcon: View { let isConnected: Bool var body: some View { - if let nsImage = NSImage(named: "MenuBarIcon") { - Image(nsImage: nsImage) - .renderingMode(.template) - } else { - // Fallback to SF Symbol - Image(systemName: isConnected ? "cursorarrow.click.2" : "cursorarrow.click") - } + Image(systemName: isConnected ? "cursorarrow.click.2" : "cursorarrow.click") } } diff --git a/project.yml b/project.yml index 65081f6..e3f84af 100644 --- a/project.yml +++ b/project.yml @@ -47,7 +47,7 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: com.dou.clicker-mac PRODUCT_NAME: ClickerRemoteReceiver MACOSX_DEPLOYMENT_TARGET: "14.0" - MARKETING_VERSION: "1.2" + MARKETING_VERSION: "1.8" CURRENT_PROJECT_VERSION: "1" CODE_SIGN_STYLE: Automatic CODE_SIGN_ENTITLEMENTS: MacApp/ClickerMac.entitlements diff --git a/wiki/Home.md b/wiki/Home.md index 6e139c5..53ffa49 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -18,7 +18,7 @@ Welcome to the ClickerRemote developer documentation. This wiki contains technic ClickerRemote is a presentation remote system consisting of three apps: - **ClickerRemote** (iOS v1.8) — Remote control app for iPhone -- **ClickerRemoteReceiver** (macOS v1.2) — Menu bar app that receives commands +- **ClickerRemoteReceiver** (macOS v1.8) — Menu bar app that receives commands - **ClickerWatch** (watchOS v1.8) — Apple Watch companion for wrist-based control ```mermaid