Skip to content

Commit 7f2efb4

Browse files
committed
Enable swiping on favorites
1 parent 1fdedeb commit 7f2efb4

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/newtab/FavouritesNewTabSectionView.kt

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import android.util.AttributeSet
2424
import android.view.LayoutInflater
2525
import android.view.MotionEvent
2626
import android.view.View
27+
import android.view.ViewConfiguration
2728
import android.widget.LinearLayout
2829
import android.widget.PopupWindow
2930
import androidx.core.text.HtmlCompat
@@ -77,6 +78,7 @@ import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.Co
7778
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.Command.DeleteSavedSiteConfirmation
7879
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.Command.ShowEditSavedSiteDialog
7980
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.SavedSiteChangedViewState
81+
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.SwipeDecision
8082
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.ViewState
8183
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionsAdapter.Companion.QUICK_ACCESS_GRID_MAX_COLUMNS
8284
import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionsAdapter.Companion.QUICK_ACCESS_ITEM_MAX_SIZE_DP
@@ -134,6 +136,14 @@ class FavouritesNewTabSectionView @JvmOverloads constructor(
134136
private val conflatedStateJob = ConflatedJob()
135137
private val conflatedCommandJob = ConflatedJob()
136138

139+
private val touchSlop: Int by lazy { ViewConfiguration.get(context).scaledTouchSlop }
140+
private val longPressTimeoutMs: Long by lazy { ViewConfiguration.getLongPressTimeout().toLong() }
141+
142+
private val longPressRunnable = Runnable {
143+
viewModel.onLongPressTriggered()
144+
parent?.requestDisallowInterceptTouchEvent(true)
145+
}
146+
137147
init {
138148
context.obtainStyledAttributes(
139149
attrs,
@@ -186,8 +196,35 @@ class FavouritesNewTabSectionView @JvmOverloads constructor(
186196
}
187197

188198
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
189-
if (swipingTabsFeature.isEnabled) {
190-
parent.requestDisallowInterceptTouchEvent(true)
199+
if (!swipingTabsFeature.isEnabled) return super.dispatchTouchEvent(ev)
200+
201+
when (ev?.actionMasked) {
202+
MotionEvent.ACTION_DOWN -> {
203+
viewModel.onTouchDown(ev.x, ev.y)
204+
removeCallbacks(longPressRunnable)
205+
postDelayed(longPressRunnable, longPressTimeoutMs)
206+
parent?.requestDisallowInterceptTouchEvent(false)
207+
}
208+
209+
MotionEvent.ACTION_MOVE -> {
210+
if (viewModel.isLongPressActive()) {
211+
parent?.requestDisallowInterceptTouchEvent(true)
212+
} else {
213+
viewModel.onTouchMove(ev.x, ev.y, touchSlop)?.let { decision ->
214+
when (decision) {
215+
SwipeDecision.CANCEL_LONG_PRESS -> removeCallbacks(longPressRunnable)
216+
SwipeDecision.HORIZONTAL -> parent?.requestDisallowInterceptTouchEvent(false)
217+
SwipeDecision.VERTICAL -> parent?.requestDisallowInterceptTouchEvent(true)
218+
}
219+
}
220+
}
221+
}
222+
223+
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
224+
removeCallbacks(longPressRunnable)
225+
viewModel.onTouchUp()
226+
parent?.requestDisallowInterceptTouchEvent(false)
227+
}
191228
}
192229
return super.dispatchTouchEvent(ev)
193230
}

saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/newtab/FavouritesNewTabSectionViewModel.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import com.duckduckgo.savedsites.impl.newtab.FavouritesNewTabSectionViewModel.Co
4141
import com.duckduckgo.sync.api.engine.SyncEngine
4242
import com.duckduckgo.sync.api.engine.SyncEngine.SyncTrigger.FEATURE_READ
4343
import javax.inject.Inject
44+
import kotlin.math.abs
4445
import kotlinx.coroutines.channels.BufferOverflow
4546
import kotlinx.coroutines.channels.Channel
4647
import kotlinx.coroutines.flow.Flow
@@ -89,6 +90,12 @@ class FavouritesNewTabSectionViewModel @Inject constructor(
8990
private val command = Channel<Command>(1, BufferOverflow.DROP_OLDEST)
9091
internal fun commands(): Flow<Command> = command.receiveAsFlow()
9192

93+
enum class SwipeDecision { HORIZONTAL, VERTICAL, CANCEL_LONG_PRESS }
94+
95+
private var initialTouchX = 0f
96+
private var initialTouchY = 0f
97+
private var longPressActivated = false
98+
9299
override fun onResume(owner: LifecycleOwner) {
93100
super.onResume(owner)
94101

@@ -287,4 +294,32 @@ class FavouritesNewTabSectionViewModel @Inject constructor(
287294
): String {
288295
return pixelName.pixelName + "_" + placement.name.lowercase()
289296
}
297+
298+
fun onTouchDown(x: Float, y: Float) {
299+
initialTouchX = x
300+
initialTouchY = y
301+
longPressActivated = false
302+
}
303+
304+
fun onTouchUp() {
305+
longPressActivated = false
306+
}
307+
308+
fun onTouchMove(x: Float, y: Float, touchSlop: Int): SwipeDecision? {
309+
val dx = abs(x - initialTouchX)
310+
val dy = abs(y - initialTouchY)
311+
312+
return when {
313+
dx > dy && dx > touchSlop -> SwipeDecision.HORIZONTAL
314+
dy > dx && dy > touchSlop -> SwipeDecision.VERTICAL
315+
dx > touchSlop || dy > touchSlop -> SwipeDecision.CANCEL_LONG_PRESS
316+
else -> null
317+
}
318+
}
319+
320+
fun onLongPressTriggered() {
321+
longPressActivated = true
322+
}
323+
324+
fun isLongPressActive(): Boolean = longPressActivated
290325
}

0 commit comments

Comments
 (0)