diff --git a/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt b/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt new file mode 100644 index 0000000..535ea80 --- /dev/null +++ b/app/src/main/java/app/revanced/manager/ui/component/AppScaffold.kt @@ -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, + 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) + } + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 1af498e..71af8d5 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -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) ) { diff --git a/app/src/main/java/app/revanced/manager/ui/screen/MainDashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/MainDashboardScreen.kt index 1893f29..ec539b7 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/MainDashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/MainDashboardScreen.kt @@ -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() } } diff --git a/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt index d18705e..803b391 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/PatcherScreen.kt @@ -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( diff --git a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt index 200b996..8a7be14 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/SettingsScreen.kt @@ -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) { diff --git a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/AppSelectorSubscreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/AppSelectorSubscreen.kt index 538cc65..bcb3a42 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/AppSelectorSubscreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/AppSelectorSubscreen.kt @@ -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) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/ContributorsSubscreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/ContributorsSubscreen.kt index 7e9b0eb..5012fd6 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/ContributorsSubscreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/ContributorsSubscreen.kt @@ -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), diff --git a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/LicensesSubscreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/LicensesSubscreen.kt index c64d89f..1e1ed4c 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/LicensesSubscreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/LicensesSubscreen.kt @@ -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 -> diff --git a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/PatchesSelectorSubscreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/PatchesSelectorSubscreen.kt index 9901f53..a4aad4d 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/PatchesSelectorSubscreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/PatchesSelectorSubscreen.kt @@ -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) ) { diff --git a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/SourceSelectorSubscreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/SourceSelectorSubscreen.kt index 1e5111d..14ad3f4 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/subscreens/SourceSelectorSubscreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/subscreens/SourceSelectorSubscreen.kt @@ -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