summaryrefslogtreecommitdiffstats
path: root/app/src/main/java
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-05 16:42:10 +0100
committerDanilo M. <danix@danix.xyz>2026-11-05 16:42:10 +0100
commit9bf0026156e4124b667cf0ed66bf150c6c8aed36 (patch)
tree27b92651ff2657ff9d66ddc751fef0cfb0b2ea80 /app/src/main/java
parent0e06d46740009d0c39564ece1e5b09a0403d2f6f (diff)
downloadHardenedPass-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')
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/CryptoExtensions.kt10
-rw-r--r--app/src/main/java/app/passwordstore/ui/list/ListDestination.kt2
-rw-r--r--app/src/main/java/app/passwordstore/ui/list/ListScreen.kt11
-rw-r--r--app/src/main/java/app/passwordstore/ui/main/MainActivity.kt2
-rw-r--r--app/src/main/java/app/passwordstore/ui/settings/AboutScreen.kt35
-rw-r--r--app/src/main/java/app/passwordstore/ui/settings/SettingsGraph.kt1
-rw-r--r--app/src/main/java/app/passwordstore/ui/settings/SettingsScreen.kt8
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(),
- )
}
}