diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index 431f57e5c3..26697a4fcb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -79,8 +79,12 @@ import com.vitorpamplona.amethyst.model.privacyOptions.RoleBasedHttpClientBuilde import com.vitorpamplona.amethyst.model.torState.AccountsTorStateConnector import com.vitorpamplona.amethyst.model.torState.TorRelayState import com.vitorpamplona.amethyst.napplet.DataStoreNappletPermissionStore +import com.vitorpamplona.amethyst.service.calendar.CALENDAR_REMINDER_LOG_STORE +import com.vitorpamplona.amethyst.service.calendar.CALENDAR_REMINDER_SETTINGS_STORE import com.vitorpamplona.amethyst.service.calendar.CalendarReminderWorker +import com.vitorpamplona.amethyst.service.calendar.calendarReminderLogMigrations import com.vitorpamplona.amethyst.service.calendar.calendarReminderSettings +import com.vitorpamplona.amethyst.service.calendar.calendarReminderSettingsMigrations import com.vitorpamplona.amethyst.service.cast.CastRegistry import com.vitorpamplona.amethyst.service.connectivity.ConnectivityManager import com.vitorpamplona.amethyst.service.crashreports.CrashReportCache @@ -257,6 +261,8 @@ class AppModules( // One file per account, so the migration is per name rather than a constant. name.startsWith(CashuPreferences.FILE_PREFIX) -> listOf(CashuPreferences.legacyMigration(appContext, name.removePrefix(CashuPreferences.FILE_PREFIX))) + name == CALENDAR_REMINDER_SETTINGS_STORE -> calendarReminderSettingsMigrations(appContext) + name == CALENDAR_REMINDER_LOG_STORE -> calendarReminderLogMigrations(appContext) else -> emptyList() } }, @@ -855,8 +861,10 @@ class AppModules( */ val nappletAccountScope: () -> String = { sessionManager.loggedInAccount()?.pubKey ?: "" } - // Singleton stores for napplet permissions — DataStore v1 enforces one instance per file. - val nappletPermissionStore by lazy { DataStoreNappletPermissionStore(appContext, nappletAccountScope) } + // Singleton stores for napplet permissions. The holder is what enforces + // DataStore's one-instance-per-file rule now; this stays a lazy val so the + // ledger below and the broker share one object. + val nappletPermissionStore by lazy { DataStoreNappletPermissionStore(appStores.getDataStore("napplet_permissions"), nappletAccountScope) } /** * The one napplet permission ledger for the main process. Its persistent half is just the store @@ -1347,7 +1355,7 @@ class AppModules( Filter(kinds = listOf(CalendarDateSlotEvent.KIND, CalendarTimeSlotEvent.KIND)), ).conflate() .collect { - if (appContext.calendarReminderSettings().load().enabled && + if (calendarReminderSettings().load().enabled && CalendarReminderWorker.couldStillFire(CalendarReminderWorker.acceptedRsvpsInCache(), TimeUtils.now()) ) { CalendarReminderWorker.schedule(appContext) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/BrowserHistoryRegistry.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/BrowserHistoryRegistry.kt index 5564139886..e9988b23e7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/BrowserHistoryRegistry.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/BrowserHistoryRegistry.kt @@ -21,9 +21,11 @@ package com.vitorpamplona.amethyst.favorites import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.browser.OmniboxInput import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.utils.Log @@ -37,7 +39,15 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.serialization.Serializable -private val Context.browserHistoryDataStore by preferencesDataStore(name = "browser_history") +/** + * The browser-history file, on the app-wide holder rather than a `Context` delegate. + * Same path the delegate resolved to, so nothing migrates. + * + * Main process only: [Amethyst.instance] is deliberately unset in the + * `:napplet` sandbox. + */ +private val browserHistoryDataStore: DataStore + get() = Amethyst.instance.appStores.getDataStore("browser_history") /** * One device-local visited site, keyed by full [url]. [visitCount]/[lastVisitedAt] drive frecency ranking @@ -83,7 +93,7 @@ object BrowserHistoryRegistry { val ctx = context.applicationContext appContext = ctx scope.launch { - val json = ctx.browserHistoryDataStore.data.first()[KEY] + val json = browserHistoryDataStore.data.first()[KEY] val loaded = if (json != null) decode(json) else emptyList() // Merge disk under anything already recorded this session (session wins, newest-first). update { current -> dedupeNewestFirst(current + loaded) } @@ -136,9 +146,9 @@ object BrowserHistoryRegistry { } private fun persist(json: String) { - val ctx = appContext ?: return + appContext ?: return scope.launch { - ctx.browserHistoryDataStore.edit { it[KEY] = json } + browserHistoryDataStore.edit { it[KEY] = json } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteAppsRegistry.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteAppsRegistry.kt index 99e36cf19b..ad9d03d325 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteAppsRegistry.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/favorites/FavoriteAppsRegistry.kt @@ -21,9 +21,11 @@ package com.vitorpamplona.amethyst.favorites import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.utils.Log @@ -38,7 +40,15 @@ import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import java.util.concurrent.ConcurrentHashMap -private val Context.favoriteAppsDataStore by preferencesDataStore(name = "favorite_apps") +/** + * The favorite-apps file, on the app-wide holder rather than a `Context` delegate. + * Same path the delegate resolved to, so nothing migrates. + * + * Main process only: [Amethyst.instance] is deliberately unset in the + * `:napplet` sandbox. + */ +private val favoriteAppsDataStore: DataStore + get() = Amethyst.instance.appStores.getDataStore("favorite_apps") /** * The user's device-local list of [FavoriteApp]s — the single source of truth shared by the bottom @@ -81,7 +91,7 @@ object FavoriteAppsRegistry { val ctx = context.applicationContext appContext = ctx scope.launch { - val prefs = ctx.favoriteAppsDataStore.data.first() + val prefs = favoriteAppsDataStore.data.first() val loaded = prefs[KEY]?.let { decode(it) } ?: emptyList() // Don't clobber adds made in this session before hydration finished, and don't resurrect // anything the user removed in that same window. @@ -139,16 +149,16 @@ object FavoriteAppsRegistry { } private fun persist(json: String) { - val ctx = appContext ?: return + appContext ?: return scope.launch { - ctx.favoriteAppsDataStore.edit { it[KEY] = json } + favoriteAppsDataStore.edit { it[KEY] = json } } } private fun persistManifests(json: String) { - val ctx = appContext ?: return + appContext ?: return scope.launch { - ctx.favoriteAppsDataStore.edit { it[MANIFESTS_KEY] = json } + favoriteAppsDataStore.edit { it[MANIFESTS_KEY] = json } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletPermissionStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletPermissionStore.kt index 073d458f83..7550c41334 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletPermissionStore.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletPermissionStore.kt @@ -20,19 +20,15 @@ */ package com.vitorpamplona.amethyst.napplet -import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore import com.vitorpamplona.amethyst.commons.napplet.NappletCapability import com.vitorpamplona.amethyst.commons.napplet.permissions.GrantState import com.vitorpamplona.amethyst.commons.napplet.permissions.NappletPermissionStore import kotlinx.coroutines.flow.first -private val Context.nappletPermissionsDataStore by preferencesDataStore(name = "napplet_permissions") - /** * Persists the standing napplet grants ([GrantState.ALLOW_ALWAYS] / [GrantState.DENY]) in a * dedicated DataStore. Keyed by `"\u0000"` so a coordinate's grants can @@ -43,9 +39,6 @@ class DataStoreNappletPermissionStore( private val dataStore: DataStore, private val accountPubKey: () -> String, ) : NappletPermissionStore { - constructor(context: Context, accountPubKey: () -> String) : - this(context.applicationContext.nappletPermissionsDataStore, accountPubKey) - /** * Grants belong to one account. [accountPubKey] is read at call time, so an account switch moves * every read and write to that account's namespace with no rebuild — a grant made by one account diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletStorage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletStorage.kt index 14d3499371..4c3141b6e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletStorage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/DataStoreNappletStorage.kt @@ -20,17 +20,13 @@ */ package com.vitorpamplona.amethyst.napplet -import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore import com.vitorpamplona.amethyst.commons.napplet.NappletStorage import kotlinx.coroutines.flow.first -private val Context.nappletStorageDataStore by preferencesDataStore(name = "napplet_storage") - /** * DataStore-backed [NappletStorage]. Every key is prefixed with the **active account** and then the * applet's coordinate, so one napplet's keys can never collide with another's, one account's data is @@ -44,9 +40,6 @@ class DataStoreNappletStorage( private val dataStore: DataStore, private val accountPubKey: () -> String, ) : NappletStorage { - constructor(context: Context, accountPubKey: () -> String) : - this(context.applicationContext.nappletStorageDataStore, accountPubKey) - override suspend fun get( coordinate: String, key: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt index de5815af52..7f98885be1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletBrokerService.kt @@ -90,7 +90,7 @@ class NappletBrokerService : Service() { private val signerLedger by lazy { NostrSignerPermissionLedger(Amethyst.instance.signerPermissionStore) } // Per-applet sandboxed key-value store (namespaced by account + coordinate inside the impl). - private val storage by lazy { DataStoreNappletStorage(applicationContext, Amethyst.instance.nappletAccountScope) } + private val storage by lazy { DataStoreNappletStorage(Amethyst.instance.appStores.getDataStore("napplet_storage"), Amethyst.instance.nappletAccountScope) } private val incoming by lazy { Messenger(Handler(Looper.getMainLooper(), ::handleMessage)) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletNetworkRegistry.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletNetworkRegistry.kt index 3dc4e46da8..1e95e1fb02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletNetworkRegistry.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/NappletNetworkRegistry.kt @@ -21,9 +21,11 @@ package com.vitorpamplona.amethyst.napplet import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import com.vitorpamplona.amethyst.Amethyst import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -32,7 +34,15 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import java.util.concurrent.ConcurrentHashMap -private val Context.nappletNetworkDataStore by preferencesDataStore(name = "napplet_network") +/** + * The per-napplet routing file, on the app-wide holder rather than a `Context` delegate. + * Same path the delegate resolved to, so nothing migrates. + * + * Main process only: [Amethyst.instance] is deliberately unset in the + * `:napplet` sandbox. + */ +private val nappletNetworkDataStore: DataStore + get() = Amethyst.instance.appStores.getDataStore("napplet_network") /** * Per-nSite network-routing preference: whether a site's traffic goes through **Tor** (the default) @@ -69,7 +79,7 @@ object NappletNetworkRegistry { appContext = ctx hydration = scope.launch { - ctx.nappletNetworkDataStore.data.first().asMap().forEach { (key, value) -> + nappletNetworkDataStore.data.first().asMap().forEach { (key, value) -> // putIfAbsent: never clobber a choice made in this session before hydration finished. modes.putIfAbsent(key.name, value != OPEN_WEB) } @@ -95,9 +105,9 @@ object NappletNetworkRegistry { useTor: Boolean, ) { modes[coordinate] = useTor - val ctx = appContext ?: return + appContext ?: return scope.launch { - ctx.nappletNetworkDataStore.edit { it[stringPreferencesKey(coordinate)] = if (useTor) TOR else OPEN_WEB } + nappletNetworkDataStore.edit { it[stringPreferencesKey(coordinate)] = if (useTor) TOR else OPEN_WEB } } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/WebAppNetworkRegistry.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/WebAppNetworkRegistry.kt index 2038417d1a..a274fb036c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/WebAppNetworkRegistry.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/napplet/WebAppNetworkRegistry.kt @@ -22,9 +22,11 @@ package com.vitorpamplona.amethyst.napplet import android.content.Context import androidx.core.net.toUri +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import com.vitorpamplona.amethyst.Amethyst import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -33,7 +35,16 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import java.util.concurrent.ConcurrentHashMap -private val Context.webUrlNetworkDataStore by preferencesDataStore(name = "weburl_network") +/** + * The per-site routing file, on the app-wide holder rather than a `Context` + * delegate. Same path the delegate resolved to, so nothing migrates. + * + * Main process only: [Amethyst.instance] is deliberately unset in the + * `:napplet` sandbox, and this registry is only touched from the browser + * chrome that runs in the main process. + */ +private val webUrlNetworkDataStore: DataStore + get() = Amethyst.instance.appStores.getDataStore("weburl_network") /** * Per-web-client network-routing preference: whether a favorited URL / browsed site routes through @@ -67,7 +78,7 @@ object WebAppNetworkRegistry { appContext = ctx hydration = scope.launch { - ctx.webUrlNetworkDataStore.data.first().asMap().forEach { (key, value) -> + webUrlNetworkDataStore.data.first().asMap().forEach { (key, value) -> // putIfAbsent: never clobber a choice made in this session before hydration finished. modes.putIfAbsent(key.name, value != OPEN_WEB) } @@ -98,9 +109,9 @@ object WebAppNetworkRegistry { ) { val host = hostKeyOf(url) modes[host] = useTor - val ctx = appContext ?: return + appContext ?: return scope.launch { - ctx.webUrlNetworkDataStore.edit { it[stringPreferencesKey(host)] = if (useTor) TOR else OPEN_WEB } + webUrlNetworkDataStore.edit { it[stringPreferencesKey(host)] = if (useTor) TOR else OPEN_WEB } } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderStores.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderStores.kt index e7105b31b8..e430a79bc0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderStores.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderStores.kt @@ -21,9 +21,11 @@ package com.vitorpamplona.amethyst.service.calendar import android.content.Context +import androidx.datastore.core.DataMigration +import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.intPreferencesKey -import androidx.datastore.preferences.preferencesDataStore +import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.model.preferences.CalendarReminderLogStore import com.vitorpamplona.amethyst.commons.model.preferences.CalendarReminderSettings import com.vitorpamplona.amethyst.commons.model.preferences.CalendarReminderSettingsStore @@ -34,43 +36,47 @@ import com.vitorpamplona.amethyst.commons.model.preferences.CopyOnceMigration * * The store classes live in commons; only the file location and the one-off * lift out of the legacy SharedPreferences are Android's business. + * + * Both files sit on `AppPreferenceStores` rather than a `Context` delegate. + * The names below are the delegate's names, and the holder reproduces the path + * it resolved to, so nothing migrates. The migrations move with them: DataStore + * runs a file's migrations once, when that file is first opened, so they have + * to be attached to the file by the holder rather than by whoever opens it. */ private const val LEGACY_SETTINGS_FILE = "amethyst_calendar_reminder_prefs" private const val LEGACY_LOG_FILE = "amethyst_calendar_reminders" -private val Context.calendarReminderSettingsData by preferencesDataStore( - name = "calendar_reminder_settings", - produceMigrations = { context -> - listOf( - CopyOnceMigration("migrated.calendarReminderSettings") { out -> - val legacy = context.getSharedPreferences(LEGACY_SETTINGS_FILE, Context.MODE_PRIVATE) - if (legacy.contains("enabled")) { - out[booleanPreferencesKey("enabled")] = legacy.getBoolean("enabled", CalendarReminderSettings.DEFAULT_ENABLED) - } - if (legacy.contains("lead_minutes")) { - out[intPreferencesKey("lead_minutes")] = legacy.getInt("lead_minutes", CalendarReminderSettings.DEFAULT_LEAD_MINUTES) - } - }, - ) - }, -) +/** Store (and file) names, as [Amethyst.appStores] keys them. */ +const val CALENDAR_REMINDER_SETTINGS_STORE = "calendar_reminder_settings" +const val CALENDAR_REMINDER_LOG_STORE = "calendar_reminder_log" -private val Context.calendarReminderLogData by preferencesDataStore( - name = "calendar_reminder_log", - produceMigrations = { context -> - listOf( - CopyOnceMigration("migrated.calendarReminderLog") { out -> - val legacy = context.getSharedPreferences(LEGACY_LOG_FILE, Context.MODE_PRIVATE) - // Values are the event-start times the reminders fired for; anything - // else in the file is not ours and is left behind. - legacy.all.forEach { (key, value) -> - if (value is Long) out[CalendarReminderLogStore.keyFor(key.removePrefix("notified:"))] = value - } - }, - ) - }, -) +/** The one-off copy of the reminder settings out of the legacy prefs file. */ +fun calendarReminderSettingsMigrations(context: Context): List> = + listOf( + CopyOnceMigration("migrated.calendarReminderSettings") { out -> + val legacy = context.getSharedPreferences(LEGACY_SETTINGS_FILE, Context.MODE_PRIVATE) + if (legacy.contains("enabled")) { + out[booleanPreferencesKey("enabled")] = legacy.getBoolean("enabled", CalendarReminderSettings.DEFAULT_ENABLED) + } + if (legacy.contains("lead_minutes")) { + out[intPreferencesKey("lead_minutes")] = legacy.getInt("lead_minutes", CalendarReminderSettings.DEFAULT_LEAD_MINUTES) + } + }, + ) -fun Context.calendarReminderSettings() = CalendarReminderSettingsStore(calendarReminderSettingsData) +/** The one-off copy of the fired-reminder log out of the legacy prefs file. */ +fun calendarReminderLogMigrations(context: Context): List> = + listOf( + CopyOnceMigration("migrated.calendarReminderLog") { out -> + val legacy = context.getSharedPreferences(LEGACY_LOG_FILE, Context.MODE_PRIVATE) + // Values are the event-start times the reminders fired for; anything + // else in the file is not ours and is left behind. + legacy.all.forEach { (key, value) -> + if (value is Long) out[CalendarReminderLogStore.keyFor(key.removePrefix("notified:"))] = value + } + }, + ) -fun Context.calendarReminderLog() = CalendarReminderLogStore(calendarReminderLogData) +fun calendarReminderSettings() = CalendarReminderSettingsStore(Amethyst.instance.appStores.getDataStore(CALENDAR_REMINDER_SETTINGS_STORE)) + +fun calendarReminderLog() = CalendarReminderLogStore(Amethyst.instance.appStores.getDataStore(CALENDAR_REMINDER_LOG_STORE)) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderWorker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderWorker.kt index 40e1134f8d..b3f34ae3ce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderWorker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/calendar/CalendarReminderWorker.kt @@ -65,7 +65,7 @@ class CalendarReminderWorker( ) : CoroutineWorker(appContext, params) { override suspend fun doWork(): Result { runCatching { Amethyst.instance.resourceUsage.add(UsageKeys.workerRuns("calendarReminder"), 1) } - val settings = applicationContext.calendarReminderSettings().load() + val settings = calendarReminderSettings().load() if (!settings.enabled) { Log.d(TAG) { "Reminders disabled; ending periodic chain." } // The settings toggle re-schedules on enable; no reason to keep @@ -75,7 +75,7 @@ class CalendarReminderWorker( } val now = TimeUtils.now() val windowEnd = now + settings.leadMinutes * 60L - val store = applicationContext.calendarReminderLog() + val store = calendarReminderLog() // Walk every kind-31925 RSVP authored by an account on this device. We don't have a // multi-account "all logged-in pubkeys" view here, so we accept any RSVP that's diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarReminderSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarReminderSettingsScreen.kt index ce1888a33d..1115110ab4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarReminderSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarReminderSettingsScreen.kt @@ -68,7 +68,7 @@ import kotlinx.coroutines.launch fun CalendarReminderSettingsScreen(nav: INav) { val context = LocalContext.current val scope = rememberCoroutineScope() - val store = remember(context) { context.calendarReminderSettings() } + val store = remember { calendarReminderSettings() } // DataStore reads are suspend, so the first frame renders the defaults and // the stored values arrive right after. Collecting the flow rather than diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessDismissedGamesData.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessDismissedGamesData.kt index dc63800518..a0cba559e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessDismissedGamesData.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessDismissedGamesData.kt @@ -20,8 +20,9 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chess -import android.content.Context -import androidx.datastore.preferences.preferencesDataStore +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import com.vitorpamplona.amethyst.Amethyst /** * Where Android keeps the dismissed-chess-games store. @@ -31,4 +32,5 @@ import androidx.datastore.preferences.preferencesDataStore * data over is not worth the code. Anyone who had dismissed a game sees it once * more and dismisses it again. */ -internal val Context.chessDismissedGamesData by preferencesDataStore(name = "chess_dismissed_games_v2") +internal val chessDismissedGamesData: DataStore + get() = Amethyst.instance.appStores.getDataStore("chess_dismissed_games_v2") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelNew.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelNew.kt index ae46d80463..9bd3819de4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelNew.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessViewModelNew.kt @@ -61,7 +61,7 @@ class ChessViewModelNew( private val publisher = AndroidChessPublisher(account) private val fetcher = AndroidRelayFetcher(account) private val metadataProvider = AndroidMetadataProvider() - private val dismissedStorage = ChessDismissedGamesStore(application.chessDismissedGamesData) + private val dismissedStorage = ChessDismissedGamesStore(chessDismissedGamesData) // Shared business logic (creates its own ChessLobbyState internally) private val logic =