A fork of Simple Time Tracker with WearOS support. (Now integrated upstream)
0

Configure Feed

Select the types of activity you want to include in your feed.

rename wear DTOs

razeeman (Mar 2, 2024, 7:48 PM +0300) e0fece08 11dac9b6

+172 -172
+16 -16
features/feature_wear/src/main/java/com/example/util/simpletimetracker/feature_wear/WearCommunicationInteractor.kt
··· 16 16 import com.example.util.simpletimetracker.domain.model.AppColor 17 17 import com.example.util.simpletimetracker.domain.model.RecordTag 18 18 import com.example.util.simpletimetracker.domain.model.RunningRecord 19 - import com.example.util.simpletimetracker.wear_api.Activity 20 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 21 - import com.example.util.simpletimetracker.wear_api.Settings 19 + import com.example.util.simpletimetracker.wear_api.WearActivity 20 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 21 + import com.example.util.simpletimetracker.wear_api.WearSettings 22 22 import com.example.util.simpletimetracker.wear_api.WearCommunicationAPI 23 - import com.example.util.simpletimetracker.wear_api.Tag 23 + import com.example.util.simpletimetracker.wear_api.WearTag 24 24 import javax.inject.Inject 25 25 26 26 class WearCommunicationInteractor @Inject constructor( ··· 33 33 private val appColorMapper: AppColorMapper, 34 34 ) : WearCommunicationAPI { 35 35 36 - override suspend fun queryActivities(): List<Activity> { 36 + override suspend fun queryActivities(): List<WearActivity> { 37 37 return recordTypeInteractor.getAll() 38 38 .filter { recordType -> !recordType.hidden } 39 39 .map { recordType -> 40 - Activity( 40 + WearActivity( 41 41 id = recordType.id, 42 42 name = recordType.name, 43 43 icon = recordType.icon, ··· 46 46 } 47 47 } 48 48 49 - override suspend fun queryCurrentActivities(): List<CurrentActivity> { 49 + override suspend fun queryCurrentActivities(): List<WearCurrentActivity> { 50 50 return runningRecordInteractor.getAll().map { record -> 51 - CurrentActivity( 51 + WearCurrentActivity( 52 52 id = record.id, 53 53 startedAt = record.timeStarted, 54 54 tags = record.tagIds.mapNotNull { tagId -> ··· 58 58 } 59 59 } 60 60 61 - override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 61 + override suspend fun setCurrentActivities(starting: List<WearCurrentActivity>) { 62 62 val currents = runningRecordInteractor.getAll() 63 63 val currentsIds = runningRecordInteractor.getAll().map(RunningRecord::id) 64 - val startingIds = starting.map(CurrentActivity::id) 64 + val startingIds = starting.map(WearCurrentActivity::id) 65 65 66 66 val stopped = currents.filter { it.id !in startingIds } 67 67 val started = starting.filter { it.id !in currentsIds } ··· 73 73 addRunningRecordMediator.add( 74 74 typeId = record.id, 75 75 timeStarted = record.startedAt, 76 - tagIds = record.tags.map(Tag::id), 76 + tagIds = record.tags.map(WearTag::id), 77 77 ) 78 78 } 79 79 } 80 80 81 - override suspend fun queryTagsForActivity(activityId: Long): List<Tag> { 81 + override suspend fun queryTagsForActivity(activityId: Long): List<WearTag> { 82 82 val activity = recordTypeInteractor.get(activityId) ?: return emptyList() 83 83 val activityColor = mapColor(activity.color) 84 84 return recordTagInteractor.getByTypeOrUntyped(activityId) ··· 91 91 private fun mapTag( 92 92 recordTag: RecordTag, 93 93 activityColor: Long? = null, 94 - ): Tag { 94 + ): WearTag { 95 95 val isGeneral = recordTag.typeId == 0L 96 96 val tagColor = if (isGeneral) { 97 97 mapColor(recordTag.color) ··· 99 99 activityColor 100 100 } 101 101 102 - return Tag( 102 + return WearTag( 103 103 id = recordTag.id, 104 104 name = recordTag.name, 105 105 isGeneral = isGeneral, ··· 111 111 return appColorMapper.mapToColorInt(appColor).toLong() 112 112 } 113 113 114 - override suspend fun querySettings(): Settings { 115 - return Settings( 114 + override suspend fun querySettings(): WearSettings { 115 + return WearSettings( 116 116 allowMultitasking = prefsInteractor.getAllowMultitasking(), 117 117 showRecordTagSelection = prefsInteractor.getShowRecordTagSelection(), 118 118 recordTagSelectionCloseAfterOne = prefsInteractor.getRecordTagSelectionCloseAfterOne(),
+10 -10
features/feature_wear/src/main/java/com/example/util/simpletimetracker/feature_wear/WearRPCServer.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.feature_wear 7 7 8 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 9 - import com.example.util.simpletimetracker.wear_api.Request 8 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 9 + import com.example.util.simpletimetracker.wear_api.WearRequests 10 10 import com.example.util.simpletimetracker.wear_api.WearCommunicationAPI 11 11 import com.google.gson.Gson 12 12 import com.google.gson.reflect.TypeToken ··· 20 20 private val gson = Gson() 21 21 22 22 suspend fun onRequest(path: String, request: ByteArray): ByteArray? { 23 - return if (path.startsWith(Request.PATH)) { 23 + return if (path.startsWith(WearRequests.PATH)) { 24 24 when (path) { 25 - Request.PING -> onPing(request) 26 - Request.QUERY_ACTIVITIES -> onQueryActivities() 27 - Request.QUERY_CURRENT_ACTIVITIES -> onQueryCurrentActivities() 28 - Request.SET_CURRENT_ACTIVITIES -> onSetCurrentActivities(request) 29 - Request.QUERY_TAGS_FOR_ACTIVITY -> onQueryTagsForActivity(request) 30 - Request.QUERY_SETTINGS -> onQuerySettings() 25 + WearRequests.PING -> onPing(request) 26 + WearRequests.QUERY_ACTIVITIES -> onQueryActivities() 27 + WearRequests.QUERY_CURRENT_ACTIVITIES -> onQueryCurrentActivities() 28 + WearRequests.SET_CURRENT_ACTIVITIES -> onSetCurrentActivities(request) 29 + WearRequests.QUERY_TAGS_FOR_ACTIVITY -> onQueryTagsForActivity(request) 30 + WearRequests.QUERY_SETTINGS -> onQuerySettings() 31 31 else -> { 32 32 Timber.d("$path is an invalid RPC call") 33 33 null ··· 44 44 } 45 45 46 46 private suspend fun onSetCurrentActivities(request: ByteArray): ByteArray? { 47 - val activities: List<CurrentActivity> = mapFromBytes(request) ?: return null 47 + val activities: List<WearCurrentActivity> = mapFromBytes(request) ?: return null 48 48 api.setCurrentActivities(activities) 49 49 return ByteArray(0) 50 50 }
+17 -17
features/feature_wear/src/test/java/com/example/util/simpletimetracker/feature_wear/WearRPCServerTest.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.feature_wear 7 7 8 - import com.example.util.simpletimetracker.wear_api.Activity 9 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 8 + import com.example.util.simpletimetracker.wear_api.WearActivity 9 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 10 10 import com.example.util.simpletimetracker.presentation.data.Messenger 11 11 import com.example.util.simpletimetracker.wear_api.MockWearCommunicationAPI 12 - import com.example.util.simpletimetracker.wear_api.Settings 13 - import com.example.util.simpletimetracker.wear_api.Tag 12 + import com.example.util.simpletimetracker.wear_api.WearSettings 13 + import com.example.util.simpletimetracker.wear_api.WearTag 14 14 import com.example.util.simpletimetracker.presentation.data.WearRPCClient 15 15 import kotlinx.coroutines.test.runTest 16 16 import org.junit.Assert.assertArrayEquals ··· 29 29 private lateinit var messenger: Messenger 30 30 private lateinit var client: WearRPCClient 31 31 32 - private val sampleSettings = Settings( 32 + private val sampleSettings = WearSettings( 33 33 allowMultitasking = true, 34 34 showRecordTagSelection = false, 35 35 recordTagSelectionCloseAfterOne = false, 36 36 recordTagSelectionEvenForGeneralTags = false, 37 37 ) 38 38 39 - private val tagFriends = Tag(1, "Friends", isGeneral = false, 0xFFFD3251) 40 - private val tagFamily = Tag(2, "Family", isGeneral = true, 0xFFFD3251) 41 - private val tagShopping = Tag(3, "Shopping", isGeneral = false, 0xFFFF0000) 42 - private val tagWork = Tag(14, "Work", isGeneral = false, 0xFF00FF00) 39 + private val tagFriends = WearTag(1, "Friends", isGeneral = false, 0xFFFD3251) 40 + private val tagFamily = WearTag(2, "Family", isGeneral = true, 0xFFFD3251) 41 + private val tagShopping = WearTag(3, "Shopping", isGeneral = false, 0xFFFF0000) 42 + private val tagWork = WearTag(14, "Work", isGeneral = false, 0xFF00FF00) 43 43 44 44 @Before 45 45 fun setup() { ··· 77 77 @Test 78 78 fun returns_no_activities_when_none_are_available() = runTest { 79 79 val response = client.queryActivities() 80 - assertArrayEquals(arrayOf<Activity>(), response) 80 + assertArrayEquals(arrayOf<WearActivity>(), response) 81 81 } 82 82 83 83 @Test 84 84 fun returns_one_activity_when_one_exists() = runTest { 85 - val activities = arrayOf(Activity(42, "Chores", "🎉", 0xFF00FF00)) 85 + val activities = arrayOf(WearActivity(42, "Chores", "🎉", 0xFF00FF00)) 86 86 api.mock_queryActivities(activities) 87 87 val response = client.queryActivities() 88 88 assertArrayEquals(activities, response) ··· 91 91 @Test 92 92 fun returns_all_existing_activities() = runTest { 93 93 val activities = arrayOf( 94 - Activity(13, "Singing", "🎶", 0xFF123456), 95 - Activity(24, "Homework", "📝", 0xFFABCDEF), 94 + WearActivity(13, "Singing", "🎶", 0xFF123456), 95 + WearActivity(24, "Homework", "📝", 0xFFABCDEF), 96 96 ) 97 97 api.mock_queryActivities(activities) 98 98 val response = client.queryActivities() ··· 101 101 102 102 @Test 103 103 fun returns_no_activities_when_none_are_running() = runTest { 104 - val activities = arrayOf<CurrentActivity>() 104 + val activities = arrayOf<WearCurrentActivity>() 105 105 val response = client.queryCurrentActivities() 106 106 assertArrayEquals(activities, response) 107 107 } ··· 110 110 fun returns_one_current_activity_when_one_exists() = runTest { 111 111 val jan_31_2024_afternoon = 1706704801L 112 112 val activities = arrayOf( 113 - CurrentActivity( 113 + WearCurrentActivity( 114 114 42, 115 115 jan_31_2024_afternoon, 116 116 arrayOf(tagFriends, tagFamily), ··· 126 126 val jan_31_2024_afternoon = 1706704801L 127 127 val jan_31_2024_evening = 1706751601L 128 128 val activities = arrayOf( 129 - CurrentActivity( 129 + WearCurrentActivity( 130 130 42, 131 131 jan_31_2024_afternoon, 132 132 arrayOf(tagFriends, tagFamily), 133 133 ), 134 - CurrentActivity( 134 + WearCurrentActivity( 135 135 42, 136 136 jan_31_2024_evening, 137 137 arrayOf(tagShopping),
+10 -10
wear/src/main/java/com/example/util/simpletimetracker/presentation/components/ActivitiesList.kt
··· 15 15 import androidx.wear.tooling.preview.devices.WearDevices 16 16 import com.example.util.simpletimetracker.R 17 17 import com.example.util.simpletimetracker.presentation.layout.ScaffoldedScrollingColumn 18 - import com.example.util.simpletimetracker.wear_api.Activity 19 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 18 + import com.example.util.simpletimetracker.wear_api.WearActivity 19 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 20 20 21 21 @Composable 22 22 fun ActivitiesList( 23 - activities: List<Activity>, 24 - currentActivities: List<CurrentActivity>, 25 - onSelectActivity: (activity: Activity) -> Unit, 26 - onEnableActivity: (activity: Activity) -> Unit, 27 - onDisableActivity: (activity: Activity) -> Unit, 23 + activities: List<WearActivity>, 24 + currentActivities: List<WearCurrentActivity>, 25 + onSelectActivity: (activity: WearActivity) -> Unit, 26 + onEnableActivity: (activity: WearActivity) -> Unit, 27 + onDisableActivity: (activity: WearActivity) -> Unit, 28 28 onRefresh: () -> Unit, 29 29 footer: @Composable () -> Unit = {} 30 30 ) { ··· 74 74 @Composable 75 75 private fun Preview() { 76 76 val activities = listOf( 77 - Activity(1234, "Chores", "🧹", 0xFFFA0000), 78 - Activity(4321, "Sleep", "🛏️", 0xFF0000FA), 77 + WearActivity(1234, "Chores", "🧹", 0xFFFA0000), 78 + WearActivity(4321, "Sleep", "🛏️", 0xFF0000FA), 79 79 ) 80 80 val currents = listOf( 81 - CurrentActivity(id = 4321, startedAt = 1708241427000L, tags = emptyList()), 81 + WearCurrentActivity(id = 4321, startedAt = 1708241427000L, tags = emptyList()), 82 82 ) 83 83 ActivitiesList( 84 84 activities = activities,
+14 -14
wear/src/main/java/com/example/util/simpletimetracker/presentation/components/ActivityChip.kt
··· 26 26 import androidx.wear.compose.material.ToggleChipDefaults 27 27 import androidx.wear.tooling.preview.devices.WearDevices 28 28 import com.example.util.simpletimetracker.presentation.remember.rememberDurationSince 29 - import com.example.util.simpletimetracker.wear_api.Activity 30 - import com.example.util.simpletimetracker.wear_api.Tag 29 + import com.example.util.simpletimetracker.wear_api.WearActivity 30 + import com.example.util.simpletimetracker.wear_api.WearTag 31 31 import java.time.Duration 32 32 import java.time.Instant 33 33 ··· 37 37 38 38 @Composable 39 39 fun ActivityChip( 40 - activity: Activity, 40 + activity: WearActivity, 41 41 startedAt: Long? = null, 42 - tags: List<Tag> = emptyList(), 42 + tags: List<WearTag> = emptyList(), 43 43 onClick: () -> Unit = {}, 44 44 onToggleOn: () -> Unit = {}, 45 45 onToggleOff: () -> Unit = {}, ··· 138 138 @Preview(device = WearDevices.LARGE_ROUND) 139 139 @Composable 140 140 fun SampleCooking() { 141 - ActivityChip(Activity(123, "Cooking", "🎉", 0xFF123456)) 141 + ActivityChip(WearActivity(123, "Cooking", "🎉", 0xFF123456)) 142 142 } 143 143 144 144 @Preview(device = WearDevices.LARGE_ROUND) 145 145 @Composable 146 146 fun SampleSleep() { 147 - ActivityChip(Activity(456, "Sleeping", "🛏️", 0xFFABCDEF)) 147 + ActivityChip(WearActivity(456, "Sleeping", "🛏️", 0xFFABCDEF)) 148 148 } 149 149 150 150 @Preview(device = WearDevices.LARGE_ROUND) 151 151 @Composable 152 152 fun SampleText() { 153 - ActivityChip(Activity(456, "Sleeping", "Zzzz", 0xFFABCDEF)) 153 + ActivityChip(WearActivity(456, "Sleeping", "Zzzz", 0xFFABCDEF)) 154 154 } 155 155 156 156 @Preview(device = WearDevices.LARGE_ROUND) 157 157 @Composable 158 158 fun SampleIcon() { 159 - ActivityChip(Activity(456, "Sleeping", "ic_hotel_24px", 0xFFABCDEF)) 159 + ActivityChip(WearActivity(456, "Sleeping", "ic_hotel_24px", 0xFFABCDEF)) 160 160 } 161 161 162 162 @Preview(device = WearDevices.LARGE_ROUND) 163 163 @Composable 164 164 fun InvalidIcon() { 165 - ActivityChip(Activity(456, "Sleeping", "ic_gobbldeegoock_24px", 0xFFABCDEF)) 165 + ActivityChip(WearActivity(456, "Sleeping", "ic_gobbldeegoock_24px", 0xFFABCDEF)) 166 166 } 167 167 168 168 @Preview(device = WearDevices.LARGE_ROUND) ··· 171 171 // TODO handle the look of light colored chips 172 172 // Note: A white color is only possible when using the RGB color picker. 173 173 // The default color options in the phone app are mostly darker shades. 174 - ActivityChip(Activity(456, "Sleeping", "🛏️", 0xFFFFFFFF)) 174 + ActivityChip(WearActivity(456, "Sleeping", "🛏️", 0xFFFFFFFF)) 175 175 } 176 176 177 177 @Preview(device = WearDevices.LARGE_ROUND) 178 178 @Composable 179 179 fun CurrentlyRunning() { 180 180 ActivityChip( 181 - Activity(456, "Sleeping", "🛏️", 0xFFABCDEF), 181 + WearActivity(456, "Sleeping", "🛏️", 0xFFABCDEF), 182 182 startedAt = Instant.now().toEpochMilli() - 360000, 183 183 ) 184 184 } ··· 187 187 @Composable 188 188 fun CurrentlyRunningWithTags() { 189 189 ActivityChip( 190 - Activity(456, "Sleeping", "🛏️", 0xFFABCDEF), 190 + WearActivity(456, "Sleeping", "🛏️", 0xFFABCDEF), 191 191 startedAt = Instant.now().toEpochMilli() - 360000, 192 192 tags = listOf( 193 - Tag(id = 2, name = "Work", isGeneral = true, color = 0xFFFFAA22), 194 - Tag(id = 4, name = "Hotel", isGeneral = false, color = 0xFFABCDEF), 193 + WearTag(id = 2, name = "Work", isGeneral = true, color = 0xFFFFAA22), 194 + WearTag(id = 4, name = "Hotel", isGeneral = false, color = 0xFFABCDEF), 195 195 ), 196 196 ) 197 197 }
+7 -7
wear/src/main/java/com/example/util/simpletimetracker/presentation/components/TagChip.kt
··· 25 25 import androidx.wear.compose.material.Text 26 26 import androidx.wear.compose.material.ToggleChipDefaults 27 27 import androidx.wear.tooling.preview.devices.WearDevices 28 - import com.example.util.simpletimetracker.wear_api.Tag 28 + import com.example.util.simpletimetracker.wear_api.WearTag 29 29 30 30 enum class TagSelectionMode { 31 31 SINGLE, MULTI, ··· 33 33 34 34 @Composable 35 35 fun TagChip( 36 - tag: Tag, 36 + tag: WearTag, 37 37 onClick: () -> Unit = {}, 38 38 onToggleOn: () -> Unit = {}, 39 39 onToggleOff: () -> Unit = {}, ··· 57 57 } 58 58 59 59 @Composable 60 - private fun SingleSelectTagChip(tag: Tag, onClick: () -> Unit) { 60 + private fun SingleSelectTagChip(tag: WearTag, onClick: () -> Unit) { 61 61 Chip( 62 62 onClick = onClick, 63 63 label = { Text(tag.name, maxLines = 1, overflow = TextOverflow.Ellipsis) }, ··· 70 70 71 71 @Composable 72 72 private fun MultiSelectTagChip( 73 - tag: Tag, 73 + tag: WearTag, 74 74 onClick: () -> Unit = {}, 75 75 onToggleOn: () -> Unit = {}, 76 76 onToggleOff: () -> Unit = {}, ··· 118 118 @Composable 119 119 private fun Default() { 120 120 TagChip( 121 - tag = Tag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 121 + tag = WearTag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 122 122 onClick = {}, 123 123 ) 124 124 } ··· 128 128 @Composable 129 129 private fun MultiSelectMode() { 130 130 TagChip( 131 - tag = Tag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF654321), 131 + tag = WearTag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF654321), 132 132 onClick = {}, 133 133 mode = TagSelectionMode.MULTI, 134 134 ) ··· 138 138 @Composable 139 139 private fun MultiSelectChecked() { 140 140 MultiSelectTagChip( 141 - tag = Tag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF654321), 141 + tag = WearTag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF654321), 142 142 onClick = {}, 143 143 checked = true, 144 144 )
+8 -8
wear/src/main/java/com/example/util/simpletimetracker/presentation/components/TagList.kt
··· 19 19 import androidx.wear.tooling.preview.devices.WearDevices 20 20 import com.example.util.simpletimetracker.R 21 21 import com.example.util.simpletimetracker.presentation.layout.ScaffoldedScrollingColumn 22 - import com.example.util.simpletimetracker.wear_api.Tag 22 + import com.example.util.simpletimetracker.wear_api.WearTag 23 23 24 24 @Composable 25 25 fun TagList( 26 - tags: List<Tag>, 26 + tags: List<WearTag>, 27 27 mode: TagSelectionMode = TagSelectionMode.SINGLE, 28 - onSelectionComplete: (tags: List<Tag>) -> Unit = {}, 28 + onSelectionComplete: (tags: List<WearTag>) -> Unit = {}, 29 29 ) { 30 - var selectedTags: List<Tag> by remember { mutableStateOf(listOf()) } 30 + var selectedTags: List<WearTag> by remember { mutableStateOf(listOf()) } 31 31 ScaffoldedScrollingColumn { 32 32 if (tags.isEmpty()) { 33 33 item { ··· 66 66 private fun WithSomeTags() { 67 67 TagList( 68 68 tags = listOf( 69 - Tag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 70 - Tag(id = 124, name = "Personal", isGeneral = true, color = 0xFF123456), 69 + WearTag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 70 + WearTag(id = 124, name = "Personal", isGeneral = true, color = 0xFF123456), 71 71 ), 72 72 ) 73 73 } ··· 77 77 private fun MultiSelectMode() { 78 78 TagList( 79 79 tags = listOf( 80 - Tag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 81 - Tag(id = 124, name = "Personal", isGeneral = true, color = 0xFF123456), 80 + WearTag(id = 123, name = "Sleep", isGeneral = false, color = 0xFF123456), 81 + WearTag(id = 124, name = "Personal", isGeneral = true, color = 0xFF123456), 82 82 ), 83 83 mode = TagSelectionMode.MULTI, 84 84 )
+20 -20
wear/src/main/java/com/example/util/simpletimetracker/presentation/data/WearRPCClient.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.presentation.data 7 7 8 - import com.example.util.simpletimetracker.wear_api.Activity 9 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 10 - import com.example.util.simpletimetracker.wear_api.Request 11 - import com.example.util.simpletimetracker.wear_api.Settings 12 - import com.example.util.simpletimetracker.wear_api.Tag 8 + import com.example.util.simpletimetracker.wear_api.WearActivity 9 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 10 + import com.example.util.simpletimetracker.wear_api.WearRequests 11 + import com.example.util.simpletimetracker.wear_api.WearSettings 12 + import com.example.util.simpletimetracker.wear_api.WearTag 13 13 import com.example.util.simpletimetracker.wear_api.WearCommunicationAPI 14 14 import com.google.gson.Gson 15 15 import com.google.gson.reflect.TypeToken ··· 23 23 24 24 override suspend fun ping(message: String): String { 25 25 val response: String? = messenger 26 - .send(Request.PING, mapToBytes(message)) 26 + .send(WearRequests.PING, mapToBytes(message)) 27 27 ?.let(::mapFromBytes) 28 28 29 29 return response ?: throw WearRPCException("No response") 30 30 } 31 31 32 - override suspend fun queryActivities(): List<Activity> { 33 - val response: List<Activity>? = messenger 34 - .send(Request.QUERY_ACTIVITIES) 32 + override suspend fun queryActivities(): List<WearActivity> { 33 + val response: List<WearActivity>? = messenger 34 + .send(WearRequests.QUERY_ACTIVITIES) 35 35 ?.let(::mapFromBytes) 36 36 37 37 return response ?: throw WearRPCException("No response") 38 38 } 39 39 40 - override suspend fun queryCurrentActivities(): List<CurrentActivity> { 41 - val response: List<CurrentActivity>? = messenger 42 - .send(Request.QUERY_CURRENT_ACTIVITIES) 40 + override suspend fun queryCurrentActivities(): List<WearCurrentActivity> { 41 + val response: List<WearCurrentActivity>? = messenger 42 + .send(WearRequests.QUERY_CURRENT_ACTIVITIES) 43 43 ?.let(::mapFromBytes) 44 44 45 45 return response ?: throw WearRPCException("No response") 46 46 } 47 47 48 - override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 49 - messenger.send(Request.SET_CURRENT_ACTIVITIES, mapToBytes(starting)) 48 + override suspend fun setCurrentActivities(starting: List<WearCurrentActivity>) { 49 + messenger.send(WearRequests.SET_CURRENT_ACTIVITIES, mapToBytes(starting)) 50 50 } 51 51 52 - override suspend fun queryTagsForActivity(activityId: Long): List<Tag> { 53 - val response: List<Tag>? = messenger 54 - .send(Request.QUERY_TAGS_FOR_ACTIVITY, mapToBytes(activityId)) 52 + override suspend fun queryTagsForActivity(activityId: Long): List<WearTag> { 53 + val response: List<WearTag>? = messenger 54 + .send(WearRequests.QUERY_TAGS_FOR_ACTIVITY, mapToBytes(activityId)) 55 55 ?.let(::mapFromBytes) 56 56 57 57 return response ?: throw WearRPCException("No response") 58 58 } 59 59 60 - override suspend fun querySettings(): Settings { 61 - val response: Settings? = messenger 62 - .send(Request.QUERY_SETTINGS) 60 + override suspend fun querySettings(): WearSettings { 61 + val response: WearSettings? = messenger 62 + .send(WearRequests.QUERY_SETTINGS) 63 63 ?.let(::mapFromBytes) 64 64 65 65 return response ?: throw WearRPCException("No response")
+7 -7
wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt
··· 1 1 package com.example.util.simpletimetracker.presentation.mediators 2 2 3 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 4 - import com.example.util.simpletimetracker.wear_api.Settings 5 - import com.example.util.simpletimetracker.wear_api.Tag 3 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 4 + import com.example.util.simpletimetracker.wear_api.WearSettings 5 + import com.example.util.simpletimetracker.wear_api.WearTag 6 6 import com.example.util.simpletimetracker.presentation.data.WearRPCClient 7 7 8 8 class CurrentActivitiesMediator( 9 9 private val rpc: WearRPCClient, 10 - private val currents: List<CurrentActivity>, 10 + private val currents: List<WearCurrentActivity>, 11 11 ) { 12 12 suspend fun start(activityId: Long) { 13 13 start(activityId, emptyList()) 14 14 } 15 - suspend fun start(activityId: Long, tags: List<Tag>) { 16 - val newCurrent = CurrentActivity( 15 + suspend fun start(activityId: Long, tags: List<WearTag>) { 16 + val newCurrent = WearCurrentActivity( 17 17 id = activityId, 18 18 startedAt = System.currentTimeMillis(), 19 19 tags = tags ··· 29 29 val remaining = currents.filter { it.id != currentId } 30 30 this.rpc.setCurrentActivities(remaining) 31 31 } 32 - private suspend fun settings(): Settings { 32 + private suspend fun settings(): WearSettings { 33 33 return this.rpc.querySettings() 34 34 } 35 35
+6 -6
wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/StartActivityMediator.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.presentation.mediators 7 7 8 - import com.example.util.simpletimetracker.wear_api.Activity 9 - import com.example.util.simpletimetracker.wear_api.Settings 8 + import com.example.util.simpletimetracker.wear_api.WearActivity 9 + import com.example.util.simpletimetracker.wear_api.WearSettings 10 10 import com.example.util.simpletimetracker.wear_api.WearCommunicationAPI 11 11 12 12 class StartActivityMediator( 13 13 private val api: WearCommunicationAPI, 14 - private val onRequestStartActivity: suspend (activity: Activity) -> Unit, 15 - private val onRequestTagSelection: suspend (activity: Activity) -> Unit, 14 + private val onRequestStartActivity: suspend (activity: WearActivity) -> Unit, 15 + private val onRequestTagSelection: suspend (activity: WearActivity) -> Unit, 16 16 ) { 17 - suspend fun requestStart(activity: Activity) { 17 + suspend fun requestStart(activity: WearActivity) { 18 18 val settings = api.querySettings() 19 19 if (settings.showRecordTagSelection) { 20 20 requestTagSelectionIfNeeded(activity, settings) ··· 23 23 } 24 24 } 25 25 26 - private suspend fun requestTagSelectionIfNeeded(activity: Activity, settings: Settings) { 26 + private suspend fun requestTagSelectionIfNeeded(activity: WearActivity, settings: WearSettings) { 27 27 val tags = api.queryTagsForActivity(activity.id) 28 28 val generalTags = tags.filter { it.isGeneral } 29 29 val nonGeneralTags = tags.filter { !it.isGeneral }
+3 -3
wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/activities.kt
··· 12 12 import androidx.compose.runtime.mutableStateOf 13 13 import androidx.compose.runtime.remember 14 14 import androidx.compose.runtime.setValue 15 - import com.example.util.simpletimetracker.wear_api.Activity 15 + import com.example.util.simpletimetracker.wear_api.WearActivity 16 16 import kotlinx.coroutines.Dispatchers 17 17 import kotlinx.coroutines.async 18 18 ··· 33 33 * from the phone. 34 34 */ 35 35 @Composable 36 - fun rememberActivities(): Pair<List<Activity>, () -> Unit> { 36 + fun rememberActivities(): Pair<List<WearActivity>, () -> Unit> { 37 37 val rpc = rememberRPCClient() 38 - var activities: List<Activity> by remember { mutableStateOf(emptyList()) } 38 + var activities: List<WearActivity> by remember { mutableStateOf(emptyList()) } 39 39 var activitiesQueryCount by remember { mutableIntStateOf(0) } 40 40 LaunchedEffect(activitiesQueryCount) { 41 41 async(Dispatchers.Default) {
+3 -3
wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/currentActivities.kt
··· 12 12 import androidx.compose.runtime.mutableStateOf 13 13 import androidx.compose.runtime.remember 14 14 import androidx.compose.runtime.setValue 15 - import com.example.util.simpletimetracker.wear_api.CurrentActivity 15 + import com.example.util.simpletimetracker.wear_api.WearCurrentActivity 16 16 import kotlinx.coroutines.Dispatchers 17 17 import kotlinx.coroutines.async 18 18 ··· 35 35 * from the phone. 36 36 */ 37 37 @Composable 38 - fun rememberCurrentActivities(): Pair<List<CurrentActivity>, () -> Unit> { 38 + fun rememberCurrentActivities(): Pair<List<WearCurrentActivity>, () -> Unit> { 39 39 val rpc = rememberRPCClient() 40 - var currentActivities: List<CurrentActivity> by remember { mutableStateOf(emptyList()) } 40 + var currentActivities: List<WearCurrentActivity> by remember { mutableStateOf(emptyList()) } 41 41 var currentActivitiesQueryCount by remember { mutableIntStateOf(0) } 42 42 val queryCurrentActivities = { currentActivitiesQueryCount++ } 43 43 LaunchedEffect(currentActivitiesQueryCount) {
+3 -3
wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/settings.kt
··· 12 12 import androidx.compose.runtime.mutableStateOf 13 13 import androidx.compose.runtime.remember 14 14 import androidx.compose.runtime.setValue 15 - import com.example.util.simpletimetracker.wear_api.Settings 15 + import com.example.util.simpletimetracker.wear_api.WearSettings 16 16 import kotlinx.coroutines.Dispatchers 17 17 import kotlinx.coroutines.async 18 18 ··· 31 31 * `refresh` is a function you can call to forcibly re-request the settings from the phone. 32 32 */ 33 33 @Composable 34 - fun rememberSettings(): Pair<Settings?, () -> Unit> { 34 + fun rememberSettings(): Pair<WearSettings?, () -> Unit> { 35 35 var rpc = rememberRPCClient() 36 - var settings: Settings? by remember { mutableStateOf(null) } 36 + var settings: WearSettings? by remember { mutableStateOf(null) } 37 37 var settingsQueryCount by remember { mutableIntStateOf(0) } 38 38 LaunchedEffect(settingsQueryCount) { 39 39 async(Dispatchers.Default) {
+3 -3
wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/tags.kt
··· 12 12 import androidx.compose.runtime.mutableStateOf 13 13 import androidx.compose.runtime.remember 14 14 import androidx.compose.runtime.setValue 15 - import com.example.util.simpletimetracker.wear_api.Tag 15 + import com.example.util.simpletimetracker.wear_api.WearTag 16 16 import kotlinx.coroutines.Dispatchers 17 17 import kotlinx.coroutines.async 18 18 ··· 34 34 * from the phone. 35 35 */ 36 36 @Composable 37 - fun rememberTags(activityId: Long): Pair<List<Tag>, () -> Unit> { 37 + fun rememberTags(activityId: Long): Pair<List<WearTag>, () -> Unit> { 38 38 val rpc = rememberRPCClient() 39 - var tags: List<Tag> by remember { mutableStateOf(emptyList()) } 39 + var tags: List<WearTag> by remember { mutableStateOf(emptyList()) } 40 40 var tagsQueryCount by remember { mutableIntStateOf(0) } 41 41 LaunchedEffect(tagsQueryCount) { 42 42 async(Dispatchers.Default) {
+4 -4
wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt
··· 14 14 import com.example.util.simpletimetracker.presentation.remember.rememberActivities 15 15 import com.example.util.simpletimetracker.presentation.remember.rememberCurrentActivities 16 16 import com.example.util.simpletimetracker.presentation.remember.rememberRPCClient 17 - import com.example.util.simpletimetracker.wear_api.Activity 17 + import com.example.util.simpletimetracker.wear_api.WearActivity 18 18 import com.example.util.simpletimetracker.presentation.mediators.StartActivityMediator 19 19 import kotlinx.coroutines.Dispatchers 20 20 import kotlinx.coroutines.launch ··· 33 33 refreshCurrentActivities() 34 34 } 35 35 val currentActivitiesMediator = CurrentActivitiesMediator(rpc, currentActivities) 36 - val startActivityWithoutTags: (Activity) -> Unit = { 36 + val startActivityWithoutTags: (WearActivity) -> Unit = { 37 37 Log.d("ActivitiesScreen", "Starting ${it.name} (#${it.id}) without tags") 38 38 coroutineScope.launch(Dispatchers.Default) { 39 39 currentActivitiesMediator.start(it.id) 40 40 refresh() 41 41 } 42 42 } 43 - val startActivityWithTags: (Activity) -> Unit = { 43 + val startActivityWithTags: (WearActivity) -> Unit = { 44 44 coroutineScope.launch(Dispatchers.Main) { 45 45 Log.d("ActivitiesScreen", "Starting ${it.name} (#${it.id}) with tags") 46 46 onRequestTagSelection(it.id) 47 47 } 48 48 } 49 - val stopActivity: (Activity) -> Unit = { 49 + val stopActivity: (WearActivity) -> Unit = { 50 50 Log.d("ActivitiesScreen", "Stopping ${it.name} (#${it.id})") 51 51 coroutineScope.launch(Dispatchers.Default) { 52 52 currentActivitiesMediator.stop(it.id)
+11 -11
wear/src/test/java/com/example/util/simpletimetracker/wear/StartActivityMediatorTest.kt
··· 6 6 package com.example.util.simpletimetracker.wear 7 7 8 8 import com.example.util.simpletimetracker.presentation.mediators.StartActivityMediator 9 - import com.example.util.simpletimetracker.wear_api.Activity 9 + import com.example.util.simpletimetracker.wear_api.WearActivity 10 10 import com.example.util.simpletimetracker.wear_api.MockWearCommunicationAPI 11 - import com.example.util.simpletimetracker.wear_api.Settings 12 - import com.example.util.simpletimetracker.wear_api.Tag 11 + import com.example.util.simpletimetracker.wear_api.WearSettings 12 + import com.example.util.simpletimetracker.wear_api.WearTag 13 13 import kotlinx.coroutines.test.runTest 14 14 import org.junit.Assert.assertEquals 15 15 import org.junit.Before ··· 26 26 onRequestTagSelection = requestTagCallback, 27 27 ) 28 28 29 - private val sampleActivity = Activity(id = 1, name = "Sleep", icon = "🛏️", color = 0xFF123456) 29 + private val sampleActivity = WearActivity(id = 1, name = "Sleep", icon = "🛏️", color = 0xFF123456) 30 30 private val sampleGeneralTag = 31 - Tag(id = 13, name = "Sleep", isGeneral = true, color = 0xFF654321) 31 + WearTag(id = 13, name = "Sleep", isGeneral = true, color = 0xFF654321) 32 32 private val sampleNonGeneralTag = 33 - Tag(id = 14, name = "Work", isGeneral = false, color = 0xFF654321) 34 - private val settings = Settings( 33 + WearTag(id = 14, name = "Work", isGeneral = false, color = 0xFF654321) 34 + private val settings = WearSettings( 35 35 allowMultitasking = false, 36 36 showRecordTagSelection = false, 37 37 recordTagSelectionCloseAfterOne = false, ··· 104 104 startCallback.assertCallsMade(0) 105 105 } 106 106 107 - class MockMediatorCallback : (Activity) -> Unit { 108 - private var calledWith: Activity? = null 107 + class MockMediatorCallback : (WearActivity) -> Unit { 108 + private var calledWith: WearActivity? = null 109 109 private var callCount: Int = 0 110 - override fun invoke(activity: Activity) { 110 + override fun invoke(activity: WearActivity) { 111 111 calledWith = activity 112 112 callCount++ 113 113 } 114 114 115 - fun assertCalledWith(activity: Activity) { 115 + fun assertCalledWith(activity: WearActivity) { 116 116 assertEquals(activity, calledWith) 117 117 } 118 118
+5 -5
wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/DTO.kt wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/WearDTO.kt
··· 15 15 */ 16 16 17 17 @Parcelize 18 - data class Activity( 18 + data class WearActivity( 19 19 val id: Long, 20 20 val name: String, 21 21 val icon: String, ··· 23 23 ): Parcelable 24 24 25 25 @Parcelize 26 - data class CurrentActivity( 26 + data class WearCurrentActivity( 27 27 val id: Long, 28 28 val startedAt: Long, 29 - val tags: List<Tag>, 29 + val tags: List<WearTag>, 30 30 ): Parcelable 31 31 32 32 @Parcelize 33 - data class Tag( 33 + data class WearTag( 34 34 val id: Long, 35 35 val name: String, 36 36 val isGeneral: Boolean, ··· 38 38 ): Parcelable 39 39 40 40 @Parcelize 41 - data class Settings( 41 + data class WearSettings( 42 42 val allowMultitasking: Boolean, 43 43 val showRecordTagSelection: Boolean, 44 44 val recordTagSelectionCloseAfterOne: Boolean,
+13 -13
wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/MockWearCommunicationAPI.kt
··· 7 7 8 8 class MockWearCommunicationAPI : WearCommunicationAPI { 9 9 10 - var activities: List<Activity> = emptyList() 11 - var currentActivities: List<CurrentActivity> = emptyList() 12 - var tags: Map<Long, List<Tag>> = mapOf() 13 - lateinit var settings: Settings 10 + var activities: List<WearActivity> = emptyList() 11 + var currentActivities: List<WearCurrentActivity> = emptyList() 12 + var tags: Map<Long, List<WearTag>> = mapOf() 13 + lateinit var settings: WearSettings 14 14 15 - override suspend fun queryActivities(): List<Activity> { 15 + override suspend fun queryActivities(): List<WearActivity> { 16 16 return activities 17 17 } 18 18 19 - fun mock_queryActivities(activities: List<Activity>) { 19 + fun mock_queryActivities(activities: List<WearActivity>) { 20 20 this.activities = activities 21 21 } 22 22 23 - override suspend fun queryCurrentActivities(): List<CurrentActivity> { 23 + override suspend fun queryCurrentActivities(): List<WearCurrentActivity> { 24 24 return currentActivities 25 25 } 26 26 27 - fun mock_queryCurrentActivities(activities: List<CurrentActivity>) { 27 + fun mock_queryCurrentActivities(activities: List<WearCurrentActivity>) { 28 28 this.currentActivities = activities 29 29 } 30 30 31 - override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 31 + override suspend fun setCurrentActivities(starting: List<WearCurrentActivity>) { 32 32 TODO("Not yet implemented") 33 33 } 34 34 35 - override suspend fun queryTagsForActivity(activityId: Long): List<Tag> { 35 + override suspend fun queryTagsForActivity(activityId: Long): List<WearTag> { 36 36 return this.tags[activityId].orEmpty() 37 37 } 38 38 39 - fun mock_queryTagsForActivity(tags: Map<Long, List<Tag>>) { 39 + fun mock_queryTagsForActivity(tags: Map<Long, List<WearTag>>) { 40 40 this.tags = tags 41 41 } 42 42 43 - override suspend fun querySettings(): Settings { 43 + override suspend fun querySettings(): WearSettings { 44 44 return settings 45 45 } 46 46 47 - fun mock_querySettings(settings: Settings) { 47 + fun mock_querySettings(settings: WearSettings) { 48 48 this.settings = settings 49 49 } 50 50
+1 -1
wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/Request.kt wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/WearRequests.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.wear_api 7 7 8 - object Request { 8 + object WearRequests { 9 9 const val PATH = "/stt" 10 10 11 11 const val PING = "$PATH//GET/ping"
+11 -11
wear_api/src/main/java/com/example/util/simpletimetracker/wear_api/WearCommunicationAPI.kt
··· 7 7 8 8 interface WearCommunicationAPI { 9 9 /** 10 - * [Request.PING] 10 + * [WearRequests.PING] 11 11 * 12 12 * Echos the message it receives 13 13 * ··· 18 18 } 19 19 20 20 /** 21 - * [Request.QUERY_ACTIVITIES] 21 + * [WearRequests.QUERY_ACTIVITIES] 22 22 * 23 23 * Retrieves a list of all the time-tracking activities available for selection 24 24 */ 25 - suspend fun queryActivities(): List<Activity> 25 + suspend fun queryActivities(): List<WearActivity> 26 26 27 27 /** 28 - * [Request.QUERY_CURRENT_ACTIVITIES] 28 + * [WearRequests.QUERY_CURRENT_ACTIVITIES] 29 29 * 30 30 * Retrieves a list of the currently running activity/activities 31 31 */ 32 - suspend fun queryCurrentActivities(): List<CurrentActivity> 32 + suspend fun queryCurrentActivities(): List<WearCurrentActivity> 33 33 34 34 /** 35 - * [Request.SET_CURRENT_ACTIVITIES] 35 + * [WearRequests.SET_CURRENT_ACTIVITIES] 36 36 * 37 37 * Replaces the currently running activity/activities with the given activities 38 38 */ 39 - suspend fun setCurrentActivities(starting: List<CurrentActivity>) 39 + suspend fun setCurrentActivities(starting: List<WearCurrentActivity>) 40 40 41 41 /** 42 - * [Request.QUERY_TAGS_FOR_ACTIVITY] 42 + * [WearRequests.QUERY_TAGS_FOR_ACTIVITY] 43 43 * 44 44 * Retrieves the tags available for association with the activity with the given ID 45 45 */ 46 - suspend fun queryTagsForActivity(activityId: Long): List<Tag> 46 + suspend fun queryTagsForActivity(activityId: Long): List<WearTag> 47 47 48 48 /** 49 - * [Request.QUERY_SETTINGS] 49 + * [WearRequests.QUERY_SETTINGS] 50 50 * 51 51 * Retrieves the settings relevant to time tracking behavior 52 52 */ 53 - suspend fun querySettings(): Settings 53 + suspend fun querySettings(): WearSettings 54 54 }