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.saveable.rememberSaveable
|
||||
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.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -164,6 +170,30 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
) { 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(
|
||||
topBar = {
|
||||
SearchAppBar(
|
||||
@@ -289,46 +319,58 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
||||
},
|
||||
floatingActionButton = {
|
||||
if (!hideInstallButton) {
|
||||
val moduleInstall = stringResource(id = R.string.module_install)
|
||||
val selectZipLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode != RESULT_OK) {
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
val data = result.data ?: return@rememberLauncherForActivityResult
|
||||
val clipData = data.clipData
|
||||
|
||||
val uris = mutableListOf<Uri>()
|
||||
if (clipData != null) {
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
clipData.getItemAt(i)?.uri?.let { uris.add(it) }
|
||||
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 selectZipLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode != RESULT_OK) {
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
} else {
|
||||
data.data?.let { uris.add(it) }
|
||||
val data = result.data ?: return@rememberLauncherForActivityResult
|
||||
val clipData = data.clipData
|
||||
|
||||
val uris = mutableListOf<Uri>()
|
||||
if (clipData != null) {
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
clipData.getItemAt(i)?.uri?.let { uris.add(it) }
|
||||
}
|
||||
} else {
|
||||
data.data?.let { uris.add(it) }
|
||||
}
|
||||
|
||||
if (uris.isEmpty()) return@rememberLauncherForActivityResult
|
||||
|
||||
viewModel.updateZipUris(uris)
|
||||
|
||||
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(uris)))
|
||||
viewModel.clearZipUris()
|
||||
viewModel.markNeedRefresh()
|
||||
}
|
||||
|
||||
if (uris.isEmpty()) return@rememberLauncherForActivityResult
|
||||
|
||||
viewModel.updateZipUris(uris)
|
||||
|
||||
navigator.navigate(FlashScreenDestination(FlashIt.FlashModules(uris)))
|
||||
viewModel.clearZipUris()
|
||||
viewModel.markNeedRefresh()
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
// Select the zip files to install
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
type = "application/zip"
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
}
|
||||
selectZipLauncher.launch(intent)
|
||||
},
|
||||
icon = { Icon(Icons.Filled.Add, moduleInstall) },
|
||||
text = { Text(text = moduleInstall) },
|
||||
)
|
||||
}
|
||||
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
// Select the zip files to install
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
type = "application/zip"
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
}
|
||||
selectZipLauncher.launch(intent)
|
||||
},
|
||||
icon = { Icon(Icons.Filled.Add, moduleInstall) },
|
||||
text = { Text(text = moduleInstall) },
|
||||
)
|
||||
}
|
||||
},
|
||||
contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||
@@ -370,7 +412,8 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
||||
}
|
||||
},
|
||||
context = context,
|
||||
snackBarHost = snackBarHost
|
||||
snackBarHost = snackBarHost,
|
||||
listState = listState
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -388,6 +431,7 @@ private fun ModuleList(
|
||||
onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,
|
||||
context: Context,
|
||||
snackBarHost: SnackbarHostState,
|
||||
listState: LazyListState
|
||||
) {
|
||||
val failedEnable = stringResource(R.string.module_failed_to_enable)
|
||||
val failedDisable = stringResource(R.string.module_failed_to_disable)
|
||||
@@ -560,6 +604,7 @@ private fun ModuleList(
|
||||
isRefreshing = viewModel.isRefreshing
|
||||
) {
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
contentPadding = remember {
|
||||
@@ -567,7 +612,7 @@ private fun ModuleList(
|
||||
start = 16.dp,
|
||||
top = 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