feat: scaffold and scrolling improvements (#21)

* feat: scaffold and scrolling improvements

* fix: apply scaffoldPadding before verticalScroll
This commit is contained in:
aliernfrog 2022-12-04 11:18:24 +03:00 committed by GitHub
parent 58c016bfb9
commit d70e750c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 191 additions and 151 deletions

View File

@ -0,0 +1,109 @@
package app.revanced.manager.ui.component
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import app.revanced.manager.ui.navigation.AppDestination
import app.revanced.manager.ui.navigation.DashboardDestination
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppScaffold(
topBar: @Composable (TopAppBarScrollBehavior) -> Unit = {},
bottomBar: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
content: @Composable (PaddingValues) -> Unit
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar(scrollBehavior) },
bottomBar = bottomBar,
floatingActionButton = floatingActionButton,
content = content
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppLargeTopBar(
topBarTitle: String,
scrollBehavior: TopAppBarScrollBehavior,
actions: @Composable (RowScope.() -> Unit) = {},
onBackClick: (() -> Unit)? = null
) {
LargeTopAppBar(
title = { Text(topBarTitle) },
scrollBehavior = scrollBehavior,
navigationIcon = {
if (onBackClick != null) {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
}
},
actions = actions
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppMediumTopBar(
topBarTitle: String,
scrollBehavior: TopAppBarScrollBehavior,
actions: @Composable (RowScope.() -> Unit) = {},
onBackClick: (() -> Unit)? = null
) {
MediumTopAppBar(
title = { Text(topBarTitle) },
scrollBehavior = scrollBehavior,
navigationIcon = {
if (onBackClick != null) {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
}
},
actions = actions
)
}
@Composable
fun AppBottomNavBar(
navItems: List<DashboardDestination>,
currentDestination: DashboardDestination,
onNavChanged: (AppDestination) -> Unit
) {
NavigationBar {
navItems.forEach { destination ->
NavigationBarItem(
selected = currentDestination == destination,
icon = {
Icon(
if (currentDestination == destination) destination.icon else destination.outlinedIcon,
stringResource(destination.label)
)
},
label = { Text(stringResource(destination.label)) },
onClick = {
if (destination != currentDestination) {
onNavChanged(destination)
}
}
)
}
}
}

View File

@ -32,8 +32,8 @@ fun DashboardScreen(viewModel: DashboardViewModel = getViewModel()) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 18.dp)
.verticalScroll(state = rememberScrollState()),
.verticalScroll(state = rememberScrollState())
.padding(horizontal = 18.dp),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(18.dp)
) {

View File

@ -3,11 +3,13 @@ package app.revanced.manager.ui.screen
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import app.revanced.manager.ui.component.AppBottomNavBar
import app.revanced.manager.ui.component.AppLargeTopBar
import app.revanced.manager.ui.component.AppScaffold
import app.revanced.manager.ui.navigation.AppDestination
import app.revanced.manager.ui.navigation.DashboardDestination
@ -19,53 +21,22 @@ fun MainDashboardScreen(
onNavChanged: (AppDestination) -> Unit,
content: @Composable () -> Unit
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
state = rememberTopAppBarState(),
canScroll = { true }
)
Scaffold(
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = {
Text(
text = stringResource(currentDestination.label),
style = MaterialTheme.typography.headlineLarge
)
},
AppScaffold(
topBar = { scrollBehavior ->
AppLargeTopBar(
topBarTitle = stringResource(currentDestination.label),
scrollBehavior = scrollBehavior
)
},
bottomBar = {
NavigationBar {
bottomNavItems.forEach { destination ->
NavigationBarItem(
selected = currentDestination == destination,
icon = {
Icon(
if (currentDestination == destination) destination.icon else destination.outlinedIcon,
stringResource(destination.label)
)
},
label = { Text(stringResource(destination.label)) },
onClick = {
if (destination != currentDestination) {
onNavChanged(destination)
}
}
)
}
}
AppBottomNavBar(
navItems = bottomNavItems,
currentDestination = currentDestination,
onNavChanged = onNavChanged
)
}
) { paddingValues ->
Box(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
) {
Box(Modifier.padding(paddingValues).fillMaxSize()) {
content()
}
}

View File

@ -1,6 +1,8 @@
package app.revanced.manager.ui.screen
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build
import androidx.compose.material3.*
@ -44,6 +46,7 @@ fun PatcherScreen(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.verticalScroll(rememberScrollState())
.padding(16.dp),
) {
ElevatedCard(

View File

@ -46,8 +46,8 @@ fun SettingsScreen(
Column(
modifier = Modifier
.fillMaxSize()
.padding(top = 48.dp, start = 18.dp, end = 18.dp)
.verticalScroll(state = rememberScrollState()),
.verticalScroll(rememberScrollState())
.padding(top = 48.dp, start = 18.dp, end = 18.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
if (vm.showThemePicker) {

View File

@ -4,10 +4,10 @@ import android.annotation.SuppressLint
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.SdStorage
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
@ -15,6 +15,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.ui.component.AppIcon
import app.revanced.manager.ui.component.AppMediumTopBar
import app.revanced.manager.ui.component.AppScaffold
import app.revanced.manager.ui.component.LoadingIndicator
import app.revanced.manager.ui.viewmodel.AppSelectorViewModel
import org.koin.androidx.compose.getViewModel
@ -26,7 +28,6 @@ fun AppSelectorSubscreen(
onBackClick: () -> Unit,
vm: AppSelectorViewModel = getViewModel(),
) {
val filePicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
it?.let { uri ->
vm.setSelectedAppPackageFromFile(uri)
@ -34,14 +35,13 @@ fun AppSelectorSubscreen(
}
}
Scaffold(
topBar = {
MediumTopAppBar(title = { Text(stringResource(R.string.app_selector_title)) },
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(Icons.Default.ArrowBack, contentDescription = null)
}
})
AppScaffold(
topBar = { scrollBehavior ->
AppMediumTopBar(
topBarTitle = stringResource(R.string.app_selector_title),
scrollBehavior = scrollBehavior,
onBackClick = onBackClick
)
},
floatingActionButton = {
ExtendedFloatingActionButton(
@ -51,10 +51,10 @@ fun AppSelectorSubscreen(
icon = { Icon(Icons.Default.SdStorage, contentDescription = null) },
text = { Text(stringResource(R.string.storage)) },
)
},
}
) { paddingValues ->
if (vm.filteredApps.isNotEmpty()) {
LazyColumn(modifier = Modifier.padding(paddingValues)) {
LazyColumn(modifier = Modifier.fillMaxSize().padding(paddingValues)) {
items(count = vm.filteredApps.size) { int ->
val app = vm.filteredApps[int]
val label = vm.applicationLabel(app)

View File

@ -4,17 +4,16 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.AppLargeTopBar
import app.revanced.manager.ui.component.AppScaffold
import app.revanced.manager.ui.component.ContributorsCard
import app.revanced.manager.ui.viewmodel.ContributorsViewModel
import app.revanced.manager.util.ghOrganization
@ -27,31 +26,14 @@ fun ContributorsSubscreen(
onBackClick: () -> Unit,
vm: ContributorsViewModel = getViewModel()
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
state = rememberTopAppBarState(),
canScroll = { true }
)
val ctx = LocalContext.current.applicationContext
Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = {
Text(
text = stringResource(R.string.screen_contributors_title)
)
},
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
},
scrollBehavior = scrollBehavior
)
AppScaffold(
topBar = { scrollBehavior ->
AppLargeTopBar(
topBarTitle = stringResource(R.string.screen_contributors_title),
scrollBehavior = scrollBehavior,
onBackClick = onBackClick
)
},
floatingActionButton = {
FloatingActionButton(onClick = { ctx.openUrl(ghOrganization) }) {
@ -62,8 +44,8 @@ fun ContributorsSubscreen(
Column(
Modifier
.padding(paddingValues)
.padding(bottom = 8.dp)
.verticalScroll(rememberScrollState())
.padding(bottom = 8.dp)
) {
ContributorsCard(
stringResource(R.string.cli_contributors),

View File

@ -1,14 +1,13 @@
package app.revanced.manager.ui.screen.subscreens
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import app.revanced.manager.R
import app.revanced.manager.ui.component.AppLargeTopBar
import app.revanced.manager.ui.component.AppScaffold
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
@ -17,25 +16,12 @@ import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
fun LicensesSubscreen(
onBackClick: () -> Unit,
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
state = rememberTopAppBarState(),
canScroll = { true }
)
Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = { Text(stringResource(R.string.opensource_licenses)) },
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
},
scrollBehavior = scrollBehavior
AppScaffold(
topBar = { scrollBehavior ->
AppLargeTopBar(
topBarTitle = stringResource(R.string.opensource_licenses),
scrollBehavior = scrollBehavior,
onBackClick = onBackClick
)
}
) { paddingValues ->

View File

@ -13,6 +13,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.AppMediumTopBar
import app.revanced.manager.ui.component.AppScaffold
import app.revanced.manager.ui.component.LoadingIndicator
import app.revanced.manager.ui.component.PatchCard
import app.revanced.manager.ui.viewmodel.PatchesSelectorViewModel
@ -36,28 +38,24 @@ fun PatchesSelectorSubscreen(
vm.filterPatches()
}
}
Scaffold(topBar = {
MediumTopAppBar(title = {
Text(
text = stringResource(R.string.card_patches_header),
style = MaterialTheme.typography.headlineLarge
)
}, navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(
imageVector = Icons.Default.ArrowBack, contentDescription = null
)
}
}, actions = {
IconButton(onClick = {
vm.selectAllPatches(patches, vm.selectedPatches.isEmpty())
}) {
if (vm.selectedPatches.isEmpty()) Icon(
Icons.Default.SelectAll, contentDescription = null
) else Icon(Icons.Default.Deselect, contentDescription = null)
}
})
}) { paddingValues ->
AppScaffold(
topBar = { scrollBehavior ->
AppMediumTopBar(
topBarTitle = stringResource(id = R.string.card_patches_header),
scrollBehavior = scrollBehavior,
actions = {
IconButton(onClick = {
vm.selectAllPatches(patches, vm.selectedPatches.isEmpty())
}) {
if (vm.selectedPatches.isEmpty()) Icon(
Icons.Default.SelectAll, contentDescription = null
) else Icon(Icons.Default.Deselect, contentDescription = null)
}
},
onBackClick = onBackClick
)
}
) { paddingValues ->
Column(
modifier = Modifier.padding(paddingValues)
) {

View File

@ -5,21 +5,22 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.revanced.manager.R
import app.revanced.manager.ui.component.AppLargeTopBar
import app.revanced.manager.ui.component.AppScaffold
import app.revanced.manager.ui.component.SourceItem
import app.revanced.manager.ui.viewmodel.SourceSelectorViewModel
import org.koin.androidx.compose.getViewModel
@ -30,10 +31,6 @@ fun SourceSelectorSubscreen(
onBackClick: () -> Unit,
viewModel: SourceSelectorViewModel = getViewModel()
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
state = rememberTopAppBarState(),
canScroll = { true }
)
val context = LocalContext.current
val filePicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
@ -44,19 +41,12 @@ fun SourceSelectorSubscreen(
}
Toast.makeText(context, "Couldn't load local patch bundle.", Toast.LENGTH_SHORT).show()
}
Scaffold(
modifier = Modifier
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = { Text(stringResource(R.string.select_sources)) },
navigationIcon = {
IconButton(onClick = onBackClick) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = null)
}
},
scrollBehavior = scrollBehavior
AppScaffold(
topBar = { scrollBehavior ->
AppLargeTopBar(
topBarTitle = stringResource(R.string.select_sources),
scrollBehavior = scrollBehavior,
onBackClick = onBackClick
)
},
floatingActionButton = {
@ -67,9 +57,10 @@ fun SourceSelectorSubscreen(
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp)
) {
ListItem(
modifier = Modifier