git.iko.soy/opencode-android
on 61cdc75 help sign in
73 lines 3.2 kB history raw
1package soy.iko.opencode.data.repo
3import android.content.Context
4import androidx.datastore.preferences.core.edit
5import androidx.datastore.preferences.core.stringSetPreferencesKey
6import androidx.datastore.preferences.preferencesDataStore
7import kotlinx.coroutines.flow.Flow
8import kotlinx.coroutines.flow.flowOf
9import kotlinx.coroutines.flow.map
11private val Context.sessionPrefsDataStore by preferencesDataStore(name = "session_prefs")
13/**
14 * Local, per-session organization flags the opencode server doesn't track: **pinned**
15 * (sorted to the top of the session list) and **archived** (hidden from the list unless the
16 * user opts to show them). Keyed by opencode session id.
17 *
18 * `open` with a `protected` no-arg constructor so tests can subclass and override the flows
19 * without a real DataStore (mirrors the other stores). The flow accessors are getters (not
20 * eager initializers) and null-guard the context so the test constructor never touches disk.
21 */
22open class SessionPrefsStore private constructor(
23 private val appContext: Context?,
24 @Suppress("unused") private val testMode: Boolean,
25) {
26 constructor(context: Context) : this(context.applicationContext, false)
27 protected constructor() : this(null, true)
29 private val pinnedKey = stringSetPreferencesKey("pinned")
30 private val archivedKey = stringSetPreferencesKey("archived")
31 private val mutedKey = stringSetPreferencesKey("muted")
33 open val pinned: Flow<Set<String>>
34 get() = appContext?.sessionPrefsDataStore?.data?.map { it[pinnedKey] ?: emptySet() }
35 ?: flowOf(emptySet())
37 open val archived: Flow<Set<String>>
38 get() = appContext?.sessionPrefsDataStore?.data?.map { it[archivedKey] ?: emptySet() }
39 ?: flowOf(emptySet())
41 /** Session ids the user has muted (suppress unread badge + completion notification). */
42 open val muted: Flow<Set<String>>
43 get() = appContext?.sessionPrefsDataStore?.data?.map { it[mutedKey] ?: emptySet() }
44 ?: flowOf(emptySet())
46 open suspend fun setPinned(sessionId: String, pinned: Boolean) = toggle(pinnedKey, sessionId, pinned)
48 open suspend fun setArchived(sessionId: String, archived: Boolean) = toggle(archivedKey, sessionId, archived)
50 open suspend fun setMuted(sessionId: String, muted: Boolean) = toggle(mutedKey, sessionId, muted)
52 /** Drop a session from all sets — call on deletion so ids don't accumulate forever. */
53 open suspend fun forget(sessionId: String) {
54 val ctx = appContext ?: return
55 ctx.sessionPrefsDataStore.edit { prefs ->
56 prefs[pinnedKey] = (prefs[pinnedKey] ?: emptySet()) - sessionId
57 prefs[archivedKey] = (prefs[archivedKey] ?: emptySet()) - sessionId
58 prefs[mutedKey] = (prefs[mutedKey] ?: emptySet()) - sessionId
59 }
60 }
62 private suspend fun toggle(
63 key: androidx.datastore.preferences.core.Preferences.Key<Set<String>>,
64 sessionId: String,
65 on: Boolean,
66 ) {
67 val ctx = appContext ?: return
68 ctx.sessionPrefsDataStore.edit { prefs ->
69 val current = prefs[key] ?: emptySet()
70 prefs[key] = if (on) current + sessionId else current - sessionId
71 }
72 }