Skip to content

Commit 876fb85

Browse files
committed
bubble cells on long press
1 parent ccc02b9 commit 876fb85

File tree

5 files changed

+196
-52
lines changed

5 files changed

+196
-52
lines changed

uipanel/Bubble.swift

Lines changed: 100 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import SwiftUI
1616

1717
let sideRatio = 0.4
1818
let shadowRadius: CGFloat = 2
19+
let cellWidth: CGFloat = 30
1920

2021
enum BubblePosition {
2122
case left
@@ -25,16 +26,26 @@ enum BubblePosition {
2526

2627
struct BubbleShape: Shape {
2728
let s: CGFloat
29+
let height: CGFloat
2830
let position: BubblePosition
31+
let labels: [String]
32+
let index: Int
2933

3034
func path(in rect: CGRect) -> Path {
3135
var path = Path()
3236
let w = rect.width
3337
let h = rect.height
3438
let r = keyCornerRadius
3539
let c = r * 2
36-
let left = position == .left ? 0 : (position == .middle ? s : 2 * s)
37-
let right = position == .left ? (w - 2 * s) : (position == .middle ? (w - s) : w)
40+
let left =
41+
position == .left ? 0 : ((position == .middle ? s : 2 * s) + CGFloat(index) * cellWidth)
42+
let right =
43+
w
44+
- (position == .right
45+
? 0 : ((position == .middle ? s : 2 * s) + CGFloat(labels.count - 1 - index) * cellWidth))
46+
let leftArc = position != .left && index > 0
47+
let rightArc = position != .right && index < labels.count - 1
48+
let middle = h - height - columnGap
3849

3950
path.move(to: CGPoint(x: 0, y: c))
4051
// top left corner
@@ -53,13 +64,32 @@ struct BubbleShape: Shape {
5364
startAngle: .degrees(270),
5465
endAngle: .degrees(360),
5566
clockwise: false)
56-
// upper right
57-
path.addLine(to: CGPoint(x: w, y: h * 0.4))
58-
// middle right
59-
path.addCurve(
60-
to: CGPoint(x: right, y: h * 0.65),
61-
control1: CGPoint(x: w, y: h * 0.55),
62-
control2: CGPoint(x: right, y: h * 0.5))
67+
if rightArc {
68+
// upper right
69+
path.addLine(to: CGPoint(x: w, y: middle - c))
70+
path.addArc(
71+
center: CGPoint(x: w - c, y: middle - c),
72+
radius: c,
73+
startAngle: .degrees(0),
74+
endAngle: .degrees(90),
75+
clockwise: false)
76+
// middle right
77+
path.addLine(to: CGPoint(x: right + columnGap + r, y: middle))
78+
path.addArc(
79+
center: CGPoint(x: right + columnGap + r, y: middle + columnGap + r),
80+
radius: columnGap + r,
81+
startAngle: .degrees(270),
82+
endAngle: .degrees(180),
83+
clockwise: true)
84+
} else {
85+
// upper right
86+
path.addLine(to: CGPoint(x: w, y: h * 0.4))
87+
// middle right
88+
path.addCurve(
89+
to: CGPoint(x: right, y: h * 0.65),
90+
control1: CGPoint(x: w, y: h * 0.55),
91+
control2: CGPoint(x: right, y: h * 0.5))
92+
}
6393
// lower right
6494
path.addLine(to: CGPoint(x: right, y: h - r))
6595
// bottom right corner
@@ -78,13 +108,32 @@ struct BubbleShape: Shape {
78108
startAngle: .degrees(90),
79109
endAngle: .degrees(180),
80110
clockwise: false)
81-
// lower left
82-
path.addLine(to: CGPoint(x: left, y: h * 0.65))
83-
// middle left
84-
path.addCurve(
85-
to: CGPoint(x: 0, y: h * 0.4),
86-
control1: CGPoint(x: left, y: h * 0.5),
87-
control2: CGPoint(x: 0, y: h * 0.55))
111+
if leftArc {
112+
// lower left
113+
path.addLine(to: CGPoint(x: left, y: middle + columnGap + r))
114+
path.addArc(
115+
center: CGPoint(x: left - columnGap - r, y: middle + columnGap + r),
116+
radius: columnGap + r,
117+
startAngle: .degrees(360),
118+
endAngle: .degrees(270),
119+
clockwise: true)
120+
// middle left
121+
path.addLine(to: CGPoint(x: c, y: middle))
122+
path.addArc(
123+
center: CGPoint(x: c, y: middle - c),
124+
radius: c,
125+
startAngle: .degrees(90),
126+
endAngle: .degrees(180),
127+
clockwise: false)
128+
} else {
129+
// lower left
130+
path.addLine(to: CGPoint(x: left, y: h * 0.65))
131+
// middle left
132+
path.addCurve(
133+
to: CGPoint(x: 0, y: h * 0.4),
134+
control1: CGPoint(x: left, y: h * 0.5),
135+
control2: CGPoint(x: 0, y: h * 0.55))
136+
}
88137
// upper left
89138
path.closeSubpath()
90139

@@ -101,21 +150,47 @@ struct BubbleView: View {
101150
let background: Color
102151
let shadow: Color
103152
let label: String?
153+
let labels: [String]
154+
let index: Int
155+
let highlight: Int
104156

105157
var body: some View {
106158
let h = 2 * height + 1.5 * rowGap - shadowRadius
107159
let s = sideRatio * width
108160
let position: BubblePosition =
109161
x - width / 2 - s < 0 ? .left : (x + width / 2 + s > keyboardWidth ? .right : .middle)
110162
let offsetX = position == .left ? s : (position == .middle ? 0 : -s)
111-
BubbleShape(s: sideRatio * width, position: position)
112-
.fill(background)
113-
.shadow(color: shadow, radius: shadowRadius)
114-
.frame(width: (1 + 2 * sideRatio) * width, height: h)
115-
.overlay(
116-
Text(label ?? "").font(.system(size: h * 0.4).weight(.light))
117-
.offset(y: -h / 4)
118-
)
119-
.position(x: x + offsetX, y: y - (h - height) / 2)
163+
if let label = label {
164+
BubbleShape(s: s, height: height, position: position, labels: [label], index: 0)
165+
.fill(background)
166+
.shadow(color: shadow, radius: shadowRadius)
167+
.frame(width: (1 + 2 * sideRatio) * width, height: h)
168+
.overlay(
169+
Text(label).font(.system(size: h * 0.4).weight(.light))
170+
.offset(y: -h / 4)
171+
)
172+
.position(x: x + offsetX, y: y - (h - height) / 2)
173+
} else {
174+
let offsetCell = (CGFloat(labels.count - 1) / 2 - CGFloat(index)) * cellWidth
175+
BubbleShape(s: s, height: height, position: position, labels: labels, index: index)
176+
.fill(background)
177+
.shadow(color: shadow, radius: shadowRadius)
178+
.frame(
179+
width: (1 + 2 * sideRatio) * width + CGFloat(labels.count - 1) * cellWidth, height: h
180+
)
181+
.overlay(
182+
HStack(spacing: 0) {
183+
ForEach(Array(labels.enumerated()), id: \.offset) { i, label in
184+
Text(label).font(.system(size: h * 0.25).weight(.light))
185+
.frame(width: cellWidth)
186+
.condition(i == highlight) {
187+
$0.foregroundColor(.white).background(highlightBackground)
188+
}
189+
.cornerRadius(keyCornerRadius)
190+
}
191+
}.offset(y: -h / 4)
192+
)
193+
.position(x: x + offsetCell + offsetX, y: y - (h - height) / 2)
194+
}
120195
}
121196
}

uipanel/Key.swift

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct KeyView: View {
3232
let key: String
3333
let subLabel: [String: String]?
3434
let swipeUp: [String: Any]?
35+
let longPress: [String: Any]?
3536

3637
var body: some View {
3738
Text(label)
@@ -47,6 +48,15 @@ struct KeyView: View {
4748
virtualKeyboardView.resetLayerIfNotLocked()
4849
client.keyPressed(key, "")
4950
},
51+
onLongPress: { highlight in
52+
if let actionsList =
53+
((longPress?["cells"] as? [[String: Any]])?.map {
54+
$0["actions"] as? [[String: String]]
55+
} as? [[[String: String]]]), highlight >= 0, highlight < actionsList.count
56+
{
57+
executeActions(actionsList[highlight])
58+
}
59+
},
5060
onSwipe: { direction in
5161
if direction == .up, let swipeUp = swipeUp,
5262
let actions = swipeUp["actions"] as? [[String: String]]
@@ -57,7 +67,10 @@ struct KeyView: View {
5767
),
5868
topRight: subLabel?["topRight"] as? String,
5969
bubbleLabel: label,
60-
swipeUpLabel: swipeUp?["label"] as? String
70+
swipeUpLabel: swipeUp?["label"] as? String,
71+
longPressLabels: (longPress?["cells"] as? [[String: Any]])?.map { $0["label"] as? String }
72+
as? [String],
73+
longPressIndex: longPress?["index"] as? Int
6174
)
6275
}
6376
}
@@ -87,11 +100,11 @@ struct SpaceView: View {
87100
},
88101
onSlide: { step in
89102
if step > 0 {
90-
for i in 0..<step {
103+
for _ in 0..<step {
91104
client.keyPressed("", "ArrowRight")
92105
}
93106
} else {
94-
for i in 0..<(-step) {
107+
for _ in 0..<(-step) {
95108
client.keyPressed("", "ArrowLeft")
96109
}
97110
}
@@ -145,7 +158,7 @@ struct BackspaceView: View {
145158
virtualKeyboardView.resetLayerIfNotLocked()
146159
client.keyPressed("", "Backspace")
147160
},
148-
onLongPress: {
161+
onLongPress: { _ in
149162
startDelete()
150163
},
151164
onSlide: { step in
@@ -191,7 +204,7 @@ struct GlobeView: View {
191204
virtualKeyboardView.resetLayerIfNotLocked()
192205
client.globe()
193206
},
194-
onLongPress: {
207+
onLongPress: { _ in
195208
let items = virtualKeyboardView.viewModel.inputMethods.map { inputMethod in
196209
MenuItem(
197210
text: inputMethod.displayName,

0 commit comments

Comments
 (0)