From cacbc80cdc4a6a6be7f47314b389b76fba2ce499 Mon Sep 17 00:00:00 2001 From: Maxwell Mapako Date: Tue, 11 Jun 2024 19:11:52 +0200 Subject: [PATCH] refactor: data and domain use caller co-routine scope (#262) * chore: remove android.work:work-test module * refactor: simplify data source and factory --- .gitignore | 2 + .../arch/buildSrc/plugin/CorePlugin.kt | 7 +- .../plugin/components/AndroidConfiguration.kt | 16 ---- ...Dependencies.kt => ProjectDependencies.kt} | 0 .../{AndroidOptions.kt => ProjectDokka.kt} | 78 +------------------ .../plugin/components/ProjectMaven.kt | 41 ++++++++++ .../{AndroidPlugins.kt => ProjectPlugins.kt} | 0 .../plugin/components/ProjectSources.kt | 35 +++++++++ .../plugin/components/ProjectSpotless.kt | 20 +++++ .../arch/core/model/ISupportViewModelState.kt | 11 --- .../arch/data/common/ISupportResponse.kt | 8 +- .../arch/data/repository/SupportRepository.kt | 39 ---------- .../repository/contract/ISupportRepository.kt | 30 ------- .../data/source/core/SupportCoreDataSource.kt | 2 - .../core/contract/AbstractDataSource.kt | 6 +- .../co/anitrend/arch/data/state/DataState.kt | 16 +--- .../source/core/SupportCoreDataSourceTest.kt | 22 ++---- .../anitrend/arch/data/state/DataStateTest.kt | 6 -- .../anitrend/arch/domain/common/IUseCase.kt | 27 ------- .../arch/domain/entities/NetworkState.kt | 6 +- .../co/anitrend/arch/domain/state/UiState.kt | 2 - gradle/libs.versions.toml | 1 - .../contract/AbstractPagingDataSource.kt | 7 +- .../contract/AbstractPagingLiveDataSource.kt | 7 +- processor/build.gradle.kts | 4 + .../ui/fragment/list/SupportFragmentList.kt | 14 ---- .../list/contract/ISupportFragmentList.kt | 1 - .../list/presenter/SupportListPresenter.kt | 4 - .../contract/ISupportListPresenter.kt | 7 -- 29 files changed, 129 insertions(+), 290 deletions(-) rename buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/{AndroidDependencies.kt => ProjectDependencies.kt} (100%) rename buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/{AndroidOptions.kt => ProjectDokka.kt} (71%) create mode 100644 buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectMaven.kt rename buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/{AndroidPlugins.kt => ProjectPlugins.kt} (100%) create mode 100644 buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSources.kt create mode 100644 buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSpotless.kt delete mode 100644 data/src/main/kotlin/co/anitrend/arch/data/repository/SupportRepository.kt delete mode 100644 data/src/main/kotlin/co/anitrend/arch/data/repository/contract/ISupportRepository.kt delete mode 100644 domain/src/main/kotlin/co/anitrend/arch/domain/common/IUseCase.kt diff --git a/.gitignore b/.gitignore index fe5288996..546f55c25 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,5 @@ fabric.properties # Exclude client credentail files secrets.properties + +.kotlin/sessions/ diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/CorePlugin.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/CorePlugin.kt index fc834f379..56112bd7c 100644 --- a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/CorePlugin.kt +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/CorePlugin.kt @@ -3,8 +3,10 @@ package co.anitrend.arch.buildSrc.plugin import co.anitrend.arch.buildSrc.plugin.components.configureAndroid import co.anitrend.arch.buildSrc.plugin.components.configureSpotless import co.anitrend.arch.buildSrc.plugin.components.configureDependencies -import co.anitrend.arch.buildSrc.plugin.components.configureOptions import co.anitrend.arch.buildSrc.plugin.components.configurePlugins +import co.anitrend.arch.buildSrc.plugin.components.configureSources +import co.anitrend.arch.buildSrc.plugin.components.configureDokka +import co.anitrend.arch.buildSrc.plugin.extensions.containsBasePlugin import co.anitrend.arch.buildSrc.plugin.extensions.isKotlinLibraryGroup import org.gradle.api.Plugin import org.gradle.api.Project @@ -30,7 +32,8 @@ open class CorePlugin : Plugin { if (!project.isKotlinLibraryGroup()) { project.configureAndroid() } - project.configureOptions() + project.configureDokka() + project.configureSources() project.configureDependencies() project.configureSpotless() project.availableExtensions() diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidConfiguration.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidConfiguration.kt index 665d56aed..790535e7f 100644 --- a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidConfiguration.kt +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidConfiguration.kt @@ -1,13 +1,11 @@ package co.anitrend.arch.buildSrc.plugin.components -import co.anitrend.arch.buildSrc.plugin.extensions.spotlessExtension import co.anitrend.arch.buildSrc.plugin.extensions.baseExtension import co.anitrend.arch.buildSrc.plugin.extensions.libraryExtension import co.anitrend.arch.buildSrc.plugin.extensions.isDomainModule import co.anitrend.arch.buildSrc.plugin.extensions.isThemeModule import co.anitrend.arch.buildSrc.plugin.extensions.kotlinAndroidProjectExtension import co.anitrend.arch.buildSrc.plugin.extensions.props -import co.anitrend.arch.buildSrc.plugin.extensions.libs import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.tasks.testing.Test @@ -22,20 +20,6 @@ private fun Project.configureLint() = libraryExtension().run { } } -internal fun Project.configureSpotless(): Unit = spotlessExtension().run { - kotlin { - target("**/*.kt") - targetExclude( - "${layout.buildDirectory.get()}/**/*.kt", - "**/androidTest/**/*.kt", - "**/test/**/*.kt", - "bin/**/*.kt" - ) - ktlint(libs.pintrest.ktlint.get().version) - licenseHeaderFile(rootProject.file("spotless/copyright.kt")) - } -} - internal fun Project.configureAndroid(): Unit = baseExtension().run { compileSdkVersion(34) defaultConfig { diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidDependencies.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectDependencies.kt similarity index 100% rename from buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidDependencies.kt rename to buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectDependencies.kt diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidOptions.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectDokka.kt similarity index 71% rename from buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidOptions.kt rename to buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectDokka.kt index c58d3794d..248b7f905 100644 --- a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidOptions.kt +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectDokka.kt @@ -1,16 +1,11 @@ package co.anitrend.arch.buildSrc.plugin.components import org.gradle.api.Project -import org.gradle.api.tasks.bundling.Jar -import org.gradle.kotlin.dsl.get import org.jetbrains.dokka.gradle.DokkaTask import co.anitrend.arch.buildSrc.module.Modules import co.anitrend.arch.buildSrc.plugin.extensions.* -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.kotlin.dsl.getValue import org.gradle.kotlin.dsl.invoke import org.gradle.kotlin.dsl.named -import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import java.net.URL private fun Project.dependenciesOfProject(): List { @@ -59,49 +54,11 @@ private fun Project.dependenciesOfProject(): List { } } -private fun Project.createMavenPublicationUsing(sources: Jar) { - publishingExtension().publications { - val component = components.findByName("android") - - val projectName = this@createMavenPublicationUsing.name - - logger.lifecycle("Configuring maven publication options for ${path}:maven with component -> ${component?.name}") - create("maven", MavenPublication::class.java) { - groupId = "co.anitrend.arch" - artifactId = projectName - version = props[PropertyTypes.VERSION] - - artifact(sources) - artifact("${layout.buildDirectory.get()}/outputs/aar/${projectName}-release.aar") - from(component) - - pom { - name.set("support-arch") - description.set("A multi-module template library that attempts to make clean arch apps easier to build") - url.set("https://github.com/anitrend/support-arch") - licenses { - license { - name.set("Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - developers { - developer { - id.set("wax911") - name.set("Maxwell Mapako") - organizationUrl.set("https://github.com/anitrend") - } - } - } - } - } -} - -private fun Project.createDokkaTaskProvider() = tasks.named("dokkaHtml") { +internal fun Project.configureDokka() = tasks.named("dokkaHtml") { outputDirectory.set(layout.buildDirectory.dir("docs/dokka")) // Set module name displayed in the final output - moduleName.set(this@createDokkaTaskProvider.name) + moduleName.set(project.name) // Use default or set to custom path to cache directory // to enable package-list caching @@ -207,35 +164,4 @@ private fun Project.createDokkaTaskProvider() = tasks.named("dokkaHtm } } } -} - -internal fun Project.configureOptions() { - if (containsBasePlugin()) { - logger.lifecycle("Applying extension options for ${project.path}") - - val mainSourceSets = when { - !isKotlinLibraryGroup() -> baseExtension().sourceSets["main"].java.srcDirs - else -> kotlinJvmProjectExtension().sourceSets["main"].kotlin.srcDirs() - } - - logger.lifecycle("Applying additional tasks options for dokka and javadoc on ${project.path}") - - createDokkaTaskProvider() - - val sourcesJar by tasks.register("sourcesJar", Jar::class.java) { - archiveClassifier.set("sources") - from(mainSourceSets) - } - - val classesJar by tasks.register("classesJar", Jar::class.java) { - from("${project.layout.buildDirectory.get()}/intermediates/classes/release") - } - - artifacts { - add("archives", classesJar) - add("archives", sourcesJar) - } - - createMavenPublicationUsing(sourcesJar) - } } \ No newline at end of file diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectMaven.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectMaven.kt new file mode 100644 index 000000000..78b688080 --- /dev/null +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectMaven.kt @@ -0,0 +1,41 @@ +package co.anitrend.arch.buildSrc.plugin.components + +import co.anitrend.arch.buildSrc.plugin.extensions.props +import co.anitrend.arch.buildSrc.plugin.extensions.publishingExtension +import org.gradle.api.Project +import org.gradle.api.publish.maven.MavenPublication + + +internal fun Project.configureMaven() { + publishingExtension().publications { + val component = components.findByName("java") + + logger.lifecycle("Configuring maven publication options for ${path}:maven with component -> ${component?.name}") + create("maven", MavenPublication::class.java) { + groupId = "co.anitrend.arch" + artifactId = project.name + version = props[PropertyTypes.VERSION] + + from(component) + + pom { + name.set("support-arch") + description.set("A multi-module template library that attempts to make clean arch apps easier to build") + url.set("https://github.com/anitrend/support-arch") + licenses { + license { + name.set("Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + id.set("wax911") + name.set("Maxwell Mapako") + organizationUrl.set("https://github.com/anitrend") + } + } + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidPlugins.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectPlugins.kt similarity index 100% rename from buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/AndroidPlugins.kt rename to buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectPlugins.kt diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSources.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSources.kt new file mode 100644 index 000000000..78a4aff44 --- /dev/null +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSources.kt @@ -0,0 +1,35 @@ +package co.anitrend.arch.buildSrc.plugin.components + +import co.anitrend.arch.buildSrc.plugin.extensions.baseExtension +import co.anitrend.arch.buildSrc.plugin.extensions.isKotlinLibraryGroup +import co.anitrend.arch.buildSrc.plugin.extensions.kotlinJvmProjectExtension +import org.gradle.api.Project +import org.gradle.api.tasks.bundling.Jar +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getValue +import org.gradle.kotlin.dsl.provideDelegate + +internal fun Project.configureSources() { + val mainSourceSets = when { + !isKotlinLibraryGroup() -> baseExtension().sourceSets["main"].java.srcDirs + else -> kotlinJvmProjectExtension().sourceSets["main"].kotlin.srcDirs() + } + + val sourcesJar by tasks.register("sourcesJar", Jar::class.java) { + archiveClassifier.set("sources") + from(mainSourceSets) + } + + val classesJar by tasks.register("classesJar", Jar::class.java) { + from("${project.layout.buildDirectory.get()}/intermediates/classes/release") + } + + artifacts { + add("archives", classesJar) + add("archives", sourcesJar) + } + + afterEvaluate { + configureMaven() + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSpotless.kt b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSpotless.kt new file mode 100644 index 000000000..841a822a9 --- /dev/null +++ b/buildSrc/src/main/java/co/anitrend/arch/buildSrc/plugin/components/ProjectSpotless.kt @@ -0,0 +1,20 @@ +package co.anitrend.arch.buildSrc.plugin.components + +import co.anitrend.arch.buildSrc.plugin.extensions.libs +import co.anitrend.arch.buildSrc.plugin.extensions.spotlessExtension +import org.gradle.api.Project + + +internal fun Project.configureSpotless(): Unit = spotlessExtension().run { + kotlin { + target("**/*.kt") + targetExclude( + "${layout.buildDirectory.get()}/**/*.kt", + "**/androidTest/**/*.kt", + "**/test/**/*.kt", + "bin/**/*.kt" + ) + ktlint(libs.pintrest.ktlint.get().version) + licenseHeaderFile(rootProject.file("spotless/copyright.kt")) + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/co/anitrend/arch/core/model/ISupportViewModelState.kt b/core/src/main/kotlin/co/anitrend/arch/core/model/ISupportViewModelState.kt index 1d6597c9c..5eadacf62 100644 --- a/core/src/main/kotlin/co/anitrend/arch/core/model/ISupportViewModelState.kt +++ b/core/src/main/kotlin/co/anitrend/arch/core/model/ISupportViewModelState.kt @@ -24,7 +24,6 @@ import co.anitrend.arch.domain.entities.LoadState * * @property model observable model from a use case output * @property loadState observable network state from underlying sources - * @property refreshState observable network refresh state from underlying sources * * @param R type of your [model] * @@ -33,7 +32,6 @@ import co.anitrend.arch.domain.entities.LoadState interface ISupportViewModelState { val model: LiveData val loadState: LiveData - val refreshState: LiveData /** * Triggers use case to perform a retry operation @@ -44,13 +42,4 @@ interface ISupportViewModelState { * Triggers use case to perform refresh operation */ suspend fun refresh() - - /** - * Called upon [androidx.lifecycle.ViewModel.onCleared] and should optionally - * call cancellation of any ongoing jobs. - * - * If your use case source is of type [co.anitrend.arch.domain.common.IUseCase] - * then you could optionally call [co.anitrend.arch.domain.common.IUseCase.onCleared] here - */ - fun onCleared() } diff --git a/data/src/main/kotlin/co/anitrend/arch/data/common/ISupportResponse.kt b/data/src/main/kotlin/co/anitrend/arch/data/common/ISupportResponse.kt index e3902bdaf..25ee516c3 100644 --- a/data/src/main/kotlin/co/anitrend/arch/data/common/ISupportResponse.kt +++ b/data/src/main/kotlin/co/anitrend/arch/data/common/ISupportResponse.kt @@ -23,9 +23,9 @@ import co.anitrend.arch.request.callback.RequestCallback * * @since v1.1.0 */ -interface ISupportResponse { +interface ISupportResponse { /** - * Response handler for coroutine contexts which need to observe [NetworkState] + * Response handler for coroutine contexts which need to observe [LoadState] * * @param resource awaiting execution * @param requestCallback for the deferred result @@ -33,7 +33,7 @@ interface ISupportResponse { * @return resource fetched if present */ suspend operator fun invoke( - resource: RESOURCE, + resource: I, requestCallback: RequestCallback, - ): RESPONSE? + ): O? } diff --git a/data/src/main/kotlin/co/anitrend/arch/data/repository/SupportRepository.kt b/data/src/main/kotlin/co/anitrend/arch/data/repository/SupportRepository.kt deleted file mode 100644 index d02b80db8..000000000 --- a/data/src/main/kotlin/co/anitrend/arch/data/repository/SupportRepository.kt +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2021 AniTrend - * - * 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 co.anitrend.arch.data.repository - -import co.anitrend.arch.data.repository.contract.ISupportRepository -import co.anitrend.arch.extension.coroutine.ISupportCoroutine - -/** - * Core repository implementation with data source cancellation support - * - * @param source Data source that implements coroutine behaviour - * - * @since v1.1.0 - */ -abstract class SupportRepository( - private val source: ISupportCoroutine?, -) : ISupportRepository { - /** - * Deals with cancellation of any pending or on going operations that the repository - * might be working on - */ - override fun onCleared() { - source?.cancelAllChildren() - } -} diff --git a/data/src/main/kotlin/co/anitrend/arch/data/repository/contract/ISupportRepository.kt b/data/src/main/kotlin/co/anitrend/arch/data/repository/contract/ISupportRepository.kt deleted file mode 100644 index 3f052f40e..000000000 --- a/data/src/main/kotlin/co/anitrend/arch/data/repository/contract/ISupportRepository.kt +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2021 AniTrend - * - * 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 co.anitrend.arch.data.repository.contract - -/** - * Repository contract with support for canceling coroutines [onCleared] - * - * @since v1.1.0 - */ -interface ISupportRepository { - /** - * Deals with cancellation of any pending or on going operations that the repository - * might be working on - */ - fun onCleared() -} diff --git a/data/src/main/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSource.kt b/data/src/main/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSource.kt index 95f24b63e..8c97ae27f 100644 --- a/data/src/main/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSource.kt +++ b/data/src/main/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSource.kt @@ -22,8 +22,6 @@ import co.anitrend.arch.request.model.Request /** * A data source that depends on [kotlinx.coroutines.flow.Flow] to publish results. * - * @param dispatcher Dispatchers that are currently available - * * @since v1.1.0 */ abstract class SupportCoreDataSource : AbstractDataSource() { diff --git a/data/src/main/kotlin/co/anitrend/arch/data/source/core/contract/AbstractDataSource.kt b/data/src/main/kotlin/co/anitrend/arch/data/source/core/contract/AbstractDataSource.kt index 1c64a60f1..4d0e7ebe4 100644 --- a/data/src/main/kotlin/co/anitrend/arch/data/source/core/contract/AbstractDataSource.kt +++ b/data/src/main/kotlin/co/anitrend/arch/data/source/core/contract/AbstractDataSource.kt @@ -18,8 +18,6 @@ package co.anitrend.arch.data.source.core.contract import co.anitrend.arch.data.source.contract.IDataSource import co.anitrend.arch.data.source.contract.ISource -import co.anitrend.arch.extension.coroutine.ISupportCoroutine -import co.anitrend.arch.extension.coroutine.extension.Default import co.anitrend.arch.extension.dispatchers.contract.ISupportDispatcher import co.anitrend.arch.request.AbstractRequestHelper import co.anitrend.arch.request.extension.createStatusFlow @@ -30,9 +28,9 @@ import co.anitrend.arch.request.helper.RequestHelper * * @since v1.1.0 */ -abstract class AbstractDataSource : IDataSource, ISource, ISupportCoroutine by Default() { +abstract class AbstractDataSource : IDataSource, ISource { /** - * Contract for multiple types of [coroutineDispatcher] + * Contract for multiple types of [kotlinx.coroutines.CoroutineDispatcher] */ protected abstract val dispatcher: ISupportDispatcher diff --git a/data/src/main/kotlin/co/anitrend/arch/data/state/DataState.kt b/data/src/main/kotlin/co/anitrend/arch/data/state/DataState.kt index 87764dfa0..d955de00c 100644 --- a/data/src/main/kotlin/co/anitrend/arch/data/state/DataState.kt +++ b/data/src/main/kotlin/co/anitrend/arch/data/state/DataState.kt @@ -21,14 +21,12 @@ import co.anitrend.arch.data.source.core.contract.AbstractDataSource import co.anitrend.arch.domain.entities.LoadState import co.anitrend.arch.domain.state.UiState import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow /** * Model that view models create for UI components to observe on * * @param model LiveData for the UI to observe * @param loadState Load status to show to the user - * @param refreshState Refresh status to show to the user. Separate from [loadState], * this value is importantly only when refresh is requested * @param refresh Refreshes & invalidates underlying data source fetches it from scratch. * @param retry Retries any failed requests. @@ -36,7 +34,6 @@ import kotlinx.coroutines.flow.MutableStateFlow data class DataState internal constructor( val model: Flow, override val loadState: Flow, - override val refreshState: Flow, override val refresh: suspend () -> Unit, override val retry: suspend () -> Unit, ) : UiState>() { @@ -49,20 +46,11 @@ data class DataState internal constructor( * @see AbstractDataSource */ infix fun IDataSource.create(model: Flow): DataState { - val refreshTrigger: MutableStateFlow = MutableStateFlow(LoadState.Idle()) - return DataState( model = model, loadState = loadState, - refreshState = refreshTrigger, - refresh = { - refreshTrigger.value = LoadState.Loading() - refresh() - refreshTrigger.value = LoadState.Success() - }, - retry = { - retryFailed() - }, + refresh = ::refresh, + retry = ::retryFailed, ) } } diff --git a/data/src/test/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSourceTest.kt b/data/src/test/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSourceTest.kt index 309778ed6..43d588d39 100644 --- a/data/src/test/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSourceTest.kt +++ b/data/src/test/kotlin/co/anitrend/arch/data/source/core/SupportCoreDataSourceTest.kt @@ -22,6 +22,8 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import kotlin.test.Test +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds class SupportCoreDataSourceTest : ISupportCoroutine by Main() { @@ -63,21 +65,7 @@ class SupportCoreDataSourceTest : ISupportCoroutine by Main() { } @Test - fun `verify data source behavior on refresh remains unchanged when no request needs to be retried`() = runTest { - val state = dataSource.create( - flow { - emit("Test event") - } - ) - - dataSource.refresh() - - val retryState = state.refreshState.first() - assertEquals(LoadState.Idle(), retryState) - } - - @Test - fun `verify data source behavior on retry changes when request fails`() = runTest { + fun `verify data source behavior on retry changes when request fails`() = runTest(timeout = 5.seconds) { val expected = Throwable("Request id: `test_request_1` simulated failure due") val requestHelper = dataSource.requestHelper @@ -94,7 +82,7 @@ class SupportCoreDataSourceTest : ISupportCoroutine by Main() { } @Test - fun `verify data source behavior on failure reports existing status of failed`() = runTest { + fun `verify data source behavior on failure reports existing status of failed`() = runTest(timeout = 5.seconds) { val error = Throwable("Request id: `test_request_1` simulated failure due") val requestHelper = dataSource.requestHelper @@ -109,7 +97,7 @@ class SupportCoreDataSourceTest : ISupportCoroutine by Main() { } @Test - fun `verify data source behavior on retry failed changes when request fails`() = runTest { + fun `verify data source behavior on retry failed changes when request fails`() = runTest(timeout = 5.seconds) { val error = Throwable("Request id: `test_request_1` simulated failure due") val requestHelper = dataSource.requestHelper diff --git a/data/src/test/kotlin/co/anitrend/arch/data/state/DataStateTest.kt b/data/src/test/kotlin/co/anitrend/arch/data/state/DataStateTest.kt index d44714e9e..75246e407 100644 --- a/data/src/test/kotlin/co/anitrend/arch/data/state/DataStateTest.kt +++ b/data/src/test/kotlin/co/anitrend/arch/data/state/DataStateTest.kt @@ -49,9 +49,6 @@ class DataStateTest : ISupportCoroutine by Main() { val loadState = state.loadState.first() assertEquals(LoadState.Loading(), loadState) - - val retryState = state.refreshState.first() - assertEquals(LoadState.Idle(), retryState) } @Test @@ -68,8 +65,5 @@ class DataStateTest : ISupportCoroutine by Main() { val loadState = state.loadState.first() assertEquals(LoadState.Idle(), loadState) - - val retryState = state.refreshState.first() - assertEquals(LoadState.Idle(), retryState) } } \ No newline at end of file diff --git a/domain/src/main/kotlin/co/anitrend/arch/domain/common/IUseCase.kt b/domain/src/main/kotlin/co/anitrend/arch/domain/common/IUseCase.kt deleted file mode 100644 index 329958e1d..000000000 --- a/domain/src/main/kotlin/co/anitrend/arch/domain/common/IUseCase.kt +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright 2021 AniTrend - * - * 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 co.anitrend.arch.domain.common - -/** - * Common use case type - */ -interface IUseCase { - /** - * Informs underlying repositories or related components running background operations to stop - */ - fun onCleared() -} diff --git a/domain/src/main/kotlin/co/anitrend/arch/domain/entities/NetworkState.kt b/domain/src/main/kotlin/co/anitrend/arch/domain/entities/NetworkState.kt index fdc4c1a96..a7e50b95d 100644 --- a/domain/src/main/kotlin/co/anitrend/arch/domain/entities/NetworkState.kt +++ b/domain/src/main/kotlin/co/anitrend/arch/domain/entities/NetworkState.kt @@ -33,19 +33,19 @@ sealed class NetworkState { * Represents a state of idle */ @Suppress("DEPRECATION") - object Idle : NetworkState() + data object Idle : NetworkState() /** * Represents a network state of loading */ @Suppress("DEPRECATION") - object Loading : NetworkState() + data object Loading : NetworkState() /** * Represents a network state that has succeeded */ @Suppress("DEPRECATION") - object Success : NetworkState() + data object Success : NetworkState() /** * Network state for failed requests with an optional message or code diff --git a/domain/src/main/kotlin/co/anitrend/arch/domain/state/UiState.kt b/domain/src/main/kotlin/co/anitrend/arch/domain/state/UiState.kt index be6b9ccd1..a6c0c75fd 100644 --- a/domain/src/main/kotlin/co/anitrend/arch/domain/state/UiState.kt +++ b/domain/src/main/kotlin/co/anitrend/arch/domain/state/UiState.kt @@ -20,14 +20,12 @@ package co.anitrend.arch.domain.state * Contract for user interface state which UI components can use to interact with state * * @property loadState Network request status to show to the user - * @property refreshState Refresh status to show to the user. Separate from [loadState], * this value is importantly only when refresh is requested * @property refresh Refreshes & invalidates underlying data source fetches it from scratch. * @property retry Retries any failed requests. */ abstract class UiState { abstract val loadState: T - abstract val refreshState: T abstract val refresh: suspend () -> Unit abstract val retry: suspend () -> Unit } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cab0ebc1b..c453ef942 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,7 +61,6 @@ androidx-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "an androidx-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-work" } androidx-runtime = { module = "androidx.work:work-runtime", version.ref = "androidx-work" } -androidx-test = { module = "androidx.work:work-test", version.ref = "androidx-work" } androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "androidx-work" } androidx-work-runtime = { module = "androidx.work:work-runtime", version.ref = "androidx-work" } diff --git a/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/contract/AbstractPagingDataSource.kt b/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/contract/AbstractPagingDataSource.kt index c8fb2cfde..96a434712 100644 --- a/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/contract/AbstractPagingDataSource.kt +++ b/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/contract/AbstractPagingDataSource.kt @@ -19,8 +19,6 @@ package co.anitrend.arch.paging.legacy.source.contract import androidx.paging.PagedList import co.anitrend.arch.data.source.contract.IDataSource import co.anitrend.arch.data.source.contract.ISource -import co.anitrend.arch.extension.coroutine.ISupportCoroutine -import co.anitrend.arch.extension.coroutine.extension.Default import co.anitrend.arch.extension.dispatchers.contract.ISupportDispatcher import co.anitrend.arch.request.AbstractRequestHelper import co.anitrend.arch.request.extension.createStatusFlow @@ -29,10 +27,9 @@ import co.anitrend.arch.request.helper.RequestHelper abstract class AbstractPagingDataSource : PagedList.BoundaryCallback(), IDataSource, - ISource, - ISupportCoroutine by Default() { + ISource { /** - * Contract for multiple types of [coroutineDispatcher] + * Contract for multiple types of [kotlinx.coroutines.CoroutineDispatcher] */ protected abstract val dispatcher: ISupportDispatcher diff --git a/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/live/contract/AbstractPagingLiveDataSource.kt b/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/live/contract/AbstractPagingLiveDataSource.kt index 50bcc237a..2ed78ec0a 100644 --- a/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/live/contract/AbstractPagingLiveDataSource.kt +++ b/paging-legacy/src/main/kotlin/co/anitrend/arch/paging/legacy/source/live/contract/AbstractPagingLiveDataSource.kt @@ -18,8 +18,6 @@ package co.anitrend.arch.paging.legacy.source.live.contract import androidx.paging.PageKeyedDataSource import co.anitrend.arch.data.source.contract.IDataSource -import co.anitrend.arch.extension.coroutine.ISupportCoroutine -import co.anitrend.arch.extension.coroutine.extension.Default import co.anitrend.arch.extension.dispatchers.contract.ISupportDispatcher import co.anitrend.arch.request.AbstractRequestHelper import co.anitrend.arch.request.extension.createStatusFlow @@ -27,10 +25,9 @@ import co.anitrend.arch.request.helper.RequestHelper abstract class AbstractPagingLiveDataSource : PageKeyedDataSource(), - IDataSource, - ISupportCoroutine by Default() { + IDataSource { /** - * Contract for multiple types of [coroutineDispatcher] + * Contract for multiple types of [kotlinx.coroutines.CoroutineDispatcher] */ protected abstract val dispatcher: ISupportDispatcher diff --git a/processor/build.gradle.kts b/processor/build.gradle.kts index da8b5f4d1..bf4789c3b 100644 --- a/processor/build.gradle.kts +++ b/processor/build.gradle.kts @@ -12,6 +12,10 @@ dependencies { testImplementation(libs.kotlin.compile.testing.ksp) } +tasks.withType(Test::class.java) { + dependsOn(":annotation:classesJar") +} + tasks.test { useJUnitPlatform() } \ No newline at end of file diff --git a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/SupportFragmentList.kt b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/SupportFragmentList.kt index 9f56e3d75..abf98b468 100644 --- a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/SupportFragmentList.kt +++ b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/SupportFragmentList.kt @@ -43,7 +43,6 @@ import co.anitrend.arch.ui.fragment.SupportFragment import co.anitrend.arch.ui.fragment.list.contract.ISupportFragmentList import co.anitrend.arch.ui.fragment.list.presenter.SupportListPresenter import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -78,11 +77,6 @@ abstract class SupportFragmentList : SupportFragment(), ISupportFragmentList< */ abstract fun onFetchDataInitialize() - override val onRefreshObserver = - Observer { loadState -> - listPresenter.onRefreshObserverChanged(loadState) - } - override val onNetworkObserver = Observer { loadState -> listPresenter.onNetworkObserverChanged(this, loadState) @@ -92,7 +86,6 @@ abstract class SupportFragmentList : SupportFragment(), ISupportFragmentList< lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { clickableFlow - .debounce(16) .filterIsInstance() .onEach { if (it.state !is LoadState.Loading) { @@ -163,7 +156,6 @@ abstract class SupportFragmentList : SupportFragment(), ISupportFragmentList< lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { listPresenter.stateLayout.interactionFlow - .debounce(16) .filterIsInstance() .onEach { if (it.state !is LoadState.Loading) { @@ -230,7 +222,6 @@ abstract class SupportFragmentList : SupportFragment(), ISupportFragmentList< super.onViewCreated(view, savedInstanceState) setUpViewModelObserver() viewModelState()?.loadState?.observe(viewLifecycleOwner, onNetworkObserver) - viewModelState()?.refreshState?.observe(viewLifecycleOwner, onRefreshObserver) } /** @@ -253,11 +244,6 @@ abstract class SupportFragmentList : SupportFragment(), ISupportFragmentList< } protected open fun afterPostModelChange(data: Collection<*>?) { - /*if (data.isNullOrEmpty()) - supportViewAdapter.networkState = NetworkState.Loading - else - supportStateLayout?.networkMutableStateFlow?.value = NetworkState.Idle*/ - listPresenter.resetWidgetStates() } diff --git a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/contract/ISupportFragmentList.kt b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/contract/ISupportFragmentList.kt index eb1e57fbf..755da7b58 100644 --- a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/contract/ISupportFragmentList.kt +++ b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/contract/ISupportFragmentList.kt @@ -31,7 +31,6 @@ import co.anitrend.arch.ui.view.widget.model.StateLayoutConfig * @since v0.9.X */ interface ISupportFragmentList : SwipeRefreshLayout.OnRefreshListener { - val onRefreshObserver: Observer val onNetworkObserver: Observer /** diff --git a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/SupportListPresenter.kt b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/SupportListPresenter.kt index 8f3243b3c..9c016e896 100644 --- a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/SupportListPresenter.kt +++ b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/SupportListPresenter.kt @@ -59,10 +59,6 @@ abstract class SupportListPresenter : ISupportListPresenter { } } - override fun onRefreshObserverChanged(loadState: LoadState?) { - swipeRefreshLayout?.isRefreshing = loadState is LoadState.Loading - } - /** * Informs the underlying [ISupportStateLayout] of changes to the [LoadState] * diff --git a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/contract/ISupportListPresenter.kt b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/contract/ISupportListPresenter.kt index 3390aedd0..dc70e7368 100644 --- a/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/contract/ISupportListPresenter.kt +++ b/ui/src/main/kotlin/co/anitrend/arch/ui/fragment/list/presenter/contract/ISupportListPresenter.kt @@ -37,13 +37,6 @@ interface ISupportListPresenter : SupportLifecycle { view: View?, ) - /** - * Responds to load state changes when refreshing - * - * @param loadState Load state or null - */ - fun onRefreshObserverChanged(loadState: LoadState?) - /** * Informs the underlying [ISupportStateLayout] of changes to the [LoadState] *