aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main
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
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')
-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
-rw-r--r--app/src/main/res/drawable/ic_open_in_new_24dp.xml12
-rw-r--r--app/src/main/res/values-it/strings.xml1
-rw-r--r--app/src/main/res/values/strings.xml1
10 files changed, 63 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(),
- )
}
}
diff --git a/app/src/main/res/drawable/ic_open_in_new_24dp.xml b/app/src/main/res/drawable/ic_open_in_new_24dp.xml
new file mode 100644
index 00000000..b82ebe62
--- /dev/null
+++ b/app/src/main/res/drawable/ic_open_in_new_24dp.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:autoMirrored="true"
+ android:tint="?android:attr/colorControlNormal"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z" />
+</vector>
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index f6de40bd..07f63cd9 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -393,5 +393,6 @@
<string name="about_license">Licenza</string>
<string name="about_license_text">GNU General Public License v3.0 only. Copyright degli autori di Android Password Store e dei contributori di HardenedPass.</string>
<string name="about_libraries">Licenze open source</string>
+ <string name="about_opens_browser">Si apre nel browser</string>
<string name="about_no_browser">Nessun browser trovato per aprire questo link</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 38ef2cdc..c8782fad 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -427,5 +427,6 @@
<string name="about_license">License</string>
<string name="about_license_text">GNU General Public License v3.0 only. Copyright the Android Password Store authors and HardenedPass contributors.</string>
<string name="about_libraries">Open source licenses</string>
+ <string name="about_opens_browser">Opens in the browser</string>
<string name="about_no_browser">No browser found to open this link</string>
</resources>