Skip to content

Commit 4626c4a

Browse files
committed
add retroactive tracking mode support to widgets, notifications
1 parent f45288b commit 4626c4a

File tree

36 files changed

+518
-140
lines changed

36 files changed

+518
-140
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class RecordRepoImpl @Inject constructor(
182182
private fun clearCache() {
183183
getFromRangeCache.evictAll()
184184
getFromRangeByTypeCache.evictAll()
185+
recordCache.evictAll()
185186
isEmpty = null
186187
}
187188

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

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,31 @@ class AddRunningRecordMediator @Inject constructor(
6262
timeStarted: Long? = null,
6363
updateNotificationSwitch: Boolean = true,
6464
) {
65+
val actualTimeStarted = timeStarted ?: System.currentTimeMillis()
66+
val retroactiveTrackingMode = prefsInteractor.getRetroactiveTrackingMode()
67+
val prevRecord = if (retroactiveTrackingMode) {
68+
recordInteractor.getPrev(actualTimeStarted).firstOrNull()
69+
} else {
70+
null
71+
}
6572
val rulesResult = processRules(
6673
typeId = typeId,
67-
timeStarted = timeStarted ?: System.currentTimeMillis(),
74+
timeStarted = if (
75+
retroactiveTrackingMode &&
76+
prevRecord != null &&
77+
shouldMergeWithPrevRecord(typeId, prevRecord)
78+
) {
79+
// If will merge - it will be one record,
80+
// so need to check rules from original start.
81+
prevRecord.timeStarted
82+
} else {
83+
actualTimeStarted
84+
},
6885
)
6986
processMultitasking(
7087
typeId = typeId,
7188
isMultitaskingAllowedByRules = rulesResult.isMultitaskingAllowed,
89+
timeEnded = actualTimeStarted,
7290
)
7391
val actualTags = getAllTags(
7492
typeId = typeId,
@@ -84,11 +102,11 @@ class AddRunningRecordMediator @Inject constructor(
84102
typeId = typeId,
85103
comment = comment,
86104
tagIds = actualTags,
87-
timeStarted = timeStarted ?: System.currentTimeMillis(),
105+
timeStarted = actualTimeStarted,
88106
updateNotificationSwitch = updateNotificationSwitch,
89107
)
90-
if (prefsInteractor.getRetroactiveTrackingMode()) {
91-
addRetroactiveModeInternal(startParams)
108+
if (retroactiveTrackingMode) {
109+
addRetroactiveModeInternal(startParams, prevRecord)
92110
} else {
93111
addInternal(startParams)
94112
}
@@ -126,9 +144,11 @@ class AddRunningRecordMediator @Inject constructor(
126144
}
127145
}
128146

129-
private suspend fun addRetroactiveModeInternal(params: StartParams) {
147+
private suspend fun addRetroactiveModeInternal(
148+
params: StartParams,
149+
prevRecord: Record?,
150+
) {
130151
val type = recordTypeInteractor.get(params.typeId) ?: return
131-
val prevRecord = recordInteractor.getPrev(params.timeStarted).firstOrNull()
132152

133153
if (type.defaultDuration > 0L) {
134154
val newTimeStarted = prevRecord?.timeEnded
@@ -186,18 +206,17 @@ class AddRunningRecordMediator @Inject constructor(
186206
params: StartParams,
187207
prevRecord: Record?,
188208
) {
189-
val shouldMergeWithPrevRecord = prevRecord != null &&
190-
prevRecord.typeId == params.typeId &&
191-
prevRecord.tagIds == params.tagIds
192-
193-
val record = if (prevRecord != null && shouldMergeWithPrevRecord) {
209+
val shouldMerge = shouldMergeWithPrevRecord(params.typeId, prevRecord)
210+
val record = if (prevRecord != null && shouldMerge) {
194211
Record(
195212
id = prevRecord.id, // Updates existing record.
196213
typeId = params.typeId,
197214
timeStarted = prevRecord.timeStarted,
198215
timeEnded = params.timeStarted,
199-
comment = params.comment,
200-
tagIds = params.tagIds,
216+
comment = params.comment.takeUnless { it.isEmpty() }
217+
?: prevRecord.comment,
218+
tagIds = params.tagIds.takeUnless { it.isEmpty() }
219+
?: prevRecord.tagIds,
201220
)
202221
} else {
203222
val newTimeStarted = prevRecord?.timeEnded
@@ -255,6 +274,7 @@ class AddRunningRecordMediator @Inject constructor(
255274
private suspend fun processMultitasking(
256275
typeId: Long,
257276
isMultitaskingAllowedByRules: ResultContainer<Boolean>,
277+
timeEnded: Long,
258278
) {
259279
val isMultitaskingAllowedByDefault = prefsInteractor.getAllowMultitasking()
260280
val isMultitaskingAllowed = isMultitaskingAllowedByRules.getValueOrNull()
@@ -265,7 +285,13 @@ class AddRunningRecordMediator @Inject constructor(
265285
// Widgets will update on adding.
266286
runningRecordInteractor.getAll()
267287
.filter { it.id != typeId }
268-
.forEach { removeRunningRecordMediator.removeWithRecordAdd(it, updateWidgets = false) }
288+
.forEach {
289+
removeRunningRecordMediator.removeWithRecordAdd(
290+
runningRecord = it,
291+
updateWidgets = false,
292+
timeEnded = timeEnded,
293+
)
294+
}
269295
}
270296
}
271297

@@ -278,6 +304,13 @@ class AddRunningRecordMediator @Inject constructor(
278304
return (tagIds + defaultTags + tagIdsFromRules).toSet().toList()
279305
}
280306

307+
private fun shouldMergeWithPrevRecord(
308+
typeId: Long,
309+
prevRecord: Record?,
310+
): Boolean {
311+
return prevRecord != null && prevRecord.typeId == typeId
312+
}
313+
281314
private data class StartParams(
282315
val typeId: Long,
283316
val timeStarted: Long,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ class RecordInteractor @Inject constructor(
8181

8282
suspend fun addFromRunning(
8383
runningRecord: RunningRecord,
84+
timeEnded: Long,
8485
) {
8586
Record(
8687
typeId = runningRecord.id,
8788
timeStarted = runningRecord.timeStarted,
88-
timeEnded = System.currentTimeMillis(),
89+
timeEnded = timeEnded,
8990
comment = runningRecord.comment,
9091
tagIds = runningRecord.tagIds,
9192
).let {

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ class RemoveRunningRecordMediator @Inject constructor(
1717
runningRecord: RunningRecord,
1818
updateWidgets: Boolean = true,
1919
updateNotificationSwitch: Boolean = true,
20+
timeEnded: Long? = null, // null - take current time.
2021
) {
22+
val recordTimeEnded = timeEnded ?: System.currentTimeMillis()
2123
val durationToIgnore = prefsInteractor.getIgnoreShortRecordsDuration()
2224
val duration = TimeUnit.MILLISECONDS
23-
.toSeconds(System.currentTimeMillis() - runningRecord.timeStarted)
25+
.toSeconds(recordTimeEnded - runningRecord.timeStarted)
2426

2527
if (duration > durationToIgnore || durationToIgnore == 0L) {
2628
// No need to update widgets and notification because it will be done in running record remove.
27-
recordInteractor.addFromRunning(runningRecord)
29+
recordInteractor.addFromRunning(
30+
runningRecord = runningRecord,
31+
timeEnded = recordTimeEnded
32+
)
2833
}
2934
activityStartedStoppedBroadcastInteractor.onActivityStopped(
3035
typeId = runningRecord.id,

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class UpdateExternalViewsInteractor @Inject constructor(
1414
private val notificationGoalTimeInteractor: NotificationGoalTimeInteractor,
1515
private val widgetInteractor: WidgetInteractor,
1616
private val wearInteractor: WearInteractor,
17+
private val prefsInteractor: PrefsInteractor,
1718
) {
1819

1920
// Also removes running records and records.
@@ -28,10 +29,12 @@ class UpdateExternalViewsInteractor @Inject constructor(
2829
Update.GoalCancel(RecordTypeGoal.IdData.Type(typeId)),
2930
Update.GoalReschedule(runningRecordIds + typeId),
3031
Update.WidgetStatistics,
31-
Update.WidgetSingleType(typeId),
32+
Update.WidgetSingleTypes.takeIf { getRetroactiveTrackingMode() }
33+
?: Update.WidgetSingleType(typeId),
34+
Update.WidgetUniversal.takeIf { getRetroactiveTrackingMode() },
3235
Update.Wear.takeIf { !fromArchive },
3336
Update.NotificationTypes.takeIf { !fromArchive },
34-
Update.NotificationWithControls.takeIf { !fromArchive }
37+
Update.NotificationWithControls.takeIf { !fromArchive },
3538
)
3639
}
3740

@@ -133,7 +136,9 @@ class UpdateExternalViewsInteractor @Inject constructor(
133136
Update.NotificationWithControls,
134137
Update.GoalReschedule(listOf(typeId)),
135138
Update.WidgetStatistics,
136-
Update.WidgetSingleType(typeId),
139+
Update.WidgetSingleTypes.takeIf { getRetroactiveTrackingMode() }
140+
?: Update.WidgetSingleType(typeId),
141+
Update.WidgetUniversal.takeIf { getRetroactiveTrackingMode() },
137142
)
138143
}
139144

@@ -146,7 +151,9 @@ class UpdateExternalViewsInteractor @Inject constructor(
146151
Update.NotificationWithControls.takeIf { updateNotificationSwitch },
147152
Update.GoalReschedule(listOf(typeId)),
148153
Update.WidgetStatistics,
149-
Update.WidgetSingleType(typeId),
154+
Update.WidgetSingleTypes.takeIf { getRetroactiveTrackingMode() }
155+
?: Update.WidgetSingleType(typeId),
156+
Update.WidgetUniversal.takeIf { getRetroactiveTrackingMode() },
150157
)
151158
}
152159

@@ -308,6 +315,15 @@ class UpdateExternalViewsInteractor @Inject constructor(
308315
)
309316
}
310317

318+
suspend fun onRetroactiveTrackingModeChange() {
319+
runUpdates(
320+
Update.WidgetSingleTypes,
321+
Update.WidgetUniversal,
322+
Update.NotificationWithControls,
323+
Update.Wear
324+
)
325+
}
326+
311327
// Update all widgets.
312328
suspend fun onWidgetsTransparencyChange() {
313329
runUpdates(
@@ -377,6 +393,10 @@ class UpdateExternalViewsInteractor @Inject constructor(
377393
)
378394
}
379395

396+
private suspend fun getRetroactiveTrackingMode(): Boolean {
397+
return prefsInteractor.getRetroactiveTrackingMode()
398+
}
399+
380400
private suspend fun runUpdates(vararg updates: Update?) {
381401
updates.filterNotNull().forEach { runUpdate(it) }
382402
}

features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/mapper/ChangeRecordActionsDelegateMapper.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ class ChangeRecordActionsDelegateMapper @Inject constructor() {
8686
updateViewData()
8787
}
8888

89-
override suspend fun onSaveClickDelegate() {
90-
parent?.onSaveClickDelegate()
89+
override suspend fun onSaveClickDelegate(doAfter: suspend () -> Unit) {
90+
parent?.onSaveClickDelegate(doAfter)
9191
}
9292
}
9393
}
@@ -163,7 +163,7 @@ class ChangeRecordActionsDelegateMapper @Inject constructor() {
163163
newTimeStarted = baseParams.newTimeStarted,
164164
newComment = baseParams.newComment,
165165
newCategoryIds = baseParams.newCategoryIds,
166-
isAdditionalActionsAvailable = continueParams.isAdditionalActionsAvailable,
166+
isAvailable = continueParams.isAvailable,
167167
isButtonEnabled = baseParams.isButtonEnabled,
168168
)
169169
}
@@ -173,7 +173,7 @@ class ChangeRecordActionsDelegateMapper @Inject constructor() {
173173
newTypeId = baseParams.newTypeId,
174174
newComment = baseParams.newComment,
175175
newCategoryIds = baseParams.newCategoryIds,
176-
isAdditionalActionsAvailable = repeatParams.isAdditionalActionsAvailable,
176+
isAvailable = repeatParams.isAvailable,
177177
isButtonEnabled = baseParams.isButtonEnabled,
178178
)
179179
}
@@ -185,7 +185,7 @@ class ChangeRecordActionsDelegateMapper @Inject constructor() {
185185
newTimeEnded = baseParams.newTimeEnded,
186186
newComment = baseParams.newComment,
187187
newCategoryIds = baseParams.newCategoryIds,
188-
isAdditionalActionsAvailable = duplicateParams.isAdditionalActionsAvailable,
188+
isAvailable = duplicateParams.isAvailable,
189189
isButtonEnabled = baseParams.isButtonEnabled,
190190
)
191191
}

features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordActionsContinueDelegate.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.example.util.simpletimetracker.feature_change_record.viewModel
22

33
import com.example.util.simpletimetracker.core.repo.ResourceRepo
4+
import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor
45
import com.example.util.simpletimetracker.domain.interactor.RecordActionContinueMediator
56
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
67
import com.example.util.simpletimetracker.feature_base_adapter.hint.HintViewData
@@ -13,6 +14,7 @@ import javax.inject.Inject
1314
class ChangeRecordActionsContinueDelegate @Inject constructor(
1415
private val router: Router,
1516
private val resourceRepo: ResourceRepo,
17+
private val prefsInteractor: PrefsInteractor,
1618
private val recordActionContinueMediator: RecordActionContinueMediator,
1719
) : ChangeRecordActionsSubDelegate<ChangeRecordActionsContinueDelegate.Parent> {
1820

@@ -57,10 +59,11 @@ class ChangeRecordActionsContinueDelegate @Inject constructor(
5759
}
5860
}
5961

60-
private fun loadContinueViewData(): List<ViewHolderType> {
62+
private suspend fun loadContinueViewData(): List<ViewHolderType> {
6163
val params = parent?.getViewDataParams()
6264
?: return emptyList()
63-
if (!params.isAdditionalActionsAvailable) return emptyList()
65+
if (!params.isAvailable) return emptyList()
66+
if (prefsInteractor.getRetroactiveTrackingMode()) return emptyList()
6467

6568
val result = mutableListOf<ViewHolderType>()
6669
result += HintViewData(
@@ -89,7 +92,7 @@ class ChangeRecordActionsContinueDelegate @Inject constructor(
8992
val newTimeStarted: Long,
9093
val newComment: String,
9194
val newCategoryIds: List<Long>,
92-
val isAdditionalActionsAvailable: Boolean,
95+
val isAvailable: Boolean,
9396
val isButtonEnabled: Boolean,
9497
)
9598
}

features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordActionsDelegate.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface ChangeRecordActionsDelegate {
1717
checkTypeSelected: Boolean = true,
1818
)
1919

20-
suspend fun onSaveClickDelegate()
20+
suspend fun onSaveClickDelegate(doAfter: suspend () -> Unit = {})
2121

2222
suspend fun onSplitComplete()
2323

@@ -49,16 +49,16 @@ interface ChangeRecordActionsDelegate {
4949
)
5050

5151
data class DuplicateParams(
52-
val isAdditionalActionsAvailable: Boolean,
52+
val isAvailable: Boolean,
5353
)
5454

5555
data class ContinueParams(
5656
val originalRecordId: Long,
57-
val isAdditionalActionsAvailable: Boolean,
57+
val isAvailable: Boolean,
5858
)
5959

6060
data class RepeatParams(
61-
val isAdditionalActionsAvailable: Boolean,
61+
val isAvailable: Boolean,
6262
)
6363

6464
data class AdjustParams(

features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordActionsDuplicateDelegate.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class ChangeRecordActionsDuplicateDelegate @Inject constructor(
4545
private fun loadDuplicateViewData(): List<ViewHolderType> {
4646
val params = parent?.getViewDataParams()
4747
?: return emptyList()
48-
if (!params.isAdditionalActionsAvailable) return emptyList()
48+
if (!params.isAvailable) return emptyList()
4949

5050
val result = mutableListOf<ViewHolderType>()
5151
result += HintViewData(
@@ -73,7 +73,7 @@ class ChangeRecordActionsDuplicateDelegate @Inject constructor(
7373
val newTimeEnded: Long,
7474
val newComment: String,
7575
val newCategoryIds: List<Long>,
76-
val isAdditionalActionsAvailable: Boolean,
76+
val isAvailable: Boolean,
7777
val isButtonEnabled: Boolean,
7878
)
7979
}

0 commit comments

Comments
 (0)