diff --git a/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothPersistenceModule.kt b/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothPersistenceModule.kt deleted file mode 100644 index d1b50970..00000000 --- a/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothPersistenceModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -package eu.darken.capod.common.bluetooth - -import android.content.Context -import androidx.datastore.core.DataStore -import androidx.datastore.preferences.core.Preferences -import androidx.datastore.preferences.preferencesDataStore -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import eu.darken.capod.common.datastore.DataStoreValue -import eu.darken.capod.common.datastore.createValue -import eu.darken.capod.common.serialization.SerializationCapod -import kotlinx.serialization.json.Json -import javax.inject.Singleton - -private val Context.bluetoothDataStore: DataStore by preferencesDataStore(name = "bluetooth_state") - -@InstallIn(SingletonComponent::class) -@Module -object BluetoothPersistenceModule { - - @Provides - @Singleton - fun provideNudgeAvailability( - @ApplicationContext context: Context, - @SerializationCapod json: Json, - ): DataStoreValue = context.bluetoothDataStore.createValue( - key = "core.bluetooth.nudge.availability", - defaultValue = NudgeAvailability.UNKNOWN, - json = json, - onErrorFallbackToDefault = true, - ) -} diff --git a/app/src/main/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStore.kt b/app/src/main/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStore.kt index 9151d537..5e62b4be 100644 --- a/app/src/main/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStore.kt +++ b/app/src/main/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStore.kt @@ -2,12 +2,12 @@ package eu.darken.capod.common.bluetooth import eu.darken.capod.common.coroutine.AppScope import eu.darken.capod.common.coroutine.DispatcherProvider -import eu.darken.capod.common.datastore.DataStoreValue import eu.darken.capod.common.datastore.value import eu.darken.capod.common.datastore.valueBlocking import eu.darken.capod.common.debug.logging.Logging.Priority.INFO import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.debug.logging.logTag +import eu.darken.capod.main.core.GeneralSettings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -19,11 +19,13 @@ import javax.inject.Singleton @Singleton class NudgeCapabilityStore @Inject constructor( - private val persistedValue: DataStoreValue, + generalSettings: GeneralSettings, @AppScope private val appScope: CoroutineScope, private val dispatcherProvider: DispatcherProvider, ) { + private val persistedValue = generalSettings.nudgeAvailability + // Resolve the persisted value synchronously at construction so consumers that read // `availability.value` (resolver, AutoConnect precondition, UI state) never see the // synthetic UNKNOWN seed before the first DataStore emission arrives. On a known-broken diff --git a/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt b/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt index fae4953a..300b9f96 100644 --- a/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt +++ b/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt @@ -9,6 +9,7 @@ import androidx.datastore.preferences.preferencesDataStore import dagger.hilt.android.qualifiers.ApplicationContext import eu.darken.capod.common.BuildConfigWrap import eu.darken.capod.common.bluetooth.BluetoothAddress +import eu.darken.capod.common.bluetooth.NudgeAvailability import eu.darken.capod.common.datastore.createValue import eu.darken.capod.common.serialization.ByteArrayBase64Serializer import eu.darken.capod.common.serialization.SerializationCapod @@ -72,6 +73,12 @@ class GeneralSettings @Inject constructor( val isOffloadedBatchingDisabled = dataStore.createValue("core.compat.offloaded.batching.disabled", false) val useIndirectScanResultCallback = dataStore.createValue("core.compat.indirectcallback.enabled", false) + /** Runtime-detected verdict for whether `BluetoothHeadset.connect()` reflection works on this device. */ + val nudgeAvailability = dataStore.createValue( + "core.bluetooth.nudge.availability", NudgeAvailability.UNKNOWN, json, + onErrorFallbackToDefault = true, + ) + val isOnboardingDone = dataStore.createValue("core.onboarding.done", false) val reactionsHintDismissed = dataStore.createValue("ui.hint.reactions_per_device.dismissed", false) diff --git a/app/src/test/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStoreTest.kt b/app/src/test/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStoreTest.kt index c4a33013..d2363e88 100644 --- a/app/src/test/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStoreTest.kt +++ b/app/src/test/java/eu/darken/capod/common/bluetooth/NudgeCapabilityStoreTest.kt @@ -1,6 +1,9 @@ package eu.darken.capod.common.bluetooth +import eu.darken.capod.main.core.GeneralSettings import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain @@ -18,11 +21,15 @@ class NudgeCapabilityStoreTest : BaseTest() { private val testDispatcher = UnconfinedTestDispatcher() private lateinit var fakePersisted: FakeDataStoreValue + private lateinit var generalSettings: GeneralSettings @BeforeEach fun setup() { Dispatchers.setMain(testDispatcher) fakePersisted = FakeDataStoreValue(NudgeAvailability.UNKNOWN) + generalSettings = mockk().also { + every { it.nudgeAvailability } returns fakePersisted.mock + } } @AfterEach @@ -31,7 +38,7 @@ class NudgeCapabilityStoreTest : BaseTest() { } private fun createStore() = NudgeCapabilityStore( - persistedValue = fakePersisted.mock, + generalSettings = generalSettings, appScope = kotlinx.coroutines.CoroutineScope(testDispatcher), dispatcherProvider = TestDispatcherProvider(testDispatcher), )