diff --git a/wear/src/main/java/com/example/util/simpletimetracker/complication/WearComplicationService.kt b/wear/src/main/java/com/example/util/simpletimetracker/complication/WearComplicationService.kt index 416a28e7d..d01805e60 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/complication/WearComplicationService.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/complication/WearComplicationService.kt @@ -75,9 +75,9 @@ class WearComplicationService : SuspendingComplicationDataSourceService() { } private suspend fun buildShortTextData(): ComplicationData { - val activities = wearDataRepo.loadActivities() + val activities = wearDataRepo.loadActivities(forceReload = false) .getOrNull().orEmpty() - val currentActivities = wearDataRepo.loadCurrentActivities() + val currentActivities = wearDataRepo.loadCurrentActivities(forceReload = false) .getOrNull().orEmpty() // Take most current activity. diff --git a/wear/src/main/java/com/example/util/simpletimetracker/data/WearDataRepo.kt b/wear/src/main/java/com/example/util/simpletimetracker/data/WearDataRepo.kt index c8d61f20a..77fbd1d37 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/data/WearDataRepo.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/data/WearDataRepo.kt @@ -5,19 +5,31 @@ */ package com.example.util.simpletimetracker.data +import android.content.ComponentName +import android.content.Context +import androidx.wear.watchface.complications.datasource.ComplicationDataSourceUpdateRequester +import com.example.util.simpletimetracker.complication.WearComplicationService import com.example.util.simpletimetracker.wear_api.WearActivity import com.example.util.simpletimetracker.wear_api.WearCurrentActivity import com.example.util.simpletimetracker.wear_api.WearSettings import com.example.util.simpletimetracker.wear_api.WearTag +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject import javax.inject.Singleton @Singleton class WearDataRepo @Inject constructor( + @ApplicationContext private val context: Context, private val wearRPCClient: WearRPCClient, ) { @@ -28,31 +40,66 @@ class WearDataRepo @Inject constructor( onBufferOverflow = BufferOverflow.DROP_OLDEST, ) + private var activitiesCache: List? = null + private var currentActivitiesCache: List? = null + private val mutex: Mutex = Mutex() + init { - wearRPCClient.addListener { _dataUpdated.emit(Unit) } + wearRPCClient.addListener { + coroutineScope { + val deferred = mutableListOf>() + deferred += async { loadActivities(forceReload = true) } + deferred += async { loadCurrentActivities(forceReload = true) } + deferred.awaitAll() + updateComplications() + _dataUpdated.emit(Unit) + } + } } - suspend fun loadActivities(): Result> { - return runCatching { wearRPCClient.queryActivities() } + suspend fun loadActivities( + forceReload: Boolean, + ): Result> = mutex.withLock { + return runCatching { + activitiesCache.takeUnless { forceReload } + ?: wearRPCClient.queryActivities() + .also { activitiesCache = it } + } } - suspend fun loadCurrentActivities(): Result> { - return runCatching { wearRPCClient.queryCurrentActivities() } + suspend fun loadCurrentActivities( + forceReload: Boolean, + ): Result> = mutex.withLock { + return runCatching { + currentActivitiesCache.takeUnless { forceReload } + ?: wearRPCClient.queryCurrentActivities() + .also { currentActivitiesCache = it } + } } - suspend fun setCurrentActivities(starting: List): Result { + suspend fun setCurrentActivities(starting: List): Result = mutex.withLock { return runCatching { wearRPCClient.setCurrentActivities(starting) } } - suspend fun loadTagsForActivity(activityId: Long): Result> { + suspend fun loadTagsForActivity(activityId: Long): Result> = mutex.withLock { return runCatching { wearRPCClient.queryTagsForActivity(activityId) } } - suspend fun loadSettings(): Result { + suspend fun loadSettings(): Result = mutex.withLock { return runCatching { wearRPCClient.querySettings() } } - suspend fun openAppPhone(): Result { + suspend fun openAppPhone(): Result = mutex.withLock { return runCatching { wearRPCClient.openPhoneApp() } } + + fun updateComplications() { + ComplicationDataSourceUpdateRequester.create( + context = context, + complicationDataSourceComponent = ComponentName( + context, + WearComplicationService::class.java, + ), + ).requestUpdateAll() + } } \ No newline at end of file diff --git a/wear/src/main/java/com/example/util/simpletimetracker/data/WearMessenger.kt b/wear/src/main/java/com/example/util/simpletimetracker/data/WearMessenger.kt index aa6394872..cb544ce4f 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/data/WearMessenger.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/data/WearMessenger.kt @@ -5,11 +5,8 @@ */ package com.example.util.simpletimetracker.data -import android.content.ComponentName import android.content.Context import android.util.Log -import androidx.wear.watchface.complications.datasource.ComplicationDataSourceUpdateRequester -import com.example.util.simpletimetracker.complication.WearComplicationService import com.example.util.simpletimetracker.wear_api.WearRequests import com.google.android.gms.tasks.Tasks import com.google.android.gms.wearable.CapabilityClient @@ -78,7 +75,6 @@ class WearMessenger @Inject constructor( when (path) { WearRequests.DATA_UPDATED -> { listener?.invoke() - updateComplications() } else -> { Log.d(tag, "$path is an invalid RPC call") @@ -88,13 +84,6 @@ class WearMessenger @Inject constructor( return null } - private fun updateComplications() { - ComplicationDataSourceUpdateRequester.create( - context = context, - complicationDataSourceComponent = ComponentName(context, WearComplicationService::class.java), - ).requestUpdateAll() - } - private fun findNearestNode(capability: String): Node? { // Find all nodes which support the time tracking message Log.d(tag, "Searching for nodes with ${context.packageName} installed") diff --git a/wear/src/main/java/com/example/util/simpletimetracker/domain/CurrentActivitiesMediator.kt b/wear/src/main/java/com/example/util/simpletimetracker/domain/CurrentActivitiesMediator.kt index 92d2410d0..77d4f6cd5 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/domain/CurrentActivitiesMediator.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/domain/CurrentActivitiesMediator.kt @@ -28,7 +28,7 @@ class CurrentActivitiesMediator @Inject constructor( .getOrNull() ?: return Result.failure(WearRPCException) return if (settings.allowMultitasking) { - val currents = wearDataRepo.loadCurrentActivities() + val currents = wearDataRepo.loadCurrentActivities(forceReload = false) .getOrNull() ?: return Result.failure(WearRPCException) wearDataRepo.setCurrentActivities(currents.plus(newCurrent)) } else { @@ -37,7 +37,7 @@ class CurrentActivitiesMediator @Inject constructor( } suspend fun stop(currentId: Long): Result { - val currents = wearDataRepo.loadCurrentActivities() + val currents = wearDataRepo.loadCurrentActivities(forceReload = false) .getOrNull() ?: return Result.failure(WearRPCException) val remaining = currents.filter { it.id != currentId } return wearDataRepo.setCurrentActivities(remaining) diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/activities/ActivitiesViewModel.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/activities/ActivitiesViewModel.kt index 6681ea7a0..734e8c7c0 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/activities/ActivitiesViewModel.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/activities/ActivitiesViewModel.kt @@ -43,7 +43,6 @@ class ActivitiesViewModel @Inject constructor( fun init() { if (isInitialized) return - loadData() subscribeToDataUpdates() isInitialized = true } @@ -63,17 +62,18 @@ class ActivitiesViewModel @Inject constructor( if (result.isFailure) showError() } - fun onRefresh() { - loadData() + fun onRefresh() = viewModelScope.launch { + loadData(forceReload = true) + wearDataRepo.updateComplications() } fun onOpenOnPhone() = viewModelScope.launch { wearDataRepo.openAppPhone() } - private fun loadData() = viewModelScope.launch { - val activities = wearDataRepo.loadActivities() - val currentActivities = wearDataRepo.loadCurrentActivities() + private suspend fun loadData(forceReload: Boolean) { + val activities = wearDataRepo.loadActivities(forceReload) + val currentActivities = wearDataRepo.loadCurrentActivities(forceReload) when { activities.isFailure || currentActivities.isFailure -> { @@ -97,7 +97,7 @@ class ActivitiesViewModel @Inject constructor( private fun subscribeToDataUpdates() { viewModelScope.launch { - wearDataRepo.dataUpdated.collect { loadData() } + wearDataRepo.dataUpdated.collect { loadData(forceReload = false) } } }