Skip to content

Commit 05ea60e

Browse files
committed
refactor(segements): improve drag selecting user experience
1 parent 7232bec commit 05ea60e

4 files changed

Lines changed: 62 additions & 19 deletions

File tree

app/src/main/java/com/osfans/trime/ime/segments/DragSelectTouchListener.kt

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,80 @@
55

66
package com.osfans.trime.ime.segments
77

8+
import android.content.Context
89
import android.view.MotionEvent
10+
import android.view.ViewConfiguration
911
import androidx.recyclerview.widget.RecyclerView
12+
import kotlin.math.abs
1013
import kotlin.math.max
1114
import kotlin.math.min
1215

1316
class DragSelectTouchListener(
17+
context: Context,
1418
private val adapter: SegmentsAdapter,
1519
private val onSelectionChanged: () -> Unit,
1620
) : RecyclerView.OnItemTouchListener {
1721

1822
private var isDragSelecting = false
1923
private var startPosition = -1
20-
private var endPosition = -1
2124
private var lastEndPosition = -1
2225
private var targetState = false
2326

2427
private var selectionSnapshot: Set<Int> = emptySet()
2528

29+
private var initialX = 0f
30+
private var initialY = 0f
31+
private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
32+
2633
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
2734
val child = rv.findChildViewUnder(e.x, e.y)
2835
val position = child?.let { rv.getChildAdapterPosition(it) } ?: -1
2936

3037
when (e.actionMasked) {
3138
MotionEvent.ACTION_DOWN -> {
3239
if (position != -1) {
33-
isDragSelecting = true
40+
initialX = e.x
41+
initialY = e.y
3442
startPosition = position
35-
endPosition = position
36-
37-
val snapshot = adapter.selectionSnapshot
38-
val state = !snapshot.contains(position)
39-
selectionSnapshot = snapshot
40-
targetState = state
41-
updateRange(rv, startPosition, startPosition)
42-
rv.parent?.requestDisallowInterceptTouchEvent(true)
43-
return true
43+
return false
44+
}
45+
}
46+
MotionEvent.ACTION_MOVE -> {
47+
if (startPosition == -1) return false
48+
49+
if (!isDragSelecting) {
50+
val dx = abs(e.x - initialX)
51+
val dy = abs(e.y - initialY)
52+
53+
if (dx > touchSlop || dy > touchSlop) {
54+
if (dx > dy) { // core condition: x offset larger than y offset
55+
isDragSelecting = true
56+
57+
// disable scrolling
58+
rv.parent?.requestDisallowInterceptTouchEvent(true)
59+
60+
// get the snapshot and judge the target state
61+
selectionSnapshot = adapter.selectionSnapshot
62+
targetState = !selectionSnapshot.contains(startPosition)
63+
64+
// update state at start position immediately
65+
updateRange(rv, startPosition, startPosition)
66+
67+
return true
68+
} else {
69+
// make scrolling still work
70+
startPosition = -1
71+
return false
72+
}
73+
}
4474
}
4575
}
76+
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
77+
startPosition = -1
78+
isDragSelecting = false
79+
}
4680
}
47-
return false
81+
return isDragSelecting
4882
}
4983

5084
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
@@ -63,7 +97,6 @@ class DragSelectTouchListener(
6397
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
6498
isDragSelecting = false
6599
startPosition = -1
66-
endPosition = -1
67100
lastEndPosition = -1
68101
rv.parent?.requestDisallowInterceptTouchEvent(false)
69102
onSelectionChanged.invoke()

app/src/main/java/com/osfans/trime/ime/segments/SegmentUi.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ package com.osfans.trime.ime.segments
88
import android.content.Context
99
import android.content.res.ColorStateList
1010
import android.graphics.drawable.StateListDrawable
11+
import android.os.Build
1112
import android.view.ViewOutlineProvider
1213
import com.osfans.trime.data.theme.ColorManager
1314
import com.osfans.trime.data.theme.FontManager
1415
import com.osfans.trime.data.theme.Theme
1516
import com.osfans.trime.ime.keyboard.GestureFrame
1617
import splitties.dimensions.dp
18+
import splitties.resources.styledDrawable
1719
import splitties.views.dsl.core.Ui
1820
import splitties.views.dsl.core.add
1921
import splitties.views.dsl.core.lParams

app/src/main/java/com/osfans/trime/ime/segments/SegmentsAdapter.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ package com.osfans.trime.ime.segments
88
import android.annotation.SuppressLint
99
import android.content.Context
1010
import android.view.ViewGroup
11-
import androidx.core.view.updateLayoutParams
1211
import androidx.recyclerview.widget.RecyclerView
1312
import com.chad.library.adapter4.BaseQuickAdapter
14-
import com.google.android.flexbox.FlexboxLayoutManager
1513
import com.osfans.trime.data.theme.Theme
16-
import splitties.dimensions.dp
1714

18-
class SegmentsAdapter(private val theme: Theme) : BaseQuickAdapter<String, SegmentsAdapter.ViewHolder>() {
15+
class SegmentsAdapter(
16+
private val theme: Theme,
17+
private val onItemClick: () -> Unit,
18+
) : BaseQuickAdapter<String, SegmentsAdapter.ViewHolder>() {
1919

2020
class ViewHolder(val ui: SegmentUi) : RecyclerView.ViewHolder(ui.root)
2121

@@ -36,6 +36,14 @@ class SegmentsAdapter(private val theme: Theme) : BaseQuickAdapter<String, Segme
3636
holder.ui.textView.text = text
3737
val isSelected = selection.contains(position)
3838
holder.ui.update(isSelected)
39+
holder.itemView.setOnClickListener {
40+
val currentPos = holder.bindingAdapterPosition
41+
if (currentPos != RecyclerView.NO_POSITION) {
42+
val newState = !isSegmentSelected(currentPos)
43+
setSegmentSelected(currentPos, newState)
44+
onItemClick.invoke()
45+
}
46+
}
3947
}
4048

4149
val selectionSnapshot: Set<Int>

app/src/main/java/com/osfans/trime/ime/segments/SegmentsWindow.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ class SegmentsWindow(private val source: String) : BoardWindow.BarBoardWindow()
3636
}
3737

3838
private val adapter by lazy {
39-
SegmentsAdapter(theme)
39+
SegmentsAdapter(theme) { onSelectionChanged() }
4040
}
4141

4242
private val touchListener by lazy {
43-
DragSelectTouchListener(adapter) {
43+
DragSelectTouchListener(context, adapter) {
4444
onSelectionChanged()
4545
}
4646
}

0 commit comments

Comments
 (0)