From faed7ebe9fbedbedd2110bccaddf56660ab4b395 Mon Sep 17 00:00:00 2001 From: Adetunji Dahunsi Date: Mon, 7 Mar 2022 10:33:20 -0500 Subject: [PATCH] Add sync method to repository defs Change-Id: Idfe402dde440e8dce47a03fbbc1d827744997e1b --- .../core/domain/di/DomainModule.kt | 4 +- .../core/domain/repository/NewsRepository.kt | 6 ++ .../domain/repository/RoomTopicsRepository.kt | 66 +++++++++++++++++++ .../domain/repository/TopicsRepository.kt | 6 ++ .../{ => fake}/FakeNewsRepository.kt | 5 +- .../{ => fake}/FakeTopicsRepository.kt | 5 +- .../repository/FakeNewsRepositoryTest.kt | 1 + core-network/build.gradle | 5 +- .../network/retrofit/RetrofitNiANetwork.kt | 29 ++++++++ .../testing/repository/TestNewsRepository.kt | 2 + .../repository/TestTopicsRepository.kt | 2 + gradle/libs.versions.toml | 4 ++ 12 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/RoomTopicsRepository.kt rename core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/{ => fake}/FakeNewsRepository.kt (92%) rename core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/{ => fake}/FakeTopicsRepository.kt (95%) create mode 100644 core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiANetwork.kt diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/di/DomainModule.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/di/DomainModule.kt index 81d9837bf..3db5bab1b 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/di/DomainModule.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/di/DomainModule.kt @@ -16,10 +16,10 @@ package com.google.samples.apps.nowinandroid.core.domain.di -import com.google.samples.apps.nowinandroid.core.domain.repository.FakeNewsRepository -import com.google.samples.apps.nowinandroid.core.domain.repository.FakeTopicsRepository import com.google.samples.apps.nowinandroid.core.domain.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.domain.repository.TopicsRepository +import com.google.samples.apps.nowinandroid.core.domain.repository.fake.FakeNewsRepository +import com.google.samples.apps.nowinandroid.core.domain.repository.fake.FakeTopicsRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/NewsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/NewsRepository.kt index b23dffec4..9a54cb793 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/NewsRepository.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/NewsRepository.kt @@ -32,4 +32,10 @@ interface NewsRepository { * Returns available news resources as a stream filtered by the topic. */ fun getNewsResourcesStream(filterTopicIds: Set): Flow> + + /** + * Synchronizes the local database in backing the repository with the network. + * Returns if the sync was successful or not. + */ + suspend fun sync(): Boolean } diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/RoomTopicsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/RoomTopicsRepository.kt new file mode 100644 index 000000000..7b020846d --- /dev/null +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/RoomTopicsRepository.kt @@ -0,0 +1,66 @@ +/* + * 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.domain.repository + +import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao +import com.google.samples.apps.nowinandroid.core.database.model.TopicEntity +import com.google.samples.apps.nowinandroid.core.database.model.asExternalModel +import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferences +import com.google.samples.apps.nowinandroid.core.domain.model.asEntity +import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.core.network.NiANetwork +import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers +import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic +import javax.inject.Inject +import kotlin.coroutines.cancellation.CancellationException +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** + * Room database backed implementation of the [TopicsRepository]. + */ +class RoomTopicsRepository @Inject constructor( + private val dispatchers: NiaDispatchers, + private val topicDao: TopicDao, + private val network: NiANetwork, + private val niaPreferences: NiaPreferences +) : TopicsRepository { + + override fun getTopicsStream(): Flow> = + topicDao.getTopicEntitiesStream() + .map { it.map(TopicEntity::asExternalModel) } + + override suspend fun setFollowedTopicIds(followedTopicIds: Set) = + niaPreferences.setFollowedTopicIds(followedTopicIds) + + override suspend fun toggleFollowedTopicId(followedTopicId: Int, followed: Boolean) = + niaPreferences.toggleFollowedTopicId(followedTopicId, followed) + + override fun getFollowedTopicIdsStream() = niaPreferences.followedTopicIds + + override suspend fun sync(): Boolean = try { + topicDao.saveTopics( + network.getTopics() + .map(NetworkTopic::asEntity) + ) + true + } catch (cancellationException: CancellationException) { + throw cancellationException + } catch (exception: Exception) { + false + } +} diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/TopicsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/TopicsRepository.kt index 224611989..f5da0ba85 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/TopicsRepository.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/TopicsRepository.kt @@ -39,4 +39,10 @@ interface TopicsRepository { * Returns the users currently followed topics */ fun getFollowedTopicIdsStream(): Flow> + + /** + * Synchronizes the local database in backing the repository with the network. + * Returns if the sync was successful or not. + */ + suspend fun sync(): Boolean } diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeNewsRepository.kt similarity index 92% rename from core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepository.kt rename to core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeNewsRepository.kt index 614e38634..c4f420f53 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepository.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeNewsRepository.kt @@ -14,8 +14,9 @@ * limitations under the License. */ -package com.google.samples.apps.nowinandroid.core.domain.repository +package com.google.samples.apps.nowinandroid.core.domain.repository.fake +import com.google.samples.apps.nowinandroid.core.domain.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers import javax.inject.Inject @@ -39,4 +40,6 @@ class FakeNewsRepository @Inject constructor( override fun getNewsResourcesStream(filterTopicIds: Set): Flow> = flowOf(emptyList()) + + override suspend fun sync() = true } diff --git a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeTopicsRepository.kt b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt similarity index 95% rename from core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeTopicsRepository.kt rename to core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt index f0e0616bc..cb2902404 100644 --- a/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeTopicsRepository.kt +++ b/core-domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/repository/fake/FakeTopicsRepository.kt @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.google.samples.apps.nowinandroid.core.domain.repository +package com.google.samples.apps.nowinandroid.core.domain.repository.fake import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferences +import com.google.samples.apps.nowinandroid.core.domain.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers import com.google.samples.apps.nowinandroid.core.network.fake.FakeDataSource @@ -60,4 +61,6 @@ class FakeTopicsRepository @Inject constructor( niaPreferences.toggleFollowedTopicId(followedTopicId, followed) override fun getFollowedTopicIdsStream() = niaPreferences.followedTopicIds + + override suspend fun sync() = true } diff --git a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepositoryTest.kt b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepositoryTest.kt index 061c9ec13..5a0a9275b 100644 --- a/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepositoryTest.kt +++ b/core-domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/repository/FakeNewsRepositoryTest.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.domain.repository +import com.google.samples.apps.nowinandroid.core.domain.repository.fake.FakeNewsRepository import com.google.samples.apps.nowinandroid.core.network.DefaultNiaDispatchers import kotlinx.serialization.json.Json import org.junit.Before diff --git a/core-network/build.gradle b/core-network/build.gradle index 3f40d9dd4..a2cf1f148 100644 --- a/core-network/build.gradle +++ b/core-network/build.gradle @@ -46,6 +46,9 @@ dependencies { implementation libs.kotlinx.serialization.json implementation libs.kotlinx.datetime + implementation libs.okhttp.logging + implementation libs.retrofit + implementation libs.hilt.android kapt libs.hilt.compiler -} \ No newline at end of file +} diff --git a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiANetwork.kt b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiANetwork.kt new file mode 100644 index 000000000..6e855c55a --- /dev/null +++ b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/retrofit/RetrofitNiANetwork.kt @@ -0,0 +1,29 @@ +/* + * 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.network.retrofit + +import com.google.samples.apps.nowinandroid.core.network.model.NetworkNewsResource +import com.google.samples.apps.nowinandroid.core.network.model.NetworkTopic +import retrofit2.http.GET + +interface RetrofitNiANetwork { + @GET(value = "/topics") + suspend fun getTopics(): List + + @GET(value = "/newsresources") + suspend fun getNewsResources(): List +} diff --git a/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestNewsRepository.kt b/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestNewsRepository.kt index 901e59c72..a6b3dfed4 100644 --- a/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestNewsRepository.kt +++ b/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestNewsRepository.kt @@ -46,4 +46,6 @@ class TestNewsRepository : NewsRepository { fun sendNewsResources(newsResources: List) { newsResourcesFlow.tryEmit(newsResources) } + + override suspend fun sync(): Boolean = true } diff --git a/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestTopicsRepository.kt b/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestTopicsRepository.kt index 9b60b2600..144b6a00c 100644 --- a/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestTopicsRepository.kt +++ b/core-testing/src/main/java/com/google/samples/apps/nowinandroid/core/testing/repository/TestTopicsRepository.kt @@ -63,4 +63,6 @@ class TestTopicsRepository : TopicsRepository { * A test-only API to allow querying the current followed topics. */ fun getCurrentFollowedTopics(): Set? = _followedTopicIds.replayCache.firstOrNull() + + override suspend fun sync(): Boolean = true } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3eae374fa..6ffcdf222 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,8 +26,10 @@ ksp = "1.6.10-1.0.2" ktlint = "0.43.0" material3 = "1.5.0-alpha05" mockk = "1.12.1" +okhttp = "4.9.3" protobuf = "3.19.1" protobufPlugin = "0.8.18" +retrofit = "2.9.0" room = "2.4.1" spotless = "6.0.0" turbine = "0.7.0" @@ -71,9 +73,11 @@ kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } material3 = { group = "com.google.android.material", name = "material", version.ref = "material3" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } +okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" } +retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }