You've already forked KernelSU-Next
mirror of
https://github.com/KernelSU-Next/KernelSU-Next.git
synced 2025-08-27 23:46:34 +00:00
manager: change FAB visibility with scrolling gestures on module screen list
This commit is contained in:
@@ -77,6 +77,12 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
|
import androidx.compose.animation.scaleIn
|
||||||
|
import androidx.compose.animation.scaleOut
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -164,6 +170,30 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
|||||||
contract = ActivityResultContracts.StartActivityForResult()
|
contract = ActivityResultContracts.StartActivityForResult()
|
||||||
) { viewModel.fetchModuleList() }
|
) { viewModel.fetchModuleList() }
|
||||||
|
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
var showFab by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
LaunchedEffect(listState) {
|
||||||
|
var lastIndex = listState.firstVisibleItemIndex
|
||||||
|
var lastOffset = listState.firstVisibleItemScrollOffset
|
||||||
|
|
||||||
|
snapshotFlow { listState.firstVisibleItemIndex to listState.firstVisibleItemScrollOffset }
|
||||||
|
.collect { (currIndex, currOffset) ->
|
||||||
|
val isScrollingDown = currIndex > lastIndex ||
|
||||||
|
(currIndex == lastIndex && currOffset > lastOffset + 4)
|
||||||
|
val isScrollingUp = currIndex < lastIndex ||
|
||||||
|
(currIndex == lastIndex && currOffset < lastOffset - 4)
|
||||||
|
|
||||||
|
when {
|
||||||
|
isScrollingDown && showFab -> showFab = false
|
||||||
|
isScrollingUp && !showFab -> showFab = true
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = currIndex
|
||||||
|
lastOffset = currOffset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
SearchAppBar(
|
SearchAppBar(
|
||||||
@@ -289,6 +319,17 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
|||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
if (!hideInstallButton) {
|
if (!hideInstallButton) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = showFab,
|
||||||
|
enter = scaleIn(
|
||||||
|
animationSpec = tween(200),
|
||||||
|
initialScale = 0.8f
|
||||||
|
) + fadeIn(animationSpec = tween(400)),
|
||||||
|
exit = scaleOut(
|
||||||
|
animationSpec = tween(200),
|
||||||
|
targetScale = 0.8f
|
||||||
|
) + fadeOut(animationSpec = tween(400))
|
||||||
|
) {
|
||||||
val moduleInstall = stringResource(id = R.string.module_install)
|
val moduleInstall = stringResource(id = R.string.module_install)
|
||||||
val selectZipLauncher = rememberLauncherForActivityResult(
|
val selectZipLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.StartActivityForResult()
|
contract = ActivityResultContracts.StartActivityForResult()
|
||||||
@@ -330,6 +371,7 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
|||||||
text = { Text(text = moduleInstall) },
|
text = { Text(text = moduleInstall) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||||
snackbarHost = { SnackbarHost(hostState = snackBarHost) }
|
snackbarHost = { SnackbarHost(hostState = snackBarHost) }
|
||||||
@@ -370,7 +412,8 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
context = context,
|
context = context,
|
||||||
snackBarHost = snackBarHost
|
snackBarHost = snackBarHost,
|
||||||
|
listState = listState
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,6 +431,7 @@ private fun ModuleList(
|
|||||||
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,
|
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,
|
||||||
context: Context,
|
context: Context,
|
||||||
snackBarHost: SnackbarHostState,
|
snackBarHost: SnackbarHostState,
|
||||||
|
listState: LazyListState
|
||||||
) {
|
) {
|
||||||
val failedEnable = stringResource(R.string.module_failed_to_enable)
|
val failedEnable = stringResource(R.string.module_failed_to_enable)
|
||||||
val failedDisable = stringResource(R.string.module_failed_to_disable)
|
val failedDisable = stringResource(R.string.module_failed_to_disable)
|
||||||
@@ -560,6 +604,7 @@ private fun ModuleList(
|
|||||||
isRefreshing = viewModel.isRefreshing
|
isRefreshing = viewModel.isRefreshing
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
state = listState,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
contentPadding = remember {
|
contentPadding = remember {
|
||||||
@@ -567,7 +612,7 @@ private fun ModuleList(
|
|||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
top = 16.dp,
|
top = 16.dp,
|
||||||
end = 16.dp,
|
end = 16.dp,
|
||||||
bottom = 16.dp + 56.dp + 16.dp + 48.dp + 6.dp /* Scaffold Fab Spacing + Fab container height + SnackBar height */
|
bottom = 16.dp
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user