From 1d8b44dd387c3b78f97e1510bb5c3c719c7d4015 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 3 Nov 2026 18:48:08 +0100 Subject: feat(app): run Settings in MainActivity The list and the welcome screen open the Compose settings; their rows open the git server, SSH key, key generation, PGP keys, proxy and git config screens within the graph. Deleting the repository returns to the welcome screen. Co-Authored-By: Claude Opus 5.5 --- .../app/passwordstore/ui/list/ListDestination.kt | 6 +- .../java/app/passwordstore/ui/main/MainActivity.kt | 12 +-- .../app/passwordstore/ui/settings/SettingsGraph.kt | 87 ++++++++++++++++++++++ .../java/app/passwordstore/ui/setup/SetupGraph.kt | 3 +- 4 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt (limited to 'app/src/main/java') diff --git a/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt b/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt index a256fb1b..adae3649 100644 --- a/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt +++ b/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt @@ -60,7 +60,8 @@ private enum class ListDialog { * The list at [path] (relative to the store root): wires [ListScreen] to the [viewModel], the * folder picker, the legacy activities and the store operations. [onOpenFolder] takes a path * relative to the root, [onOpenEntry] an entry file; [onNewEntry] opens the editor in this folder, - * [onClone] the git server screen for a clone; [onNoStore] runs when the store is gone. + * [onClone] the git server screen for a clone, [onSettings] the settings; [onNoStore] runs when the + * store is gone. */ @Composable fun ListDestination( @@ -70,6 +71,7 @@ fun ListDestination( onOpenEntry: (File) -> Unit, onNewEntry: () -> Unit, onClone: () -> Unit, + onSettings: () -> Unit, onNoStore: () -> Unit, modifier: Modifier = Modifier, viewModel: SearchableRepositoryViewModel = hiltViewModel(), @@ -151,7 +153,7 @@ fun ListDestination( } }, onGitOp = { op -> ifInitialized { runGit(op) } }, - onSettings = activity::openSettings, + onSettings = onSettings, onNew = { dialog = ListDialog.Create }, onMove = { dialog = ListDialog.Move }, onDelete = { diff --git a/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt b/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt index 5cc2da86..4d618cca 100644 --- a/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt @@ -30,12 +30,12 @@ import app.passwordstore.ui.entry.EntryViewModel import app.passwordstore.ui.git.base.BaseGitActivity import app.passwordstore.ui.list.ListDestination import app.passwordstore.ui.list.folderMoves -import app.passwordstore.ui.settings.SettingsActivity +import app.passwordstore.ui.settings.SettingsRoute +import app.passwordstore.ui.settings.settingsGraph import app.passwordstore.ui.setup.GitServerRoute import app.passwordstore.ui.setup.SetupStart import app.passwordstore.ui.setup.WelcomeRoute import app.passwordstore.ui.setup.setupGraph -import app.passwordstore.util.extensions.launchActivity import app.passwordstore.util.extensions.sharedPrefs import app.passwordstore.util.settings.AuthMode import app.passwordstore.util.settings.PreferenceKeys @@ -127,6 +127,9 @@ class MainActivity : BaseGitActivity() { if (nav.currentBackStackEntry?.id == entry.id) nav.navigate(GitServerRoute(clone = true)) }, + onSettings = { + if (nav.currentBackStackEntry?.id == entry.id) nav.navigate(SettingsRoute) + }, onNoStore = { // The store is gone (deleted from Settings): setup starts over. if (nav.currentBackStackEntry?.id == entry.id) @@ -195,6 +198,7 @@ class MainActivity : BaseGitActivity() { ) } setupGraph(this@MainActivity, nav) + settingsGraph(this@MainActivity, nav) } } } @@ -246,10 +250,6 @@ class MainActivity : BaseGitActivity() { shortcutHandler.addPinnedShortcut(item, item.createAuthEnabledIntent(this)) } - fun openSettings() { - launchActivity(SettingsActivity::class.java) - } - private fun entryItem(file: File) = PasswordItem.newPassword(file.name, file, PasswordRepository.getRepositoryDirectory()) diff --git a/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt b/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt new file mode 100644 index 00000000..ae4e277b --- /dev/null +++ b/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2026 Danilo M. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package app.passwordstore.ui.settings + +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.toRoute +import app.passwordstore.ui.main.MainActivity +import app.passwordstore.ui.setup.GitServerRoute +import app.passwordstore.ui.setup.PgpKeysRoute +import app.passwordstore.ui.setup.SshKeyGenRoute +import app.passwordstore.ui.setup.SshKeyRoute +import app.passwordstore.ui.setup.WelcomeRoute +import kotlinx.serialization.Serializable + +/** The settings categories. */ +@Serializable data object SettingsRoute + +/** One settings category. */ +@Serializable data class SettingsSectionRoute(val section: SettingsSection) + +/** Author name and email, and the repository utilities. */ +@Serializable data object GitConfigRoute + +/** The store's commit log. */ +@Serializable data object GitLogRoute + +/** HTTP(S) proxy settings. */ +@Serializable data object ProxyRoute + +/** The settings destinations, and where their rows lead. */ +fun NavGraphBuilder.settingsGraph(activity: MainActivity, nav: NavHostController) { + fun onTop(entry: NavBackStackEntry) = nav.currentBackStackEntry?.id == entry.id + + fun close(entry: NavBackStackEntry) { + if (onTop(entry)) nav.popBackStack() + } + + composable { entry -> + SettingsScreen( + onSection = { if (onTop(entry)) nav.navigate(SettingsSectionRoute(it)) }, + onBack = { close(entry) }, + ) + } + composable { entry -> + SettingsSectionDestination( + activity = activity, + section = entry.toRoute().section, + onBack = { close(entry) }, + onOpen = { action -> + if (onTop(entry)) + when (action) { + SettingsAction.GitServer -> nav.navigate(GitServerRoute(clone = false)) + SettingsAction.Proxy -> nav.navigate(ProxyRoute) + SettingsAction.GitConfig -> nav.navigate(GitConfigRoute) + SettingsAction.SshKey -> nav.navigate(SshKeyRoute) + SettingsAction.SshKeyGen -> nav.navigate(SshKeyGenRoute) + SettingsAction.KeyManager -> nav.navigate(PgpKeysRoute()) + // Handled by the destination itself. + SettingsAction.ClearSecret, + SettingsAction.DeleteRepository, + SettingsAction.Export -> Unit + } + }, + onDeleted = { + // No store any more: setup starts over, as after a deletion from the list's side. + if (onTop(entry)) nav.navigate(WelcomeRoute) { popUpTo(nav.graph.id) { inclusive = true } } + }, + ) + } + composable { entry -> + GitConfigDestination( + activity = activity, + onClose = { close(entry) }, + onLog = { if (onTop(entry)) nav.navigate(GitLogRoute) }, + ) + } + composable { entry -> GitLogDestination(onClose = { close(entry) }) } + composable { entry -> + ProxyDestination(activity = activity, onClose = { close(entry) }) + } +} diff --git a/app/src/main/java/app/passwordstore/ui/setup/SetupGraph.kt b/app/src/main/java/app/passwordstore/ui/setup/SetupGraph.kt index ffa47511..c2c2a2ac 100644 --- a/app/src/main/java/app/passwordstore/ui/setup/SetupGraph.kt +++ b/app/src/main/java/app/passwordstore/ui/setup/SetupGraph.kt @@ -13,6 +13,7 @@ import androidx.navigation.compose.composable import androidx.navigation.toRoute import app.passwordstore.ui.main.ListRoute import app.passwordstore.ui.main.MainActivity +import app.passwordstore.ui.settings.SettingsRoute import kotlinx.serialization.Serializable /** The first screen without a store. */ @@ -63,7 +64,7 @@ fun NavGraphBuilder.setupGraph(activity: MainActivity, nav: NavHostController) { WelcomeScreen( onClone = { if (onTop(entry)) nav.navigate(GitServerRoute(clone = true)) }, onCreate = { if (onTop(entry)) nav.navigate(PgpKeysRoute(KeysMode.Choose)) }, - onSettings = activity::openSettings, + onSettings = { if (onTop(entry)) nav.navigate(SettingsRoute) }, ) } composable { entry -> -- cgit v1.2.3