feat: Collapse ExtendedFAB on scroll (#1630)

This commit is contained in:
Ushie 2024-02-03 22:12:12 +03:00 committed by GitHub
parent 607d8b67c9
commit 39536c0e18
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 29 deletions

View file

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
@ -69,6 +70,7 @@ import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNSUPPORTED
import app.revanced.manager.util.Options
import app.revanced.manager.util.PatchSelection
import app.revanced.manager.util.isScrollingUp
import kotlinx.coroutines.launch
import org.koin.compose.rememberKoinInject
@ -273,7 +275,7 @@ fun PatchesSelectorScreen(
}
}
val patchLazyListState = rememberLazyListState()
Scaffold(
topBar = {
AppTopBar(
@ -302,6 +304,7 @@ fun PatchesSelectorScreen(
ExtendedFloatingActionButton(
text = { Text(stringResource(R.string.save)) },
icon = { Icon(Icons.Outlined.Save, null) },
expanded = patchLazyListState.isScrollingUp,
onClick = {
// TODO: only allow this if all required options have been set.
onSave(vm.getCustomSelection(), vm.getOptions())
@ -344,7 +347,8 @@ fun PatchesSelectorScreen(
val bundle = bundles[index]
LazyColumnWithScrollbar(
modifier = Modifier.fillMaxSize()
modifier = Modifier.fillMaxSize(),
state = patchLazyListState
) {
patchList(
uid = bundle.uid,

View file

@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.ExperimentalMaterial3Api
@ -32,11 +34,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import app.revanced.manager.R
import app.revanced.manager.data.room.apps.installed.InstallType
import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.ColumnWithScrollbar
import app.revanced.manager.ui.component.GroupHeader
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
import app.revanced.manager.ui.component.LoadingIndicator
import app.revanced.manager.ui.model.SelectedApp
import app.revanced.manager.ui.viewmodel.VersionSelectorViewModel
import app.revanced.manager.util.isScrollingUp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -63,6 +66,7 @@ fun VersionSelectorScreen(
var selectedVersion: SelectedApp? by rememberSaveable { mutableStateOf(null) }
val lazyListState = rememberLazyListState()
Scaffold(
topBar = {
AppTopBar(
@ -74,38 +78,47 @@ fun VersionSelectorScreen(
ExtendedFloatingActionButton(
text = { Text(stringResource(R.string.select_version)) },
icon = { Icon(Icons.Default.Check, null) },
expanded = lazyListState.isScrollingUp,
onClick = { selectedVersion?.let(onAppClick) }
)
}
) { paddingValues ->
ColumnWithScrollbar(
LazyColumnWithScrollbar(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
horizontalAlignment = Alignment.CenterHorizontally,
state = lazyListState
) {
viewModel.installedApp?.let { (packageInfo, installedApp) ->
SelectedApp.Installed(
packageName = viewModel.packageName,
version = packageInfo.versionName
).let {
SelectedAppItem(
selectedApp = it,
selected = selectedVersion == it,
onClick = { selectedVersion = it },
patchCount = supportedVersions[it.version],
enabled =
item {
SelectedAppItem(
selectedApp = it,
selected = selectedVersion == it,
onClick = { selectedVersion = it },
patchCount = supportedVersions[it.version],
enabled =
!(installedApp?.installType == InstallType.ROOT && !viewModel.rootInstaller.hasRootAccess()),
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT
)
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT
)
}
}
}
Row(Modifier.fillMaxWidth()) {
GroupHeader(stringResource(R.string.downloadable_versions))
item {
Row(Modifier.fillMaxWidth()) {
GroupHeader(stringResource(R.string.downloadable_versions))
}
}
list.forEach {
items(
items = list,
key = { it.packageName }
) {
SelectedAppItem(
selectedApp = it,
selected = selectedVersion == it,
@ -115,19 +128,23 @@ fun VersionSelectorScreen(
}
if (viewModel.errorMessage != null) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(stringResource(R.string.error_occurred))
Text(
text = viewModel.errorMessage!!,
modifier = Modifier.padding(horizontal = 15.dp)
)
item {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(stringResource(R.string.error_occurred))
Text(
text = viewModel.errorMessage!!,
modifier = Modifier.padding(horizontal = 15.dp)
)
}
}
} else if (viewModel.isLoading)
LoadingIndicator()
} else if (viewModel.isLoading) {
item {
LoadingIndicator()
}
}
}
}
}

View file

@ -11,6 +11,14 @@ import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
@ -165,4 +173,25 @@ fun String.relativeTime(context: Context): String {
} catch (e: DateTimeParseException) {
return context.getString(R.string.invalid_date)
}
}
}
@Composable
fun LazyListState.isScrollingUp(): State<Boolean> {
return remember(this) {
var previousIndex by mutableIntStateOf(firstVisibleItemIndex)
var previousScrollOffset by mutableIntStateOf(firstVisibleItemScrollOffset)
derivedStateOf {
if (previousIndex != firstVisibleItemIndex) {
previousIndex > firstVisibleItemIndex
} else {
previousScrollOffset >= firstVisibleItemScrollOffset
}.also {
previousIndex = firstVisibleItemIndex
previousScrollOffset = firstVisibleItemScrollOffset
}
}
}
}
val LazyListState.isScrollingUp: Boolean @Composable get() = this.isScrollingUp().value