sync

abstract suspend fun sync(): Flow<SyncProgress>

Synchronizes data and returns a Flow emitting the progress of the sync operation.

Return

A Flow emitting SyncProgress objects representing the progress of the sync operation.

Samples

import dev.atick.core.preferences.data.UserPreferencesDataSource
import dev.atick.core.room.data.LocalDataSource
import dev.atick.core.room.model.SyncAction
import dev.atick.core.utils.suspendRunCatching
import dev.atick.data.model.home.Jetpack
import dev.atick.data.model.home.mapToJetpacks
import dev.atick.data.model.home.toFirebaseJetpack
import dev.atick.data.model.home.toJetpack
import dev.atick.data.model.home.toJetpackEntity
import dev.atick.data.utils.SyncManager
import dev.atick.data.utils.SyncProgress
import dev.atick.firebase.firestore.data.FirebaseDataSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import timber.log.Timber
import javax.inject.Inject

fun main() { 
   //sampleStart 
   return flow {
    val userId = preferencesDataSource.getUserIdOrThrow()

    // Unsynced jetpacks
    val unsyncedJetpacks = localDataSource.getUnsyncedJetpacks(userId)
    val totalUnsyncedJetpacks = unsyncedJetpacks.size
    Timber.d("Syncing $totalUnsyncedJetpacks unsynced jetpacks")

    // Push updates to remote
    unsyncedJetpacks.forEachIndexed { index, unsyncedJetpack ->
        when (unsyncedJetpack.syncAction) {
            SyncAction.UPSERT -> {
                Timber.d("Syncing create/update jetpack: ${unsyncedJetpack.id}")
                firebaseDataSource.createOrUpdateJetpack(
                    unsyncedJetpack
                        .toFirebaseJetpack()
                        .copy(
                            lastSynced = System.currentTimeMillis(),
                        ),
                )
            }

            SyncAction.DELETE -> {
                firebaseDataSource.deleteJetpack(
                    unsyncedJetpack
                        .toFirebaseJetpack()
                        .copy(
                            lastSynced = System.currentTimeMillis(),
                        ),
                )
            }

            SyncAction.NONE -> {
                // Do nothing
            }
        }

        localDataSource.markAsSynced(unsyncedJetpack.id)
        emit(
            SyncProgress(
                total = totalUnsyncedJetpacks,
                current = index + 1,
                message = "Syncing jetpacks with the cloud",
            ),
        )
    }

    // Remote jetpacks
    val lastSynced = localDataSource.getLatestUpdateTimestamp(userId)
    val remoteJetpacks = firebaseDataSource.pullJetpacks(userId, lastSynced)
    val totalRemoteJetpacks = remoteJetpacks.size
    Timber.d("Syncing $totalRemoteJetpacks remote jetpacks")

    // Pull updates from remote
    // We pull after pushing local changes to save the local changes to the cloud first
    // and avoid accidentally overwriting them with stale data
    remoteJetpacks.forEachIndexed { index, remoteJetpack ->
        localDataSource.upsertJetpack(remoteJetpack.toJetpackEntity())
        emit(
            SyncProgress(
                total = totalRemoteJetpacks,
                current = index + 1,
                message = "Fetching jetpacks from the cloud",
            ),
        )
    }
} 
   //sampleEnd
}