diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt index 02567659d..9afd0ec0b 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/root/RootView.kt @@ -18,6 +18,7 @@ import app.omnivore.omnivore.feature.library.SearchViewModel import app.omnivore.omnivore.feature.save.SaveViewModel import app.omnivore.omnivore.feature.settings.SettingsScreen import app.omnivore.omnivore.feature.settings.SettingsViewModel +import app.omnivore.omnivore.feature.settings.about.AboutScreen import app.omnivore.omnivore.feature.web.WebViewScreen import app.omnivore.omnivore.navigation.Routes @@ -91,6 +92,13 @@ fun PrimaryNavigator( ) } + composable(Routes.About.route) { + AboutScreen( + navController = navController, + settingsViewModel = settingsViewModel + ) + } + composable(Routes.Documentation.route) { WebViewScreen(navController = navController, url = "https://docs.omnivore.app") } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/LogoHeader.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/LogoHeader.kt new file mode 100644 index 000000000..e32491e03 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/LogoHeader.kt @@ -0,0 +1,34 @@ +package app.omnivore.omnivore.feature.settings + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import app.omnivore.omnivore.R + +@Composable +fun LogoHeader() { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + painter = painterResource(R.drawable.ic_omnivore), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier + .padding(vertical = 56.dp) + .size(64.dp), + ) + + HorizontalDivider() + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/SettingsScreen.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/SettingsScreen.kt index 2f1714b92..22bc7b891 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/SettingsScreen.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/SettingsScreen.kt @@ -1,7 +1,7 @@ package app.omnivore.omnivore.feature.settings import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -11,7 +11,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -24,13 +23,15 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController -import app.omnivore.omnivore.BuildConfig import app.omnivore.omnivore.R import app.omnivore.omnivore.feature.auth.LoginViewModel +import app.omnivore.omnivore.feature.settings.account.ManageAccountDialog import app.omnivore.omnivore.navigation.Routes @OptIn(ExperimentalMaterial3Api::class) @@ -46,7 +47,8 @@ internal fun SettingsScreen( navigationIcon = { IconButton(onClick = { navController.navigateUp() }) { Icon( - imageVector = Icons.AutoMirrored.Outlined.ArrowBack, contentDescription = null + imageVector = Icons.AutoMirrored.Outlined.ArrowBack, + contentDescription = null ) } @@ -76,90 +78,90 @@ fun SettingsViewContent( val showManageAccountDialog = remember { mutableStateOf(false) } val state = rememberLazyListState() - val version = "Omnivore Version: " + BuildConfig.VERSION_NAME - LazyColumn( - state = state, - contentPadding = paddingValues, - ) { + LazyColumn( + state = state, + contentPadding = paddingValues, + ) { - item { - SettingRow(text = stringResource(R.string.settings_view_setting_row_documentation)) { - navController.navigate(Routes.Documentation.route) - } - } - - item { - SettingRow(text = stringResource(R.string.settings_view_setting_row_feedback)) { - settingsViewModel.presentIntercom() - } - } - - item { - SettingRow(text = stringResource(R.string.settings_view_setting_row_privacy_policy)) { - navController.navigate(Routes.PrivacyPolicy.route) - } - } - - item { - SettingRow(text = stringResource(R.string.settings_view_setting_row_terms_and_conditions)) { - navController.navigate(Routes.TermsAndConditions.route) - } - } - - item { HorizontalDivider() } - - item { - SettingRow(text = stringResource(R.string.settings_view_setting_row_manage_account)) { - showManageAccountDialog.value = true - } - } - - item { - SettingRow( - text = stringResource(R.string.settings_view_setting_row_logout) - ) { - showLogoutDialog.value = true - } - } - - item { - Text( - text = version, fontSize = 12.sp, modifier = Modifier.padding(15.dp) - ) + item { + SettingRow(title = stringResource(R.string.settings_view_setting_row_manage_account)) { + showManageAccountDialog.value = true } } - if (showLogoutDialog.value) { - LogoutDialog { performLogout -> - if (performLogout) { - loginViewModel.logout() - } - showLogoutDialog.value = false + item { + SettingRow( + title = stringResource(R.string.settings_view_setting_row_logout) + ) { + showLogoutDialog.value = true } } - if (showManageAccountDialog.value) { - ManageAccountDialog( - onDismiss = { showManageAccountDialog.value = false }, - settingsViewModel = settingsViewModel - ) + item { + SettingRow(title = stringResource(R.string.about_view_title)) { + navController.navigate(Routes.About.route) + } } + } + + if (showLogoutDialog.value) { + LogoutDialog { performLogout -> + if (performLogout) { + loginViewModel.logout() + } + showLogoutDialog.value = false + } + } + + if (showManageAccountDialog.value) { + ManageAccountDialog( + onDismiss = { showManageAccountDialog.value = false }, + settingsViewModel = settingsViewModel + ) + } } @Composable -private fun SettingRow(text: String, tapAction: () -> Unit) { - Row(horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, +internal fun SettingRow( + title: String, subtitle: String? = null, onClick: (() -> Unit)? +) { + Row( modifier = Modifier - .fillMaxWidth() - .clickable { tapAction() }) { - Text( - text = text, + .clickable(enabled = onClick != null, onClick = { onClick?.invoke() }) + .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically + ) { + Column( modifier = Modifier - .align(Alignment.CenterVertically) - .padding(16.dp) - ) + .weight(1f) + .padding(vertical = SettingsVerticalPadding) + ) { + Text( + modifier = Modifier.padding(horizontal = SettingsHorizontalPadding), + text = title, + overflow = TextOverflow.Ellipsis, + maxLines = 2, + style = MaterialTheme.typography.titleLarge, + fontSize = SettingsTitleFontSize, + ) + if (!subtitle.isNullOrBlank()) { + Text( + text = subtitle, + modifier = Modifier + .padding(horizontal = SettingsHorizontalPadding) + .alpha(SettingsSecondaryItemAlpha), + style = MaterialTheme.typography.bodySmall, + maxLines = 10, + ) + } + } } } + +internal val SettingsHorizontalPadding = 16.dp +internal val SettingsVerticalPadding = 16.dp +internal const val SettingsSecondaryItemAlpha = .78f +internal val SettingsTitleFontSize = 16.sp + +internal const val RELEASE_URL = "https://github.com/omnivore-app/omnivore/releases" diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/about/AboutScreen.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/about/AboutScreen.kt new file mode 100644 index 000000000..9e0b1220c --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/about/AboutScreen.kt @@ -0,0 +1,111 @@ +package app.omnivore.omnivore.feature.settings.about + +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavHostController +import app.omnivore.omnivore.BuildConfig +import app.omnivore.omnivore.R +import app.omnivore.omnivore.feature.settings.LogoHeader +import app.omnivore.omnivore.feature.settings.RELEASE_URL +import app.omnivore.omnivore.feature.settings.SettingRow +import app.omnivore.omnivore.feature.settings.SettingsViewModel +import app.omnivore.omnivore.navigation.Routes + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun AboutScreen( + navController: NavHostController, + settingsViewModel: SettingsViewModel +) { + + val uriHandler = LocalUriHandler.current + + Scaffold( + topBar = { + TopAppBar( + title = { Text(stringResource(R.string.about_view_title)) }, + navigationIcon = { + IconButton(onClick = { navController.navigateUp() }) { + Icon( + imageVector = Icons.AutoMirrored.Outlined.ArrowBack, contentDescription = null + ) + } + + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.background + ), + ) + }, + ) { contentPadding -> + LazyColumn( + contentPadding = contentPadding, + ) { + item { + LogoHeader() + } + + item { + SettingRow( + title = stringResource(R.string.about_view_row_version), + subtitle = getVersionName(), + onClick = { }, + ) + } + + item { + SettingRow( + title = stringResource(R.string.about_view_row_whats_new), + onClick = { uriHandler.openUri(RELEASE_URL) }, + ) + } + + item { + SettingRow(title = stringResource(R.string.settings_view_setting_row_documentation)) { + navController.navigate(Routes.Documentation.route) + } + } + + item { + SettingRow(title = stringResource(R.string.settings_view_setting_row_feedback)) { + settingsViewModel.presentIntercom() + } + } + + item { + SettingRow(title = stringResource(R.string.settings_view_setting_row_privacy_policy)) { + navController.navigate(Routes.PrivacyPolicy.route) + } + } + + item { + SettingRow(title = stringResource(R.string.settings_view_setting_row_terms_and_conditions)) { + navController.navigate(Routes.TermsAndConditions.route) + } + } + } + } +} + +fun getVersionName(): String { + return when { + BuildConfig.DEBUG -> { + "Debug ${BuildConfig.VERSION_NAME}" + } + else -> { + "Stable ${BuildConfig.VERSION_NAME}" + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/ManageAccount.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/account/AccountScreen.kt similarity index 95% rename from android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/ManageAccount.kt rename to android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/account/AccountScreen.kt index 2d9da4b58..57d8cde41 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/ManageAccount.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/settings/account/AccountScreen.kt @@ -1,4 +1,4 @@ -package app.omnivore.omnivore.feature.settings +package app.omnivore.omnivore.feature.settings.account import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -24,6 +24,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import app.omnivore.omnivore.R +import app.omnivore.omnivore.feature.settings.SettingsViewModel @Composable fun ManageAccountDialog(onDismiss: () -> Unit, settingsViewModel: SettingsViewModel) { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/navigation/Routes.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/navigation/Routes.kt index 62f1a780b..e10ee6e94 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/navigation/Routes.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/navigation/Routes.kt @@ -3,6 +3,7 @@ package app.omnivore.omnivore.navigation sealed class Routes(val route: String) { object Library : Routes("Library") object Settings : Routes("Settings") + object About : Routes("About") object Search : Routes("Search") object Documentation : Routes("Documentation") object PrivacyPolicy : Routes("PrivacyPolicy") diff --git a/android/Omnivore/app/src/main/res/drawable/ic_omnivore.xml b/android/Omnivore/app/src/main/res/drawable/ic_omnivore.xml new file mode 100644 index 000000000..8608e8300 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/ic_omnivore.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/Omnivore/app/src/main/res/values/strings.xml b/android/Omnivore/app/src/main/res/values/strings.xml index d1cce247c..d737b53fd 100644 --- a/android/Omnivore/app/src/main/res/values/strings.xml +++ b/android/Omnivore/app/src/main/res/values/strings.xml @@ -212,6 +212,11 @@ Manage Account Logout + + About + Version + What\'s new + Inbox Non-Feed Items