diff options
| author | Danilo M. <danix@danix.xyz> | 2026-11-05 16:42:10 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-11-05 16:42:10 +0100 |
| commit | 9bf0026156e4124b667cf0ed66bf150c6c8aed36 (patch) | |
| tree | 27b92651ff2657ff9d66ddc751fef0cfb0b2ea80 /app/src/main/java | |
| parent | 0e06d46740009d0c39564ece1e5b09a0403d2f6f (diff) | |
| download | HardenedPass-9bf0026156e4124b667cf0ed66bf150c6c8aed36.tar.gz HardenedPass-9bf0026156e4124b667cf0ed66bf150c6c8aed36.zip | |
feat(app): move About to the list's menu and mark its links
The version and certificate are no secrets, so they are copied without the
sensitive flag that hid them in the clipboard preview. Rows that leave for the
browser now show an icon saying so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'app/src/main/java')
7 files changed, 49 insertions, 20 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt b/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt index 4a6813f7..626ec130 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt @@ -48,12 +48,14 @@ fun getLongName(fullPath: String, repositoryPath: String, basename: String): Str } } -/** Copies provided [text] to the clipboard, flagged sensitive. */ -fun FragmentActivity.copyTextToClipboard(text: String?) { +/** Copies provided [text] to the clipboard; [sensitive] text is hidden from its preview. */ +fun FragmentActivity.copyTextToClipboard(text: String?, sensitive: Boolean = true) { val clipboard = clipboard ?: return val clip = ClipData.newPlainText("pgp_handler_result_pm", text) - clip.description.extras = - PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } + if (sensitive) { + clip.description.extras = + PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } + } clipboard.setPrimaryClip(clip) } 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 54a7e66c..97092716 100644 --- a/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt +++ b/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt @@ -73,6 +73,7 @@ fun ListDestination( onNewEntry: () -> Unit, onClone: () -> Unit, onSettings: () -> Unit, + onAbout: () -> Unit, onNoStore: () -> Unit, modifier: Modifier = Modifier, viewModel: SearchableRepositoryViewModel = hiltViewModel(), @@ -159,6 +160,7 @@ fun ListDestination( }, onGitOp = { op -> ifInitialized { runGit(op) } }, onSettings = onSettings, + onAbout = onAbout, onNew = { dialog = ListDialog.Create }, onMove = { dialog = ListDialog.Move }, onDelete = { diff --git a/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt b/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt index 1b359d5b..593c744b 100644 --- a/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt +++ b/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt @@ -91,6 +91,7 @@ fun ListScreen( onSync: () -> Unit, onGitOp: (GitOp) -> Unit, onSettings: () -> Unit, + onAbout: () -> Unit, onNew: () -> Unit, onMove: () -> Unit, onDelete: () -> Unit, @@ -133,7 +134,7 @@ fun ListScreen( SelectionBar(rows, selected, onClearSelection, onMove, onDelete, onRename, onPin) } else { Column(horizontalAlignment = Alignment.CenterHorizontally) { - SearchField(query, gitOps, onQueryChange, onGitOp, onSettings, searchFocus) + SearchField(query, gitOps, onQueryChange, onGitOp, onSettings, onAbout, searchFocus) BreadcrumbBar( crumbsFor(path), stringResource(R.string.list_store_root), @@ -238,6 +239,7 @@ private fun SearchField( onQueryChange: (String) -> Unit, onGitOp: (GitOp) -> Unit, onSettings: () -> Unit, + onAbout: () -> Unit, focus: FocusRequester, ) { val focusManager = LocalFocusManager.current @@ -282,6 +284,13 @@ private fun SearchField( onSettings() }, ) + DropdownMenuItem( + text = { Text(stringResource(R.string.about)) }, + onClick = { + menu = false + onAbout() + }, + ) } } } 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 f3d7d3a0..5037e646 100644 --- a/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/main/MainActivity.kt @@ -30,6 +30,7 @@ import app.passwordstore.ui.git.base.BaseGitActivity import app.passwordstore.ui.list.ListDestination import app.passwordstore.ui.list.folderMoves import app.passwordstore.ui.prompts.PromptHost +import app.passwordstore.ui.settings.AboutRoute import app.passwordstore.ui.settings.SettingsRoute import app.passwordstore.ui.settings.settingsGraph import app.passwordstore.ui.setup.GitServerRoute @@ -130,6 +131,7 @@ class MainActivity : BaseGitActivity() { onSettings = { if (nav.currentBackStackEntry?.id == entry.id) nav.navigate(SettingsRoute) }, + onAbout = { if (nav.currentBackStackEntry?.id == entry.id) nav.navigate(AboutRoute) }, onNoStore = { // The store is gone (deleted from Settings): setup starts over. if (nav.currentBackStackEntry?.id == entry.id) diff --git a/app/src/main/java/app/passwordstore/ui/settings/AboutScreen.kt b/app/src/main/java/app/passwordstore/ui/settings/AboutScreen.kt index fd47c119..4a366390 100644 --- a/app/src/main/java/app/passwordstore/ui/settings/AboutScreen.kt +++ b/app/src/main/java/app/passwordstore/ui/settings/AboutScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -110,7 +111,7 @@ fun AboutDestination( versionLine(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.GIT_COMMIT), changelog = changelogUrl(BuildConfig.VERSION_NAME), fingerprint = fingerprint, - onCopy = { activity.copyTextToClipboard(it) }, + onCopy = { activity.copyTextToClipboard(it, sensitive = false) }, onOpen = { url -> try { activity.startActivity(Intent(Intent.ACTION_VIEW, url.toUri())) @@ -147,10 +148,10 @@ private fun AboutScreen( Text(stringResource(R.string.about_summary), textAlign = TextAlign.Center) } AboutRow(stringResource(R.string.about_version), version) { onCopy(version) } - AboutRow(stringResource(R.string.about_docs)) { onOpen(DOCUMENTATION) } - AboutRow(stringResource(R.string.about_changelog)) { onOpen(changelog) } - AboutRow(stringResource(R.string.about_source)) { onOpen(REPOSITORY) } - AboutRow(stringResource(R.string.about_issues)) { onOpen("$REPOSITORY/issues") } + LinkRow(stringResource(R.string.about_docs)) { onOpen(DOCUMENTATION) } + LinkRow(stringResource(R.string.about_changelog)) { onOpen(changelog) } + LinkRow(stringResource(R.string.about_source)) { onOpen(REPOSITORY) } + LinkRow(stringResource(R.string.about_issues)) { onOpen("$REPOSITORY/issues") } // White in both themes: the logo's dark outline disappears on a dark background, and Ko-fi // asks that the logo itself stays as it is. Button( @@ -198,11 +199,33 @@ private fun AboutScreen( } @Composable -private fun AboutRow(title: String, summary: String? = null, onClick: () -> Unit) { +private fun AboutRow( + title: String, + summary: String? = null, + trailing: (@Composable () -> Unit)? = null, + onClick: () -> Unit, +) { ListItem( headlineContent = { Text(title) }, supportingContent = summary?.let { { Text(it) } }, + trailingContent = trailing, modifier = Modifier.clickable(role = Role.Button, onClick = onClick), colors = rowColors(), ) } + +/** A row that leaves for the browser, and says so. */ +@Composable +private fun LinkRow(title: String, summary: String? = null, onClick: () -> Unit) { + AboutRow( + title = title, + summary = summary, + trailing = { + Icon( + painterResource(R.drawable.ic_open_in_new_24dp), + contentDescription = stringResource(R.string.about_opens_browser), + ) + }, + onClick = onClick, + ) +} diff --git a/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt b/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt index 44ae06d8..ba4d158c 100644 --- a/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt +++ b/app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt @@ -47,7 +47,6 @@ fun NavGraphBuilder.settingsGraph(activity: MainActivity, nav: NavHostController composable<SettingsRoute> { entry -> SettingsScreen( onSection = { if (onTop(entry)) nav.navigate(SettingsSectionRoute(it)) }, - onAbout = { if (onTop(entry)) nav.navigate(AboutRoute) }, onBack = { close(entry) }, ) } diff --git a/app/src/main/java/app/passwordstore/ui/settings/SettingsScreen.kt b/app/src/main/java/app/passwordstore/ui/settings/SettingsScreen.kt index 14895017..ed78608f 100644 --- a/app/src/main/java/app/passwordstore/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/app/passwordstore/ui/settings/SettingsScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Info import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -98,7 +97,6 @@ internal fun SettingsScaffold( @Composable fun SettingsScreen( onSection: (SettingsSection) -> Unit, - onAbout: () -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier, ) { @@ -111,12 +109,6 @@ fun SettingsScreen( colors = rowColors(), ) } - ListItem( - headlineContent = { Text(stringResource(R.string.about)) }, - modifier = Modifier.clickable(role = Role.Button, onClick = onAbout), - leadingContent = { Icon(Icons.Filled.Info, contentDescription = null) }, - colors = rowColors(), - ) } } |
