Merge pull request #42 from lihenggui/compose_multiplatform

Remove datastore and datastore-test module
pull/1323/head
Mercury Li 2 years ago committed by GitHub
commit 7fca23b3f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -121,7 +121,6 @@ dependencies {
androidTestImplementation(projects.core.testing)
androidTestImplementation(projects.core.dataTest)
androidTestImplementation(projects.core.datastoreTest)
androidTestImplementation(libs.androidx.test.espresso.core)
androidTestImplementation(libs.androidx.navigation.testing)
androidTestImplementation(libs.accompanist.testharness)

@ -43,10 +43,9 @@ kotlin {
}
commonTest.dependencies {
implementation(libs.kotlinx.coroutines.test)
implementation(libs.multiplatform.settings.test)
implementation(libs.kotlinx.serialization.json)
// implementation(projects.core.datastoreTest)
// implementation(projects.core.testing)
implementation(projects.core.testing)
}
androidMain.dependencies {

@ -42,10 +42,10 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@ -70,7 +70,7 @@ class OfflineFirstNewsRepositoryTest {
@get:Rule
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
@Before
@BeforeTest
fun setup() {
niaPreferencesDataSource = NiaPreferencesDataSource(
tmpFolder.testUserPreferencesDataStore(testScope),

@ -50,9 +50,6 @@ class OfflineFirstTopicsRepositoryTest {
private lateinit var synchronizer: Synchronizer
@get:Rule
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
@BeforeTest
fun setup() {
topicDao = TestTopicDao()

@ -18,10 +18,11 @@ package com.google.samples.apps.nowinandroid.core.data.repository
import com.google.samples.apps.nowinandroid.core.analytics.NoOpAnalyticsHelper
import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSource
import com.google.samples.apps.nowinandroid.core.datastore.test.testUserPreferencesDataStore
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
import com.google.samples.apps.nowinandroid.core.model.data.UserData
import com.russhwolf.settings.MapSettings
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.TestScope
@ -35,7 +36,12 @@ import kotlin.test.assertTrue
class OfflineFirstUserDataRepositoryTest {
private val testScope = TestScope(UnconfinedTestDispatcher())
@OptIn(ExperimentalCoroutinesApi::class)
private val dispatcher = UnconfinedTestDispatcher()
private val settings = MapSettings()
private val testScope = TestScope(dispatcher)
private lateinit var subject: OfflineFirstUserDataRepository
@ -43,13 +49,11 @@ class OfflineFirstUserDataRepositoryTest {
private val analyticsHelper = NoOpAnalyticsHelper()
@get:Rule
val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()
@BeforeTest
fun setup() {
niaPreferencesDataSource = NiaPreferencesDataSource(
tmpFolder.testUserPreferencesDataStore(testScope),
settings,
dispatcher,
)
subject = OfflineFirstUserDataRepository(

@ -17,6 +17,7 @@
package com.google.samples.apps.nowinandroid.core.data.testdoubles
import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDao
import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDaoInterface
import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceEntity
import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceTopicCrossRef
import com.google.samples.apps.nowinandroid.core.database.model.PopulatedNewsResource
@ -32,7 +33,7 @@ val nonPresentInterestsIds = setOf("2")
/**
* Test double for [NewsResourceDao]
*/
class TestNewsResourceDao : NewsResourceDao {
class TestNewsResourceDao : NewsResourceDaoInterface {
private val entitiesStateFlow = MutableStateFlow(emptyList<NewsResourceEntity>())
@ -92,6 +93,10 @@ class TestNewsResourceDao : NewsResourceDao {
result.map { it.entity.id }
}
override suspend fun insertOrIgnoreNewsResources(entities: List<NewsResourceEntity>): List<Long> {
TODO("Not yet implemented")
}
override suspend fun upsertNewsResources(newsResourceEntities: List<NewsResourceEntity>) {
entitiesStateFlow.update { oldValues ->
// New values come first so they overwrite old values

@ -17,6 +17,7 @@
package com.google.samples.apps.nowinandroid.core.data.testdoubles
import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao
import com.google.samples.apps.nowinandroid.core.database.dao.TopicDaoInterface
import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -26,7 +27,7 @@ import kotlinx.coroutines.flow.update
/**
* Test double for [TopicDao]
*/
class TestTopicDao : TopicDao {
class TestTopicDao : TopicDaoInterface {
private val entitiesStateFlow = MutableStateFlow(emptyList<TopicEntity>())

@ -19,7 +19,7 @@ package com.google.samples.apps.nowinandroid.core.database.model
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import kotlinx.datetime.Instant
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
class PopulatedNewsResourceKtTest {

@ -30,17 +30,17 @@ import kotlinx.datetime.Instant
/**
* DAO for [NewsResource] and [NewsResourceEntity] access
*/
class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) : NewsResourceDaoInterface {
private val query = db.newsResourceQueries
/**
* Fetches news resources that match the query parameters
*/
fun getNewsResources(
useFilterTopicIds: Boolean = false,
filterTopicIds: Set<String> = emptySet(),
useFilterNewsIds: Boolean = false,
filterNewsIds: Set<String> = emptySet(),
override fun getNewsResources(
useFilterTopicIds: Boolean,
filterTopicIds: Set<String>,
useFilterNewsIds: Boolean,
filterNewsIds: Set<String>,
): Flow<List<PopulatedNewsResource>> {
return query.getNewsResources(
useFilterTopicIds = useFilterTopicIds,
@ -69,11 +69,11 @@ class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatch
/**
* Fetches ids of news resources that match the query parameters
*/
fun getNewsResourceIds(
useFilterTopicIds: Boolean = false,
filterTopicIds: Set<String> = emptySet(),
useFilterNewsIds: Boolean = false,
filterNewsIds: Set<String> = emptySet(),
override fun getNewsResourceIds(
useFilterTopicIds: Boolean,
filterTopicIds: Set<String>,
useFilterNewsIds: Boolean,
filterNewsIds: Set<String>,
): Flow<List<String>> {
return query.getNewsResourceIds(
useFilterTopicIds = useFilterTopicIds,
@ -88,7 +88,7 @@ class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatch
/**
* Inserts [entities] into the db if they don't exist, and ignores those that do
*/
suspend fun insertOrIgnoreNewsResources(entities: List<NewsResourceEntity>): List<Long> {
override suspend fun insertOrIgnoreNewsResources(entities: List<NewsResourceEntity>): List<Long> {
entities.forEach {
query.insertOrIgnoreNewsResource(
id = it.id,
@ -109,7 +109,7 @@ class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatch
/**
* Inserts or updates [newsResourceEntities] in the db under the specified primary keys
*/
suspend fun upsertNewsResources(newsResourceEntities: List<NewsResourceEntity>) {
override suspend fun upsertNewsResources(newsResourceEntities: List<NewsResourceEntity>) {
newsResourceEntities.forEach {
query.upsertNewsResource(
id = it.id,
@ -123,7 +123,7 @@ class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatch
}
}
suspend fun insertOrIgnoreTopicCrossRefEntities(
override suspend fun insertOrIgnoreTopicCrossRefEntities(
newsResourceTopicCrossReferences: List<NewsResourceTopicCrossRef>,
) {
newsResourceTopicCrossReferences.forEach {
@ -137,7 +137,7 @@ class NewsResourceDao(db: NiaDatabase, private val dispatcher: CoroutineDispatch
/**
* Deletes rows in the db matching the specified [ids]
*/
suspend fun deleteNewsResources(ids: List<String>) {
override suspend fun deleteNewsResources(ids: List<String>) {
query.deleteNewsResources(ids)
}
}

@ -0,0 +1,43 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.database.dao
import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceEntity
import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceTopicCrossRef
import com.google.samples.apps.nowinandroid.core.database.model.PopulatedNewsResource
import kotlinx.coroutines.flow.Flow
interface NewsResourceDaoInterface {
fun getNewsResources(
useFilterTopicIds: Boolean = false,
filterTopicIds: Set<String> = emptySet(),
useFilterNewsIds: Boolean = false,
filterNewsIds: Set<String> = emptySet(),
): Flow<List<PopulatedNewsResource>>
fun getNewsResourceIds(
useFilterTopicIds: Boolean = false,
filterTopicIds: Set<String> = emptySet(),
useFilterNewsIds: Boolean = false,
filterNewsIds: Set<String> = emptySet(),
): Flow<List<String>>
suspend fun insertOrIgnoreNewsResources(entities: List<NewsResourceEntity>): List<Long>
suspend fun upsertNewsResources(newsResourceEntities: List<NewsResourceEntity>)
suspend fun insertOrIgnoreTopicCrossRefEntities(newsResourceTopicCrossReferences: List<NewsResourceTopicCrossRef>)
suspend fun deleteNewsResources(ids: List<String>)
}

@ -28,9 +28,9 @@ import kotlinx.coroutines.flow.map
/**
* DAO for [NewsResourceFtsEntity] access.
*/
class NewsResourceFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
class NewsResourceFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) : NewsResourceFtsDaoInterface {
private val dbQuery = db.newsResourceFtsQueries
suspend fun insertAll(newsResources: List<NewsResourceFtsEntity>) {
override suspend fun insertAll(newsResources: List<NewsResourceFtsEntity>) {
newsResources.forEach {
dbQuery.insert(
news_resource_id = it.newsResourceId,
@ -40,13 +40,13 @@ class NewsResourceFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispa
}
}
fun searchAllNewsResources(query: String): Flow<List<String>> {
override fun searchAllNewsResources(query: String): Flow<List<String>> {
return dbQuery.searchAllNewsResources(query)
.asFlow()
.mapToList(dispatcher)
}
fun getCount(): Flow<Int> {
override fun getCount(): Flow<Int> {
return dbQuery.getCount()
.asFlow()
.mapToOneNotNull(dispatcher)

@ -14,10 +14,13 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.datastore
package com.google.samples.apps.nowinandroid.core.database.dao
enum class ThemeBrandProto {
THEME_BRAND_UNSPECIFIED,
THEME_BRAND_DEFAULT,
THEME_BRAND_ANDROID,
import com.google.samples.apps.nowinandroid.core.database.model.NewsResourceFtsEntity
import kotlinx.coroutines.flow.Flow
interface NewsResourceFtsDaoInterface {
suspend fun insertAll(newsResources: List<NewsResourceFtsEntity>)
fun searchAllNewsResources(query: String): Flow<List<String>>
fun getCount(): Flow<Int>
}

@ -28,11 +28,11 @@ import kotlinx.datetime.Instant
/**
* DAO for [RecentSearchQueryEntity] access
*/
class RecentSearchQueryDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
class RecentSearchQueryDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) : RecentSearchQueryDaoInterface {
private val query = db.recentSearchQueryQueries
fun getRecentSearchQueryEntities(limit: Int): Flow<List<RecentSearchQueryEntity>> {
override fun getRecentSearchQueryEntities(limit: Int): Flow<List<RecentSearchQueryEntity>> {
return query.getRecentSearchQueryEntities(limit.toLong()) { query, timestamp ->
RecentSearchQueryEntity(
query = query,
@ -43,7 +43,7 @@ class RecentSearchQueryDao(db: NiaDatabase, private val dispatcher: CoroutineDis
.mapToList(dispatcher)
}
suspend fun insertOrReplaceRecentSearchQuery(recentSearchQuery: RecentSearchQueryEntity) {
override suspend fun insertOrReplaceRecentSearchQuery(recentSearchQuery: RecentSearchQueryEntity) {
query.insertOrReplaceRecentSearchQuery(
recent_search_query = Recent_search_query(
query = recentSearchQuery.query,
@ -52,7 +52,7 @@ class RecentSearchQueryDao(db: NiaDatabase, private val dispatcher: CoroutineDis
)
}
suspend fun clearRecentSearchQueries() {
override suspend fun clearRecentSearchQueries() {
query.clearRecentSearchQueries()
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2022 The Android Open Source Project
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,17 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
alias(libs.plugins.nowinandroid.android.library)
alias(libs.plugins.nowinandroid.android.hilt)
}
android {
namespace = "com.google.samples.apps.nowinandroid.core.datastore.test"
}
package com.google.samples.apps.nowinandroid.core.database.dao
import com.google.samples.apps.nowinandroid.core.database.model.RecentSearchQueryEntity
import kotlinx.coroutines.flow.Flow
dependencies {
implementation(libs.hilt.android.testing)
implementation(projects.core.common)
implementation(projects.core.datastore)
interface RecentSearchQueryDaoInterface {
fun getRecentSearchQueryEntities(limit: Int): Flow<List<RecentSearchQueryEntity>>
suspend fun insertOrReplaceRecentSearchQuery(recentSearchQuery: RecentSearchQueryEntity)
suspend fun clearRecentSearchQueries()
}

@ -29,11 +29,11 @@ import kotlinx.coroutines.flow.map
* DAO for [TopicEntity] access
*/
class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) : TopicDaoInterface {
private val query = db.topicsQueries
fun getTopicEntity(topicId: String): Flow<TopicEntity> {
override fun getTopicEntity(topicId: String): Flow<TopicEntity> {
return query.getTopicEntity(topicId) { id, name, shortDescription, longDescription, url, imageUrl ->
TopicEntity(
id = id,
@ -48,7 +48,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
.mapToOne(dispatcher)
}
fun getTopicEntities(): Flow<List<TopicEntity>> {
override fun getTopicEntities(): Flow<List<TopicEntity>> {
return query.getOneOffTopicEntities { id, name, shortDescription, longDescription, url, imageUrl ->
TopicEntity(
id = id,
@ -63,7 +63,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
.mapToList(dispatcher)
}
suspend fun getOneOffTopicEntities(): List<TopicEntity> {
override suspend fun getOneOffTopicEntities(): List<TopicEntity> {
// TODO: Use flow?
return query.getOneOffTopicEntities { id, name, shortDescription, longDescription, url, imageUrl ->
TopicEntity(
@ -77,7 +77,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
}.executeAsList()
}
fun getTopicEntities(ids: Set<String>): Flow<List<TopicEntity>> {
override fun getTopicEntities(ids: Set<String>): Flow<List<TopicEntity>> {
return query.getTopicEntities { id, name, shortDescription, longDescription, url, imageUrl ->
TopicEntity(
id = id,
@ -98,7 +98,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
/**
* Inserts [topicEntities] into the db if they don't exist, and ignores those that do
*/
suspend fun insertOrIgnoreTopics(topicEntities: List<TopicEntity>): List<Long> {
override suspend fun insertOrIgnoreTopics(topicEntities: List<TopicEntity>): List<Long> {
topicEntities.map {
query.insertOrIgnoreTopic(
id = it.id,
@ -116,7 +116,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
/**
* Inserts or updates [entities] in the db under the specified primary keys
*/
suspend fun upsertTopics(entities: List<TopicEntity>) {
override suspend fun upsertTopics(entities: List<TopicEntity>) {
entities.forEach {
query.upsertTopic(
id = it.id,
@ -132,7 +132,7 @@ class TopicDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
/**
* Deletes rows in the db matching the specified [ids]
*/
suspend fun deleteTopics(ids: List<String>) {
override suspend fun deleteTopics(ids: List<String>) {
query.deleteTopics(ids)
}
}

@ -0,0 +1,30 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.database.dao
import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity
import kotlinx.coroutines.flow.Flow
interface TopicDaoInterface {
fun getTopicEntity(topicId: String): Flow<TopicEntity>
fun getTopicEntities(): Flow<List<TopicEntity>>
suspend fun getOneOffTopicEntities(): List<TopicEntity>
fun getTopicEntities(ids: Set<String>): Flow<List<TopicEntity>>
suspend fun insertOrIgnoreTopics(topicEntities: List<TopicEntity>): List<Long>
suspend fun upsertTopics(entities: List<TopicEntity>)
suspend fun deleteTopics(ids: List<String>)
}

@ -28,11 +28,11 @@ import kotlinx.coroutines.flow.map
/**
* DAO for [TopicFtsEntity] access.
*/
class TopicFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) {
class TopicFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher) : TopicFtsDaoInterface {
private val dbQuery = db.topicFtsQueries
suspend fun insertAll(topics: List<TopicFtsEntity>) {
override suspend fun insertAll(topics: List<TopicFtsEntity>) {
topics.forEach {
dbQuery.insert(
topic_id = it.topicId,
@ -43,7 +43,7 @@ class TopicFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher)
}
}
fun searchAllTopics(query: String): Flow<List<String>> {
override fun searchAllTopics(query: String): Flow<List<String>> {
return dbQuery.searchAllTopics(query) {
it.orEmpty()
}
@ -51,7 +51,7 @@ class TopicFtsDao(db: NiaDatabase, private val dispatcher: CoroutineDispatcher)
.mapToList(dispatcher)
}
fun getCount(): Flow<Int> {
override fun getCount(): Flow<Int> {
return dbQuery.getCount()
.asFlow()
.mapToOne(dispatcher)

@ -14,11 +14,13 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.datastore
package com.google.samples.apps.nowinandroid.core.database.dao
enum class DarkThemeConfigProto {
DARK_THEME_CONFIG_UNSPECIFIED,
DARK_THEME_CONFIG_FOLLOW_SYSTEM,
DARK_THEME_CONFIG_LIGHT,
DARK_THEME_CONFIG_DARK,
import com.google.samples.apps.nowinandroid.core.database.model.TopicFtsEntity
import kotlinx.coroutines.flow.Flow
interface TopicFtsDaoInterface {
suspend fun insertAll(topics: List<TopicFtsEntity>)
fun searchAllTopics(query: String): Flow<List<String>>
fun getCount(): Flow<Int>
}

@ -1,50 +0,0 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
alias(libs.plugins.nowinandroid.kmp.library)
alias(libs.plugins.protobuf)
id("kotlinx-serialization")
}
android {
namespace = "com.google.samples.apps.nowinandroid.core.datastore.proto"
}
// Setup protobuf configuration, generating lite Java and Kotlin classes
protobuf {
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
generateProtoTasks {
all().forEach { task ->
task.builtins {
register("kotlin") {
option("lite")
}
}
}
}
}
kotlin {
sourceSets {
commonMain.dependencies {
api(libs.protobuf.kotlin.lite)
implementation(libs.kotlinx.serialization.core)
}
}
}

@ -1,53 +0,0 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.datastore
import com.google.samples.apps.nowinandroid.core.datastore.DarkThemeConfigProto.DARK_THEME_CONFIG_FOLLOW_SYSTEM
import com.google.samples.apps.nowinandroid.core.datastore.ThemeBrandProto.THEME_BRAND_UNSPECIFIED
import kotlinx.serialization.Serializable
// A lot of workaround brought by Proto
@Serializable
data class UserPreferences(
val topicChangeListVersion: Int,
val authorChangeListVersion: Int,
val newsResourceChangeListVersion: Int,
val hasDoneIntToStringIdMigration: Boolean,
val hasDoneListToMapMigration: Boolean,
val followedTopicIds: Set<String> = emptySet(),
val followedAuthorIds: Set<String> = emptySet(),
val bookmarkedNewsResourceIds: Set<String> = emptySet(),
val viewedNewsResourceIds: Set<String> = emptySet(),
val themeBrand: ThemeBrandProto,
val darkThemeConfig: DarkThemeConfigProto,
val shouldHideOnboarding: Boolean,
val useDynamicColor: Boolean,
) {
companion object {
val DEFAULT = UserPreferences(
topicChangeListVersion = 0,
authorChangeListVersion = 0,
newsResourceChangeListVersion = 0,
hasDoneIntToStringIdMigration = false,
hasDoneListToMapMigration = false,
themeBrand = THEME_BRAND_UNSPECIFIED,
darkThemeConfig = DARK_THEME_CONFIG_FOLLOW_SYSTEM,
shouldHideOnboarding = false,
useDynamicColor = false,
)
}
}

@ -1,27 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
option java_package = "com.google.samples.apps.nowinandroid.core.datastore";
option java_multiple_files = true;
enum DarkThemeConfigProto {
DARK_THEME_CONFIG_UNSPECIFIED = 0;
DARK_THEME_CONFIG_FOLLOW_SYSTEM = 1;
DARK_THEME_CONFIG_LIGHT = 2;
DARK_THEME_CONFIG_DARK = 3;
}

@ -1,26 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
option java_package = "com.google.samples.apps.nowinandroid.core.datastore";
option java_multiple_files = true;
enum ThemeBrandProto {
THEME_BRAND_UNSPECIFIED = 0;
THEME_BRAND_DEFAULT = 1;
THEME_BRAND_ANDROID = 2;
}

@ -1,53 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
import "com/google/samples/apps/nowinandroid/data/dark_theme_config.proto";
import "com/google/samples/apps/nowinandroid/data/theme_brand.proto";
option java_package = "com.google.samples.apps.nowinandroid.core.datastore";
option java_multiple_files = true;
message UserPreferences {
reserved 2;
repeated int32 deprecated_int_followed_topic_ids = 1;
int32 topicChangeListVersion = 3;
int32 authorChangeListVersion = 4;
int32 newsResourceChangeListVersion = 6;
repeated int32 deprecated_int_followed_author_ids = 7;
bool has_done_int_to_string_id_migration = 8;
repeated string deprecated_followed_topic_ids = 9;
repeated string deprecated_followed_author_ids = 10;
repeated string deprecated_bookmarked_news_resource_ids = 11;
bool has_done_list_to_map_migration = 12;
// Each map is used to store a set of string IDs. The bool has no meaning, but proto3 doesn't
// have a Set type so this is the closest we can get to a Set.
map<string, bool> followed_topic_ids = 13;
map<string, bool> followed_author_ids = 14;
map<string, bool> bookmarked_news_resource_ids = 15;
map<string, bool> viewed_news_resource_ids = 20;
ThemeBrandProto theme_brand = 16;
DarkThemeConfigProto dark_theme_config = 17;
bool should_hide_onboarding = 18;
bool use_dynamic_color = 19;
// NEXT AVAILABLE ID: 21
}

@ -1,3 +0,0 @@
# :core:datastore-test module
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore_test.png)

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest />

@ -1,61 +0,0 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.core.datastore.test
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferencesSerializer
import com.google.samples.apps.nowinandroid.core.datastore.di.DataStoreModule
import com.google.samples.apps.nowinandroid.core.di.ApplicationScope
import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import kotlinx.coroutines.CoroutineScope
import org.junit.rules.TemporaryFolder
import javax.inject.Singleton
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [DataStoreModule::class],
)
internal object TestDataStoreModule {
@Provides
@Singleton
fun providesUserPreferencesDataStore(
@ApplicationScope scope: CoroutineScope,
userPreferencesSerializer: UserPreferencesSerializer,
tmpFolder: TemporaryFolder,
): DataStore<UserPreferences> =
tmpFolder.testUserPreferencesDataStore(
coroutineScope = scope,
userPreferencesSerializer = userPreferencesSerializer,
)
}
fun TemporaryFolder.testUserPreferencesDataStore(
coroutineScope: CoroutineScope,
userPreferencesSerializer: UserPreferencesSerializer = UserPreferencesSerializer(),
) = DataStoreFactory.create(
serializer = userPreferencesSerializer,
scope = coroutineScope,
) {
newFile("user_preferences_test.pb")
}

@ -42,7 +42,6 @@ kotlin {
implementation(libs.kotlinx.serialization.core)
implementation(projects.core.model)
implementation(projects.core.common)
implementation(projects.core.datastoreProto)
}
commonTest.dependencies {
implementation(libs.multiplatform.settings.test)

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.core.designsystem
import android.R.string
import androidx.activity.ComponentActivity
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable

@ -143,8 +143,8 @@ fun NiaGradientBackground(
* Multipreview annotation that represents light and dark themes. Add this annotation to a
* composable to render the both themes.
*/
//@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme")
//@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme")
// @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme")
// @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme")
@Preview
annotation class ThemePreviews

@ -18,7 +18,6 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
@ -31,7 +30,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import org.jetbrains.compose.ui.tooling.preview.Preview
/**
* Now in Android filter chip with included leading checked icon as well as text content slot.

@ -49,7 +49,7 @@ fun DynamicAsyncImage(
imageLoader: ImageLoader,
contentDescription: String?,
modifier: Modifier = Modifier,
//TODO Use Compose resources to present a placeholder
// TODO Use Compose resources to present a placeholder
// placeholder: Painter = painterResource(R.drawable.core_designsystem_ic_placeholder_default),
) {
val iconTint = LocalTintTheme.current.iconTint

@ -236,7 +236,7 @@ fun NiaTheme(
}
}
//@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
//fun supportsDynamicTheming() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
// @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
// fun supportsDynamicTheming() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
// A workaround for the dynamic theming support in Compose Multiplatform
fun supportsDynamicTheming() = false

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.core.testing.di
import com.google.samples.apps.nowinandroid.core.di.DispatchersComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.TestDispatcher
import me.tatarka.inject.annotations.Component

@ -45,8 +45,6 @@ include(":core:data")
include(":core:data-test")
include(":core:database")
include(":core:datastore")
include(":core:datastore-proto")
include(":core:datastore-test")
include(":core:designsystem")
include(":core:domain")
include(":core:model")

Loading…
Cancel
Save