SyncAlertStore.kt

2.2 KB · raw

1package com.peachpasswords.sync23import android.content.Context4import androidx.security.crypto.EncryptedSharedPreferences5import androidx.security.crypto.MasterKey6import dagger.hilt.android.qualifiers.ApplicationContext7import kotlinx.coroutines.flow.MutableStateFlow8import kotlinx.coroutines.flow.StateFlow9import kotlinx.coroutines.flow.asStateFlow10import kotlinx.serialization.builtins.ListSerializer11import kotlinx.serialization.json.Json12import javax.inject.Inject13import javax.inject.Singleton1415@Singleton16class SyncAlertStore @Inject constructor(17    @ApplicationContext context: Context,18) : SyncAlertRecorder {19    private val masterKey = MasterKey.Builder(context)20        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)21        .build()2223    private val prefs = EncryptedSharedPreferences.create(24        context,25        PREFS_FILE,26        masterKey,27        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,28        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,29    )3031    private val listSerializer = ListSerializer(SyncAlert.serializer())32    private val _alerts = MutableStateFlow(load())33    val alerts: StateFlow<List<SyncAlert>> = _alerts.asStateFlow()3435    override fun record(alerts: List<SyncAlert>) {36        if (alerts.isEmpty()) return37        persist(boundedSyncAlerts(load(), alerts))38    }3940    fun dismiss(alert: SyncAlert) {41        val current = load().toMutableList()42        val index = current.indexOf(alert)43        if (index != -1) {44            current.removeAt(index)45            persist(current)46        }47    }4849    fun clear() {50        persist(emptyList())51    }5253    private fun load(): List<SyncAlert> {54        val raw = prefs.getString(KEY_ALERTS, null) ?: return emptyList()55        return runCatching { json.decodeFromString(listSerializer, raw) }.getOrDefault(emptyList())56    }5758    private fun persist(alerts: List<SyncAlert>) {59        prefs.edit()60            .putString(KEY_ALERTS, json.encodeToString(listSerializer, alerts))61            .apply()62        _alerts.value = alerts63    }6465    private companion object {66        const val PREFS_FILE = "peach_sync_alerts"67        const val KEY_ALERTS = "sync_alerts"68        val json = Json { encodeDefaults = true; ignoreUnknownKeys = true }69    }70}