Skip to content

Commit

Permalink
feat: SmartValue implementation for updatable multi-source values
Browse files Browse the repository at this point in the history
  • Loading branch information
y9vad9 committed Jan 10, 2024
1 parent c7e1927 commit 051757a
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
11 changes: 11 additions & 0 deletions foundation/smart-value/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id(libs.plugins.configurations.multiplatform.library.get().pluginId)
}

kotlin {
explicitApi()
}

dependencies {
commonMainImplementation(libs.kotlinx.coroutines)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.timemates.remote.value

import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.flow.Flow

/**
* A generic interface representing a remote value with local storage capabilities.
*
* This interface provides access to the current value, local value, and remote value.
* It also supports setting a listener to be notified when the value is received.
*
* @param T The type of the value.
*/
public interface SmartValue<T> {
/**
* A [Flow] representing the local value. This flow can emit multiple values if any change
* has occurred in the local storage (if watching for updates is supported).
*
* **Note**: Some [SmartValue]s can support remote only value meaning there's no
* value will be present.
*
* @see kotlinx.coroutines.flow.Flow
*/
public val localValue: Flow<T?>

/**
* A [Flow] representing the remote value. This flow can have multiple outputs depending on the
* implementation, as it may receive updates from external sources, such as the server.
*
* **Note**: [remoteValue] shouldn't be considered as 'last actual source' as for specific cases
* [localValue] can receive updates that made on client that appears much faster than on server
* or actual 'update watching' system could be missing.
*
* @see kotlinx.coroutines.flow.Flow
*/
public val remoteValue: Flow<T?>

public companion object {
/**
* A factory method for creating instances of [SmartValue].
*
* This method is used to construct a [SmartValue] instance with specified local and remote update
* logic, along with optional channels for receiving updates from local and remote sources.
*
* @param T The type of the value.
* @param local A suspending lambda representing the logic to retrieve the initial local value.
* @param remote A suspending lambda representing the logic to retrieve the initial remote value.
* @param localUpdates An optional [ReceiveChannel] to receive updates from local sources.
* @param remoteUpdates An optional [ReceiveChannel] to receive updates from remote sources.
* @return A [SmartValue] instance configured with the provided parameters.
*
* @see SmartValue
* @see kotlinx.coroutines.channels.ReceiveChannel
*/
public fun <T> of(
local: suspend () -> T?,
remote: suspend () -> T?,
localUpdates: ReceiveChannel<T>? = null,
remoteUpdates: ReceiveChannel<T>? = null,
): SmartValue<T> {
return UpdatableSmartValue(
local, remote, localUpdates, remoteUpdates
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.timemates.remote.value

import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.receiveAsFlow

internal class UpdatableSmartValue<T>(
private val local: suspend () -> T?,
private val remote: suspend () -> T?,
private val localUpdates: ReceiveChannel<T>? = null,
private val remoteUpdates: ReceiveChannel<T>? = null,
) : SmartValue<T> {
override val localValue: Flow<T?> = flow {
emit(local())

localUpdates?.receiveAsFlow()?.collect {
emit(it)
}
}
override val remoteValue: Flow<T?> = flow {
emit(remote())

remoteUpdates?.receiveAsFlow()?.collect {
emit(it)
}
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ include(
":foundation:system-tray",
":foundation:shimmer-compose",
":foundation:time",
":foundation:smart-value",
)

include(
Expand Down

0 comments on commit 051757a

Please sign in to comment.