Skip to content

Instantly share code, notes, and snippets.

// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
fun startUpSyncWork() = OneTimeWorkRequestBuilder<DelegatingWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.setConstraints(SyncConstraints)
// You can add any other input data as necessary
.setInputData(SyncWorker::class.classNameData())
.build()
// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
fun KClass<out CoroutineWorker>.classNameData() =
Data.Builder()
.putString(WORKER_CLASS_NAME, qualifiedName)
.build()
// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
class SyncInitializer : Initializer<Sync> {
override fun create(context: Context): Sync {
WorkManager.getInstance(context).apply {
// Run sync on app startup and ensure only one sync worker runs at any time
enqueueUniqueWork(
SyncWorkName,
ExistingWorkPolicy.KEEP,
// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
class DelegatingWorker(
appContext: Context,
workerParams: WorkerParameters,
) : CoroutineWorker(appContext, workerParams) {
private val workerClassName =
workerParams.inputData.getString(WORKER_CLASS_NAME) ?: ""
fun <Action : Any, State : Any> Flow<Action>.toStateStream(
initialState: State,
transform: (Flow<Action>) -> Flow<State.() -> State>
): Flow<State> = transform(this)
.scan(initialState) { state, mutation ->
mutation(state)
}
/**
* Class holding the context of the [Action] emitted that is being split out into
* a [Mutation] [Flow].
*
* Use typically involves invoking [type] to identify the [Action] stream being transformed, and
* subsequently invoking [flow] to perform a custom transformation on the split out [Flow].
*/
data class TransformationContext<Action : Any>(
private val type: Action,
val backing: Flow<Action>
/**
* Every toggle isExpanded == null should be processed, however every specific request to
* expand or collapse, should be distinct until changed.
*/
private fun Flow<Action.ToggleFilter>.filterToggleMutations(): Flow<Mutation<State>> =
map { it.isExpanded }
.scan(listOf<Boolean?>()) { emissions, isExpanded ->
(emissions + isExpanded).takeLast(2)
}
.transformWhile { emissions ->
private fun Flow<Action.GridSize>.gridSizeMutations(): Flow<Mutation<State>> =
distinctUntilChanged()
.map {
Mutation {
copy(gridSize = it.size)
}
}
fun archiveMutator(
scope: CoroutineScope,
route: ArchiveRoute,
repo: ArchiveRepository,
appMutator: AppMutator,
): Mutator<Action, StateFlow<State>> = stateFlowMutator(
scope = scope,
initialState = State(...),
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 2000),
transform = { actions ->
data class State(
val count: Int = 0
)
sealed class Action {
abstract val value: Int
data class Add(override val value: Int) : Action()
data class Subtract(override val value: Int) : Action()
}