mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2024-11-10 01:01:56 +01:00
feat: Collapse ExtendedFAB on scroll (#1630)
This commit is contained in:
parent
607d8b67c9
commit
39536c0e18
3 changed files with 79 additions and 29 deletions
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyListScope
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
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.ui.viewmodel.PatchesSelectorViewModel.Companion.SHOW_UNSUPPORTED
|
||||||
import app.revanced.manager.util.Options
|
import app.revanced.manager.util.Options
|
||||||
import app.revanced.manager.util.PatchSelection
|
import app.revanced.manager.util.PatchSelection
|
||||||
|
import app.revanced.manager.util.isScrollingUp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.compose.rememberKoinInject
|
import org.koin.compose.rememberKoinInject
|
||||||
|
|
||||||
|
@ -273,7 +275,7 @@ fun PatchesSelectorScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val patchLazyListState = rememberLazyListState()
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
AppTopBar(
|
AppTopBar(
|
||||||
|
@ -302,6 +304,7 @@ fun PatchesSelectorScreen(
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(stringResource(R.string.save)) },
|
text = { Text(stringResource(R.string.save)) },
|
||||||
icon = { Icon(Icons.Outlined.Save, null) },
|
icon = { Icon(Icons.Outlined.Save, null) },
|
||||||
|
expanded = patchLazyListState.isScrollingUp,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: only allow this if all required options have been set.
|
// TODO: only allow this if all required options have been set.
|
||||||
onSave(vm.getCustomSelection(), vm.getOptions())
|
onSave(vm.getCustomSelection(), vm.getOptions())
|
||||||
|
@ -344,7 +347,8 @@ fun PatchesSelectorScreen(
|
||||||
val bundle = bundles[index]
|
val bundle = bundles[index]
|
||||||
|
|
||||||
LazyColumnWithScrollbar(
|
LazyColumnWithScrollbar(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
state = patchLazyListState
|
||||||
) {
|
) {
|
||||||
patchList(
|
patchList(
|
||||||
uid = bundle.uid,
|
uid = bundle.uid,
|
||||||
|
|
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
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.Icons
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
@ -32,11 +34,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
import app.revanced.manager.data.room.apps.installed.InstallType
|
import app.revanced.manager.data.room.apps.installed.InstallType
|
||||||
import app.revanced.manager.ui.component.AppTopBar
|
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.GroupHeader
|
||||||
|
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||||
import app.revanced.manager.ui.component.LoadingIndicator
|
import app.revanced.manager.ui.component.LoadingIndicator
|
||||||
import app.revanced.manager.ui.model.SelectedApp
|
import app.revanced.manager.ui.model.SelectedApp
|
||||||
import app.revanced.manager.ui.viewmodel.VersionSelectorViewModel
|
import app.revanced.manager.ui.viewmodel.VersionSelectorViewModel
|
||||||
|
import app.revanced.manager.util.isScrollingUp
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -63,6 +66,7 @@ fun VersionSelectorScreen(
|
||||||
|
|
||||||
var selectedVersion: SelectedApp? by rememberSaveable { mutableStateOf(null) }
|
var selectedVersion: SelectedApp? by rememberSaveable { mutableStateOf(null) }
|
||||||
|
|
||||||
|
val lazyListState = rememberLazyListState()
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
AppTopBar(
|
AppTopBar(
|
||||||
|
@ -74,38 +78,47 @@ fun VersionSelectorScreen(
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(stringResource(R.string.select_version)) },
|
text = { Text(stringResource(R.string.select_version)) },
|
||||||
icon = { Icon(Icons.Default.Check, null) },
|
icon = { Icon(Icons.Default.Check, null) },
|
||||||
|
expanded = lazyListState.isScrollingUp,
|
||||||
onClick = { selectedVersion?.let(onAppClick) }
|
onClick = { selectedVersion?.let(onAppClick) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
ColumnWithScrollbar(
|
LazyColumnWithScrollbar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
state = lazyListState
|
||||||
) {
|
) {
|
||||||
viewModel.installedApp?.let { (packageInfo, installedApp) ->
|
viewModel.installedApp?.let { (packageInfo, installedApp) ->
|
||||||
SelectedApp.Installed(
|
SelectedApp.Installed(
|
||||||
packageName = viewModel.packageName,
|
packageName = viewModel.packageName,
|
||||||
version = packageInfo.versionName
|
version = packageInfo.versionName
|
||||||
).let {
|
).let {
|
||||||
SelectedAppItem(
|
item {
|
||||||
selectedApp = it,
|
SelectedAppItem(
|
||||||
selected = selectedVersion == it,
|
selectedApp = it,
|
||||||
onClick = { selectedVersion = it },
|
selected = selectedVersion == it,
|
||||||
patchCount = supportedVersions[it.version],
|
onClick = { selectedVersion = it },
|
||||||
enabled =
|
patchCount = supportedVersions[it.version],
|
||||||
|
enabled =
|
||||||
!(installedApp?.installType == InstallType.ROOT && !viewModel.rootInstaller.hasRootAccess()),
|
!(installedApp?.installType == InstallType.ROOT && !viewModel.rootInstaller.hasRootAccess()),
|
||||||
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT
|
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(Modifier.fillMaxWidth()) {
|
item {
|
||||||
GroupHeader(stringResource(R.string.downloadable_versions))
|
Row(Modifier.fillMaxWidth()) {
|
||||||
|
GroupHeader(stringResource(R.string.downloadable_versions))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list.forEach {
|
items(
|
||||||
|
items = list,
|
||||||
|
key = { it.packageName }
|
||||||
|
) {
|
||||||
SelectedAppItem(
|
SelectedAppItem(
|
||||||
selectedApp = it,
|
selectedApp = it,
|
||||||
selected = selectedVersion == it,
|
selected = selectedVersion == it,
|
||||||
|
@ -115,19 +128,23 @@ fun VersionSelectorScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewModel.errorMessage != null) {
|
if (viewModel.errorMessage != null) {
|
||||||
Column(
|
item {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
Text(stringResource(R.string.error_occurred))
|
) {
|
||||||
Text(
|
Text(stringResource(R.string.error_occurred))
|
||||||
text = viewModel.errorMessage!!,
|
Text(
|
||||||
modifier = Modifier.padding(horizontal = 15.dp)
|
text = viewModel.errorMessage!!,
|
||||||
)
|
modifier = Modifier.padding(horizontal = 15.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (viewModel.isLoading)
|
} else if (viewModel.isLoading) {
|
||||||
LoadingIndicator()
|
item {
|
||||||
|
LoadingIndicator()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,14 @@ import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.StringRes
|
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.compose.ui.graphics.Color
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
|
@ -165,4 +173,25 @@ fun String.relativeTime(context: Context): String {
|
||||||
} catch (e: DateTimeParseException) {
|
} catch (e: DateTimeParseException) {
|
||||||
return context.getString(R.string.invalid_date)
|
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
|
Loading…
Reference in a new issue