aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-02 21:37:38 +0100
committerDanilo M. <danix@danix.xyz>2026-11-02 21:37:38 +0100
commit815f18752f99fb8cc7f57401eafaef20d9c59ca5 (patch)
tree8f108fdb135647fb513bfedc10a78f1229953a17 /app/src/main
parent0ba7321ce6b94a0046119e62a7ced8badb5baa5f (diff)
downloadHardenedPass-815f18752f99fb8cc7f57401eafaef20d9c59ca5.tar.gz
HardenedPass-815f18752f99fb8cc7f57401eafaef20d9c59ca5.zip
fix(app): keep list work alive across rotation and tidy search focus
- MainActivity handles orientation|screenSize itself so rotation no longer cancels store and git work running in lifecycleScope. - Search-on-start focus moved into SearchField (own FocusRequester), only at the store root, fixing "FocusRequester is not initialized". - refresh() leaves an open folder removed by a pull; used on resume and after git, move, rename and delete. - Zero-count delete uses deleteWithoutFollowingLinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml2
-rw-r--r--app/src/main/java/app/passwordstore/ui/list/ListDestination.kt24
-rw-r--r--app/src/main/java/app/passwordstore/ui/list/ListScreen.kt8
3 files changed, 18 insertions, 16 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5c54c683..4840ca1f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -64,8 +64,10 @@
</intent-filter>
</activity>
+ <!-- ponytail: rotation must not cancel store and git work in lifecycleScope; theme or locale changes still recreate. -->
<activity
android:name=".ui.main.MainActivity"
+ android:configChanges="orientation|screenSize"
android:exported="false"
android:theme="@style/NoActionBarThemeM3"
android:windowSoftInputMode="adjustResize" />
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 3045e43e..40f9ce41 100644
--- a/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt
+++ b/app/src/main/java/app/passwordstore/ui/list/ListDestination.kt
@@ -80,7 +80,6 @@ fun ListDestination(
var deleteCount by rememberSaveable { mutableIntStateOf(0) }
var refreshing by remember { mutableStateOf(false) }
var resumes by remember { mutableIntStateOf(0) }
- val searchFocus = remember { FocusRequester() }
// Declared before the collection below on purpose: effects start in order, so the ViewModel
// already points at this folder when the first rows are built (no flash of the store root).
@@ -92,14 +91,13 @@ fun ListDestination(
val gitOps = remember(resumes) { activity.gitOps() }
val canSync = remember(resumes) { !prefs.getBoolean(PreferenceKeys.DISABLE_SYNC_ACTION, false) }
- LaunchedEffect(Unit) {
- if (prefs.getBoolean(PreferenceKeys.SEARCH_ON_START, false)) searchFocus.requestFocus()
+ fun refresh() {
+ if (path.isNotEmpty() && !dir.isDirectory) onOpenFolder("") else viewModel.forceRefresh()
}
+
// Every return to this folder (back from a child, or from a legacy activity) re-reads it.
LifecycleResumeEffect(Unit) {
- if (activity.checkStore()) {
- if (path.isNotEmpty() && !dir.isDirectory) onOpenFolder("") else viewModel.forceRefresh()
- }
+ if (activity.checkStore()) refresh()
resumes++
onPauseOrDispose {}
}
@@ -115,7 +113,7 @@ fun ListDestination(
selected = emptyList()
activity.lifecycleScope.launch {
activity.moveItems(files, target)
- viewModel.forceRefresh()
+ refresh()
}
}
}
@@ -129,7 +127,7 @@ fun ListDestination(
activity.lifecycleScope.launch {
activity.runGit(op)
refreshing = false
- viewModel.forceRefresh()
+ refresh()
}
}
@@ -176,9 +174,9 @@ fun ListDestination(
val files = selected.map(::File)
val count = countFiles(files)
if (count == 0) {
- files.forEach { it.deleteRecursively() }
+ files.forEach { it.deleteWithoutFollowingLinks() }
selected = emptyList()
- viewModel.forceRefresh()
+ refresh()
} else {
deleteCount = count
dialog = ListDialog.Delete
@@ -189,7 +187,7 @@ fun ListDestination(
activity.pinEntry(File(selected.single()))
selected = emptyList()
},
- searchFocus = searchFocus,
+ focusSearch = path.isEmpty() && prefs.getBoolean(PreferenceKeys.SEARCH_ON_START, false),
)
when (dialog) {
@@ -232,7 +230,7 @@ fun ListDestination(
selected = emptyList()
activity.lifecycleScope.launch {
activity.renameFolder(folder, File(folder.parentFile, name))
- viewModel.forceRefresh()
+ refresh()
}
},
onDismiss = { dialog = ListDialog.None },
@@ -248,7 +246,7 @@ fun ListDestination(
selected = emptyList()
activity.lifecycleScope.launch {
activity.deleteItems(files)
- viewModel.forceRefresh()
+ refresh()
}
},
onDismiss = { dialog = ListDialog.None },
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 5a39cb5c..fdb05ae9 100644
--- a/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt
+++ b/app/src/main/java/app/passwordstore/ui/list/ListScreen.kt
@@ -94,7 +94,7 @@ fun ListScreen(
onRename: () -> Unit,
onPin: () -> Unit,
modifier: Modifier = Modifier,
- searchFocus: FocusRequester = remember { FocusRequester() },
+ focusSearch: Boolean = false,
) {
val selecting = selected.isNotEmpty()
val listState = rememberLazyListState()
@@ -108,7 +108,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, focusSearch)
BreadcrumbBar(
crumbsFor(path),
stringResource(R.string.list_store_root),
@@ -212,8 +212,10 @@ private fun SearchField(
onQueryChange: (String) -> Unit,
onGitOp: (GitOp) -> Unit,
onSettings: () -> Unit,
- focus: FocusRequester,
+ focusSearch: Boolean,
) {
+ val focus = remember { FocusRequester() }
+ LaunchedEffect(Unit) { if (focusSearch) focus.requestFocus() }
val focusManager = LocalFocusManager.current
var menu by remember { mutableStateOf(false) }
SearchBar(