From 3fc345230435e8970138028c59be9a08d3667704 Mon Sep 17 00:00:00 2001 From: lihenggui Date: Mon, 11 Mar 2024 14:30:29 -0700 Subject: [PATCH] WIP: Make :core:data as the multiplatform module --- core/data/build.gradle.kts | 39 +++++++++----- .../{main => androidMain}/AndroidManifest.xml | 0 .../di/PlatformDependentDataModule.android.kt | 35 +++++++++++++ .../util/ConnectivityManagerNetworkMonitor.kt | 10 ++-- .../data/util/TimeZoneBroadcastMonitor.kt} | 28 +++------- .../nowinandroid/core/data/SyncUtilities.kt | 11 ++-- .../nowinandroid/core/data/di/DataModule.kt | 51 +++++++------------ .../data/di/PlatformDependentDataModule.kt | 29 +++++++++++ .../di/UserNewsResourceRepositoryModule.kt | 15 +++--- .../core/data/model/NewsResource.kt | 0 .../core/data/model/RecentSearchQuery.kt | 0 .../nowinandroid/core/data/model/Topic.kt | 0 .../data/repository/AnalyticsExtensions.kt | 0 .../CompositeUserNewsResourceRepository.kt | 5 +- .../DefaultRecentSearchRepository.kt | 5 +- .../DefaultSearchContentsRepository.kt | 11 ++-- .../core/data/repository/NewsRepository.kt | 0 .../repository/OfflineFirstNewsRepository.kt | 5 +- .../OfflineFirstTopicsRepository.kt | 5 +- .../OfflineFirstUserDataRepository.kt | 7 ++- .../data/repository/RecentSearchRepository.kt | 0 .../repository/SearchContentsRepository.kt | 0 .../core/data/repository/TopicsRepository.kt | 0 .../data/repository/UserDataRepository.kt | 0 .../repository/UserNewsResourceRepository.kt | 0 .../core/data/util/NetworkMonitor.kt | 0 .../core/data/util/SyncManager.kt | 0 .../core/data/util/TimeZoneMonitor.kt | 28 ++++++++++ ...CompositeUserNewsResourceRepositoryTest.kt | 2 +- .../core/data/UserNewsResourceTest.kt | 6 +-- .../core/data/model/NetworkEntityKtTest.kt | 2 +- .../OfflineFirstNewsRepositoryTest.kt | 0 .../OfflineFirstTopicsRepositoryTest.kt | 8 ++- .../OfflineFirstUserDataRepositoryTest.kt | 8 ++- .../core/data/repository/TestSynchronizer.kt | 0 .../data/testdoubles/TestNewsResourceDao.kt | 0 .../testdoubles/TestNiaNetworkDataSource.kt | 0 .../core/data/testdoubles/TestTopicDao.kt | 0 .../model/PopulatedNewsResourceKtTest.kt | 0 .../di/PlatformDependentDataModule.jvm.kt | 48 +++++++++++++++++ .../di/PlatformDependentDataModule.native.kt | 48 +++++++++++++++++ .../datastore/NiaPreferencesDataSource.kt | 45 ++++++++++++---- 42 files changed, 321 insertions(+), 130 deletions(-) rename core/data/src/{main => androidMain}/AndroidManifest.xml (100%) create mode 100644 core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt rename core/data/src/{main => androidMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt (92%) rename core/data/src/{main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt => androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt} (80%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt (96%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt (61%) create mode 100644 core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt (78%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NewsResource.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/model/RecentSearchQuery.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/model/Topic.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/AnalyticsExtensions.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt (96%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt (94%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt (91%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt (98%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt (96%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt (95%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/RecentSearchRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/SearchContentsRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TopicsRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserDataRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserNewsResourceRepository.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/util/NetworkMonitor.kt (100%) rename core/data/src/{main => commonMain}/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SyncManager.kt (100%) create mode 100644 core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt (99%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt (97%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt (99%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt (100%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt (98%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt (98%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TestSynchronizer.kt (100%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt (100%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNiaNetworkDataSource.kt (100%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestTopicDao.kt (100%) rename core/data/src/{test => commonTest}/kotlin/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt (100%) create mode 100644 core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt create mode 100644 core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 142637ff9..0d21ea909 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -14,9 +14,9 @@ * limitations under the License. */ plugins { - alias(libs.plugins.nowinandroid.android.library) + alias(libs.plugins.nowinandroid.kmp.library) + alias(libs.plugins.nowinandroid.kotlin.inject) alias(libs.plugins.nowinandroid.android.library.jacoco) - alias(libs.plugins.nowinandroid.android.hilt) id("kotlinx-serialization") } @@ -30,17 +30,30 @@ android { } } -dependencies { - api(projects.core.common) - api(projects.core.database) - api(projects.core.datastore) - api(projects.core.network) +kotlin { + sourceSets { + commonMain.dependencies { + api(projects.core.common) + api(projects.core.database) + api(projects.core.datastore) + api(projects.core.network) - implementation(projects.core.analytics) - implementation(projects.core.notifications) + implementation(projects.core.analytics) + implementation(projects.core.notifications) + } + + commonTest.dependencies { + implementation(libs.kotlin.test) + implementation(libs.kotlinx.coroutines.test) + implementation(libs.kotlinx.serialization.json) +// implementation(projects.core.datastoreTest) +// implementation(projects.core.testing) + } - testImplementation(libs.kotlinx.coroutines.test) - testImplementation(libs.kotlinx.serialization.json) - testImplementation(projects.core.datastoreTest) - testImplementation(projects.core.testing) + androidMain.dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.tracing.ktx) + } + } } + diff --git a/core/data/src/main/AndroidManifest.xml b/core/data/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/data/src/main/AndroidManifest.xml rename to core/data/src/androidMain/AndroidManifest.xml diff --git a/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt new file mode 100644 index 000000000..87f01db64 --- /dev/null +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.android.kt @@ -0,0 +1,35 @@ +/* + * 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.data.di + +import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import me.tatarka.inject.annotations.Component +import me.tatarka.inject.annotations.Provides + +@Component +internal actual abstract class PlatformDependentDataModule { + @Provides + internal actual fun bindsNetworkMonitor(): NetworkMonitor { + TODO() + } + + @Provides + internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { + TODO() + } +} diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt similarity index 92% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt rename to core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt index e9599c555..bb653dd40 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ConnectivityManagerNetworkMonitor.kt @@ -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. @@ -26,15 +26,15 @@ import android.net.NetworkRequest.Builder import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.core.content.getSystemService -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject -internal class ConnectivityManagerNetworkMonitor @Inject constructor( - @ApplicationContext private val context: Context, +@Inject +internal class ConnectivityManagerNetworkMonitor( + private val context: Context, ) : NetworkMonitor { override val isOnline: Flow = callbackFlow { val connectivityManager = context.getSystemService() diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt similarity index 80% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt rename to core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt index 031bc9388..27fb21eda 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt +++ b/core/data/src/androidMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneBroadcastMonitor.kt @@ -23,14 +23,9 @@ import android.content.IntentFilter import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.tracing.trace -import com.google.samples.apps.nowinandroid.core.network.Dispatcher -import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO -import com.google.samples.apps.nowinandroid.core.network.di.ApplicationScope -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.CoroutineDispatcher +import com.google.samples.apps.nowinandroid.core.di.IODispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow @@ -40,23 +35,14 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.shareIn import kotlinx.datetime.TimeZone import kotlinx.datetime.toKotlinTimeZone +import me.tatarka.inject.annotations.Inject import java.time.ZoneId -import javax.inject.Inject -import javax.inject.Singleton -/** - * Utility for reporting current timezone the device has set. - * It always emits at least once with default setting and then for each TZ change. - */ -interface TimeZoneMonitor { - val currentTimeZone: Flow -} - -@Singleton -internal class TimeZoneBroadcastMonitor @Inject constructor( - @ApplicationContext private val context: Context, - @ApplicationScope appScope: CoroutineScope, - @Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher, +@Inject +internal class TimeZoneBroadcastMonitor( + private val context: Context, + appScope: CoroutineScope, + private val ioDispatcher: IODispatcher, ) : TimeZoneMonitor { override val currentTimeZone: SharedFlow = diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt similarity index 96% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt index 5d069dbaf..9ee73b11a 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/SyncUtilities.kt @@ -16,7 +16,7 @@ package com.google.samples.apps.nowinandroid.core.data -import android.util.Log +import co.touchlab.kermit.Logger import com.google.samples.apps.nowinandroid.core.datastore.ChangeListVersions import com.google.samples.apps.nowinandroid.core.network.model.NetworkChangeList import kotlinx.coroutines.flow.Flow @@ -59,11 +59,10 @@ private suspend fun suspendRunCatching(block: suspend () -> T): Result = } catch (cancellationException: CancellationException) { throw cancellationException } catch (exception: Exception) { - Log.i( - "suspendRunCatching", - "Failed to evaluate a suspendRunCatchingBlock. Returning failure Result", - exception, - ) + Logger.i { + "suspendRunCatching" + + "Failed to evaluate a suspendRunCatchingBlock. Returning failure Result" + } Result.failure(exception) } diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt similarity index 61% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt index fa4bde8b8..496f08e4d 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/DataModule.kt @@ -26,49 +26,34 @@ import com.google.samples.apps.nowinandroid.core.data.repository.RecentSearchRep import com.google.samples.apps.nowinandroid.core.data.repository.SearchContentsRepository import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository -import com.google.samples.apps.nowinandroid.core.data.util.ConnectivityManagerNetworkMonitor -import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor -import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneBroadcastMonitor -import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent +import me.tatarka.inject.annotations.Component +import me.tatarka.inject.annotations.Provides -@Module -@InstallIn(SingletonComponent::class) +@Component abstract class DataModule { - @Binds - internal abstract fun bindsTopicRepository( + @Provides + internal fun bindsTopicRepository( topicsRepository: OfflineFirstTopicsRepository, - ): TopicsRepository + ): TopicsRepository = topicsRepository - @Binds - internal abstract fun bindsNewsResourceRepository( + @Provides + internal fun bindsNewsResourceRepository( newsRepository: OfflineFirstNewsRepository, - ): NewsRepository + ): NewsRepository = newsRepository - @Binds - internal abstract fun bindsUserDataRepository( + @Provides + internal fun bindsUserDataRepository( userDataRepository: OfflineFirstUserDataRepository, - ): UserDataRepository + ): UserDataRepository = userDataRepository - @Binds - internal abstract fun bindsRecentSearchRepository( + @Provides + internal fun bindsRecentSearchRepository( recentSearchRepository: DefaultRecentSearchRepository, - ): RecentSearchRepository + ): RecentSearchRepository = recentSearchRepository - @Binds - internal abstract fun bindsSearchContentsRepository( + @Provides + internal fun bindsSearchContentsRepository( searchContentsRepository: DefaultSearchContentsRepository, - ): SearchContentsRepository - - @Binds - internal abstract fun bindsNetworkMonitor( - networkMonitor: ConnectivityManagerNetworkMonitor, - ): NetworkMonitor - - @Binds - internal abstract fun binds(impl: TimeZoneBroadcastMonitor): TimeZoneMonitor + ): SearchContentsRepository = searchContentsRepository } diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt new file mode 100644 index 000000000..d4c6409b7 --- /dev/null +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.kt @@ -0,0 +1,29 @@ +/* + * 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.data.di + +import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import me.tatarka.inject.annotations.Provides + +internal expect abstract class PlatformDependentDataModule { + @Provides + internal fun bindsNetworkMonitor(): NetworkMonitor + + @Provides + internal fun bindsTimeZoneMonitor(): TimeZoneMonitor +} diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt similarity index 78% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt index 7f4e27b41..59293fa9d 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/UserNewsResourceRepositoryModule.kt @@ -18,16 +18,13 @@ package com.google.samples.apps.nowinandroid.core.data.di import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent +import me.tatarka.inject.annotations.Component +import me.tatarka.inject.annotations.Provides -@Module -@InstallIn(SingletonComponent::class) -internal interface UserNewsResourceRepositoryModule { - @Binds +@Component +internal abstract class UserNewsResourceRepositoryModule { + @Provides fun bindsUserNewsResourceRepository( userDataRepository: CompositeUserNewsResourceRepository, - ): UserNewsResourceRepository + ): UserNewsResourceRepository = userDataRepository } diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NewsResource.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NewsResource.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NewsResource.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NewsResource.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/RecentSearchQuery.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/RecentSearchQuery.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/RecentSearchQuery.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/RecentSearchQuery.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/Topic.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/Topic.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/model/Topic.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/model/Topic.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/AnalyticsExtensions.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/AnalyticsExtensions.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/AnalyticsExtensions.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/AnalyticsExtensions.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt similarity index 96% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt index 64e02e7d9..a02967bf2 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/CompositeUserNewsResourceRepository.kt @@ -24,13 +24,14 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject /** * Implements a [UserNewsResourceRepository] by combining a [NewsRepository] with a * [UserDataRepository]. */ -class CompositeUserNewsResourceRepository @Inject constructor( +@Inject +class CompositeUserNewsResourceRepository( val newsRepository: NewsRepository, val userDataRepository: UserDataRepository, ) : UserNewsResourceRepository { diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt similarity index 94% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt index 32239362d..62b8691da 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultRecentSearchRepository.kt @@ -23,9 +23,10 @@ import com.google.samples.apps.nowinandroid.core.database.model.RecentSearchQuer import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.datetime.Clock -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject -internal class DefaultRecentSearchRepository @Inject constructor( +@Inject +internal class DefaultRecentSearchRepository( private val recentSearchQueryDao: RecentSearchQueryDao, ) : RecentSearchRepository { override suspend fun insertOrReplaceRecentSearch(searchQuery: String) { diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt similarity index 91% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt index 3bacb8a14..7b6b48e8d 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/DefaultSearchContentsRepository.kt @@ -23,10 +23,8 @@ import com.google.samples.apps.nowinandroid.core.database.dao.TopicFtsDao import com.google.samples.apps.nowinandroid.core.database.model.PopulatedNewsResource import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel import com.google.samples.apps.nowinandroid.core.database.model.asFtsEntity +import com.google.samples.apps.nowinandroid.core.di.IODispatcher import com.google.samples.apps.nowinandroid.core.model.data.SearchResult -import com.google.samples.apps.nowinandroid.core.network.Dispatcher -import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -34,14 +32,15 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.withContext -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject -internal class DefaultSearchContentsRepository @Inject constructor( +@Inject +internal class DefaultSearchContentsRepository( private val newsResourceDao: NewsResourceDao, private val newsResourceFtsDao: NewsResourceFtsDao, private val topicDao: TopicDao, private val topicFtsDao: TopicFtsDao, - @Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher, + private val ioDispatcher: IODispatcher, ) : SearchContentsRepository { override suspend fun populateFtsData() { diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt similarity index 98% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt index d33c904e5..02c75c04a 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepository.kt @@ -35,7 +35,7 @@ import com.google.samples.apps.nowinandroid.core.notifications.Notifier import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject // Heuristic value to optimize for serialization and deserialization cost on client and server // for each news resource batch. @@ -45,7 +45,8 @@ private const val SYNC_BATCH_SIZE = 40 * Disk storage backed implementation of the [NewsRepository]. * Reads are exclusively from local storage to support offline access. */ -internal class OfflineFirstNewsRepository @Inject constructor( +@Inject +internal class OfflineFirstNewsRepository( private val niaPreferencesDataSource: NiaPreferencesDataSource, private val newsResourceDao: NewsResourceDao, private val topicDao: TopicDao, diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt similarity index 96% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt index 5c8cecce8..864be34e6 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepository.kt @@ -28,13 +28,14 @@ import com.google.samples.apps.nowinandroid.core.network.NiaNetworkDataSource import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject /** * Disk storage backed implementation of the [TopicsRepository]. * Reads are exclusively from local storage to support offline access. */ -internal class OfflineFirstTopicsRepository @Inject constructor( +@Inject +internal class OfflineFirstTopicsRepository( private val topicDao: TopicDao, private val network: NiaNetworkDataSource, ) : TopicsRepository { diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt similarity index 95% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt index c0b1bcc33..f5c65440e 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepository.kt @@ -16,16 +16,16 @@ package com.google.samples.apps.nowinandroid.core.data.repository -import androidx.annotation.VisibleForTesting import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsHelper import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferencesDataSource 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 kotlinx.coroutines.flow.Flow -import javax.inject.Inject +import me.tatarka.inject.annotations.Inject -internal class OfflineFirstUserDataRepository @Inject constructor( +@Inject +internal class OfflineFirstUserDataRepository( private val niaPreferencesDataSource: NiaPreferencesDataSource, private val analyticsHelper: AnalyticsHelper, ) : UserDataRepository { @@ -33,7 +33,6 @@ internal class OfflineFirstUserDataRepository @Inject constructor( override val userData: Flow = niaPreferencesDataSource.userData - @VisibleForTesting override suspend fun setFollowedTopicIds(followedTopicIds: Set) = niaPreferencesDataSource.setFollowedTopicIds(followedTopicIds) diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/RecentSearchRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/RecentSearchRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/RecentSearchRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/RecentSearchRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/SearchContentsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/SearchContentsRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/SearchContentsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/SearchContentsRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TopicsRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TopicsRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TopicsRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TopicsRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserDataRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserDataRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserDataRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserDataRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserNewsResourceRepository.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserNewsResourceRepository.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserNewsResourceRepository.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/UserNewsResourceRepository.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/NetworkMonitor.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/NetworkMonitor.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/NetworkMonitor.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/NetworkMonitor.kt diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SyncManager.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SyncManager.kt similarity index 100% rename from core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SyncManager.kt rename to core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SyncManager.kt diff --git a/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt new file mode 100644 index 000000000..92611d6a5 --- /dev/null +++ b/core/data/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/data/util/TimeZoneMonitor.kt @@ -0,0 +1,28 @@ +/* + * 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.data.util + +import kotlinx.coroutines.flow.Flow +import kotlinx.datetime.TimeZone + +/** + * Utility for reporting current timezone the device has set. + * It always emits at least once with default setting and then for each TZ change. + */ +interface TimeZoneMonitor { + val currentTimeZone: Flow +} diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt similarity index 99% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt index 05811f4be..f4786485c 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt +++ b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/CompositeUserNewsResourceRepositoryTest.kt @@ -27,7 +27,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserDat import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant -import org.junit.Test +import kotlin.test.Test import kotlin.test.assertEquals class CompositeUserNewsResourceRepositoryTest { diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt similarity index 97% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt index c7dfd99d0..0623a4632 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt +++ b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/UserNewsResourceTest.kt @@ -24,9 +24,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.UserData import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import kotlinx.datetime.Clock -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class UserNewsResourceTest { diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt similarity index 99% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt index 7dd251a99..da64b9ee8 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt +++ b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/model/NetworkEntityKtTest.kt @@ -20,7 +20,7 @@ import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResour import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResourceExpanded import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic import kotlinx.datetime.Instant -import org.junit.Test +import kotlin.test.Test import kotlin.test.assertEquals class NetworkEntityKtTest { diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstNewsRepositoryTest.kt diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt similarity index 98% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt index 3bd314eae..215caeb9b 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt +++ b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstTopicsRepositoryTest.kt @@ -32,10 +32,8 @@ 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 class OfflineFirstTopicsRepositoryTest { @@ -55,7 +53,7 @@ class OfflineFirstTopicsRepositoryTest { @get:Rule val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before + @BeforeTest fun setup() { topicDao = TestTopicDao() network = TestNiaNetworkDataSource() diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt similarity index 98% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt index 27e86f2f4..be4f12e56 100644 --- a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt +++ b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/OfflineFirstUserDataRepositoryTest.kt @@ -27,10 +27,8 @@ import kotlinx.coroutines.flow.map 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.assertFalse import kotlin.test.assertTrue @@ -48,7 +46,7 @@ class OfflineFirstUserDataRepositoryTest { @get:Rule val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build() - @Before + @BeforeTest fun setup() { niaPreferencesDataSource = NiaPreferencesDataSource( tmpFolder.testUserPreferencesDataStore(testScope), diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TestSynchronizer.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TestSynchronizer.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TestSynchronizer.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/repository/TestSynchronizer.kt diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNewsResourceDao.kt diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNiaNetworkDataSource.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNiaNetworkDataSource.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNiaNetworkDataSource.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestNiaNetworkDataSource.kt diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestTopicDao.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestTopicDao.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestTopicDao.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/data/testdoubles/TestTopicDao.kt diff --git a/core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt b/core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt similarity index 100% rename from core/data/src/test/kotlin/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt rename to core/data/src/commonTest/kotlin/com/google/samples/apps/nowinandroid/core/database/model/PopulatedNewsResourceKtTest.kt diff --git a/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt b/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt new file mode 100644 index 000000000..df3acd1a3 --- /dev/null +++ b/core/data/src/jvmMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.jvm.kt @@ -0,0 +1,48 @@ +/* + * 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.data.di + +import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import me.tatarka.inject.annotations.Component +import me.tatarka.inject.annotations.Provides + +/** + * JVM module that provides platform dependent data + * Leave empty for now + */ +@Component +internal actual abstract class PlatformDependentDataModule { + @Provides + internal actual fun bindsNetworkMonitor(): NetworkMonitor { + return object : NetworkMonitor { + override val isOnline: Flow + get() = flowOf(true) + } + } + + @Provides + internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return object : TimeZoneMonitor { + override val currentTimeZone: Flow + get() = flowOf(TimeZone.UTC) + } + } +} diff --git a/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt b/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt new file mode 100644 index 000000000..1600ad86b --- /dev/null +++ b/core/data/src/nativeMain/kotlin/com/google/samples/apps/nowinandroid/core/data/di/PlatformDependentDataModule.native.kt @@ -0,0 +1,48 @@ +/* + * 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.data.di + +import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor +import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import me.tatarka.inject.annotations.Component +import me.tatarka.inject.annotations.Provides + +/** + * Native module that provides platform dependent data + * Leave empty for now + */ +@Component +internal actual abstract class PlatformDependentDataModule { + @Provides + internal actual fun bindsNetworkMonitor(): NetworkMonitor { + return object : NetworkMonitor { + override val isOnline: Flow + get() = flowOf(true) + } + } + + @Provides + internal actual fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return object : TimeZoneMonitor { + override val currentTimeZone: Flow + get() = flowOf(TimeZone.UTC) + } + } +} diff --git a/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt index 078af8243..59ac0433d 100644 --- a/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/com/google/samples/apps/nowinandroid/core/datastore/NiaPreferencesDataSource.kt @@ -19,12 +19,15 @@ package com.google.samples.apps.nowinandroid.core.datastore import com.google.samples.apps.nowinandroid.core.di.IODispatcher 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.ExperimentalSettingsApi import com.russhwolf.settings.Settings import com.russhwolf.settings.serialization.decodeValue import com.russhwolf.settings.serialization.decodeValueOrNull import com.russhwolf.settings.serialization.encodeValue +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi @@ -37,7 +40,7 @@ class NiaPreferencesDataSource( ) { // FlowSettings did not support JS, use a workaround instead // https://github.com/russhwolf/multiplatform-settings/issues/139 - val userData = MutableStateFlow( + private val _userData = MutableStateFlow( settings.decodeValue( key = USER_DATA_KEY, serializer = UserPreferences.serializer(), @@ -48,12 +51,24 @@ class NiaPreferencesDataSource( ), ) + val userData: Flow = _userData.map { + UserData( + bookmarkedNewsResources = it.bookmarkedNewsResourceIds, + viewedNewsResources = it.viewedNewsResourceIds, + followedTopics = it.followedTopicIds, + themeBrand = it.themeBrand.toThemeBrand(), + darkThemeConfig = it.darkThemeConfig.toDarkThemeConfig(), + useDynamicColor = it.useDynamicColor, + shouldHideOnboarding = it.shouldHideOnboarding, + ) + } + suspend fun setFollowedTopicIds(topicIds: Set) = withContext(dispatcher) { val preference = settings.getUserPreference() .copy(followedTopicIds = topicIds) .updateShouldHideOnboardingIfNecessary() settings.putUserPreference(preference) - userData.value = preference + _userData.value = preference } suspend fun setTopicIdFollowed(topicId: String, followed: Boolean) = withContext(dispatcher) { @@ -68,28 +83,28 @@ class NiaPreferencesDataSource( ) .updateShouldHideOnboardingIfNecessary() settings.putUserPreference(newPreference) - userData.value = newPreference + _userData.value = newPreference } suspend fun setThemeBrand(themeBrand: ThemeBrand) = withContext(dispatcher) { val newPreference = settings.getUserPreference() .copy(themeBrand = themeBrand.toThemeBrandProto()) settings.putUserPreference(newPreference) - userData.value = newPreference + _userData.value = newPreference } suspend fun setDynamicColorPreference(useDynamicColor: Boolean) = withContext(dispatcher) { val newPreference = settings.getUserPreference() .copy(useDynamicColor = useDynamicColor) settings.putUserPreference(newPreference) - userData.value = newPreference + _userData.value = newPreference } suspend fun setDarkThemeConfig(darkThemeConfig: DarkThemeConfig) = withContext(dispatcher) { val newPreference = settings.getUserPreference() .copy(darkThemeConfig = darkThemeConfig.toDarkThemeConfigProto()) settings.putUserPreference(newPreference) - userData.value = newPreference + _userData.value = newPreference } suspend fun setNewsResourceBookmarked(newsResourceId: String, bookmarked: Boolean) = @@ -104,7 +119,7 @@ class NiaPreferencesDataSource( }, ) settings.putUserPreference(newPreferences) - userData.value = newPreferences + _userData.value = newPreferences } suspend fun setNewsResourceViewed(newsResourceId: String, viewed: Boolean) { @@ -123,7 +138,7 @@ class NiaPreferencesDataSource( }, ) settings.putUserPreference(newPreferences) - userData.value = newPreferences + _userData.value = newPreferences } suspend fun getChangeListVersions(): ChangeListVersions = withContext(dispatcher) { @@ -151,14 +166,14 @@ class NiaPreferencesDataSource( newsResourceChangeListVersion = updatedChangeListVersions.newsResourceVersion, ) settings.putUserPreference(updatedPreference) - userData.value = updatedPreference + _userData.value = updatedPreference } suspend fun setShouldHideOnboarding(shouldHideOnboarding: Boolean) = withContext(dispatcher) { val newPreference = settings.getUserPreference() .copy(shouldHideOnboarding = shouldHideOnboarding) settings.putUserPreference(newPreference) - userData.value = newPreference + _userData.value = newPreference } } @@ -212,3 +227,13 @@ private fun DarkThemeConfig.toDarkThemeConfigProto(): DarkThemeConfigProto { DarkThemeConfig.LIGHT -> DarkThemeConfigProto.DARK_THEME_CONFIG_LIGHT } } + +private fun DarkThemeConfigProto.toDarkThemeConfig(): DarkThemeConfig { + return when (this) { + DarkThemeConfigProto.DARK_THEME_CONFIG_UNSPECIFIED, + DarkThemeConfigProto.DARK_THEME_CONFIG_FOLLOW_SYSTEM, + -> DarkThemeConfig.FOLLOW_SYSTEM + DarkThemeConfigProto.DARK_THEME_CONFIG_DARK -> DarkThemeConfig.DARK + DarkThemeConfigProto.DARK_THEME_CONFIG_LIGHT -> DarkThemeConfig.LIGHT + } +}