Skip to content

Commit 01d9d7e

Browse files
committed
change retroactive multitasking logic
1 parent d710325 commit 01d9d7e

File tree

13 files changed

+84
-172
lines changed

13 files changed

+84
-172
lines changed

data_local/src/main/java/com/example/util/simpletimetracker/data_local/database/RecordDao.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ interface RecordDao {
9393
comment: String,
9494
)
9595

96+
@Query("UPDATE records SET time_ended = :timeEnded WHERE id = :recordId")
97+
suspend fun updateTimeEnded(recordId: Long, timeEnded: Long)
98+
9699
@Query("DELETE FROM records WHERE id = :id")
97100
suspend fun delete(id: Long)
98101

data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/RecordRepoImpl.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.example.util.simpletimetracker.data_local.mapper.RecordDataLocalMappe
66
import com.example.util.simpletimetracker.data_local.model.RecordWithRecordTagsDBO
77
import com.example.util.simpletimetracker.data_local.utils.logDataAccess
88
import com.example.util.simpletimetracker.data_local.utils.withLockedCache
9+
import com.example.util.simpletimetracker.domain.extension.dropMillis
910
import com.example.util.simpletimetracker.domain.model.Range
1011
import com.example.util.simpletimetracker.domain.model.Record
1112
import com.example.util.simpletimetracker.domain.repo.RecordRepo
@@ -25,6 +26,7 @@ class RecordRepoImpl @Inject constructor(
2526
private var getFromRangeByTypeCache = LruCache<GetFromRangeByTypeKey, List<Record>>(1)
2627
private var recordCache = LruCache<Long, Record>(1)
2728
private var isEmpty: Boolean? = null
29+
2830
private val mutex: Mutex = Mutex()
2931

3032
override suspend fun isEmpty(): Boolean = mutex.withLockedCache(
@@ -171,6 +173,20 @@ class RecordRepoImpl @Inject constructor(
171173
afterSourceAccess = { clearCache() },
172174
)
173175

176+
override suspend fun updateTimeEnded(
177+
recordId: Long,
178+
timeEnded: Long,
179+
) = mutex.withLockedCache(
180+
logMessage = "updateTimeEnded",
181+
accessSource = {
182+
recordDao.updateTimeEnded(
183+
recordId = recordId,
184+
timeEnded = timeEnded.dropMillis(),
185+
)
186+
},
187+
afterSourceAccess = { clearCache() },
188+
)
189+
174190
override suspend fun remove(id: Long) = mutex.withLockedCache(
175191
logMessage = "remove",
176192
accessSource = { recordDao.delete(id) },

domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/AddRunningRecordMediator.kt

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,31 +54,14 @@ class AddRunningRecordMediator @Inject constructor(
5454
}
5555
}
5656

57-
suspend fun startTimers(
58-
typeIds: Set<Long>,
59-
) {
60-
val current = System.currentTimeMillis()
61-
val timeStarted = StartTime.Current(current)
62-
val prevRecords = recordInteractor.getAllPrev(current)
63-
typeIds.forEachIndexed { index, id ->
64-
startTimer(
65-
typeId = id,
66-
tagIds = emptyList(),
67-
comment = "",
68-
timeStarted = timeStarted,
69-
prevRecords = PrevRecords.Records(prevRecords),
70-
// Update only on last.
71-
updateNotificationSwitch = index == typeIds.size - 1,
72-
)
73-
}
74-
}
75-
57+
// TODO test retroactive mode
58+
// TODO test several prev records at the same time, merge accordingly.
59+
// TODO test retroactive multitask
7660
suspend fun startTimer(
7761
typeId: Long,
7862
tagIds: List<Long>,
7963
comment: String,
8064
timeStarted: StartTime = StartTime.TakeCurrent,
81-
prevRecords: PrevRecords = PrevRecords.Load,
8265
updateNotificationSwitch: Boolean = true,
8366
checkDefaultDuration: Boolean = true,
8467
) {
@@ -90,10 +73,7 @@ class AddRunningRecordMediator @Inject constructor(
9073
}
9174
val retroactiveTrackingMode = prefsInteractor.getRetroactiveTrackingMode()
9275
val actualPrevRecords = if (retroactiveTrackingMode) {
93-
when (prevRecords) {
94-
is PrevRecords.Load -> recordInteractor.getAllPrev(actualTimeStarted)
95-
is PrevRecords.Records -> prevRecords.records
96-
}
76+
recordInteractor.getAllPrev(actualTimeStarted)
9777
} else {
9878
emptyList()
9979
}
@@ -113,9 +93,12 @@ class AddRunningRecordMediator @Inject constructor(
11393
prevRecords = actualPrevRecords,
11494
)
11595
}
96+
val isMultitaskingAllowedByDefault = prefsInteractor.getAllowMultitasking()
97+
val isMultitaskingAllowed = rulesResult.isMultitaskingAllowed.getValueOrNull()
98+
?: isMultitaskingAllowedByDefault
11699
processMultitasking(
117100
typeId = typeId,
118-
isMultitaskingAllowedByRules = rulesResult.isMultitaskingAllowed,
101+
isMultitaskingAllowed = isMultitaskingAllowed,
119102
splitTime = when (timeStarted) {
120103
is StartTime.Current -> timeStarted.currentTimeStampMs
121104
is StartTime.TakeCurrent -> currentTime
@@ -138,6 +121,7 @@ class AddRunningRecordMediator @Inject constructor(
138121
tagIds = actualTags,
139122
timeStarted = actualTimeStarted,
140123
updateNotificationSwitch = updateNotificationSwitch,
124+
isMultitaskingAllowed = isMultitaskingAllowed,
141125
)
142126
if (retroactiveTrackingMode) {
143127
addRetroactiveModeInternal(startParams, actualPrevRecords)
@@ -165,6 +149,7 @@ class AddRunningRecordMediator @Inject constructor(
165149
comment = comment,
166150
tagIds = tagIds,
167151
updateNotificationSwitch = true,
152+
isMultitaskingAllowed = true,
168153
),
169154
checkDefaultDuration = false,
170155
)
@@ -188,9 +173,13 @@ class AddRunningRecordMediator @Inject constructor(
188173
) {
189174
val type = recordTypeInteractor.get(params.typeId) ?: return
190175

176+
processRetroactiveMultitasking(
177+
params = params,
178+
prevRecords = prevRecords,
179+
)
180+
191181
if (type.defaultDuration > 0L) {
192-
val newTimeStarted = prevRecords.firstOrNull()?.timeEnded
193-
?: (params.timeStarted - type.defaultDuration * 1000)
182+
val newTimeStarted = params.timeStarted - type.defaultDuration * 1000
194183
addInstantRecord(
195184
params = params.copy(timeStarted = newTimeStarted),
196185
type = type,
@@ -307,13 +296,9 @@ class AddRunningRecordMediator @Inject constructor(
307296

308297
private suspend fun processMultitasking(
309298
typeId: Long,
310-
isMultitaskingAllowedByRules: ResultContainer<Boolean>,
299+
isMultitaskingAllowed: Boolean,
311300
splitTime: Long,
312301
) {
313-
val isMultitaskingAllowedByDefault = prefsInteractor.getAllowMultitasking()
314-
val isMultitaskingAllowed = isMultitaskingAllowedByRules.getValueOrNull()
315-
?: isMultitaskingAllowedByDefault
316-
317302
// Stop running records if multitasking is disabled.
318303
if (!isMultitaskingAllowed) {
319304
// Widgets will update on adding.
@@ -330,6 +315,36 @@ class AddRunningRecordMediator @Inject constructor(
330315
}
331316
}
332317

318+
private suspend fun processRetroactiveMultitasking(
319+
params: StartParams,
320+
prevRecords: List<Record>,
321+
) {
322+
if (!params.isMultitaskingAllowed) return
323+
324+
val recordTypesMap = recordTypeInteractor.getAll().associateBy(RecordType::id)
325+
val mergedRecord = getPrevRecordToMergeWith(params.typeId, prevRecords)
326+
327+
// Extend prev records to current time.
328+
prevRecords.filter {
329+
// Skip record that would be merge.
330+
it.id != mergedRecord?.id
331+
}.filter {
332+
// Skip records with default duration.
333+
val thisType = recordTypesMap[it.typeId]
334+
thisType != null && thisType.defaultDuration == 0L
335+
}.map { prevRecord ->
336+
recordInteractor.updateTimeEnded(
337+
recordId = prevRecord.id,
338+
timeEnded = params.timeStarted,
339+
)
340+
prevRecord.typeId
341+
}.let {
342+
updateExternalViewsInteractor.onRecordTimeEndedChange(
343+
typeIds = it,
344+
)
345+
}
346+
}
347+
333348
private suspend fun getAllTags(
334349
typeId: Long,
335350
tagIds: List<Long>,
@@ -352,16 +367,12 @@ class AddRunningRecordMediator @Inject constructor(
352367
val comment: String,
353368
val tagIds: List<Long>,
354369
val updateNotificationSwitch: Boolean,
370+
val isMultitaskingAllowed: Boolean,
355371
)
356372

357373
sealed interface StartTime {
358374
data class Current(val currentTimeStampMs: Long) : StartTime
359375
data class Timestamp(val timestampMs: Long) : StartTime
360376
object TakeCurrent : StartTime
361377
}
362-
363-
sealed interface PrevRecords {
364-
data class Records(val records: List<Record>) : PrevRecords
365-
object Load : PrevRecords
366-
}
367378
}

domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RecordInteractor.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ class RecordInteractor @Inject constructor(
122122
updateTags(recordId, tagIds)
123123
}
124124

125+
suspend fun updateTimeEnded(recordId: Long, timeEnded: Long) {
126+
recordRepo.updateTimeEnded(
127+
recordId = recordId,
128+
timeEnded = timeEnded,
129+
)
130+
}
131+
125132
suspend fun remove(id: Long) {
126133
recordToRecordTagRepo.removeAllByRecordId(id)
127134
recordRepo.remove(id)

domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/UpdateExternalViewsInteractor.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ class UpdateExternalViewsInteractor @Inject constructor(
159159
)
160160
}
161161

162+
suspend fun onRecordTimeEndedChange(
163+
typeIds: List<Long>,
164+
) {
165+
runUpdates(
166+
Update.GoalReschedule(typeIds),
167+
)
168+
}
169+
162170
suspend fun onInstantRecordAdd() {
163171
runUpdates(
164172
Update.Wear,

domain/src/main/java/com/example/util/simpletimetracker/domain/repo/RecordRepo.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ interface RecordRepo {
4949
comment: String,
5050
)
5151

52+
suspend fun updateTimeEnded(recordId: Long, timeEnded: Long)
53+
5254
suspend fun remove(id: Long)
5355

5456
suspend fun removeByType(typeId: Long)

features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeAdapterDelegate.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ fun createRecordTypeAdapterDelegate(
3737
itemIsChecked = item.isChecked.orFalse()
3838
itemCompleteIsAnimated = true
3939
itemIsComplete = item.isComplete
40-
val newItemScale = if (item.isSelected) 1.1f else 1.0f
41-
scaleX = newItemScale
42-
scaleY = newItemScale
4340
getCheckmarkOutline().itemIsFiltered = item.itemIsFiltered
4441
onItemClick?.let { setOnClickWith(item, it) }
4542
onItemLongClick?.let { setOnLongClick { it(item, mapOf(this to transitionName)) } }

features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeViewData.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ data class RecordTypeViewData(
1717
val isChecked: Boolean? = null,
1818
val itemIsFiltered: Boolean = false,
1919
val isComplete: Boolean = false,
20-
val isSelected: Boolean = false,
2120
) : ViewHolderType {
2221

2322
override fun getUniqueId(): Long = id

features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
3535

3636
suspend fun getViewData(
3737
completeTypeIds: Set<Long>,
38-
multitaskingSelectionEnabled: Boolean,
39-
multiSelectedActivityIds: Set<Long>,
4038
): List<ViewHolderType> {
4139
val recordTypes = recordTypeInteractor.getAll()
4240
val recordTypesMap = recordTypes.associateBy(RecordType::id)
@@ -54,7 +52,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
5452
val showRepeatButton = prefsInteractor.getEnableRepeatButton()
5553
val isPomodoroStarted = prefsInteractor.getPomodoroModeStartedTimestampMs() != 0L
5654
val retroactiveTrackingModeEnabled = prefsInteractor.getRetroactiveTrackingMode()
57-
val allowMultitasking = prefsInteractor.getAllowMultitasking()
5855
val goals = filterGoalsByDayOfWeekInteractor
5956
.execute(recordTypeGoalInteractor.getAllTypeGoals())
6057
.groupBy { it.idData.value }
@@ -84,9 +81,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
8481
useProportionalMinutes = useProportionalMinutes,
8582
useMilitaryTime = useMilitaryTime,
8683
showSeconds = showSeconds,
87-
allowMultitasking = allowMultitasking,
88-
multitaskingSelectionEnabled = multitaskingSelectionEnabled,
89-
multiSelectedActivityIds = multiSelectedActivityIds,
9084
)
9185
}
9286
runningRecords.isEmpty() -> {
@@ -146,17 +140,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
146140
isComplete = it.id in completeTypeIds,
147141
)
148142
}
149-
.map {
150-
if (multitaskingSelectionEnabled) {
151-
val isSelected = it.id in multiSelectedActivityIds
152-
it.copy(
153-
isComplete = isSelected,
154-
isSelected = isSelected,
155-
)
156-
} else {
157-
it
158-
}
159-
}
160143
.let { data ->
161144
mutableListOf<ViewHolderType>().apply {
162145
data.let(::addAll)

features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/mapper/RunningRecordsViewDataMapper.kt

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ import com.example.util.simpletimetracker.domain.model.RecordTag
1212
import com.example.util.simpletimetracker.domain.model.RecordType
1313
import com.example.util.simpletimetracker.domain.model.RunningRecord
1414
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
15-
import com.example.util.simpletimetracker.feature_base_adapter.divider.DividerViewData
1615
import com.example.util.simpletimetracker.feature_base_adapter.empty.EmptyViewData
1716
import com.example.util.simpletimetracker.feature_base_adapter.hint.HintViewData
1817
import com.example.util.simpletimetracker.feature_base_adapter.hintBig.HintBigViewData
19-
import com.example.util.simpletimetracker.feature_base_adapter.recordFilter.FilterViewData
2018
import com.example.util.simpletimetracker.feature_base_adapter.recordWithHint.RecordWithHintViewData
2119
import com.example.util.simpletimetracker.feature_running_records.R
22-
import com.example.util.simpletimetracker.feature_running_records.model.RunningRecordsFilterType
2320
import javax.inject.Inject
2421

2522
class RunningRecordsViewDataMapper @Inject constructor(
@@ -65,9 +62,6 @@ class RunningRecordsViewDataMapper @Inject constructor(
6562
useProportionalMinutes: Boolean,
6663
useMilitaryTime: Boolean,
6764
showSeconds: Boolean,
68-
allowMultitasking: Boolean,
69-
multitaskingSelectionEnabled: Boolean,
70-
multiSelectedActivityIds: Set<Long>,
7165
): List<ViewHolderType> {
7266
val result = mutableListOf<ViewHolderType>()
7367

@@ -125,42 +119,6 @@ class RunningRecordsViewDataMapper @Inject constructor(
125119
paddingTop = 0,
126120
paddingBottom = 0,
127121
)
128-
if (allowMultitasking) {
129-
// TODO test retroactive mode
130-
// TODO test several prev records at the same time, merge accordingly.
131-
// TODO test retroactive multitask
132-
// enable, go to other screen
133-
// enable, go to edit type
134-
// disable by clicking
135-
// disable by removing
136-
result += DividerViewData(3)
137-
result += FilterViewData(
138-
id = 0,
139-
type = RunningRecordsFilterType.EnableMultitaskingSelection,
140-
name = resourceRepo.getString(R.string.multitask_time_name),
141-
color = if (multitaskingSelectionEnabled) {
142-
colorMapper.toActiveColor(isDarkTheme)
143-
} else {
144-
colorMapper.toInactiveColor(isDarkTheme)
145-
},
146-
selected = multitaskingSelectionEnabled,
147-
removeBtnVisible = multitaskingSelectionEnabled,
148-
)
149-
if (multitaskingSelectionEnabled) {
150-
result += FilterViewData(
151-
id = 1,
152-
type = RunningRecordsFilterType.FinishMultitaskingSelection,
153-
name = resourceRepo.getString(R.string.records_filter_select),
154-
color = if (multiSelectedActivityIds.isNotEmpty()) {
155-
colorMapper.toActiveColor(isDarkTheme)
156-
} else {
157-
colorMapper.toInactiveColor(isDarkTheme)
158-
},
159-
selected = false,
160-
removeBtnVisible = false,
161-
)
162-
}
163-
}
164122
}
165123

166124
return result

0 commit comments

Comments
 (0)