@@ -12,6 +12,17 @@ enum SwipeDirection {
1212 case up, down, left, right
1313}
1414
15+ private func getSwipeDirection( _ dx: CGFloat , _ dy: CGFloat ) -> SwipeDirection {
16+ if abs ( dx) > abs ( dy) {
17+ return dx > 0 ? . right : . left
18+ }
19+ return dy > 0 ? . down : . up
20+ }
21+
22+ private func clearBubble( ) {
23+ virtualKeyboardView. setBubble ( 0 , 0 , 0 , 0 , . clear, . clear, nil )
24+ }
25+
1526struct KeyModifier : ViewModifier {
1627 let threshold : CGFloat = 30
1728 let stepSize : CGFloat = 15
@@ -35,6 +46,8 @@ struct KeyModifier: ViewModifier {
3546 let action : GestureAction
3647 let pressedView : ( any View ) ?
3748 let topRight : String ?
49+ let bubbleLabel : String ?
50+ let swipeUpLabel : String ?
3851
3952 func body( content: Content ) -> some View {
4053 VStack {
@@ -59,51 +72,68 @@ struct KeyModifier: ViewModifier {
5972 . gesture (
6073 DragGesture ( minimumDistance: 0 )
6174 . onChanged { value in
75+ let bubbleX = x + width / 2
76+ let bubbleY = y + height / 2
77+ let bubbleWidth = width - columnGap
78+ let bubbleHeight = height - rowGap
79+
6280 if startLocation == nil {
6381 startLocation = value. startLocation
6482 lastLocation = value. startLocation. x
6583 isPressed = true
6684 didTriggerLongPress = false
6785 didMoveFarEnough = false
86+ virtualKeyboardView. setBubble (
87+ bubbleX, bubbleY, bubbleWidth, bubbleHeight, background, shadow, bubbleLabel)
6888
6989 // Schedule long press that can be interrupted by move.
7090 DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.3 ) {
7191 if isPressed && !didTriggerLongPress && !didMoveFarEnough {
7292 didTriggerLongPress = true
93+ clearBubble ( )
7394 action. onLongPress ? ( )
7495 }
7596 }
7697 } else {
7798 let dx = value. location. x - ( startLocation? . x ?? 0 )
7899 let dy = value. location. y - ( startLocation? . y ?? 0 )
79100
80- if !didTriggerLongPress && !didMoveFarEnough {
81- if abs ( dx) > threshold || abs ( dy) > threshold {
101+ if !didTriggerLongPress {
102+ if !didMoveFarEnough && ( abs ( dx) > threshold || abs ( dy) > threshold) {
82103 didMoveFarEnough = true
83104 }
105+ if getSwipeDirection ( dx, dy) == . up {
106+ virtualKeyboardView. setBubble (
107+ bubbleX, bubbleY, bubbleWidth, bubbleHeight, background, shadow, swipeUpLabel)
108+ } else {
109+ clearBubble ( )
110+ }
84111 }
85112 // Process slide.
86- if !slideActivated {
87- if abs ( dx) >= threshold, let start = startLocation {
88- slideActivated = true
89- lastLocation = start. x + ( dx > 0 ? threshold : - threshold)
113+ if let onSlide = action. onSlide {
114+ if !slideActivated {
115+ if abs ( dx) >= threshold, let start = startLocation {
116+ slideActivated = true
117+ lastLocation = start. x + ( dx > 0 ? threshold : - threshold)
118+ }
90119 }
91- }
92- if slideActivated {
93- if let start = startLocation, let last = lastLocation {
94- let totalPast = Int ( floor ( ( last - start. x) / stepSize) )
95- let totalNow = Int ( floor ( ( value. location. x - start. x) / stepSize) )
96- let delta = totalNow - totalPast
97- if delta != 0 {
98- action. onSlide ? ( delta)
120+ if slideActivated {
121+ if let start = startLocation, let last = lastLocation {
122+ let totalPast = Int ( floor ( ( last - start. x) / stepSize) )
123+ let totalNow = Int ( floor ( ( value. location. x - start. x) / stepSize) )
124+ let delta = totalNow - totalPast
125+ if delta != 0 {
126+ onSlide ( delta)
127+ }
128+ lastLocation = value. location. x
99129 }
100- lastLocation = value. location. x
101130 }
102131 }
103132 }
104133 }
105134 . onEnded { value in
106135 isPressed = false
136+ clearBubble ( )
107137 defer {
108138 startLocation = nil
109139 lastLocation = nil
@@ -122,11 +152,7 @@ struct KeyModifier: ViewModifier {
122152
123153 if didMoveFarEnough {
124154 if !didTriggerLongPress {
125- if abs ( dx) > abs ( dy) {
126- action. onSwipe ? ( dx > 0 ? . right : . left)
127- } else {
128- action. onSwipe ? ( dy > 0 ? . down : . up)
129- }
155+ action. onSwipe ? ( getSwipeDirection ( dx, dy) )
130156 }
131157 } else {
132158 if !didTriggerLongPress {
@@ -155,14 +181,16 @@ extension View {
155181 x: CGFloat = 0 , y: CGFloat = 0 ,
156182 width: CGFloat , height: CGFloat , background: Color , pressedBackground: Color , foreground: Color ,
157183 shadow: Color , action: GestureAction , pressedForeground: Color ? = nil ,
158- pressedView: ( any View ) ? = nil , topRight: String ? = nil
184+ pressedView: ( any View ) ? = nil , topRight: String ? = nil , bubbleLabel: String ? = nil ,
185+ swipeUpLabel: String ? = nil
159186 ) -> some View {
160187 self . modifier (
161188 KeyModifier (
162189 x: x, y: y, width: width, height: height, background: background,
163190 pressedBackground: pressedBackground,
164191 foreground: foreground, pressedForeground: pressedForeground ?? foreground,
165- shadow: shadow, action: action, pressedView: pressedView, topRight: topRight
192+ shadow: shadow, action: action, pressedView: pressedView, topRight: topRight,
193+ bubbleLabel: bubbleLabel, swipeUpLabel: swipeUpLabel
166194 )
167195 )
168196 }
0 commit comments