Set up project skeleton (milestone 1)
- Architecture and feature overview in docs/ARCHITECTURE.md - Gradle 9.8 / AGP 9.4 / Kotlin 2.4 with version catalog and convention plugins - Modules :app, :core:*, :device-profiles, :feature:* (placeholder screens) - Flavors core (no INTERNET, enforced by a build check) and full - Material You theme, navigation, expert mode and dry-run settings (DataStore) - Pixel 8-10 device detection, unit tests, GPLv3 license, English README with Obtainium badge Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
alias(libs.plugins.pixelwall.android.library)
|
||||
alias(libs.plugins.pixelwall.android.hilt)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.pixelwall.core.data"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":core:domain"))
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.pixelwall.core.data
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.pixelwall.core.domain.UserPreferences
|
||||
import org.pixelwall.core.domain.UserPreferencesRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class DataStoreUserPreferencesRepository @Inject constructor(
|
||||
private val dataStore: DataStore<Preferences>,
|
||||
) : UserPreferencesRepository {
|
||||
|
||||
override val preferences: Flow<UserPreferences> = dataStore.data.map { prefs ->
|
||||
UserPreferences(
|
||||
expertMode = prefs[EXPERT_MODE] ?: false,
|
||||
dryRun = prefs[DRY_RUN] ?: false,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun setExpertMode(enabled: Boolean) {
|
||||
dataStore.edit { it[EXPERT_MODE] = enabled }
|
||||
}
|
||||
|
||||
override suspend fun setDryRun(enabled: Boolean) {
|
||||
dataStore.edit { it[DRY_RUN] = enabled }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val EXPERT_MODE = booleanPreferencesKey("expert_mode")
|
||||
val DRY_RUN = booleanPreferencesKey("dry_run")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.pixelwall.core.data.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.pixelwall.core.data.DataStoreUserPreferencesRepository
|
||||
import org.pixelwall.core.domain.UserPreferencesRepository
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class DataModule {
|
||||
|
||||
@Binds
|
||||
abstract fun bindUserPreferencesRepository(impl: DataStoreUserPreferencesRepository): UserPreferencesRepository
|
||||
|
||||
companion object {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore<Preferences> =
|
||||
PreferenceDataStoreFactory.create { context.preferencesDataStoreFile("user_preferences") }
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package org.pixelwall.core.data
|
||||
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.pixelwall.core.domain.UserPreferences
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class DataStoreUserPreferencesRepositoryTest {
|
||||
|
||||
@get:Rule
|
||||
val tmp = TemporaryFolder()
|
||||
|
||||
private val testScope = TestScope(UnconfinedTestDispatcher())
|
||||
|
||||
private fun repository() = DataStoreUserPreferencesRepository(
|
||||
PreferenceDataStoreFactory.create(scope = testScope.backgroundScope) {
|
||||
tmp.newFile("test.preferences_pb")
|
||||
},
|
||||
)
|
||||
|
||||
@Test
|
||||
fun defaultsAreSafe() = testScope.runTest {
|
||||
assertThat(repository().preferences.first()).isEqualTo(UserPreferences(expertMode = false, dryRun = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun togglesArePersisted() = testScope.runTest {
|
||||
val repo = repository()
|
||||
repo.setExpertMode(true)
|
||||
repo.setDryRun(true)
|
||||
assertThat(repo.preferences.first()).isEqualTo(UserPreferences(expertMode = true, dryRun = true))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user