Skip to content

Commit 8d8bd3a

Browse files
committed
cleanups
1 parent 062d742 commit 8d8bd3a

File tree

2 files changed

+113
-79
lines changed

2 files changed

+113
-79
lines changed

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/notificationactions/NotificationActionsReorderController.kt

Lines changed: 92 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ private const val SWAP_HYSTERESIS_PX = 8f
1212

1313
internal data class ReorderVisibleItem(
1414
val key: String,
15-
val index: Int,
1615
val offset: Int,
1716
val size: Int,
1817
)
@@ -47,16 +46,6 @@ internal class NotificationActionsReorderController(
4746
initialActions: List<MessageNotificationAction>,
4847
initialCutoff: Int,
4948
) {
50-
val currentActions = renderedItemsState
51-
.filterIsInstance<NotificationListItem.Action>()
52-
.map { it.action }
53-
val currentCutoff = cutoffIndexState
54-
55-
val normalizedIncomingCutoff = initialCutoff.coerceIn(0, initialActions.size)
56-
if (currentActions == initialActions && currentCutoff == normalizedIncomingCutoff) {
57-
return
58-
}
59-
6049
renderedItemsState.clear()
6150
renderedItemsState.addAll(buildRenderedItems(actions = initialActions, cutoff = initialCutoff))
6251
cutoffIndexState = renderedItemsState.indexOfFirst { it is NotificationListItem.Cutoff }
@@ -79,35 +68,86 @@ internal class NotificationActionsReorderController(
7968
val fromIndex = renderedItemsState.indexOfFirst { it.key == key }
8069
if (fromIndex == -1) return
8170

82-
if (deltaY > 0f) {
83-
val nextItemKey = renderedItemsState.getOrNull(fromIndex + 1)?.key ?: return
84-
val nextItem = visibleItems.firstOrNull { it.key == nextItemKey } ?: return
85-
86-
val draggedBottom = draggedItem.offset + draggedItem.size + draggedOffsetY
87-
val nextThreshold = nextItem.offset + (nextItem.size / 2f)
88-
if (draggedBottom >= nextThreshold + SWAP_HYSTERESIS_PX) {
89-
if (moveRenderedItem(from = fromIndex, to = fromIndex + 1)) {
90-
dragDidMove = true
91-
draggedOffsetY -= nextItem.size.toFloat()
92-
}
93-
}
94-
} else if (deltaY < 0f) {
95-
val upwardSwap = calculateUpwardSwap(
71+
val swapDecision = findSwapDecision(
72+
deltaY = deltaY,
73+
fromIndex = fromIndex,
74+
draggedItem = draggedItem,
75+
visibleItems = visibleItems,
76+
) ?: return
77+
78+
if (moveRenderedItem(from = fromIndex, to = swapDecision.toIndex)) {
79+
dragDidMove = true
80+
draggedOffsetY += swapDecision.offsetCompensation
81+
}
82+
}
83+
84+
private data class SwapDecision(
85+
val toIndex: Int,
86+
val offsetCompensation: Float,
87+
)
88+
89+
private fun findSwapDecision(
90+
deltaY: Float,
91+
fromIndex: Int,
92+
draggedItem: ReorderVisibleItem,
93+
visibleItems: List<ReorderVisibleItem>,
94+
): SwapDecision? {
95+
return when {
96+
deltaY > 0f -> findDownwardSwapDecision(
9697
fromIndex = fromIndex,
98+
draggedItem = draggedItem,
9799
visibleItems = visibleItems,
98-
) ?: return
99-
if (draggedItem.offset + draggedOffsetY <= upwardSwap.threshold - SWAP_HYSTERESIS_PX) {
100-
if (moveRenderedItem(from = fromIndex, to = fromIndex - 1)) {
101-
dragDidMove = true
102-
draggedOffsetY += upwardSwap.offsetCompensation.toFloat()
103-
}
104-
}
100+
)
101+
102+
deltaY < 0f -> findUpwardSwapDecision(
103+
fromIndex = fromIndex,
104+
draggedItem = draggedItem,
105+
visibleItems = visibleItems,
106+
)
107+
108+
else -> null
105109
}
106110
}
107111

112+
private fun findDownwardSwapDecision(
113+
fromIndex: Int,
114+
draggedItem: ReorderVisibleItem,
115+
visibleItems: List<ReorderVisibleItem>,
116+
): SwapDecision? {
117+
val nextItemKey = renderedItemsState.getOrNull(fromIndex + 1)?.key ?: return null
118+
val nextItem = visibleItems.firstOrNull { it.key == nextItemKey } ?: return null
119+
120+
val draggedBottom = draggedItem.offset + draggedItem.size + draggedOffsetY
121+
val nextThreshold = nextItem.offset + (nextItem.size / 2f)
122+
if (draggedBottom < nextThreshold + SWAP_HYSTERESIS_PX) return null
123+
124+
return SwapDecision(
125+
toIndex = fromIndex + 1,
126+
offsetCompensation = -nextItem.size.toFloat(),
127+
)
128+
}
129+
130+
private fun findUpwardSwapDecision(
131+
fromIndex: Int,
132+
draggedItem: ReorderVisibleItem,
133+
visibleItems: List<ReorderVisibleItem>,
134+
): SwapDecision? {
135+
val upwardSwap = calculateUpwardSwap(
136+
fromIndex = fromIndex,
137+
visibleItems = visibleItems,
138+
) ?: return null
139+
val draggedTop = draggedItem.offset + draggedOffsetY
140+
if (draggedTop > upwardSwap.threshold - SWAP_HYSTERESIS_PX) return null
141+
142+
return SwapDecision(
143+
toIndex = fromIndex - 1,
144+
offsetCompensation = upwardSwap.offsetCompensation,
145+
)
146+
}
147+
108148
private data class UpwardSwapConfig(
109149
val threshold: Float,
110-
val offsetCompensation: Int,
150+
val offsetCompensation: Float,
111151
)
112152

113153
private fun calculateUpwardSwap(
@@ -117,23 +157,22 @@ internal class NotificationActionsReorderController(
117157
val previousItemKey = renderedItemsState.getOrNull(fromIndex - 1)?.key ?: return null
118158
val previousItem = visibleItems.firstOrNull { it.key == previousItemKey } ?: return null
119159

120-
val maxPos = NOTIFICATION_PREFERENCE_MAX_MESSAGE_ACTIONS_SHOWN
121-
.coerceAtMost(renderedItemsState.lastIndex)
160+
val maxPos = maxAllowedCutoffIndex()
122161
val crossingUpThroughFullCutoff = previousItemKey == NotificationListItem.Cutoff.key &&
123162
cutoffIndexState >= maxPos
124163

125164
if (!crossingUpThroughFullCutoff) {
126165
return UpwardSwapConfig(
127166
threshold = previousItem.offset + (previousItem.size / 2f),
128-
offsetCompensation = previousItem.size,
167+
offsetCompensation = previousItem.size.toFloat(),
129168
)
130169
}
131170

132171
val lastAboveKey = renderedItemsState.getOrNull(fromIndex - 2)?.key ?: return null
133172
val lastAboveItem = visibleItems.firstOrNull { it.key == lastAboveKey } ?: return null
134173
return UpwardSwapConfig(
135174
threshold = lastAboveItem.offset + (lastAboveItem.size / 2f),
136-
offsetCompensation = previousItem.size + lastAboveItem.size,
175+
offsetCompensation = (previousItem.size + lastAboveItem.size).toFloat(),
137176
)
138177
}
139178

@@ -165,16 +204,22 @@ internal class NotificationActionsReorderController(
165204
if (from == -1) return false
166205

167206
val to = from + delta
168-
return from in renderedItemsState.indices && to in renderedItemsState.indices && from != to
207+
return isMoveAllowed(from = from, to = to)
169208
}
170209

171-
private fun moveRenderedItem(from: Int, to: Int): Boolean {
210+
private fun isMoveAllowed(from: Int, to: Int): Boolean {
172211
if (from !in renderedItemsState.indices || to !in renderedItemsState.indices || from == to) return false
173-
val maxPos = NOTIFICATION_PREFERENCE_MAX_MESSAGE_ACTIONS_SHOWN
174-
.coerceAtMost(renderedItemsState.lastIndex)
212+
213+
val maxPos = maxAllowedCutoffIndex()
175214

176215
// Don't allow the divider to be dragged to more than the max position
177-
if (from == cutoffIndexState && to > maxPos) return false
216+
return !(from == cutoffIndexState && to > maxPos)
217+
}
218+
219+
private fun moveRenderedItem(from: Int, to: Int): Boolean {
220+
if (!isMoveAllowed(from = from, to = to)) return false
221+
222+
val maxPos = maxAllowedCutoffIndex()
178223

179224
val previousCutoff = cutoffIndexState
180225
val crossedCutoffUpward = previousCutoff in to..<from
@@ -201,6 +246,11 @@ internal class NotificationActionsReorderController(
201246
return true
202247
}
203248

249+
private fun maxAllowedCutoffIndex(): Int {
250+
return NOTIFICATION_PREFERENCE_MAX_MESSAGE_ACTIONS_SHOWN
251+
.coerceAtMost(renderedItemsState.lastIndex)
252+
}
253+
204254
private fun buildRenderedItems(
205255
actions: List<MessageNotificationAction>,
206256
cutoff: Int,

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/settings/notificationactions/NotificationActionsSettingsScreen.kt

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,18 @@ internal fun NotificationActionsSettingsScreen(
6969
)
7070
}
7171

72-
fun visibleItems(): List<ReorderVisibleItem> {
73-
return listState.layoutInfo.visibleItemsInfo.mapNotNull { info ->
74-
val key = info.key as? String ?: return@mapNotNull null
75-
ReorderVisibleItem(
76-
key = key,
77-
index = info.index,
78-
offset = info.offset,
79-
size = info.size,
80-
)
81-
}
82-
}
83-
84-
fun onDrag(deltaY: Float) {
85-
val visibleItems = visibleItems()
86-
reorderController.dragBy(deltaY = deltaY, visibleItems = visibleItems)
72+
val onDrag: (Float) -> Unit = { deltaY ->
73+
reorderController.dragBy(
74+
deltaY = deltaY,
75+
visibleItems = listState.layoutInfo.visibleItemsInfo.mapNotNull { info ->
76+
val key = info.key as? String ?: return@mapNotNull null
77+
ReorderVisibleItem(
78+
key = key,
79+
offset = info.offset,
80+
size = info.size,
81+
)
82+
},
83+
)
8784
}
8885

8986
Surface(modifier = modifier.fillMaxSize()) {
@@ -116,7 +113,7 @@ internal fun NotificationActionsSettingsScreen(
116113
action = item.action,
117114
isDimmed = index > reorderController.cutoffIndex,
118115
onDragStart = { reorderController.startDrag(item.key) },
119-
onDrag = ::onDrag,
116+
onDrag = onDrag,
120117
onDragEnd = reorderController::endDrag,
121118
onMoveUp = { reorderController.moveByStep(item.key, -1) },
122119
onMoveDown = { reorderController.moveByStep(item.key, 1) },
@@ -129,7 +126,7 @@ internal fun NotificationActionsSettingsScreen(
129126

130127
is NotificationListItem.Cutoff -> NotificationCutoffRow(
131128
onDragStart = { reorderController.startDrag(item.key) },
132-
onDrag = ::onDrag,
129+
onDrag = onDrag,
133130
onDragEnd = reorderController::endDrag,
134131
onMoveUp = { reorderController.moveByStep(item.key, -1) },
135132
onMoveDown = { reorderController.moveByStep(item.key, 1) },
@@ -164,13 +161,6 @@ private fun NotificationActionRow(
164161
val moveDownLabel = stringResource(R.string.accessibility_move_down)
165162
val contentLabel = stringResource(action.labelRes)
166163

167-
val dragScale by animateFloatAsState(
168-
targetValue = if (isDragged) 1.02f else 1.0f,
169-
label = "notificationActionDragScale",
170-
)
171-
val density = LocalDensity.current
172-
val dragElevationPx = with(density) { if (isDragged) 12.dp.toPx() else 0f }
173-
174164
NotificationReorderRow(
175165
contentDescription = contentLabel,
176166
onMoveUp = onMoveUp,
@@ -179,8 +169,6 @@ private fun NotificationActionRow(
179169
moveDownLabel = moveDownLabel,
180170
isDragged = isDragged,
181171
draggedOffsetY = draggedOffsetY,
182-
dragScale = dragScale,
183-
dragElevationPx = dragElevationPx,
184172
alpha = if (isDragged) 1.0f else if (isDimmed) 0.6f else 1.0f,
185173
startPadding = MainTheme.spacings.default,
186174
onDragStart = onDragStart,
@@ -236,13 +224,6 @@ private fun NotificationCutoffRow(
236224
val moveDownLabel = stringResource(R.string.accessibility_move_down)
237225
val cutoffContentLabel = stringResource(R.string.notification_actions_cutoff_description)
238226

239-
val dragScale by animateFloatAsState(
240-
targetValue = if (isDragged) 1.02f else 1.0f,
241-
label = "notificationCutoffDragScale",
242-
)
243-
val density = LocalDensity.current
244-
val dragElevationPx = with(density) { if (isDragged) 12.dp.toPx() else 0f }
245-
246227
NotificationReorderRow(
247228
contentDescription = cutoffContentLabel,
248229
onMoveUp = onMoveUp,
@@ -251,8 +232,6 @@ private fun NotificationCutoffRow(
251232
moveDownLabel = moveDownLabel,
252233
isDragged = isDragged,
253234
draggedOffsetY = draggedOffsetY,
254-
dragScale = dragScale,
255-
dragElevationPx = dragElevationPx,
256235
alpha = 1f,
257236
startPadding = MainTheme.spacings.double,
258237
onDragStart = onDragStart,
@@ -287,8 +266,6 @@ private fun NotificationReorderRow(
287266
moveDownLabel: String,
288267
isDragged: Boolean,
289268
draggedOffsetY: Float,
290-
dragScale: Float,
291-
dragElevationPx: Float,
292269
alpha: Float,
293270
startPadding: androidx.compose.ui.unit.Dp,
294271
onDragStart: () -> Unit,
@@ -297,6 +274,13 @@ private fun NotificationReorderRow(
297274
modifier: Modifier = Modifier,
298275
content: @Composable RowScope.() -> Unit,
299276
) {
277+
val dragScale by animateFloatAsState(
278+
targetValue = if (isDragged) 1.02f else 1.0f,
279+
label = "notificationRowDragScale",
280+
)
281+
val density = LocalDensity.current
282+
val dragElevationPx = with(density) { if (isDragged) 12.dp.toPx() else 0f }
283+
300284
Row(
301285
modifier = modifier
302286
.fillMaxWidth()

0 commit comments

Comments
 (0)