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.

feat: Create `StartActivityMediator`

Handles all the logic for determining whether the watch should
start the activity outright, or request tags first.

Joseph Hale (Feb 26, 2024, 10:27 PM -0700) 6a00fcc9 bdf97cd1

+154
+34
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/StartActivityMediator.kt
··· 1 + /* 2 + * This Source Code Form is subject to the terms of the Mozilla Public 3 + * License, v. 2.0. If a copy of the MPL was not distributed with this 4 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 + */ 6 + package com.example.util.simpletimetracker.wearrpc 7 + 8 + class StartActivityMediator( 9 + private val api: SimpleTimeTrackerAPI, 10 + private val onRequestStartActivity: suspend (activity: Activity) -> Unit, 11 + private val onRequestTagSelection: suspend (activity: Activity) -> Unit, 12 + ) { 13 + suspend fun requestStart(activity: Activity) { 14 + val settings = api.querySettings() 15 + if (settings.showRecordTagSelection) { 16 + requestTagSelectionIfNeeded(activity, settings) 17 + } else { 18 + onRequestStartActivity(activity) 19 + } 20 + } 21 + 22 + private suspend fun requestTagSelectionIfNeeded(activity: Activity, settings: Settings) { 23 + val tags = api.queryTagsForActivity(activity.id) 24 + val generalTags = tags.filter { it.isGeneral } 25 + val nonGeneralTags = tags.filter { !it.isGeneral } 26 + val tagSelectionNeeded = 27 + nonGeneralTags.isNotEmpty() || generalTags.isNotEmpty() && settings.recordTagSelectionEvenForGeneralTags 28 + if (tagSelectionNeeded) { 29 + onRequestTagSelection(activity) 30 + } else { 31 + onRequestStartActivity(activity) 32 + } 33 + } 34 + }
+120
wearrpc/src/test/java/com/example/util/simpletimetracker/wearrpc/StartActivityMediatorTest.kt
··· 1 + /* 2 + * This Source Code Form is subject to the terms of the Mozilla Public 3 + * License, v. 2.0. If a copy of the MPL was not distributed with this 4 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 + */ 6 + package com.example.util.simpletimetracker.wearrpc 7 + 8 + import kotlinx.coroutines.test.runTest 9 + import org.junit.Before 10 + import org.junit.Test 11 + import org.junit.Assert.* 12 + 13 + 14 + open class StartActivityMediatorTestBase { 15 + 16 + protected val api = MockSimpleTimeTrackerAPI() 17 + protected val startCallback = MockMediatorCallback() 18 + protected val requestTagCallback = MockMediatorCallback() 19 + protected val mediator = StartActivityMediator( 20 + api = api, 21 + onRequestStartActivity = startCallback, 22 + onRequestTagSelection = requestTagCallback, 23 + ) 24 + 25 + protected val sampleActivity = Activity(id = 1, name = "Sleep", icon = "🛏️", color = "#123456") 26 + protected val sampleGeneralTag = Tag(id = 13, name = "Sleep", isGeneral = true) 27 + protected val sampleNonGeneralTag = Tag(id = 14, name = "Work", isGeneral = false) 28 + protected val settings = Settings( 29 + allowMultitasking = false, 30 + showRecordTagSelection = false, 31 + recordTagSelectionCloseAfterOne = false, 32 + recordTagSelectionEvenForGeneralTags = false, 33 + ) 34 + 35 + @Before 36 + fun setup() { 37 + api.mockReset() 38 + startCallback.reset() 39 + requestTagCallback.reset() 40 + } 41 + } 42 + 43 + class `Starts Activity When` : StartActivityMediatorTestBase() { 44 + @Test 45 + fun `tag selection disabled`() = runTest { 46 + api.mock_querySettings(settings.copy(showRecordTagSelection = false)) 47 + mediator.requestStart(sampleActivity) 48 + `assert only start callback invoked`() 49 + } 50 + 51 + @Test 52 + fun `tag selection enabled and activity has no tags`() = runTest { 53 + api.mock_querySettings(settings.copy(showRecordTagSelection = true)) 54 + api.mock_queryTagsForActivity(mapOf()) 55 + mediator.requestStart(sampleActivity) 56 + `assert only start callback invoked`() 57 + } 58 + 59 + @Test 60 + fun `tag selection enabled, but not for generals alone, and activity has only general tags`() = runTest { 61 + api.mock_querySettings(settings.copy(showRecordTagSelection = true, recordTagSelectionEvenForGeneralTags = false)) 62 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleGeneralTag))) 63 + mediator.requestStart(sampleActivity) 64 + `assert only start callback invoked`() 65 + } 66 + 67 + private fun `assert only start callback invoked`() { 68 + startCallback.assertCalledWith(sampleActivity) 69 + startCallback.assertCallsMade(1) 70 + requestTagCallback.assertCallsMade(0) 71 + } 72 + } 73 + 74 + class `Requests tags when tag selection enabled and`: StartActivityMediatorTestBase() { 75 + private val sampleSettings = settings.copy(showRecordTagSelection = true) 76 + 77 + @Test 78 + fun `activity has non-general tags`() = runTest { 79 + api.mock_querySettings(sampleSettings) 80 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleNonGeneralTag))) 81 + mediator.requestStart(sampleActivity) 82 + `assert only tag callback invoked`() 83 + } 84 + 85 + @Test 86 + fun `activity has only general tags and tag selection enabled for only generals`() = runTest { 87 + api.mock_querySettings(sampleSettings.copy(recordTagSelectionEvenForGeneralTags = true)) 88 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleGeneralTag))) 89 + mediator.requestStart(sampleActivity) 90 + `assert only tag callback invoked`() 91 + } 92 + 93 + private fun `assert only tag callback invoked`() { 94 + requestTagCallback.assertCalledWith(sampleActivity) 95 + requestTagCallback.assertCallsMade(1) 96 + startCallback.assertCallsMade(0) 97 + } 98 + } 99 + 100 + class MockMediatorCallback: (Activity) -> Unit { 101 + private var calledWith: Activity? = null 102 + private var callCount: Int = 0 103 + override fun invoke(activity: Activity) { 104 + calledWith = activity 105 + callCount++ 106 + } 107 + 108 + fun assertCalledWith(activity: Activity) { 109 + assertEquals(activity, calledWith) 110 + } 111 + 112 + fun assertCallsMade(count: Int) { 113 + assertEquals(count, callCount) 114 + } 115 + 116 + fun reset() { 117 + calledWith = null 118 + callCount = 0 119 + } 120 + }