@@ -5,19 +5,16 @@ import android.view.View
5
5
import android.view.ViewGroup
6
6
import android.view.ViewStructure
7
7
import android.view.accessibility.AccessibilityEvent
8
+ import com.facebook.react.bridge.Arguments
8
9
import com.facebook.react.bridge.LifecycleEventListener
9
10
import com.facebook.react.bridge.UiThreadUtil
11
+ import com.facebook.react.bridge.WritableMap
10
12
import com.facebook.react.uimanager.ThemedReactContext
11
13
import com.facebook.react.uimanager.UIManagerHelper
12
14
import com.facebook.react.uimanager.events.EventDispatcher
13
15
import com.google.android.material.bottomsheet.BottomSheetBehavior
14
16
import com.lodev09.truesheet.core.RootSheetView
15
17
import com.lodev09.truesheet.core.Utils
16
- import com.lodev09.truesheet.events.ContainerSizeChangeEvent
17
- import com.lodev09.truesheet.events.DismissEvent
18
- import com.lodev09.truesheet.events.MountEvent
19
- import com.lodev09.truesheet.events.PresentEvent
20
- import com.lodev09.truesheet.events.SizeChangeEvent
21
18
22
19
class TrueSheetView (context : Context ) :
23
20
ViewGroup (context),
@@ -33,6 +30,11 @@ class TrueSheetView(context: Context) :
33
30
var initialIndex: Int = - 1
34
31
var initialIndexAnimated: Boolean = true
35
32
33
+ /* *
34
+ * Determines if the sheet is being dragged by the user.
35
+ */
36
+ private var isDragging = false
37
+
36
38
/* *
37
39
* Current activeIndex.
38
40
*/
@@ -70,7 +72,10 @@ class TrueSheetView(context: Context) :
70
72
// Configure Sheet Dialog
71
73
sheetDialog.apply {
72
74
setOnSizeChangeListener { w, h ->
73
- eventDispatcher?.dispatchEvent(ContainerSizeChangeEvent (surfaceId, id, Utils .toDIP(w.toFloat()), Utils .toDIP(h.toFloat())))
75
+ val data = Arguments .createMap()
76
+ data.putDouble(" width" , Utils .toDIP(w.toFloat()).toDouble())
77
+ data.putDouble(" height" , Utils .toDIP(h.toFloat()).toDouble())
78
+ dispatchEvent(TrueSheetEvent .CONTAINER_SIZE_CHANGE , data)
74
79
}
75
80
76
81
// Setup listener when the dialog has been presented.
@@ -92,7 +97,7 @@ class TrueSheetView(context: Context) :
92
97
}
93
98
94
99
// Dispatch onPresent event
95
- eventDispatcher?. dispatchEvent(PresentEvent (surfaceId, id, sheetDialog.getSizeInfoForIndex(currentSizeIndex)))
100
+ dispatchEvent(TrueSheetEvent . PRESENT , sizeInfoData( sheetDialog.getSizeInfoForIndex(currentSizeIndex)))
96
101
}
97
102
98
103
// Setup listener when the dialog has been dismissed.
@@ -106,13 +111,21 @@ class TrueSheetView(context: Context) :
106
111
}
107
112
108
113
// Dispatch onDismiss event
109
- eventDispatcher?. dispatchEvent(DismissEvent (surfaceId, id) )
114
+ dispatchEvent(TrueSheetEvent . DISMISS )
110
115
}
111
116
112
117
// Configure sheet behavior events
113
118
behavior.addBottomSheetCallback(
114
119
object : BottomSheetBehavior .BottomSheetCallback () {
115
120
override fun onSlide (sheetView : View , slideOffset : Float ) {
121
+ when (sheetDialog.behavior.state) {
122
+ // For consistency with IOS, we consider SETTLING as dragging change.
123
+ BottomSheetBehavior .STATE_DRAGGING ,
124
+ BottomSheetBehavior .STATE_SETTLING -> handleDragChange(sheetView)
125
+
126
+ else -> { }
127
+ }
128
+
116
129
footerView?.let {
117
130
val y = (maxScreenHeight - sheetView.top - footerHeight).toFloat()
118
131
if (slideOffset >= 0 ) {
@@ -125,23 +138,20 @@ class TrueSheetView(context: Context) :
125
138
}
126
139
}
127
140
128
- override fun onStateChanged (view : View , newState : Int ) {
141
+ override fun onStateChanged (sheetView : View , newState : Int ) {
129
142
if (! isShowing) return
130
143
131
- val sizeInfo = getSizeInfoForState(newState)
132
- if (sizeInfo == null || sizeInfo.index == currentSizeIndex) return
133
-
134
- // Invoke promise when sheet resized programmatically
135
- presentPromise?.let { promise ->
136
- promise()
137
- presentPromise = null
138
- }
144
+ when (newState) {
145
+ // When changed to dragging, we know that the drag has started
146
+ BottomSheetBehavior .STATE_DRAGGING -> handleDragBegin(sheetView)
139
147
140
- currentSizeIndex = sizeInfo.index
141
- setupDimmedBackground(sizeInfo.index)
148
+ // Either of the following state determines drag end
149
+ BottomSheetBehavior .STATE_EXPANDED ,
150
+ BottomSheetBehavior .STATE_COLLAPSED ,
151
+ BottomSheetBehavior .STATE_HALF_EXPANDED -> handleDragEnd(newState)
142
152
143
- // Dispatch onSizeChange event
144
- eventDispatcher?.dispatchEvent( SizeChangeEvent (surfaceId, id, sizeInfo))
153
+ else -> { }
154
+ }
145
155
}
146
156
}
147
157
)
@@ -192,7 +202,7 @@ class TrueSheetView(context: Context) :
192
202
}
193
203
194
204
// Dispatch onMount event
195
- eventDispatcher?. dispatchEvent(MountEvent (surfaceId, id) )
205
+ dispatchEvent(TrueSheetEvent . MOUNT )
196
206
}
197
207
}
198
208
}
@@ -239,6 +249,68 @@ class TrueSheetView(context: Context) :
239
249
sheetDialog.dismiss()
240
250
}
241
251
252
+ private fun sizeInfoData (sizeInfo : SizeInfo ): WritableMap {
253
+ val data = Arguments .createMap()
254
+ data.putInt(" index" , sizeInfo.index)
255
+ data.putDouble(" value" , sizeInfo.value.toDouble())
256
+
257
+ return data
258
+ }
259
+
260
+ private fun getCurrentSizeInfo (sheetView : View ): SizeInfo {
261
+ val height = sheetDialog.maxScreenHeight - sheetView.top
262
+ val currentSizeInfo = SizeInfo (currentSizeIndex, Utils .toDIP(height.toFloat()))
263
+
264
+ return currentSizeInfo
265
+ }
266
+
267
+ private fun handleDragBegin (sheetView : View ) {
268
+ // Dispatch drag started event
269
+ dispatchEvent(TrueSheetEvent .DRAG_BEGIN , sizeInfoData(getCurrentSizeInfo(sheetView)))
270
+ // Flag sheet is being dragged
271
+ isDragging = true
272
+ }
273
+
274
+ private fun handleDragChange (sheetView : View ) {
275
+ if (! isDragging) return
276
+
277
+ // Dispatch drag change event
278
+ dispatchEvent(TrueSheetEvent .DRAG_CHANGE , sizeInfoData(getCurrentSizeInfo(sheetView)))
279
+ }
280
+
281
+ private fun handleDragEnd (state : Int ) {
282
+ if (! isDragging) return
283
+
284
+ // For consistency with IOS,
285
+ // we only handle state changes after dragging.
286
+ //
287
+ // Changing size programmatically is handled via the present method.
288
+ val sizeInfo = sheetDialog.getSizeInfoForState(state)
289
+ sizeInfo?.let {
290
+ // Dispatch drag ended after dragging
291
+ dispatchEvent(TrueSheetEvent .DRAG_END , sizeInfoData(it))
292
+ if (it.index != currentSizeIndex) {
293
+ // Invoke promise when sheet resized programmatically
294
+ presentPromise?.let { promise ->
295
+ promise()
296
+ presentPromise = null
297
+ }
298
+
299
+ currentSizeIndex = it.index
300
+ sheetDialog.setupDimmedBackground(it.index)
301
+
302
+ // Dispatch onSizeChange event
303
+ dispatchEvent(TrueSheetEvent .SIZE_CHANGE , sizeInfoData(it))
304
+ }
305
+ }
306
+
307
+ isDragging = false
308
+ }
309
+
310
+ private fun dispatchEvent (name : String , data : WritableMap ? = null) {
311
+ eventDispatcher?.dispatchEvent(TrueSheetEvent (surfaceId, id, name, data))
312
+ }
313
+
242
314
private fun configureIfShowing () {
243
315
if (sheetDialog.isShowing) {
244
316
sheetDialog.configure()
@@ -322,11 +394,19 @@ class TrueSheetView(context: Context) :
322
394
* Present the sheet at given size index.
323
395
*/
324
396
fun present (sizeIndex : Int , promiseCallback : () -> Unit ) {
325
- if (! sheetDialog.isShowing) {
326
- currentSizeIndex = sizeIndex
397
+ currentSizeIndex = sizeIndex
398
+
399
+ if (sheetDialog.isShowing) {
400
+ // For consistency with IOS, we are not waiting
401
+ // for the state to change before dispatching onSizeChange event.
402
+ val sizeInfo = sheetDialog.getSizeInfoForIndex(sizeIndex)
403
+ dispatchEvent(TrueSheetEvent .SIZE_CHANGE , sizeInfoData(sizeInfo))
404
+
405
+ promiseCallback()
406
+ } else {
407
+ presentPromise = promiseCallback
327
408
}
328
409
329
- presentPromise = promiseCallback
330
410
sheetDialog.present(sizeIndex)
331
411
}
332
412
@@ -337,8 +417,4 @@ class TrueSheetView(context: Context) :
337
417
dismissPromise = promiseCallback
338
418
sheetDialog.dismiss()
339
419
}
340
-
341
- companion object {
342
- const val TAG = " TrueSheetView"
343
- }
344
420
}
0 commit comments