From 83cfd398405dcb4e30b1d1b11a2793118210a0e0 Mon Sep 17 00:00:00 2001 From: Joseph Hale Date: Thu, 22 Feb 2024 01:39:43 -0700 Subject: [PATCH] feat(wear): Respect multi-tasking setting The WearOS app now follows the phone's multitasking setting. When multi-tasking is disabled, starting a new activity will stop all other running activities. When multi-tasking is enabled, starting/stopping an activity affects only that activity's state. closes thehale/SimpleTimeTracker-WearOS#18 --- .../mediators/CurrentActivitiesMediator.kt | 36 +++++++++++++++++++ .../remember/currentActivities.kt | 22 ++---------- .../presentation/screens/ActivitiesScreen.kt | 33 +++++------------ .../presentation/screens/TagsScreen.kt | 22 ++++++++---- 4 files changed, 62 insertions(+), 51 deletions(-) create mode 100644 wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt new file mode 100644 index 00000000..41398315 --- /dev/null +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt @@ -0,0 +1,36 @@ +package com.example.util.simpletimetracker.presentation.mediators + +import com.example.util.simpletimetracker.wearrpc.CurrentActivity +import com.example.util.simpletimetracker.wearrpc.Settings +import com.example.util.simpletimetracker.wearrpc.Tag +import com.example.util.simpletimetracker.wearrpc.WearRPCClient + +class CurrentActivitiesMediator( + private val rpc: WearRPCClient, + private val currents: Array, +) { + suspend fun start(activityId: Long) { + start(activityId, arrayOf()) + } + suspend fun start(activityId: Long, tags: Array) { + val newCurrent = CurrentActivity( + id = activityId, + startedAt = System.currentTimeMillis(), + tags = tags + ) + if (settings().multitasking) { + this.rpc.setCurrentActivities(currents.plus(newCurrent)) + } else { + this.rpc.setCurrentActivities(arrayOf(newCurrent)) + } + } + + suspend fun stop(currentId: Long) { + val remaining = currents.filter { it.id != currentId }.toTypedArray() + this.rpc.setCurrentActivities(remaining) + } + private suspend fun settings(): Settings { + return this.rpc.querySettings() + } + +} \ No newline at end of file diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/currentActivities.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/currentActivities.kt index 960c9f7e..9b1a1c9c 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/currentActivities.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/currentActivities.kt @@ -11,13 +11,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import com.example.util.simpletimetracker.wearrpc.CurrentActivity -import com.example.util.simpletimetracker.wearrpc.WearRPCClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async -import kotlinx.coroutines.launch /** * Handles asynchronous retrieval of the currently running activities in Simple Time Tracker on the @@ -38,30 +35,15 @@ import kotlinx.coroutines.launch * from the phone. */ @Composable -fun rememberCurrentActivities(): Triple< - Array, - (Array) -> Unit, - () -> Unit, - > { +fun rememberCurrentActivities(): Pair, () -> Unit> { var rpc = rememberRPCClient() var currentActivities: Array by remember { mutableStateOf(arrayOf()) } var currentActivitiesQueryCount by remember { mutableIntStateOf(0) } val queryCurrentActivities = { currentActivitiesQueryCount++ } - val coroutineScope = rememberCoroutineScope() LaunchedEffect(currentActivitiesQueryCount) { async(Dispatchers.Default) { currentActivities = rpc.queryCurrentActivities() } } - - return Triple( - currentActivities, - { updatedCurrentActivities -> - coroutineScope.launch(Dispatchers.Default) { - rpc.setCurrentActivities(updatedCurrentActivities) - queryCurrentActivities() - } - }, - { queryCurrentActivities() }, - ) + return Pair(currentActivities, { queryCurrentActivities() }) } \ No newline at end of file diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt index 8bd8fda7..b0e271b3 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt @@ -8,11 +8,11 @@ package com.example.util.simpletimetracker.presentation.screens import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import com.example.util.simpletimetracker.presentation.components.ActivitiesList +import com.example.util.simpletimetracker.presentation.mediators.CurrentActivitiesMediator import com.example.util.simpletimetracker.presentation.remember.rememberActivities import com.example.util.simpletimetracker.presentation.remember.rememberCurrentActivities import com.example.util.simpletimetracker.presentation.remember.rememberRPCClient import com.example.util.simpletimetracker.wearrpc.Activity -import com.example.util.simpletimetracker.wearrpc.CurrentActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -21,7 +21,8 @@ fun ActivitiesScreen(onSelectActivity: (activityId: Long) -> Unit) { val coroutineScope = rememberCoroutineScope() val rpc = rememberRPCClient() val (activities, refreshActivities) = rememberActivities() - val (currentActivities, setCurrentActivities, refreshCurrentActivities) = rememberCurrentActivities() + val (currentActivities, refreshCurrentActivities) = rememberCurrentActivities() + val currentActivitiesMediator = CurrentActivitiesMediator(rpc, currentActivities) val refresh = { refreshActivities() refreshCurrentActivities() @@ -36,38 +37,22 @@ fun ActivitiesScreen(onSelectActivity: (activityId: Long) -> Unit) { if (activityTags.isNotEmpty()) { coroutineScope.launch(Dispatchers.Main) { onSelectActivity(it.id) } } else { - rpc.setCurrentActivities( - arrayOf( - CurrentActivity( - it.id, - System.currentTimeMillis(), - arrayOf(), - ), - ), - ) + currentActivitiesMediator.start(it.id) refresh() } } }, onEnableActivity = { coroutineScope.launch(Dispatchers.Default) { - rpc.setCurrentActivities( - arrayOf( - CurrentActivity( - it.id, - System.currentTimeMillis(), - arrayOf(), - ), - ), - ) + currentActivitiesMediator.start(it.id) refresh() } }, onDisableActivity = { deselectedActivity: Activity -> - val remainingActivities = - currentActivities.filter { it.id != deselectedActivity.id }.toTypedArray() - setCurrentActivities(remainingActivities) - refresh() + coroutineScope.launch(Dispatchers.Default) { + currentActivitiesMediator.stop(deselectedActivity.id) + refresh() + } }, onRefresh = refresh, ) diff --git a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt index 837ed846..fdda1ab3 100644 --- a/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt +++ b/wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/TagsScreen.kt @@ -6,26 +6,34 @@ package com.example.util.simpletimetracker.presentation.screens import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import com.example.util.simpletimetracker.presentation.components.TagList +import com.example.util.simpletimetracker.presentation.mediators.CurrentActivitiesMediator import com.example.util.simpletimetracker.presentation.remember.rememberCurrentActivities +import com.example.util.simpletimetracker.presentation.remember.rememberRPCClient import com.example.util.simpletimetracker.presentation.remember.rememberTags import com.example.util.simpletimetracker.wearrpc.CurrentActivity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.time.Instant @Composable fun TagsScreen(activityId: Long, onSelectTag: () -> Unit) { + val coroutineScope = rememberCoroutineScope() + val rpc = rememberRPCClient() val (tags) = rememberTags(activityId) - val (_, setCurrents) = rememberCurrentActivities() + val (currentActivities) = rememberCurrentActivities() + val currentActivitiesMediator = CurrentActivitiesMediator(rpc, currentActivities) TagList( tags, onSelectTag = { - setCurrents( - arrayOf( - CurrentActivity(activityId, Instant.now().toEpochMilli(), arrayOf(it)), - ), - ) - onSelectTag() + coroutineScope.launch(Dispatchers.Default) { + currentActivitiesMediator.start(activityId, arrayOf(it)) + coroutineScope.launch(Dispatchers.Main) { + onSelectTag() + } + } }, ) } -- 2.51.2