summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/data/Settings.kt
blob: ce05974d1d8ed897556cad8178372f7969be68a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package org.terst.feedreader.data

import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map

val Context.settingsDataStore by preferencesDataStore(name = "settings")

private object SettingsKeys {
    val STASH_BASE_URL = stringPreferencesKey("stash_base_url")
    val STASH_API_KEY = stringPreferencesKey("stash_api_key")
    val LAST_FETCH_AT = longPreferencesKey("last_fetch_at")
    val LAST_FETCH_NEW_ARTICLES = intPreferencesKey("last_fetch_new_articles")
    val LAST_ACKNOWLEDGED_FETCH_AT = longPreferencesKey("last_acknowledged_fetch_at")
}

/** Stash connection settings, configured on the Settings screen. Both blank until set. */
class Settings(private val context: Context) {
    val stashBaseUrl: Flow<String> =
        context.settingsDataStore.data.map { it[SettingsKeys.STASH_BASE_URL] ?: "" }
    val stashApiKey: Flow<String> =
        context.settingsDataStore.data.map { it[SettingsKeys.STASH_API_KEY] ?: "" }

    suspend fun stashBaseUrlNow(): String = stashBaseUrl.first()
    suspend fun stashApiKeyNow(): String = stashApiKey.first()

    suspend fun setStash(baseUrl: String, apiKey: String) {
        context.settingsDataStore.edit { prefs ->
            prefs[SettingsKeys.STASH_BASE_URL] = baseUrl.trim().trimEnd('/')
            prefs[SettingsKeys.STASH_API_KEY] = apiKey.trim()
        }
    }

    // Durable record of "when did a feed fetch last finish, and with how many new
    // articles" -- deliberately NOT derived from WorkManager's WorkInfo.State. A
    // PeriodicWorkRequest's state cycles back to ENQUEUED after every successful run
    // (it never settles on SUCCEEDED the way a one-time request does), so anything
    // watching for SUCCEEDED only ever sees manual/alarm-triggered one-time fetches --
    // the actual hourly background fetch is invisible to that approach. Writing the
    // result here on every run (periodic or one-time alike) gives the UI one consistent
    // signal regardless of which triggered it.
    val lastFetchAt: Flow<Long> =
        context.settingsDataStore.data.map { it[SettingsKeys.LAST_FETCH_AT] ?: 0L }
    val lastFetchNewArticles: Flow<Int> =
        context.settingsDataStore.data.map { it[SettingsKeys.LAST_FETCH_NEW_ARTICLES] ?: 0 }
    val lastAcknowledgedFetchAt: Flow<Long> =
        context.settingsDataStore.data.map { it[SettingsKeys.LAST_ACKNOWLEDGED_FETCH_AT] ?: 0L }

    suspend fun recordFetchResult(newArticles: Int) {
        context.settingsDataStore.edit { prefs ->
            prefs[SettingsKeys.LAST_FETCH_AT] = System.currentTimeMillis()
            prefs[SettingsKeys.LAST_FETCH_NEW_ARTICLES] = newArticles
        }
    }

    // Persisted (not just in-memory Compose state) so that navigating away from a screen
    // and back doesn't forget a fetch was already acknowledged and re-show its snackbar.
    suspend fun acknowledgeFetch(at: Long) {
        context.settingsDataStore.edit { prefs -> prefs[SettingsKeys.LAST_ACKNOWLEDGED_FETCH_AT] = at }
    }
}