summaryrefslogtreecommitdiffstats
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/app/passwordstore/ui/settings/SettingsModel.kt79
-rw-r--r--app/src/main/java/app/passwordstore/util/settings/GitSettings.kt2
-rw-r--r--app/src/main/java/app/passwordstore/util/settings/Migrations.kt19
-rw-r--r--app/src/main/java/app/passwordstore/util/settings/PasswordSortOrder.kt17
-rw-r--r--app/src/main/java/app/passwordstore/util/viewmodel/SearchableRepositoryViewModel.kt7
5 files changed, 106 insertions, 18 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/settings/SettingsModel.kt b/app/src/main/java/app/passwordstore/ui/settings/SettingsModel.kt
new file mode 100644
index 00000000..eca6770c
--- /dev/null
+++ b/app/src/main/java/app/passwordstore/ui/settings/SettingsModel.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package app.passwordstore.ui.settings
+
+import app.passwordstore.util.extensions.hash
+import app.passwordstore.util.extensions.time
+import app.passwordstore.util.git.GitCommit
+import java.io.IOException
+import logcat.LogPriority.ERROR
+import logcat.asLog
+import logcat.logcat
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.api.errors.GitAPIException
+import org.eclipse.jgit.api.errors.JGitInternalException
+import org.eclipse.jgit.lib.Constants
+import org.eclipse.jgit.lib.Repository
+import org.eclipse.jgit.lib.RepositoryState
+
+private const val TAG = "SettingsModel"
+
+/**
+ * The proxy port typed as [text]: -1 when empty (no port, as stored before any was set), null when
+ * it is not a port number from 1 to 65535.
+ */
+fun proxyPort(text: String): Int? {
+ val trimmed = text.trim()
+ if (trimmed.isEmpty()) return -1
+ return trimmed.toIntOrNull()?.takeIf { it in 1..65535 }
+}
+
+/** Where HEAD points, as the git config screen reports it. */
+sealed interface HeadStatus {
+ data class Branch(val name: String) : HeadStatus
+
+ data class Detached(val hash: String) : HeadStatus
+
+ data object Missing : HeadStatus
+}
+
+/** [repo]'s HEAD: a branch (also one without commits yet), a detached commit, or missing. */
+fun headStatus(repo: Repository): HeadStatus =
+ try {
+ val head = repo.findRef(Constants.HEAD)
+ when {
+ head == null -> HeadStatus.Missing
+ head.isSymbolic -> HeadStatus.Branch(Repository.shortenRefName(head.target.name))
+ else ->
+ head.objectId?.let { HeadStatus.Detached(it.abbreviate(8).name()) } ?: HeadStatus.Missing
+ }
+ } catch (e: IOException) {
+ logcat(TAG, ERROR) { e.asLog() }
+ HeadStatus.Missing
+ }
+
+/** Whether a rebase or a merge is in progress, so "Abort rebase" has something to abort. */
+fun needsAbort(repo: Repository): Boolean =
+ repo.repositoryState.let { it.isRebasing || it == RepositoryState.MERGING }
+
+/**
+ * The commits reachable from HEAD, newest first; empty without a repository or a commit. Blocking:
+ * call it off the main thread.
+ */
+// ponytail: the whole log at once, as the old screen did (tested there with 1000 commits); page it
+// if a store's history ever makes this slow.
+fun gitLog(repo: Repository?): List<GitCommit> {
+ if (repo == null) return emptyList()
+ return try {
+ Git(repo).log().call().map { GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time) }
+ } catch (e: GitAPIException) {
+ logcat(TAG, ERROR) { e.asLog() }
+ emptyList()
+ } catch (e: JGitInternalException) {
+ logcat(TAG, ERROR) { e.asLog() }
+ emptyList()
+ }
+}
diff --git a/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt b/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
index d315daf3..004028c4 100644
--- a/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
+++ b/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
@@ -108,7 +108,7 @@ constructor(
}
var proxyUsername
- get() = settings.getString(PreferenceKeys.PROXY_USERNAME)
+ get() = proxySettings.getString(PreferenceKeys.PROXY_USERNAME)
set(value) {
proxySettings.edit { putString(PreferenceKeys.PROXY_USERNAME, value) }
}
diff --git a/app/src/main/java/app/passwordstore/util/settings/Migrations.kt b/app/src/main/java/app/passwordstore/util/settings/Migrations.kt
index 06075655..82847f02 100644
--- a/app/src/main/java/app/passwordstore/util/settings/Migrations.kt
+++ b/app/src/main/java/app/passwordstore/util/settings/Migrations.kt
@@ -32,6 +32,8 @@ fun runMigrations(filesDirPath: String, sharedPrefs: SharedPreferences, gitSetti
migrateToDiceware(sharedPrefs)
removeExternalStorageProperties(sharedPrefs)
removeCurrentBranchValue(sharedPrefs)
+ migrateRemovedSortOrders(sharedPrefs)
+ removeOpenKeystoreKeyId(sharedPrefs)
}
/**
@@ -194,3 +196,20 @@ private fun removeExternalStorageProperties(prefs: SharedPreferences) {
}
}
}
+
+/**
+ * "Files first" and "type independent" were removed with the Compose list, which shows folders and
+ * entries in separate groups: a stored one becomes folders first, the list's default.
+ */
+private fun migrateRemovedSortOrders(sharedPrefs: SharedPreferences) {
+ val stored = sharedPrefs.getString(PreferenceKeys.SORT_ORDER) ?: return
+ if (stored != "FILE_FIRST" && stored != "INDEPENDENT") return
+ logcat(TAG, INFO) { "Replacing the removed sort order $stored" }
+ sharedPrefs.edit { putString(PreferenceKeys.SORT_ORDER, PasswordSortOrder.FOLDER_FIRST.name) }
+}
+
+/** OpenKeychain SSH support is gone and nothing reads the remembered key ID any more. */
+private fun removeOpenKeystoreKeyId(sharedPrefs: SharedPreferences) {
+ if (!sharedPrefs.contains(PreferenceKeys.SSH_OPENKEYSTORE_KEYID)) return
+ sharedPrefs.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
+}
diff --git a/app/src/main/java/app/passwordstore/util/settings/PasswordSortOrder.kt b/app/src/main/java/app/passwordstore/util/settings/PasswordSortOrder.kt
index 224d9d66..921e9bc4 100644
--- a/app/src/main/java/app/passwordstore/util/settings/PasswordSortOrder.kt
+++ b/app/src/main/java/app/passwordstore/util/settings/PasswordSortOrder.kt
@@ -18,11 +18,6 @@ enum class PasswordSortOrder(val comparator: java.util.Comparator<PasswordItem>)
(p1.type + p1.name).compareTo(p2.type + p2.name, ignoreCase = true)
}
),
- INDEPENDENT(
- Comparator { p1: PasswordItem, p2: PasswordItem ->
- p1.name.compareTo(p2.name, ignoreCase = true)
- }
- ),
RECENTLY_USED(
Comparator { p1: PasswordItem, p2: PasswordItem ->
val recentHistory =
@@ -36,18 +31,18 @@ enum class PasswordSortOrder(val comparator: java.util.Comparator<PasswordItem>)
else -> p1.name.compareTo(p2.name, ignoreCase = true)
}
}
- ),
- FILE_FIRST(
- Comparator { p1: PasswordItem, p2: PasswordItem ->
- (p2.type + p1.name).compareTo(p1.type + p2.name, ignoreCase = true)
- }
);
companion object {
+ /**
+ * The stored sort order; anything else (the removed "files first" and "type independent", a
+ * value from another version) reads as [FOLDER_FIRST].
+ */
@JvmStatic
fun getSortOrder(settings: SharedPreferences): PasswordSortOrder {
- return valueOf(settings.getString(PreferenceKeys.SORT_ORDER) ?: FOLDER_FIRST.name)
+ val stored = settings.getString(PreferenceKeys.SORT_ORDER)
+ return entries.firstOrNull { it.name == stored } ?: FOLDER_FIRST
}
}
}
diff --git a/app/src/main/java/app/passwordstore/util/viewmodel/SearchableRepositoryViewModel.kt b/app/src/main/java/app/passwordstore/util/viewmodel/SearchableRepositoryViewModel.kt
index ca570dc4..f8cbf1e4 100644
--- a/app/src/main/java/app/passwordstore/util/viewmodel/SearchableRepositoryViewModel.kt
+++ b/app/src/main/java/app/passwordstore/util/viewmodel/SearchableRepositoryViewModel.kt
@@ -71,12 +71,7 @@ private fun PasswordItem.Companion.makeComparator(
directoryStructure: DirectoryStructure,
): Comparator<PasswordItem> {
return when (typeSortOrder) {
- PasswordSortOrder.FOLDER_FIRST -> compareBy { it.type }
- // In order to let INDEPENDENT not distinguish between items based on their type, we
- // simply
- // declare them all equal at this stage.
- PasswordSortOrder.INDEPENDENT -> Comparator { _, _ -> 0 }
- PasswordSortOrder.FILE_FIRST -> compareByDescending { it.type }
+ PasswordSortOrder.FOLDER_FIRST -> compareBy<PasswordItem> { it.type }
PasswordSortOrder.RECENTLY_USED -> PasswordSortOrder.RECENTLY_USED.comparator
}
.then(