Feat(About): Add about page

Add about page, add libraries page framework. Add page switching animation and navigation bar animation.
This commit is contained in:
2024-04-03 18:12:00 +08:00
parent 8b200d14c6
commit 92cd20f36f
15 changed files with 460 additions and 46 deletions

View File

@@ -0,0 +1,40 @@
package top.fatweb.oxygen.toolbox.navigation
import androidx.compose.animation.scaleIn
import androidx.compose.animation.slideOutVertically
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import top.fatweb.oxygen.toolbox.ui.about.AboutRoute
const val ABOUT_ROUTE = "about_route"
fun NavController.navigateToAbout(navOptions: NavOptions? = null) =
navigate(ABOUT_ROUTE, navOptions)
fun NavGraphBuilder.aboutScreen(
onBackClick: () -> Unit,
onNavigateToLibraries: () -> Unit
) {
composable(
route = ABOUT_ROUTE,
enterTransition = {
scaleIn()
},
exitTransition = {
slideOutVertically { it }
},
popEnterTransition = {
scaleIn()
},
popExitTransition = {
slideOutVertically { it }
}
) {
AboutRoute(
onBackClick = onBackClick,
onNavigateToLibraries = onNavigateToLibraries
)
}
}

View File

@@ -0,0 +1,36 @@
package top.fatweb.oxygen.toolbox.navigation
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import top.fatweb.oxygen.toolbox.ui.about.LibrariesRoute
const val LIBRARIES_ROUTE = "libraries_route"
fun NavController.navigateToLibraries(navOptions: NavOptions? = null) =
navigate(LIBRARIES_ROUTE, navOptions)
fun NavGraphBuilder.librariesScreen(
onBackClick: () -> Unit
) {
composable(
route = LIBRARIES_ROUTE,
enterTransition = {
scaleIn()
},
exitTransition = {
scaleOut()
},
popEnterTransition = {
scaleIn()
},
popExitTransition = {
scaleOut()
}
) {
LibrariesRoute(onBackClick = onBackClick)
}
}

View File

@@ -21,6 +21,13 @@ fun OxygenNavHost(
searchScreen( searchScreen(
onBackClick = navController::popBackStack onBackClick = navController::popBackStack
) )
aboutScreen(
onBackClick = navController::popBackStack,
onNavigateToLibraries = navController::navigateToLibraries
)
librariesScreen(
onBackClick = navController::popBackStack
)
toolsScreen( toolsScreen(
) )

View File

@@ -4,6 +4,7 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import top.fatweb.oxygen.toolbox.ui.star.StarRoute
const val STAR_ROUTE = "star_route" const val STAR_ROUTE = "star_route"
@@ -13,6 +14,6 @@ fun NavGraphBuilder.starScreen() {
composable( composable(
route = STAR_ROUTE route = STAR_ROUTE
) { ) {
StarRoute()
} }
} }

View File

@@ -1,5 +1,7 @@
package top.fatweb.oxygen.toolbox.ui package top.fatweb.oxygen.toolbox.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
@@ -74,7 +76,7 @@ fun OxygenApp(appState: OxygenAppState) {
val isOffline by appState.isOffline.collectAsStateWithLifecycle() val isOffline by appState.isOffline.collectAsStateWithLifecycle()
val noConnectMessage = stringResource(R.string.no_connect) val noConnectMessage = stringResource(R.string.core_no_connect)
val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior() val bottomAppBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior()
@@ -90,7 +92,9 @@ fun OxygenApp(appState: OxygenAppState) {
if (showSettingsDialog) { if (showSettingsDialog) {
SettingsDialog( SettingsDialog(
onDismiss = { showSettingsDialog = false } onDismiss = { showSettingsDialog = false },
onNavigateToLibraries = appState::navigateToLibraries,
onNavigateToAbout = appState::navigateToAbout
) )
} }
@@ -103,7 +107,9 @@ fun OxygenApp(appState: OxygenAppState) {
contentWindowInsets = WindowInsets(0, 0, 0, 0), contentWindowInsets = WindowInsets(0, 0, 0, 0),
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
bottomBar = { bottomBar = {
if (appState.shouldShowBottomBar && destination != null) { AnimatedVisibility(
visible = appState.shouldShowBottomBar && destination != null,
enter = slideInVertically { it }) {
BottomAppBar( BottomAppBar(
scrollBehavior = bottomAppBarScrollBehavior scrollBehavior = bottomAppBarScrollBehavior
) { ) {
@@ -127,7 +133,7 @@ fun OxygenApp(appState: OxygenAppState) {
) )
) )
) { ) {
if (appState.shouldShowNavRail && destination != null) { AnimatedVisibility(appState.shouldShowNavRail && destination != null) {
OxygenNavRail( OxygenNavRail(
modifier = Modifier.safeDrawingPadding(), modifier = Modifier.safeDrawingPadding(),
destinations = appState.topLevelDestinations, destinations = appState.topLevelDestinations,

View File

@@ -23,6 +23,8 @@ import top.fatweb.oxygen.toolbox.monitor.TimeZoneMonitor
import top.fatweb.oxygen.toolbox.navigation.STAR_ROUTE import top.fatweb.oxygen.toolbox.navigation.STAR_ROUTE
import top.fatweb.oxygen.toolbox.navigation.TOOLS_ROUTE import top.fatweb.oxygen.toolbox.navigation.TOOLS_ROUTE
import top.fatweb.oxygen.toolbox.navigation.TopLevelDestination import top.fatweb.oxygen.toolbox.navigation.TopLevelDestination
import top.fatweb.oxygen.toolbox.navigation.navigateToAbout
import top.fatweb.oxygen.toolbox.navigation.navigateToLibraries
import top.fatweb.oxygen.toolbox.navigation.navigateToSearch import top.fatweb.oxygen.toolbox.navigation.navigateToSearch
import top.fatweb.oxygen.toolbox.navigation.navigateToStar import top.fatweb.oxygen.toolbox.navigation.navigateToStar
import top.fatweb.oxygen.toolbox.navigation.navigateToTools import top.fatweb.oxygen.toolbox.navigation.navigateToTools
@@ -56,7 +58,7 @@ fun rememberOxygenAppState(
@Stable @Stable
class OxygenAppState( class OxygenAppState(
val windowSizeClass: WindowSizeClass, private val windowSizeClass: WindowSizeClass,
networkMonitor: NetworkMonitor, networkMonitor: NetworkMonitor,
timeZoneMonitor: TimeZoneMonitor, timeZoneMonitor: TimeZoneMonitor,
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
@@ -114,4 +116,8 @@ class OxygenAppState(
} }
fun navigateToSearch() = navController.navigateToSearch() fun navigateToSearch() = navController.navigateToSearch()
fun navigateToLibraries() = navController.navigateToLibraries()
fun navigateToAbout() = navController.navigateToAbout()
} }

View File

@@ -0,0 +1,162 @@
package top.fatweb.oxygen.toolbox.ui.about
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
import top.fatweb.oxygen.toolbox.ui.component.ApiLevelPreviews
import top.fatweb.oxygen.toolbox.ui.component.OxygenPreviews
import top.fatweb.oxygen.toolbox.ui.component.ThemePreviews
import top.fatweb.oxygen.toolbox.ui.theme.OxygenTheme
import top.fatweb.oxygen.toolbox.ui.util.ResourcesUtils
@Composable
internal fun AboutRoute(
modifier: Modifier = Modifier, onBackClick: () -> Unit, onNavigateToLibraries: () -> Unit
) {
AboutScreen(
modifier = modifier,
onBackClick = onBackClick,
onNavigateToLibraries = onNavigateToLibraries
)
}
@Composable
internal fun AboutScreen(
modifier: Modifier = Modifier, onBackClick: () -> Unit, onNavigateToLibraries: () -> Unit
) {
Column(
modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally
) {
AboutToolBar(
onBackClick = onBackClick
)
Spacer(
modifier = Modifier.height(64.dp)
)
AboutAppInfo()
Spacer(
modifier = Modifier.weight(1f)
)
AboutFooter(
onNavigateToLibraries = onNavigateToLibraries
)
}
}
@Composable
private fun AboutToolBar(
modifier: Modifier = Modifier, onBackClick: () -> Unit
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = onBackClick) {
Icon(
imageVector = OxygenIcons.ArrowBack,
contentDescription = stringResource(R.string.core_back)
)
}
}
}
@Composable
private fun AboutAppInfo(
modifier: Modifier = Modifier
) {
Column(
modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
imageVector = ImageVector.vectorResource(R.drawable.ic_oxygen),
contentDescription = stringResource(R.string.app_full_name)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold,
text = stringResource(R.string.app_name)
)
Spacer(modifier = Modifier.height(8.dp))
Text(
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.outline,
text = stringResource(R.string.app_description)
)
Spacer(modifier = Modifier.height(8.dp))
Text(
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.outline,
text = "${ResourcesUtils.getAppVersionName(LocalContext.current)}(${
ResourcesUtils.getAppVersionCode(
LocalContext.current
)
})"
)
}
}
@Composable
private fun AboutFooter(
modifier: Modifier = Modifier, onNavigateToLibraries: () -> Unit
) {
Row(
modifier = modifier.padding(32.dp)
) {
TextButton(
onClick = onNavigateToLibraries
) {
Text(
color = MaterialTheme.colorScheme.primary,
text = stringResource(R.string.feature_settings_open_source_license)
)
}
}
}
@ThemePreviews
@Composable
fun AboutToolBarPreview() {
OxygenTheme {
AboutToolBar(onBackClick = {})
}
}
@ApiLevelPreviews
@Composable
fun AboutAppInfoPreview() {
OxygenTheme {
AboutAppInfo()
}
}
@OxygenPreviews
@Composable
fun AboutScreenPreview() {
OxygenTheme {
AboutScreen(onBackClick = {}, onNavigateToLibraries = {})
}
}

View File

@@ -0,0 +1,61 @@
package top.fatweb.oxygen.toolbox.ui.about
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
@Composable
internal fun LibrariesRoute(
modifier: Modifier = Modifier,
onBackClick: () -> Unit
) {
LibrariesScreen(
modifier = modifier,
onBackClick = onBackClick
)
}
@Composable
internal fun LibrariesScreen(
modifier: Modifier = Modifier,
onBackClick: () -> Unit
) {
Column(
modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally
) {
LibrariesToolBar(
onBackClick = onBackClick
)
Spacer(modifier = Modifier.weight(1f))
}
}
@Composable
private fun LibrariesToolBar(
modifier: Modifier = Modifier, onBackClick: () -> Unit
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = onBackClick) {
Icon(
imageVector = OxygenIcons.ArrowBack,
contentDescription = stringResource(R.string.core_back)
)
}
}
}

View File

@@ -92,10 +92,20 @@ fun OxygenGradientBackground(
} }
} }
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme")
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme") @Preview(name = "Light theme", group = "ThemePreviews", uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark theme", group = "ThemePreviews", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(name = "Api 21", group = "ApiLevelPreviews", apiLevel = 21)
annotation class OxygenPreviews
@Preview(name = "Light theme", group = "ThemePreviews", uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark theme", group = "ThemePreviews", uiMode = Configuration.UI_MODE_NIGHT_YES)
annotation class ThemePreviews annotation class ThemePreviews
@Preview(name = "Api 21", group = "ApiLevelPreviews", apiLevel = 21)
@Preview(name = "Api Default", group = "ApiLevelPreviews")
annotation class ApiLevelPreviews
@ThemePreviews @ThemePreviews
@Composable @Composable
fun BackgroundDefault() { fun BackgroundDefault() {

View File

@@ -17,6 +17,7 @@ import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -24,6 +25,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
@@ -31,6 +33,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import top.fatweb.oxygen.toolbox.R import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
import top.fatweb.oxygen.toolbox.model.userdata.DarkThemeConfig import top.fatweb.oxygen.toolbox.model.userdata.DarkThemeConfig
import top.fatweb.oxygen.toolbox.model.userdata.LanguageConfig import top.fatweb.oxygen.toolbox.model.userdata.LanguageConfig
import top.fatweb.oxygen.toolbox.model.userdata.LaunchPageConfig import top.fatweb.oxygen.toolbox.model.userdata.LaunchPageConfig
@@ -43,8 +46,10 @@ import top.fatweb.oxygen.toolbox.ui.theme.supportsDynamicTheming
@Composable @Composable
fun SettingsDialog( fun SettingsDialog(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SettingsViewModel = hiltViewModel(),
onDismiss: () -> Unit, onDismiss: () -> Unit,
viewModel: SettingsViewModel = hiltViewModel() onNavigateToLibraries: () -> Unit,
onNavigateToAbout: () -> Unit
) { ) {
val settingsUiState by viewModel.settingsUiState.collectAsStateWithLifecycle() val settingsUiState by viewModel.settingsUiState.collectAsStateWithLifecycle()
SettingsDialog( SettingsDialog(
@@ -55,7 +60,9 @@ fun SettingsDialog(
onChangeLaunchPageConfig = viewModel::updateLaunchPageConfig, onChangeLaunchPageConfig = viewModel::updateLaunchPageConfig,
onchangeThemeBrandConfig = viewModel::updateThemeBrandConfig, onchangeThemeBrandConfig = viewModel::updateThemeBrandConfig,
onChangeDarkThemeConfig = viewModel::updateDarkThemeConfig, onChangeDarkThemeConfig = viewModel::updateDarkThemeConfig,
onchangeUseDynamicColor = viewModel::updateUseDynamicColor onchangeUseDynamicColor = viewModel::updateUseDynamicColor,
onNavigateToLibraries = onNavigateToLibraries,
onNavigateToAbout = onNavigateToAbout
) )
} }
@@ -69,7 +76,9 @@ fun SettingsDialog(
onChangeLaunchPageConfig: (launchPageConfig: LaunchPageConfig) -> Unit, onChangeLaunchPageConfig: (launchPageConfig: LaunchPageConfig) -> Unit,
onchangeThemeBrandConfig: (themeBrandConfig: ThemeBrandConfig) -> Unit, onchangeThemeBrandConfig: (themeBrandConfig: ThemeBrandConfig) -> Unit,
onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit, onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit,
onchangeUseDynamicColor: (useDynamicColor: Boolean) -> Unit onchangeUseDynamicColor: (useDynamicColor: Boolean) -> Unit,
onNavigateToLibraries: () -> Unit,
onNavigateToAbout: () -> Unit
) { ) {
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
@@ -101,11 +110,14 @@ fun SettingsDialog(
SettingsPanel( SettingsPanel(
settings = settingsUiState.settings, settings = settingsUiState.settings,
supportDynamicColor = supportDynamicColor, supportDynamicColor = supportDynamicColor,
onDismiss = onDismiss,
onChangeLanguageConfig = onChangeLanguageConfig, onChangeLanguageConfig = onChangeLanguageConfig,
onChangeLaunchPageConfig = onChangeLaunchPageConfig, onChangeLaunchPageConfig = onChangeLaunchPageConfig,
onchangeThemeBrandConfig = onchangeThemeBrandConfig, onchangeThemeBrandConfig = onchangeThemeBrandConfig,
onChangeDarkThemeConfig = onChangeDarkThemeConfig, onChangeDarkThemeConfig = onChangeDarkThemeConfig,
onchangeUseDynamicColor = onchangeUseDynamicColor onchangeUseDynamicColor = onchangeUseDynamicColor,
onNavigateToLibraries = onNavigateToLibraries,
onNavigateToAbout = onNavigateToAbout
) )
} }
} }
@@ -117,7 +129,7 @@ fun SettingsDialog(
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)
.clickable { onDismiss() }, .clickable { onDismiss() },
text = stringResource(R.string.feature_settings_dismiss_dialog_button_text), text = stringResource(R.string.core_ok),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary color = MaterialTheme.colorScheme.primary
) )
@@ -129,27 +141,30 @@ fun SettingsDialog(
private fun ColumnScope.SettingsPanel( private fun ColumnScope.SettingsPanel(
settings: UserData, settings: UserData,
supportDynamicColor: Boolean, supportDynamicColor: Boolean,
onDismiss: () -> Unit,
onChangeLanguageConfig: (languageConfig: LanguageConfig) -> Unit, onChangeLanguageConfig: (languageConfig: LanguageConfig) -> Unit,
onChangeLaunchPageConfig: (launchPageConfig: LaunchPageConfig) -> Unit, onChangeLaunchPageConfig: (launchPageConfig: LaunchPageConfig) -> Unit,
onchangeThemeBrandConfig: (themeBrandConfig: ThemeBrandConfig) -> Unit, onchangeThemeBrandConfig: (themeBrandConfig: ThemeBrandConfig) -> Unit,
onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit, onChangeDarkThemeConfig: (darkThemeConfig: DarkThemeConfig) -> Unit,
onchangeUseDynamicColor: (useDynamicColor: Boolean) -> Unit onchangeUseDynamicColor: (useDynamicColor: Boolean) -> Unit,
onNavigateToLibraries: () -> Unit,
onNavigateToAbout: () -> Unit
) { ) {
SettingsDialogSectionTitle(text = stringResource(R.string.feature_settings_language)) SettingsDialogSectionTitle(text = stringResource(R.string.feature_settings_language))
Column( Column(
modifier = Modifier.selectableGroup() modifier = Modifier.selectableGroup()
) { ) {
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_language_system_default), text = stringResource(R.string.feature_settings_language_system_default),
selected = settings.languageConfig == LanguageConfig.FOLLOW_SYSTEM, selected = settings.languageConfig == LanguageConfig.FOLLOW_SYSTEM,
onClick = { onChangeLanguageConfig(LanguageConfig.FOLLOW_SYSTEM) } onClick = { onChangeLanguageConfig(LanguageConfig.FOLLOW_SYSTEM) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_language_chinese), text = stringResource(R.string.feature_settings_language_chinese),
selected = settings.languageConfig == LanguageConfig.CHINESE, selected = settings.languageConfig == LanguageConfig.CHINESE,
onClick = { onChangeLanguageConfig(LanguageConfig.CHINESE) } onClick = { onChangeLanguageConfig(LanguageConfig.CHINESE) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_language_english), text = stringResource(R.string.feature_settings_language_english),
selected = settings.languageConfig == LanguageConfig.ENGLISH, selected = settings.languageConfig == LanguageConfig.ENGLISH,
onClick = { onChangeLanguageConfig(LanguageConfig.ENGLISH) } onClick = { onChangeLanguageConfig(LanguageConfig.ENGLISH) }
@@ -159,12 +174,12 @@ private fun ColumnScope.SettingsPanel(
Column( Column(
modifier = Modifier.selectableGroup() modifier = Modifier.selectableGroup()
) { ) {
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_launch_page_tools), text = stringResource(R.string.feature_settings_launch_page_tools),
selected = settings.launchPageConfig == LaunchPageConfig.TOOLS, selected = settings.launchPageConfig == LaunchPageConfig.TOOLS,
onClick = { onChangeLaunchPageConfig(LaunchPageConfig.TOOLS) } onClick = { onChangeLaunchPageConfig(LaunchPageConfig.TOOLS) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_launch_page_star), text = stringResource(R.string.feature_settings_launch_page_star),
selected = settings.launchPageConfig == LaunchPageConfig.STAR, selected = settings.launchPageConfig == LaunchPageConfig.STAR,
onClick = { onChangeLaunchPageConfig(LaunchPageConfig.STAR) } onClick = { onChangeLaunchPageConfig(LaunchPageConfig.STAR) }
@@ -174,12 +189,12 @@ private fun ColumnScope.SettingsPanel(
Column( Column(
modifier = Modifier.selectableGroup() modifier = Modifier.selectableGroup()
) { ) {
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_theme_brand_default), text = stringResource(R.string.feature_settings_theme_brand_default),
selected = settings.themeBrandConfig == ThemeBrandConfig.DEFAULT, selected = settings.themeBrandConfig == ThemeBrandConfig.DEFAULT,
onClick = { onchangeThemeBrandConfig(ThemeBrandConfig.DEFAULT) } onClick = { onchangeThemeBrandConfig(ThemeBrandConfig.DEFAULT) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_theme_brand_android), text = stringResource(R.string.feature_settings_theme_brand_android),
selected = settings.themeBrandConfig == ThemeBrandConfig.ANDROID, selected = settings.themeBrandConfig == ThemeBrandConfig.ANDROID,
onClick = { onchangeThemeBrandConfig(ThemeBrandConfig.ANDROID) } onClick = { onchangeThemeBrandConfig(ThemeBrandConfig.ANDROID) }
@@ -190,12 +205,12 @@ private fun ColumnScope.SettingsPanel(
modifier = Modifier.selectableGroup() modifier = Modifier.selectableGroup()
) { ) {
SettingsDialogSectionTitle(text = stringResource(R.string.feature_settings_dynamic_color)) SettingsDialogSectionTitle(text = stringResource(R.string.feature_settings_dynamic_color))
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_dynamic_color_enable), text = stringResource(R.string.feature_settings_dynamic_color_enable),
selected = settings.useDynamicColor, selected = settings.useDynamicColor,
onClick = { onchangeUseDynamicColor(true) } onClick = { onchangeUseDynamicColor(true) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_dynamic_color_disable), text = stringResource(R.string.feature_settings_dynamic_color_disable),
selected = !settings.useDynamicColor, selected = !settings.useDynamicColor,
onClick = { onchangeUseDynamicColor(false) } onClick = { onchangeUseDynamicColor(false) }
@@ -206,22 +221,43 @@ private fun ColumnScope.SettingsPanel(
Column( Column(
modifier = Modifier.selectableGroup() modifier = Modifier.selectableGroup()
) { ) {
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_dark_mode_system_default), text = stringResource(R.string.feature_settings_dark_mode_system_default),
selected = settings.darkThemeConfig == DarkThemeConfig.FOLLOW_SYSTEM, selected = settings.darkThemeConfig == DarkThemeConfig.FOLLOW_SYSTEM,
onClick = { onChangeDarkThemeConfig(DarkThemeConfig.FOLLOW_SYSTEM) } onClick = { onChangeDarkThemeConfig(DarkThemeConfig.FOLLOW_SYSTEM) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_dark_mode_light), text = stringResource(R.string.feature_settings_dark_mode_light),
selected = settings.darkThemeConfig == DarkThemeConfig.LIGHT, selected = settings.darkThemeConfig == DarkThemeConfig.LIGHT,
onClick = { onChangeDarkThemeConfig(DarkThemeConfig.LIGHT) } onClick = { onChangeDarkThemeConfig(DarkThemeConfig.LIGHT) }
) )
SettingsDialogThemeChooserRow( SettingsDialogChooserRow(
text = stringResource(R.string.feature_settings_dark_mode_dark), text = stringResource(R.string.feature_settings_dark_mode_dark),
selected = settings.darkThemeConfig == DarkThemeConfig.DARK, selected = settings.darkThemeConfig == DarkThemeConfig.DARK,
onClick = { onChangeDarkThemeConfig(DarkThemeConfig.DARK) } onClick = { onChangeDarkThemeConfig(DarkThemeConfig.DARK) }
) )
} }
SettingsDialogSectionTitle(text = stringResource(R.string.feature_settings_more))
Column(
modifier = Modifier.selectableGroup()
) {
SettingsDialogClickerRow(
icon = OxygenIcons.Code,
text = stringResource(R.string.feature_settings_open_source_license),
onClick = {
onNavigateToLibraries()
onDismiss()
}
)
SettingsDialogClickerRow(
icon = OxygenIcons.Info,
text = stringResource(R.string.feature_settings_more_about),
onClick = {
onNavigateToAbout()
onDismiss()
}
)
}
} }
@Composable @Composable
@@ -234,7 +270,7 @@ private fun SettingsDialogSectionTitle(text: String) {
} }
@Composable @Composable
private fun SettingsDialogThemeChooserRow( private fun SettingsDialogChooserRow(
text: String, text: String,
selected: Boolean, selected: Boolean,
onClick: () -> Unit onClick: () -> Unit
@@ -259,6 +295,27 @@ private fun SettingsDialogThemeChooserRow(
} }
} }
@Composable
private fun SettingsDialogClickerRow(
icon: ImageVector? = null,
text: String,
onClick: () -> Unit
) {
Row(
modifier = Modifier
.fillMaxSize()
.clickable(
onClick = onClick
)
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(imageVector = icon ?: OxygenIcons.Reorder, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text(text)
}
}
@ThemePreviews @ThemePreviews
@Composable @Composable
private fun SettingsDialogLoadingPreview() { private fun SettingsDialogLoadingPreview() {
@@ -270,7 +327,9 @@ private fun SettingsDialogLoadingPreview() {
onChangeLaunchPageConfig = {}, onChangeLaunchPageConfig = {},
onchangeThemeBrandConfig = {}, onchangeThemeBrandConfig = {},
onChangeDarkThemeConfig = {}, onChangeDarkThemeConfig = {},
onchangeUseDynamicColor = {} onchangeUseDynamicColor = {},
onNavigateToLibraries = {},
onNavigateToAbout = {}
) )
} }
} }
@@ -294,7 +353,9 @@ private fun SettingDialogPreview() {
onChangeLaunchPageConfig = {}, onChangeLaunchPageConfig = {},
onchangeThemeBrandConfig = {}, onchangeThemeBrandConfig = {},
onChangeDarkThemeConfig = {}, onChangeDarkThemeConfig = {},
onchangeUseDynamicColor = {} onchangeUseDynamicColor = {},
onNavigateToLibraries = {},
onNavigateToAbout = {}
) )
} }
} }

View File

@@ -1,3 +1,20 @@
package top.fatweb.oxygen.toolbox.ui.star package top.fatweb.oxygen.toolbox.ui.star
class StarScreen import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
internal fun StarRoute(
modifier: Modifier = Modifier
) {
StarScreen(
modifier = modifier
)
}
@Composable
internal fun StarScreen(
modifier: Modifier = Modifier
) {
}

View File

@@ -22,9 +22,6 @@ import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridS
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -41,7 +38,7 @@ import top.fatweb.oxygen.toolbox.ui.component.scrollbar.rememberDraggableScrolle
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.scrollbarState import top.fatweb.oxygen.toolbox.ui.component.scrollbar.scrollbarState
@Composable @Composable
fun ToolsRoute( internal fun ToolsRoute(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: ToolsScreenViewModel = hiltViewModel() viewModel: ToolsScreenViewModel = hiltViewModel()
) { ) {
@@ -54,7 +51,7 @@ fun ToolsRoute(
} }
@Composable @Composable
fun ToolsScreen( internal fun ToolsScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
toolsScreenUiState: ToolsScreenUiState toolsScreenUiState: ToolsScreenUiState
) { ) {
@@ -67,8 +64,6 @@ fun ToolsScreen(
val state = rememberLazyStaggeredGridState() val state = rememberLazyStaggeredGridState()
val scrollbarState = state.scrollbarState(itemsAvailable = itemsAvailable) val scrollbarState = state.scrollbarState(itemsAvailable = itemsAvailable)
var isExpanded by remember { mutableStateOf(mapOf<String, Boolean>()) }
Box( Box(
modifier.fillMaxSize() modifier.fillMaxSize()
) { ) {

View File

@@ -23,7 +23,7 @@ object ResourcesUtils {
fun getAppVersionName(context: Context): String = fun getAppVersionName(context: Context): String =
try { try {
context.packageManager.getPackageInfo(context.packageName, 0).versionName context.packageManager.getPackageInfo(context.packageName, 0)?.versionName ?: "Unknown"
} catch (e: PackageManager.NameNotFoundException) { } catch (e: PackageManager.NameNotFoundException) {
"Unknown" "Unknown"
} }
@@ -32,8 +32,8 @@ object ResourcesUtils {
fun getAppVersionCode(context: Context): Long = fun getAppVersionCode(context: Context): Long =
try { try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
context.packageManager.getPackageInfo(context.packageName, 0).longVersionCode context.packageManager.getPackageInfo(context.packageName, 0)?.longVersionCode ?: -1
else context.packageManager.getPackageInfo(context.packageName, 0).versionCode.toLong() else context.packageManager.getPackageInfo(context.packageName, 0)?.versionCode?.toLong() ?: -1
} catch (e: PackageManager.NameNotFoundException) { } catch (e: PackageManager.NameNotFoundException) {
-1 -1
} }

View File

@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">OxygenToolbox</string> <string name="app_name">氧工具</string>
<string name="no_connect">⚠️ 无法连接至互联网</string> <string name="app_full_name">氧工具</string>
<string name="app_description">All in One</string>
<string name="core_ok">完成</string>
<string name="core_back">返回</string>
<string name="core_no_connect">⚠️ 无法连接至互联网</string>
<string name="feature_tools_title">工具</string> <string name="feature_tools_title">工具</string>
<string name="feature_star_title">收藏</string> <string name="feature_star_title">收藏</string>
<string name="feature_settings_title">设置</string> <string name="feature_settings_title">设置</string>
@@ -21,7 +25,9 @@
<string name="feature_settings_dynamic_color">动态颜色</string> <string name="feature_settings_dynamic_color">动态颜色</string>
<string name="feature_settings_dynamic_color_enable">启用</string> <string name="feature_settings_dynamic_color_enable">启用</string>
<string name="feature_settings_dynamic_color_disable">禁用</string> <string name="feature_settings_dynamic_color_disable">禁用</string>
<string name="feature_settings_more">更多</string>
<string name="feature_settings_open_source_license">开源许可</string>
<string name="feature_settings_more_about">关于</string>
<string name="feature_settings_top_app_bar_action_icon_description">更多</string> <string name="feature_settings_top_app_bar_action_icon_description">更多</string>
<string name="feature_settings_top_app_bar_navigation_icon_description">搜索</string> <string name="feature_settings_top_app_bar_navigation_icon_description">搜索</string>
<string name="feature_settings_dismiss_dialog_button_text">完成</string>
</resources> </resources>

View File

@@ -1,6 +1,10 @@
<resources> <resources>
<string name="app_name">OxygenToolbox</string> <string name="app_name">Oxygen</string>
<string name="no_connect">⚠️ Unable to connect to the internet</string> <string name="app_full_name">Oxygen Toolbox</string>
<string name="app_description">All in One</string>
<string name="core_ok">OK</string>
<string name="core_back">Back</string>
<string name="core_no_connect">⚠️ Unable to connect to the internet</string>
<string name="feature_tools_title">Tools</string> <string name="feature_tools_title">Tools</string>
<string name="feature_star_title">Star</string> <string name="feature_star_title">Star</string>
<string name="feature_settings_title">Settings</string> <string name="feature_settings_title">Settings</string>
@@ -22,7 +26,9 @@
<string name="feature_settings_dynamic_color">Dynamic Color</string> <string name="feature_settings_dynamic_color">Dynamic Color</string>
<string name="feature_settings_dynamic_color_enable">Enable</string> <string name="feature_settings_dynamic_color_enable">Enable</string>
<string name="feature_settings_dynamic_color_disable">Disable</string> <string name="feature_settings_dynamic_color_disable">Disable</string>
<string name="feature_settings_more">More</string>
<string name="feature_settings_open_source_license">Open Source License</string>
<string name="feature_settings_more_about">About</string>
<string name="feature_settings_top_app_bar_action_icon_description">More</string> <string name="feature_settings_top_app_bar_action_icon_description">More</string>
<string name="feature_settings_top_app_bar_navigation_icon_description">Search</string> <string name="feature_settings_top_app_bar_navigation_icon_description">Search</string>
<string name="feature_settings_dismiss_dialog_button_text">OK</string>
</resources> </resources>