Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import app.futured.kmptemplate.gradle.configuration.ProjectSettings
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.android.application)
Expand All @@ -14,6 +15,9 @@ plugins {

kotlin {
jvmToolchain(ProjectSettings.Kotlin.JvmToolchainVersion)
compilerOptions {
jvmTarget = JvmTarget.fromTarget(ProjectSettings.Android.KotlinJvmTargetNum)
}
}

android {
Expand Down Expand Up @@ -89,10 +93,6 @@ android {
targetCompatibility = ProjectSettings.Android.JavaCompatibility
}

kotlinOptions {
jvmTarget = ProjectSettings.Android.KotlinJvmTargetNum
}

lint {
textReport = true // Write a text report to the console (Useful for CI logs)
xmlReport = true // Write XML report
Expand All @@ -111,7 +111,7 @@ dependencies {
implementation(projects.shared.app)
implementation(projects.shared.feature)
implementation(projects.shared.platform)
implementation(projects.shared.arkitektDecompose)
implementation(projects.shared.arkitektDecompose.architecture)
implementation(projects.shared.resources)

implementation(platform(libs.androidx.compose.bom))
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#Gradle
org.gradle.jvmargs=-Xmx6g -Xms256m -Dfile.encoding=UTF-8 -XX:+UseParallelGC -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dkotlin.daemon.jvm.options=-XX:MaxMetaspaceSize=1g
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.caching=false
org.gradle.configureondemand=true
org.gradle.configuration-cache=true
org.gradle.configuration-cache=false
Comment on lines +4 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the necessity of disabling Gradle optimizations.

Disabling both caching and configuration cache will significantly slow down build times. These optimizations are generally safe and recommended for most projects.

Please confirm that these optimizations need to be disabled for this specific refactor. If they're causing issues with the context parameters feature or the architectural changes, consider:

  1. Identifying the specific incompatible plugins or configurations
  2. Using selective exclusions rather than global disabling
  3. Re-enabling these optimizations once the refactor stabilizes

🏁 Script executed:

#!/bin/bash
# Search for any build script configurations that might be incompatible with Gradle caching
echo "Searching for potential caching incompatibilities..."

# Look for custom tasks that might not be cache-friendly
ast-grep --pattern 'task $_ {'

# Check for configurations that might conflict with configuration cache
rg -A 3 -B 3 "configuration.*cache|cache.*configuration"

# Look for any explicit cache-related configurations
rg -A 5 "gradle\.cache|caching|configuration-cache"

Length of output: 1151


Re-enable Gradle caching and configuration-cache by default

Our search didn’t surface any custom tasks or configurations that are known to break Gradle’s caching features—only the flags in gradle.properties themselves. Disabling both org.gradle.caching and org.gradle.configuration-cache will noticeably slow down every build. Unless you’ve encountered concrete cache-related errors in this refactor, please restore the defaults and, if needed, opt out specific tasks or plugins instead of disabling globally.

• File: gradle.properties
Lines 4–6:

- org.gradle.caching=false
+ org.gradle.caching=true

- org.gradle.configuration-cache=false
+ org.gradle.configuration-cache=true

If you’ve run into build failures or stale outputs tied to configuration-cache or build caching, please document those errors and exclude only the incompatible tasks/plugins. Otherwise, let’s turn these optimizations back on to keep builds fast.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
org.gradle.caching=false
org.gradle.configureondemand=true
org.gradle.configuration-cache=true
org.gradle.configuration-cache=false
org.gradle.caching=true
org.gradle.configureondemand=true
org.gradle.configuration-cache=true
🤖 Prompt for AI Agents
In gradle.properties around lines 4–6, the file has globally disabled Gradle
build cache and configuration-cache which slows builds; revert these to defaults
by setting org.gradle.caching=true and org.gradle.configuration-cache=true (or
remove those properties so Gradle uses defaults), keep
org.gradle.configureondemand as desired, and if you previously encountered
cache-related failures, document the errors and opt-out only the incompatible
tasks/plugins instead of disabling caching globally.

# Use this flag carefully in case some of the plugins are not fully compatible.
org.gradle.configuration-cache.problems=warn

Expand Down
22 changes: 11 additions & 11 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
[versions]
agp = "8.9.0"
kotlin = "2.1.10"
ksp = "2.1.10-1.0.31" # Must be compatible with: `kotlin`
kotlin = "2.2.0"
ksp = "2.2.0-2.0.2" # Must be compatible with: `kotlin`
Comment on lines +3 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify compatibility between Kotlin 2.2.0 and KSP 2.2.0-2.0.2.

The major Kotlin version upgrade may introduce breaking changes or require adjustments in existing code.


🌐 Web query:

Are there any known compatibility issues or breaking changes when upgrading from Kotlin 2.1.10 to 2.2.0, especially regarding context parameters feature?

💡 Result:

Short answer: Yes — there are a few compatibility changes you should be aware of when moving from Kotlin 2.1.10 → 2.2.0, and the biggest user-facing change around the context feature is that context receivers are being replaced by the new context parameters preview. You can keep compiling, but you’ll likely need small code/build/IDE changes if your code uses context receivers (or other now-stricter language checks). (blog.jetbrains.com, kotlinlang.org)

What matters most (context parameters)

  • Context parameters replace the older context receivers feature in 2.2.0 (context parameters are available as a preview/preview‑flag feature). If you used context receivers in 2.1.x, you should migrate to context parameters; the compiler/IDE will help. (Blog: April 2025; docs: 2.2.0). (blog.jetbrains.com, kotlinlang.org)
  • To enable context parameters you must use the compiler flag -Xcontext-parameters (or add it to the kotlin.compilerOptions.freeCompilerArgs). Specifying both -Xcontext-receivers and -Xcontext-parameters at once is an error. (kotlinlang.org)
  • Migration notes / limitations in 2.2.0: callable references to functions with context parameters are NOT supported in 2.2.0 (you’ll need to replace such callable references with lambdas or other workarounds). Context receivers in classes have no direct automatic counterpart and require manual refactoring. IntelliJ (2025.1+) provides automatic quick‑fixes/inspections to help migrate file/module/project scopes. (blog.jetbrains.com, kotlinlang.org)
  • Some restrictions still apply to context parameters in 2.2.0 (constructors can’t declare them; properties with context parameters can’t have backing fields, initializers, or delegation). Check the docs for current list. (kotlinlang.org)

Other important breaking/deprecation items in Kotlin 2.2.0 you should check when upgrading from 2.1.10

  • kotlinOptions { } in Gradle: the old kotlinOptions block’s deprecation level is raised — use the new compilerOptions { } block (migrate build scripts). Failing to do this will become an error. (kotlinlang.org)
  • Compatibility/strictness changes (examples from the 2.2 compatibility guide you should scan for in your codebase):
    • field-targeted annotations on annotation properties are now an error.
    • reified type parameters are forbidden on type aliases (was warned previously; now an error).
    • stricter visibility / type accessibility checks (e.g., exposing private types via non-private inline functions now errors).
    • non-local returns in lambdas used as a parameter default value are now an error.
    • behavioral change: type checks on inline value classes for Number/Comparable were corrected.
      These are source/behavioral changes that can break code that previously compiled. See the compatibility guide and scan your code. (kotlinlang.org)

Practical checklist to upgrade safely

  1. Update Kotlin version to 2.2.0 in your build. Update your IDE plugin / IntelliJ to a version that bundles the 2.2.0 Kotlin plugin (IntelliJ 2025.1+ recommended for migration tooling). (kotlinlang.org, blog.jetbrains.com)
  2. Replace kotlinOptions { } with compilerOptions { } in Gradle builds. (kotlinlang.org)
  3. If you used context receivers:
    • Decide to migrate to context parameters and add -Xcontext-parameters to compiler free args; remove -Xcontext-receivers.
    • Use the IDE quick‑fix (Analyze / Run inspection / Migrate from context receivers to context parameters) to do bulk migrations where possible.
    • Manually fix cases the tool can’t convert (callable references, context receivers in classes). (blog.jetbrains.com, kotlinlang.org)
  4. Run a full clean build and test suite; fix compilation errors reported by the stricter checks (visibility/type accessibility, typealias/reified, annotation targets, etc.). Review the 2.2 compatibility guide and search your repo for patterns called out there. (kotlinlang.org)
  5. If you relied on experimental behavior that changed between 2.1.10 and 2.2.0, add small targeted tests and run them — especially for inline/inline-class behaviors and reflection/IR plugins. (kotlinlang.org)

If you want, I can:

  • scan your build.gradle(.kts) and a few Kotlin source files (paste them) for the specific patterns that will break (context receivers usage, kotlinOptions, callable references to context functions, reified in typealias, etc.) and give a line‑by‑line migration plan; or
  • produce the exact Gradle snippets to convert kotlinOptions → compilerOptions and to enable the -Xcontext-parameters flag.

Which would you prefer?

Citations:


Ensure Kotlin 2.2.0 and KSP 2.2.0-2.0.2 Compatibility

Kotlin 2.2.0 introduces several source‐breaking changes—including the switch from context receivers to context parameters (preview), stricter language checks, and a new Gradle DSL for compiler flags—that you must address when upgrading. Please update your build and code as follows:

• File ​gradle/libs.versions.toml (lines 3–4)

kotlin = "2.2.0"
ksp    = "2.2.0-2.0.2"  # aligns with Kotlin 2.2.0

• Build script changes

  • Replace the deprecated kotlinOptions { … } block with compilerOptions { … }.
  • Add -Xcontext-parameters to compilerOptions.freeCompilerArgs and remove any -Xcontext-receivers flags.

• Context-parameters migration

  • Use the IDE’s “Migrate from context receivers” inspection to bulk-convert to context parameters.
  • Manually refactor any remaining context-receiver usage (especially in classes) and replace callable references to context-parameter functions with lambdas.

• Global compatibility checks

  • Scan for now-errors such as reified type parameters on type aliases, field-targeted annotation property issues, stricter visibility/type accessibility violations, and non-local returns in default lambdas.
  • Review the Kotlin 2.2 compatibility guide: https://kotlinlang.org/docs/compatibility-guide-22.html

• Verify changes

  1. Update your IDE to IntelliJ 2025.1+ (bundles Kotlin 2.2.0 tooling).
  2. Run a clean build and full test suite; resolve any compilation or runtime failures.
  3. Add targeted tests if you relied on inline-class or IR plugin behaviors that changed.
🤖 Prompt for AI Agents
In gradle/libs.versions.toml around lines 3–4, you've pinned kotlin = "2.2.0"
and ksp = "2.2.0-2.0.2" but need to update build and code to be compatible with
Kotlin 2.2.0: replace any kotlinOptions { … } blocks in Gradle scripts with
compilerOptions { … }, add "-Xcontext-parameters" to
compilerOptions.freeCompilerArgs and remove any "-Xcontext-receivers" flags, run
the IDE “Migrate from context receivers” refactor and manually convert remaining
context-receiver usages (replace callable references to context-parameter
functions with lambdas where necessary), scan and fix new compilation errors
noted in the compatibility guide (reified type params on type aliases,
field-targeted annotation property issues, stricter visibility/type
accessibility, non-local returns in default lambdas, etc.), update to IntelliJ
2025.1+ Kotlin tooling, then run a clean build and full test suite and add tests
for any changed inline/IR plugin behavior.

desugarLibs = "2.1.5"
androidxLifecycle = "2.8.6"
androidxComposeBom = "2024.10.00"
jetbrainsComposeRuntime = "1.7.0" # Needs to align with version in Compose BOM as closely as possible
androidxActivity = "1.9.2"
decompose = "3.1.0"
essenty = "2.1.0"
koin = "3.5.6"
koinAnnotations = "1.4.0" # Must be compatible with: `ksp`
kotlinx-coroutines = "1.8.1"
koin = "4.1.0"
koinAnnotations = "2.1.0" # Must be compatible with: `ksp`
kotlinx-coroutines = "1.10.2"
kotlinx-immutableCollections = "0.3.8"
kotlinx-dateTime = "0.6.1"
ktlintGradlePlugin = "12.2.0"
ktlint = "1.5.0"
detektGradlePlugin = "1.23.8"
composeLint = "1.3.1"
apollo = "4.0.0"
ktorfit = "2.4.0" # Must be compatible with: `ksp`
ktor = "3.1.0" # Must be compatible with: `ktorfit`
apollo = "4.3.1"
ktorfit = "2.6.1" # Must be compatible with: `ksp`
ktor = "3.2.1" # Must be compatible with: `ktorfit`
kotlinx-serialization = "1.8.0" # Must be compatible with: `kotlin`
timber = "5.0.1"
kermit = "2.0.2"
skie = "0.10.1" # Must be compatible with: `kotlin`
kermit = "2.0.6"
skie = "0.10.4" # Must be compatible with: `kotlin`
buildkonfig = "0.15.2"
nsExceptionKt = "1.0.0-BETA-7"
datastore = "1.1.1"
moko-resources = "0.24.5"
moko-resources = "0.25.0"
baselineProfile = "1.3.0"
junit = "1.2.1"
espressoCore = "3.6.1"
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ rootProject.name = "KMP_Futured_template"
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

include(":androidApp")
include(":shared:arkitekt-decompose")
include(":shared:arkitekt-decompose:architecture")
include(":shared:arkitekt-decompose:annotation")
include(":shared:arkitekt-decompose:processor")
include(":shared:arkitekt-cr-usecases")
Expand Down
4 changes: 2 additions & 2 deletions shared/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ kotlin {
isStatic = true

export(projects.shared.platform)
export(projects.shared.arkitektDecompose)
export(projects.shared.arkitektDecompose.architecture)
export(projects.shared.feature)
export(projects.shared.resources)

Expand Down Expand Up @@ -88,7 +88,7 @@ kotlin {
iosMain {
dependencies {
api(projects.shared.platform)
api(projects.shared.arkitektDecompose)
api(projects.shared.arkitektDecompose.architecture)
api(projects.shared.feature)
api(projects.shared.resources)

Expand Down
4 changes: 4 additions & 0 deletions shared/arkitekt-cr-usecases/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ kotlin {
iosArm64()
iosSimulatorArm64()

compilerOptions {
freeCompilerArgs.add("-Xcontext-parameters")
}

sourceSets {
commonMain {
dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package app.futured.arkitekt.crusecases

import app.futured.arkitekt.crusecases.scope.FlowUseCaseExecutionScope
import app.futured.arkitekt.crusecases.error.UseCaseErrorHandler
import app.futured.arkitekt.crusecases.scope.CoroutineScopeOwner
import app.futured.arkitekt.crusecases.scope.FlowUseCaseConfig
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlin.coroutines.cancellation.CancellationException

/**
* Base [Flow] use case meant to use in [FlowUseCaseExecutionScope] implementations
* Base [Flow] use case meant to use in [CoroutineScopeOwner] implementations
*/
abstract class FlowUseCase<ARGS, T> {

Expand All @@ -20,3 +30,110 @@ abstract class FlowUseCase<ARGS, T> {
*/
abstract fun build(args: ARGS): Flow<T>
}

/**
* Asynchronously executes use case and consumes data from flow on UI thread.
* By default all previous pending executions are canceled, this can be changed
* by [config]. When suspend function in use case finishes, onComplete is called
* on UI thread. This version is gets initial arguments by [args].
*
* In case that an error is thrown during the execution of [FlowUseCase] then
* [UseCaseErrorHandler.globalOnErrorLogger] is called with the error as an argument.
*
* @param args Arguments used for initial use case initialization.
* @param config [FlowUseCaseConfig] used to process results of internal
* Flow and to set configuration options.
**/
context(coroutineScopeOwner: CoroutineScopeOwner)
fun <ARGS, T : Any?> FlowUseCase<ARGS, T>.execute(
args: ARGS,
config: FlowUseCaseConfig.Builder<T, T>.() -> Unit,
) {
val flowUseCaseConfig = FlowUseCaseConfig.Builder<T, T>().run {
config.invoke(this)
return@run build()
}

if (flowUseCaseConfig.disposePrevious) {
job?.cancel()
}

job = build(args)
.flowOn(coroutineScopeOwner.getWorkerDispatcher())
.onStart { flowUseCaseConfig.onStart() }
.onEach { flowUseCaseConfig.onNext(it) }
.onCompletion { error ->
when {
error is CancellationException -> {
// ignore this exception
}

error != null -> {
UseCaseErrorHandler.globalOnErrorLogger(error)
flowUseCaseConfig.onError(error)
}

else -> flowUseCaseConfig.onComplete()
}
}
.catch { /* handled in onCompletion */ }
.launchIn(coroutineScopeOwner.viewModelScope)
}

context(coroutineScopeOwner: CoroutineScopeOwner)
fun <T : Any?> FlowUseCase<Unit, T>.execute(config: FlowUseCaseConfig.Builder<T, T>.() -> Unit) =
execute(Unit, config)

context(coroutineScopeOwner: CoroutineScopeOwner)
fun <T : Any?, M : Any?> FlowUseCase<Unit, T>.executeMapped(config: FlowUseCaseConfig.Builder<T, M>.() -> Unit) =
executeMapped(Unit, config)

/**
* Asynchronously executes use case and consumes data from flow on UI thread.
* By default all previous pending executions are canceled, this can be changed
* by [config]. When suspend function in use case finishes, onComplete is called
* on UI thread. This version is gets initial arguments by [args].
*
* In case that an error is thrown during the execution of [FlowUseCase] then
* [UseCaseErrorHandler.globalOnErrorLogger] is called with the error as an argument.
*
* @param args Arguments used for initial use case initialization.
* @param config [FlowUseCaseConfig] used to process results of internal
* Flow and to set configuration options.
**/
context(coroutineScopeOwner: CoroutineScopeOwner)
fun <ARGS, T : Any?, M : Any?> FlowUseCase<ARGS, T>.executeMapped(
args: ARGS,
config: FlowUseCaseConfig.Builder<T, M>.() -> Unit,
) {
val flowUseCaseConfig = FlowUseCaseConfig.Builder<T, M>().run {
config.invoke(this)
return@run build()
}

if (flowUseCaseConfig.disposePrevious) {
job?.cancel()
}

job = build(args)
.flowOn(coroutineScopeOwner.getWorkerDispatcher())
.onStart { flowUseCaseConfig.onStart() }
.mapNotNull { flowUseCaseConfig.onMap?.invoke(it) }
.onEach { flowUseCaseConfig.onNext(it) }
.onCompletion { error ->
when {
error is CancellationException -> {
// ignore this exception
}

error != null -> {
UseCaseErrorHandler.globalOnErrorLogger(error)
flowUseCaseConfig.onError(error)
}

else -> flowUseCaseConfig.onComplete()
}
}
.catch { /* handled in onCompletion */ }
.launchIn(coroutineScopeOwner.viewModelScope)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package app.futured.arkitekt.crusecases

import app.futured.arkitekt.crusecases.scope.SingleUseCaseExecutionScope
import app.futured.arkitekt.crusecases.error.UseCaseErrorHandler
import app.futured.arkitekt.crusecases.scope.CoroutineScopeOwner
import app.futured.arkitekt.crusecases.scope.UseCaseConfig
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlin.coroutines.cancellation.CancellationException

/**
* Base Coroutine use case meant to use in [SingleUseCaseExecutionScope] implementations
* Base Coroutine use case meant to use in [CoroutineScopeOwner] implementations
*/
abstract class UseCase<ARGS, T> {

Expand All @@ -18,3 +25,95 @@ abstract class UseCase<ARGS, T> {
*/
abstract suspend fun build(args: ARGS): T
}

/**
* Asynchronously executes use case and saves it's Deferred. By default, all previous
* pending executions are canceled, this can be changed by the [config].
* This version is used for use cases without initial arguments.
*
* @param config [UseCaseConfig] used to process results of internal
* Coroutine and to set configuration options.
*/
context(coroutineScopeOwner: CoroutineScopeOwner)
fun <T : Any?> UseCase<Unit, T>.execute(config: UseCaseConfig.Builder<T>.() -> Unit) =
execute(Unit, config)

/**
* Asynchronously executes use case and saves it's Deferred. By default, all previous
* pending executions are canceled, this can be changed by the [config].
* This version gets initial arguments by [args].
*
* In case that an error is thrown during the execution of [UseCase] then [UseCaseErrorHandler.globalOnErrorLogger]
* is called with the error as an argument.
*
* @param args Arguments used for initial use case initialization.
* @param config [UseCaseConfig] used to process results of internal
* Coroutine and to set configuration options.
*/
context(coroutineScopeOwner: CoroutineScopeOwner)
fun <ARGS, T : Any?> UseCase<ARGS, T>.execute(
args: ARGS,
config: UseCaseConfig.Builder<T>.() -> Unit,
) {
val useCaseConfig = UseCaseConfig.Builder<T>().run {
config.invoke(this)
return@run build()
}
if (useCaseConfig.disposePrevious) {
deferred?.cancel()
}

useCaseConfig.onStart()
deferred = coroutineScopeOwner.viewModelScope
.async(context = coroutineScopeOwner.getWorkerDispatcher(), start = CoroutineStart.LAZY) {
build(args)
}
.also {
coroutineScopeOwner.viewModelScope.launch(Dispatchers.Main) {
try {
useCaseConfig.onSuccess(it.await())
} catch (cancellation: CancellationException) {
// do nothing - this is normal way of suspend function interruption
} catch (error: Throwable) {
UseCaseErrorHandler.globalOnErrorLogger(error)
useCaseConfig.onError(error)
}
}
}
}

/**
* Synchronously executes use case and saves it's Deferred. By default all previous
* pending executions are canceled, this can be changed by the [cancelPrevious].
* This version gets initial arguments by [args].
*
* [UseCaseErrorHandler.globalOnErrorLogger] is not used in this version of the execute
* method since it is recommended to call all execute methods with [Result] return type
* from [UseCaseExecutionScope.launchWithHandler] method,
* where [UseCaseErrorHandler.globalOnErrorLogger] is used.
*
* @param args Arguments used for initial use case initialization.
* @return [Result] that encapsulates either a successful result with [Success] or a failed result with [Error]
*/
@Suppress("TooGenericExceptionCaught")
context(coroutineScopeOwner: CoroutineScopeOwner)
suspend fun <ARGS, T : Any?> UseCase<ARGS, T>.execute(
args: ARGS,
cancelPrevious: Boolean = true,
): Result<T> {
if (cancelPrevious) {
deferred?.cancel()
}

return try {
val newDeferred = coroutineScopeOwner.viewModelScope.async(coroutineScopeOwner.getWorkerDispatcher(), CoroutineStart.LAZY) {
build(args)
}.also { deferred = it }

Result.success(newDeferred.await())
} catch (exception: CancellationException) {
throw exception
} catch (exception: Throwable) {
Result.failure(exception)
}
}
Loading