diff --git a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt index d501e2f1..cfd3655d 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/PatchesSelectorScreen.kt @@ -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, diff --git a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt index e0a198e1..e2240210 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/VersionSelectorScreen.kt @@ -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() + } + } } } } diff --git a/app/src/main/java/app/revanced/manager/util/Util.kt b/app/src/main/java/app/revanced/manager/util/Util.kt index e2973fb3..56dfc4ae 100644 --- a/app/src/main/java/app/revanced/manager/util/Util.kt +++ b/app/src/main/java/app/revanced/manager/util/Util.kt @@ -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) } -} \ No newline at end of file +} + +@Composable +fun LazyListState.isScrollingUp(): State { + 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 \ No newline at end of file