git.iko.soy/opencode-android
on 2794fda help sign in
90 lines 4.1 kB history raw
1package soy.iko.opencode.data.repo
3import android.content.Context
4import androidx.datastore.preferences.core.booleanPreferencesKey
5import androidx.datastore.preferences.core.edit
6import androidx.datastore.preferences.core.stringPreferencesKey
7import androidx.datastore.preferences.preferencesDataStore
8import kotlinx.coroutines.flow.Flow
9import kotlinx.coroutines.flow.flowOf
10import kotlinx.coroutines.flow.map
12private val Context.fileBrowserPrefsDataStore by preferencesDataStore(name = "file_browser_prefs")
14/** Sort axis for the file-browser directory listing. Name is always available; Size/Modified
15 * depend on the server emitting size/mtime (otherwise they sort nulls to the bottom). */
16enum class FileSortKey { NAME, SIZE, MODIFIED }
18/**
19 * Persisted file-browser display prefs (folders-first, show-hidden, sort key + direction,
20 * changed-only filter) so a user who prefers size-sort or hidden-files-visible keeps it
21 * across restarts, not just rotation.
22 *
23 * `open` with a `protected` no-arg constructor so tests can subclass and override the flows
24 * without a real DataStore (mirrors the other stores). The flow accessors are getters (not
25 * eager initializers) and null-guard the context so the test constructor never touches disk.
26 */
27@Suppress("TooManyFunctions")
28open class FileBrowserPrefs private constructor(
29 private val appContext: Context?,
30 @Suppress("unused") private val testMode: Boolean,
31) {
32 constructor(context: Context) : this(context.applicationContext, false)
33 protected constructor() : this(null, true)
35 private val foldersFirstKey = booleanPreferencesKey("folders_first")
36 private val showHiddenKey = booleanPreferencesKey("show_hidden")
37 private val sortKeyPref = stringPreferencesKey("sort_key")
38 private val sortDescKey = booleanPreferencesKey("sort_desc")
39 private val changedOnlyKey = booleanPreferencesKey("changed_only")
41 // Folders-first is the most useful default; the toggle flips between folders-first name
42 // sort and the server's raw order.
43 open val foldersFirst: Flow<Boolean>
44 get() = appContext?.fileBrowserPrefsDataStore?.data?.map { it[foldersFirstKey] ?: true }
45 ?: flowOf(true)
47 // Default off so the listing isn't cluttered with dotfiles; the user reveals .env / .git
48 // / .opencode on demand.
49 open val showHidden: Flow<Boolean>
50 get() = appContext?.fileBrowserPrefsDataStore?.data?.map { it[showHiddenKey] ?: false }
51 ?: flowOf(false)
53 // Stored as the enum name; an unknown value falls back to NAME (forward-compatible with a
54 // future rename/removal of an enum entry).
55 open val sortKey: Flow<FileSortKey>
56 get() = appContext?.fileBrowserPrefsDataStore?.data?.map { prefs ->
57 runCatching { FileSortKey.valueOf(prefs[sortKeyPref] ?: FileSortKey.NAME.name) }
58 .getOrDefault(FileSortKey.NAME)
59 } ?: flowOf(FileSortKey.NAME)
61 open val sortDesc: Flow<Boolean>
62 get() = appContext?.fileBrowserPrefsDataStore?.data?.map { it[sortDescKey] ?: false }
63 ?: flowOf(false)
65 // Default off: the changed-only filter narrows the listing to git-tracked changes, which is
66 // useful when reviewing a diff but not the default browsing view.
67 open val changedOnly: Flow<Boolean>
68 get() = appContext?.fileBrowserPrefsDataStore?.data?.map { it[changedOnlyKey] ?: false }
69 ?: flowOf(false)
71 open suspend fun setFoldersFirst(value: Boolean) {
72 appContext?.fileBrowserPrefsDataStore?.edit { it[foldersFirstKey] = value }
73 }
75 open suspend fun setShowHidden(value: Boolean) {
76 appContext?.fileBrowserPrefsDataStore?.edit { it[showHiddenKey] = value }
77 }
79 open suspend fun setSortKey(key: FileSortKey) {
80 appContext?.fileBrowserPrefsDataStore?.edit { it[sortKeyPref] = key.name }
81 }
83 open suspend fun setSortDesc(value: Boolean) {
84 appContext?.fileBrowserPrefsDataStore?.edit { it[sortDescKey] = value }
85 }
87 open suspend fun setChangedOnly(value: Boolean) {
88 appContext?.fileBrowserPrefsDataStore?.edit { it[changedOnlyKey] = value }
89 }