2020
2121package net.newpipe.newplayer.ui.videoplayer.gesture_ui
2222
23+ import android.util.Log
2324import android.view.MotionEvent
2425import androidx.compose.foundation.layout.Box
2526import androidx.compose.foundation.layout.fillMaxSize
@@ -36,13 +37,16 @@ import androidx.compose.ui.ExperimentalComposeUiApi
3637import androidx.compose.ui.Modifier
3738import androidx.compose.ui.graphics.Color
3839import androidx.compose.ui.input.pointer.pointerInteropFilter
40+ import androidx.compose.ui.platform.LocalDensity
41+ import androidx.compose.ui.unit.dp
3942import kotlinx.coroutines.Job
4043import kotlinx.coroutines.delay
4144import kotlinx.coroutines.launch
4245import kotlin.math.abs
4346
44- private const val MULTITAB_MODE_DELAY : Long = 300
47+ private const val TAG = " GestureSurface "
4548
49+ private const val ENTER_MULTITAB_MODE_DELAY : Long = 300
4650
4751@Composable
4852@OptIn(ExperimentalComposeUiApi ::class )
@@ -67,59 +71,97 @@ internal fun GestureSurface(
6771 mutableFloatStateOf(0f )
6872 }
6973
74+ var lastFingerDownTime by remember {
75+ mutableStateOf(0L )
76+ }
77+
7078 var lastFingerUpTime by remember {
71- mutableStateOf(System .currentTimeMillis() )
79+ mutableStateOf(0L )
7280 }
7381
7482 val composableScope = rememberCoroutineScope()
7583 var regularTabJob: Job ? by remember {
7684 mutableStateOf(null )
7785 }
7886
79- val defaultActionDown = { event: MotionEvent ->
80- lastTouchedPosition = TouchedPosition (event.x, event.y)
81- yMovementSum = 0f
82-
83- true
84- }
85-
86- var multitapAmount: Int by remember {
87+ var multitapAmount: Int by remember {
8788 mutableIntStateOf(0 )
8889 }
8990
9091 var cancelMultitapJob: Job ? by remember {
9192 mutableStateOf(null )
9293 }
9394
94- val defaultActionUp = { onMultiTap: (Int ) -> Unit , onRegularTap: () -> Unit ->
95- onUp()
95+ val onMultitap = {
96+ Log .d(TAG , " Trigger multitab" )
97+ regularTabJob?.cancel()
98+ cancelMultitapJob?.cancel()
99+ multitapAmount++
100+ onMultiTap(multitapAmount)
101+ cancelMultitapJob = composableScope.launch {
102+ delay(ENTER_MULTITAB_MODE_DELAY )
103+ multitapAmount = 0
104+ onMultiTapFinished()
105+ }
106+ }
107+
108+ /*
109+ * Only use this function in tab down.
110+ */
111+ val isAMultitapEvent = {
112+ val currentTime = System .currentTimeMillis()
113+ val timeSinceLastFingerDown = currentTime - lastFingerDownTime
114+ timeSinceLastFingerDown <= ENTER_MULTITAB_MODE_DELAY
115+ }
116+
117+ val fingerDownAndUpHappenedInShortEnoughTimeForARegularTab = {
118+ val current = System .currentTimeMillis()
119+ val timeSinceLastFingerUp = current - lastFingerUpTime
120+ timeSinceLastFingerUp < ENTER_MULTITAB_MODE_DELAY
121+ }
96122
97- if (yMovementSum < 10 ) {
98- val currentTime = System .currentTimeMillis()
99- val timeSinceLastTouch = currentTime - lastFingerUpTime
100- if (timeSinceLastTouch <= MULTITAB_MODE_DELAY ) {
101- regularTabJob?.cancel()
102- cancelMultitapJob?.cancel()
103- multitapAmount++
104- onMultiTap(multitapAmount)
105- cancelMultitapJob = composableScope.launch {
106- delay(MULTITAB_MODE_DELAY )
107- multitapAmount = 0
108- onMultiTapFinished()
109- }
123+ val startToFigureOutIfItsRegularTab = {
124+ Log .d(TAG , " Maybe regular tab?" )
125+ regularTabJob = composableScope.launch {
126+ delay(ENTER_MULTITAB_MODE_DELAY )
127+
128+ val isMultitab = isAMultitapEvent();
129+ val fingerDownUpOk = fingerDownAndUpHappenedInShortEnoughTimeForARegularTab()
130+ if (multitapAmount <= 0 && fingerDownUpOk) {
131+ onRegularTap()
132+ Log .d(TAG , " Yes Tab" )
110133 } else {
111- regularTabJob = composableScope.launch {
112- delay(MULTITAB_MODE_DELAY )
113- onRegularTap()
114- }
134+ Log .d(TAG , " No Tab: multitab: $isMultitab , downUpOk: $fingerDownUpOk " )
115135 }
136+ }
137+ }
138+
116139
117- lastFingerUpTime = currentTime
140+ val handleActionDown = { event: MotionEvent ->
141+ Log .d(TAG , " finger down" )
142+ lastTouchedPosition = TouchedPosition (event.x, event.y)
143+ yMovementSum = 0f
144+ if (isAMultitapEvent()) {
145+ onMultitap();
146+ } else {
147+ startToFigureOutIfItsRegularTab()
118148 }
149+ lastFingerDownTime = System .currentTimeMillis()
150+ true
151+ }
152+
153+ val handleActionUp = { onMultiTap: (Int ) -> Unit , onRegularTap: () -> Unit ->
154+ Log .d(TAG , " finger up" );
155+ onUp()
119156 yMovementSum = 0f
157+ lastFingerUpTime = System .currentTimeMillis();
120158 true
121159 }
122160
161+ val rangeAtWhichItsIntendedMovement = with (LocalDensity .current) {
162+ 15 .dp.toPx()
163+ }
164+
123165 val handleMove = { event: MotionEvent , lambda: (movement: TouchedPosition ) -> Unit ->
124166 val currentTouchedPosition = TouchedPosition (event.x, event.y)
125167 val movement = currentTouchedPosition - lastTouchedPosition
@@ -128,17 +170,22 @@ internal fun GestureSurface(
128170
129171 yMovementSum + = abs(movement.y)
130172
173+ if (yMovementSum < rangeAtWhichItsIntendedMovement) {
174+ Log .d(TAG , " cancel regular tab" )
175+ regularTabJob?.cancel()
176+ }
177+
131178 // filter out left and right movements as these are not important for the app
132- if (abs(movement.x) <= abs(movement.y)) {
179+ if (abs(movement.x) <= abs(movement.y)) {
133180 lambda(movement)
134181 }
135182 true
136183 }
137184
138185 Box (modifier = modifier.pointerInteropFilter {
139186 when (it.action) {
140- MotionEvent .ACTION_DOWN -> defaultActionDown (it)
141- MotionEvent .ACTION_UP -> defaultActionUp (onMultiTap, onRegularTap)
187+ MotionEvent .ACTION_DOWN -> handleActionDown (it)
188+ MotionEvent .ACTION_UP -> handleActionUp (onMultiTap, onRegularTap)
142189 MotionEvent .ACTION_MOVE -> handleMove(it, onMovement)
143190
144191 else -> false
0 commit comments