Skip to content

Commit 4428126

Browse files
authored
Merge pull request #16 from douinc/claude/apple-watch-flick-toggle-wOv2d
bring back wrist flick in ios
2 parents ff720aa + e6e1aee commit 4428126

18 files changed

Lines changed: 625 additions & 111 deletions

CLAUDE.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
## Project Overview
44

55
This is a SwiftUI-based presentation remote system with three apps:
6-
- **Mac App** (`ClickerRemoteReceiver` v1.8): Menu bar app that receives commands and sends keystrokes to presentation software
7-
- **iPhone App** (`ClickerRemote` v1.8): Remote control with vertical slide navigation and presentation timer
8-
- **Apple Watch App** (`ClickerWatch` v1.8): Companion watch app with gesture-based slide control using double tap motion for next slide
6+
- **Mac App** (`ClickerRemoteReceiver` v1.10): Menu bar app that receives commands and sends keystrokes to presentation software
7+
- **iPhone App** (`ClickerRemote` v1.10): Remote control with vertical slide navigation and presentation timer
8+
- **Apple Watch App** (`ClickerWatch` v1.10): Companion watch app with gesture-based slide control using double tap motion for next slide
99

1010
## Tech Stack
1111

@@ -64,7 +64,7 @@ The notarized DMG is created at `./build/ClickerRemoteReceiver-{version}.dmg`.
6464
**Create GitHub release and update Homebrew tap:**
6565
```bash
6666
# Create the release
67-
gh release create v1.8 ./build/ClickerRemoteReceiver-1.8.dmg --title 'Clicker v1.8' --notes 'Release notes'
67+
gh release create v1.10 ./build/ClickerRemoteReceiver-1.10.dmg --title 'Clicker v1.10' --notes 'Release notes'
6868

6969
# Trigger homebrew-tap update (auto-calculates SHA256)
7070
just update-tap
@@ -115,6 +115,9 @@ The `update-tap` command triggers a GitHub Action in `douinc/homebrew-tap` that:
115115
- Bundle ID: `com.dou.clicker-ios.watchkitapp`
116116
- Double-tap gesture via `handGestureShortcut(.primaryAction)` on watchOS 11+ (Apple Watch Series 9+ / Ultra 2) for next slide
117117
- Note: Double-tap requires active display (wrist raised); does not work in always-on / luminance-reduced state
118+
- Wrist flick mode uses CoreMotion gyroscope (`rotationRate.x`) to detect forward/backward wrist flicks for next/previous slide
119+
- "No Going Back" toggle (`gestureNoGoingBack` in UserDefaults) disables backward flick gestures for forward-only navigation, reducing accidental triggers during presentations
120+
- Flick mode settings: gesture lock (3s cooldown), invert gestures, auto-toggle with wrist raise, no going back
118121
- Extended WatchKit runtime session (`WKExtendedRuntimeSession` with `self-care` background mode) keeps app active during presentations
119122

120123
## Development Team

Casks/clicker-remote-receiver.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cask("clicker-remote-receiver") do
2-
version("1.8")
2+
version("1.10")
33
sha256("c93cc1b685318f5fa61d7bfb8f7e5a7896c6400e22268b7097535b5bf8ab3dc3")
44

55
url("https://github.com/douinc/clicker/releases/download/v#{version}/ClickerRemoteReceiver-#{version}.dmg")

LiveActivityWidget/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundlePackageType</key>
1818
<string>XPC!</string>
1919
<key>CFBundleShortVersionString</key>
20-
<string>1.8</string>
20+
<string>1.10</string>
2121
<key>CFBundleVersion</key>
2222
<string>1</string>
2323
<key>NSExtension</key>

MacApp/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>APPL</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>1.8</string>
18+
<string>1.10</string>
1919
<key>CFBundleVersion</key>
2020
<string>1</string>
2121
<key>LSUIElement</key>

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ Download **ClickerRemote** from the [App Store](https://apps.apple.com/us/app/cl
142142
| **Visual Progress** | Color-coded timer bar (green → yellow → orange → red) |
143143
| **Duration Presets** | 5, 10, 15, 20, 30 minutes or unlimited |
144144
| **Haptic Feedback** | Vibrate every 30s, 1m, 2m, or 5m |
145+
| **Wrist Flick Navigation** | Flick your wrist to navigate slides hands-free, with optional "No Going Back" mode for forward-only control |
145146
| **Double-Tap Gesture** | Hands-free next slide on Apple Watch Series 9+ / Ultra 2 (watchOS 11+) |
146147
| **Stays Active** | Extended runtime session keeps Watch app visible during presentations |
147148

WatchApp/ClickerWatchApp.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,48 @@ import SwiftUI
44
struct ClickerWatchApp: App {
55
@StateObject private var connectionManager = WatchConnectionManager()
66
@StateObject private var sessionManager = ExtendedSessionManager()
7+
@StateObject private var gestureManager = GestureManager()
8+
@AppStorage("gestureMode") private var gestureMode = "doubleTap"
79
@Environment(\.scenePhase) var scenePhase
810

11+
private var isFlickMode: Bool { gestureMode == "flickWrist" }
12+
913
var body: some Scene {
1014
WindowGroup {
1115
ContentView()
1216
.environmentObject(connectionManager)
1317
.environmentObject(sessionManager)
18+
.environmentObject(gestureManager)
1419
.onAppear {
1520
sessionManager.start()
21+
wireGestureCallbacks()
1622
}
1723
.onChange(of: scenePhase) { _, phase in
1824
switch phase {
1925
case .active:
2026
sessionManager.start()
21-
case .inactive, .background:
27+
if isFlickMode && gestureManager.autoToggleWithWrist {
28+
gestureManager.start()
29+
}
30+
case .inactive:
31+
if isFlickMode && gestureManager.autoToggleWithWrist {
32+
gestureManager.stop()
33+
}
34+
case .background:
2235
break
2336
@unknown default:
2437
break
2538
}
2639
}
2740
}
2841
}
42+
43+
private func wireGestureCallbacks() {
44+
gestureManager.onNextSlide = { [weak connectionManager] in
45+
connectionManager?.nextSlide()
46+
}
47+
gestureManager.onPreviousSlide = { [weak connectionManager] in
48+
connectionManager?.previousSlide()
49+
}
50+
}
2951
}

0 commit comments

Comments
 (0)