Skip to content

Commit cd72ccc

Browse files
committed
Improve Apple Watch crown controls
1 parent 0239b78 commit cd72ccc

2 files changed

Lines changed: 72 additions & 9 deletions

File tree

WatchApp/ContentView.swift

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ struct ContentView: View {
1212
@State private var showSettings = false
1313
@State private var crownOffset: Double = 0
1414
@State private var lastCrownDetent: Int = 0
15+
@State private var crownDetentAccumulator: Int = 0
1516
@AppStorage("invertCrown") private var invertCrown = false
17+
@AppStorage("crownControlEnabled") private var crownControlEnabled = true
18+
@AppStorage("crownDetentsPerSlide") private var crownDetentsPerSlide = 1
1619

1720
private var isFlickMode: Bool { gestureMode == "flickWrist" }
1821

@@ -49,16 +52,38 @@ struct ContentView: View {
4952
isContinuous: true
5053
)
5154
.onChange(of: crownOffset) { _, newValue in
52-
let detent = Int(newValue.rounded())
53-
guard detent != lastCrownDetent else { return }
54-
let isForward = invertCrown ? (detent < lastCrownDetent) : (detent > lastCrownDetent)
55-
WKInterfaceDevice.current().play(.click)
56-
if isForward {
55+
handleCrownChange(newValue)
56+
}
57+
.onChange(of: crownDetentsPerSlide) { _, _ in
58+
crownDetentAccumulator = 0
59+
}
60+
}
61+
62+
// MARK: - Digital Crown
63+
64+
private func handleCrownChange(_ newValue: Double) {
65+
let detent = Int(newValue.rounded())
66+
let delta = detent - lastCrownDetent
67+
guard delta != 0 else { return }
68+
lastCrownDetent = detent
69+
70+
guard crownControlEnabled else {
71+
crownDetentAccumulator = 0
72+
return
73+
}
74+
75+
crownDetentAccumulator += invertCrown ? -delta : delta
76+
let detentsNeeded = max(crownDetentsPerSlide, 1)
77+
78+
while abs(crownDetentAccumulator) >= detentsNeeded {
79+
if crownDetentAccumulator > 0 {
5780
connectionManager.nextSlide()
81+
crownDetentAccumulator -= detentsNeeded
5882
} else {
5983
connectionManager.previousSlide()
84+
crownDetentAccumulator += detentsNeeded
6085
}
61-
lastCrownDetent = detent
86+
WKInterfaceDevice.current().play(.click)
6287
}
6388
}
6489

WatchApp/SettingsView.swift

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,32 @@ struct SettingsView: View {
44
@EnvironmentObject var gestureManager: GestureManager
55
@AppStorage("gestureMode") private var gestureMode = "doubleTap"
66
@AppStorage("invertCrown") private var invertCrown = false
7+
@AppStorage("crownControlEnabled") private var crownControlEnabled = true
8+
@AppStorage("crownDetentsPerSlide") private var crownDetentsPerSlide = 1
9+
10+
private var crownFooterText: String {
11+
guard crownControlEnabled else {
12+
return "Digital Crown slide navigation is disabled to prevent accidental slide changes."
13+
}
14+
15+
let direction = invertCrown
16+
? "clockwise = previous slide, counterclockwise = next slide"
17+
: "clockwise = next slide, counterclockwise = previous slide"
18+
19+
let sensitivity: String
20+
switch crownDetentsPerSlide {
21+
case 1:
22+
sensitivity = "Fast: every crown detent advances a slide."
23+
case 2:
24+
sensitivity = "Balanced: two detents are required per slide."
25+
case 3:
26+
sensitivity = "Deliberate: three detents are required per slide."
27+
default:
28+
sensitivity = "Locked-in: five detents are required per slide."
29+
}
30+
31+
return "\(sensitivity) Crown \(direction)."
32+
}
733

834
var body: some View {
935
List {
@@ -71,14 +97,26 @@ struct SettingsView: View {
7197
}
7298

7399
Section {
100+
Toggle(isOn: $crownControlEnabled) {
101+
Label("Crown Control", systemImage: "digitalcrown.horizontal.arrow.clockwise")
102+
.font(.system(size: 15))
103+
}
104+
105+
Picker("Sensitivity", selection: $crownDetentsPerSlide) {
106+
Text("Fast").tag(1)
107+
Text("Balanced").tag(2)
108+
Text("Deliberate").tag(3)
109+
Text("Locked-in").tag(5)
110+
}
111+
.disabled(!crownControlEnabled)
112+
74113
Toggle(isOn: $invertCrown) {
75114
Label("Invert Crown", systemImage: "digitalcrown.horizontal.arrow.counterclockwise")
76115
.font(.system(size: 15))
77116
}
117+
.disabled(!crownControlEnabled)
78118
} footer: {
79-
Text(invertCrown
80-
? "Crown clockwise = previous slide, counterclockwise = next slide."
81-
: "Crown clockwise = next slide, counterclockwise = previous slide.")
119+
Text(crownFooterText)
82120
.font(.system(size: 11))
83121
.foregroundColor(.secondary)
84122
}

0 commit comments

Comments
 (0)