mirror of
https://github.com/mihonapp/mihon.git
synced 2025-01-31 04:14:58 +01:00
scroll to next/previous group of errors
This commit is contained in:
parent
58d59a555d
commit
f1310ba879
@ -24,6 +24,8 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.ZeroCornerSize
|
import androidx.compose.foundation.shape.ZeroCornerSize
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.ArrowDownward
|
||||||
|
import androidx.compose.material.icons.outlined.ArrowUpward
|
||||||
import androidx.compose.material.icons.outlined.FindReplace
|
import androidx.compose.material.icons.outlined.FindReplace
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
import androidx.compose.material.icons.outlined.FlipToBack
|
||||||
import androidx.compose.material.icons.outlined.SelectAll
|
import androidx.compose.material.icons.outlined.SelectAll
|
||||||
@ -36,9 +38,11 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.material3.ripple
|
import androidx.compose.material3.ripple
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@ -93,6 +97,21 @@ fun LibraryUpdateErrorScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val headerIndexes = remember { mutableStateOf<List<Int>>(emptyList()) }
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
headerIndexes.value = state.getHeaderIndexes()
|
||||||
|
}
|
||||||
|
val enableScrollToPrevious by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
headerIndexes.value.any { it < listState.firstVisibleItemIndex }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val enableScrollToNext by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
headerIndexes.value.any { it > listState.firstVisibleItemIndex }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) })
|
BackHandler(enabled = state.selectionMode, onBack = { onSelectAll(false) })
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@ -128,6 +147,26 @@ fun LibraryUpdateErrorScreen(
|
|||||||
listState.scrollToItem(state.items.size - 1)
|
listState.scrollToItem(state.items.size - 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
enableScrollToPrevious = enableScrollToTop && enableScrollToPrevious,
|
||||||
|
enableScrollToNext = enableScrollToBottom && enableScrollToNext,
|
||||||
|
scrollToPrevious = {
|
||||||
|
scope.launch {
|
||||||
|
listState.scrollToItem(
|
||||||
|
state.getHeaderIndexes()
|
||||||
|
.filter { it < listState.firstVisibleItemIndex }
|
||||||
|
.maxOrNull() ?: 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToNext = {
|
||||||
|
scope.launch {
|
||||||
|
listState.scrollToItem(
|
||||||
|
state.getHeaderIndexes()
|
||||||
|
.filter { it > listState.firstVisibleItemIndex }
|
||||||
|
.minOrNull() ?: 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
@ -166,6 +205,10 @@ private fun LibraryUpdateErrorsBottomBar(
|
|||||||
enableScrollToBottom: Boolean,
|
enableScrollToBottom: Boolean,
|
||||||
scrollToTop: () -> Unit,
|
scrollToTop: () -> Unit,
|
||||||
scrollToBottom: () -> Unit,
|
scrollToBottom: () -> Unit,
|
||||||
|
enableScrollToPrevious: Boolean,
|
||||||
|
enableScrollToNext: Boolean,
|
||||||
|
scrollToPrevious: () -> Unit,
|
||||||
|
scrollToNext: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
Surface(
|
Surface(
|
||||||
@ -177,11 +220,11 @@ private fun LibraryUpdateErrorsBottomBar(
|
|||||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
) {
|
) {
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val confirm = remember { mutableStateListOf(false, false, false) }
|
val confirm = remember { mutableStateListOf(false, false, false, false, false) }
|
||||||
var resetJob: Job? = remember { null }
|
var resetJob: Job? = remember { null }
|
||||||
val onLongClickItem: (Int) -> Unit = { toConfirmIndex ->
|
val onLongClickItem: (Int) -> Unit = { toConfirmIndex ->
|
||||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
(0 until 3).forEach { i -> confirm[i] = i == toConfirmIndex }
|
(0 until 5).forEach { i -> confirm[i] = i == toConfirmIndex }
|
||||||
resetJob?.cancel()
|
resetJob?.cancel()
|
||||||
resetJob = scope.launch {
|
resetJob = scope.launch {
|
||||||
delay(1.seconds)
|
delay(1.seconds)
|
||||||
@ -210,10 +253,22 @@ private fun LibraryUpdateErrorsBottomBar(
|
|||||||
enabled = enableScrollToTop,
|
enabled = enableScrollToTop,
|
||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
title = stringResource(MR.strings.migrate),
|
title = stringResource(MR.strings.action_scroll_to_previous),
|
||||||
icon = Icons.Outlined.FindReplace,
|
icon = Icons.Outlined.ArrowUpward,
|
||||||
toConfirm = confirm[1],
|
toConfirm = confirm[1],
|
||||||
onLongClick = { onLongClickItem(1) },
|
onLongClick = { onLongClickItem(1) },
|
||||||
|
onClick = if (enableScrollToPrevious) {
|
||||||
|
scrollToPrevious
|
||||||
|
} else {
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
enabled = enableScrollToPrevious,
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
title = stringResource(MR.strings.migrate),
|
||||||
|
icon = Icons.Outlined.FindReplace,
|
||||||
|
toConfirm = confirm[2],
|
||||||
|
onLongClick = { onLongClickItem(2) },
|
||||||
onClick = if (selected.isNotEmpty()) {
|
onClick = if (selected.isNotEmpty()) {
|
||||||
onMultiMigrateClicked
|
onMultiMigrateClicked
|
||||||
} else {
|
} else {
|
||||||
@ -221,11 +276,23 @@ private fun LibraryUpdateErrorsBottomBar(
|
|||||||
},
|
},
|
||||||
enabled = selected.isNotEmpty(),
|
enabled = selected.isNotEmpty(),
|
||||||
)
|
)
|
||||||
|
Button(
|
||||||
|
title = stringResource(MR.strings.action_scroll_to_next),
|
||||||
|
icon = Icons.Outlined.ArrowDownward,
|
||||||
|
toConfirm = confirm[3],
|
||||||
|
onLongClick = { onLongClickItem(3) },
|
||||||
|
onClick = if (enableScrollToNext) {
|
||||||
|
scrollToNext
|
||||||
|
} else {
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
enabled = enableScrollToNext,
|
||||||
|
)
|
||||||
Button(
|
Button(
|
||||||
title = stringResource(MR.strings.action_scroll_to_bottom),
|
title = stringResource(MR.strings.action_scroll_to_bottom),
|
||||||
icon = Icons.Outlined.VerticalAlignBottom,
|
icon = Icons.Outlined.VerticalAlignBottom,
|
||||||
toConfirm = confirm[2],
|
toConfirm = confirm[4],
|
||||||
onLongClick = { onLongClickItem(2) },
|
onLongClick = { onLongClickItem(4) },
|
||||||
onClick = if (enableScrollToBottom) {
|
onClick = if (enableScrollToBottom) {
|
||||||
scrollToBottom
|
scrollToBottom
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,6 +159,11 @@ data class LibraryUpdateErrorScreenState(
|
|||||||
}
|
}
|
||||||
return uiModels
|
return uiModels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getHeaderIndexes(): List<Int> = getUiModel()
|
||||||
|
.withIndex()
|
||||||
|
.filter { it.value is LibraryUpdateErrorUiModel.Header }
|
||||||
|
.map { it.index }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
@ -579,6 +579,8 @@
|
|||||||
<string name="info_empty_library_update_errors">You have no library update errors.</string>
|
<string name="info_empty_library_update_errors">You have no library update errors.</string>
|
||||||
<string name="action_scroll_to_top">Scroll to top</string>
|
<string name="action_scroll_to_top">Scroll to top</string>
|
||||||
<string name="action_scroll_to_bottom">Scroll to bottom</string>
|
<string name="action_scroll_to_bottom">Scroll to bottom</string>
|
||||||
|
<string name="action_scroll_to_previous">Scroll to previous</string>
|
||||||
|
<string name="action_scroll_to_next">Scroll to next</string>
|
||||||
|
|
||||||
<!-- Advanced section -->
|
<!-- Advanced section -->
|
||||||
<string name="label_network">Networking</string>
|
<string name="label_network">Networking</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user