Skip to content

Commit

Permalink
change retroactive multitasking logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Nov 22, 2024
1 parent d710325 commit 01d9d7e
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ interface RecordDao {
comment: String,
)

@Query("UPDATE records SET time_ended = :timeEnded WHERE id = :recordId")
suspend fun updateTimeEnded(recordId: Long, timeEnded: Long)

@Query("DELETE FROM records WHERE id = :id")
suspend fun delete(id: Long)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.example.util.simpletimetracker.data_local.mapper.RecordDataLocalMappe
import com.example.util.simpletimetracker.data_local.model.RecordWithRecordTagsDBO
import com.example.util.simpletimetracker.data_local.utils.logDataAccess
import com.example.util.simpletimetracker.data_local.utils.withLockedCache
import com.example.util.simpletimetracker.domain.extension.dropMillis
import com.example.util.simpletimetracker.domain.model.Range
import com.example.util.simpletimetracker.domain.model.Record
import com.example.util.simpletimetracker.domain.repo.RecordRepo
Expand All @@ -25,6 +26,7 @@ class RecordRepoImpl @Inject constructor(
private var getFromRangeByTypeCache = LruCache<GetFromRangeByTypeKey, List<Record>>(1)
private var recordCache = LruCache<Long, Record>(1)
private var isEmpty: Boolean? = null

private val mutex: Mutex = Mutex()

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

override suspend fun updateTimeEnded(
recordId: Long,
timeEnded: Long,
) = mutex.withLockedCache(
logMessage = "updateTimeEnded",
accessSource = {
recordDao.updateTimeEnded(
recordId = recordId,
timeEnded = timeEnded.dropMillis(),
)
},
afterSourceAccess = { clearCache() },
)

override suspend fun remove(id: Long) = mutex.withLockedCache(
logMessage = "remove",
accessSource = { recordDao.delete(id) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,31 +54,14 @@ class AddRunningRecordMediator @Inject constructor(
}
}

suspend fun startTimers(
typeIds: Set<Long>,
) {
val current = System.currentTimeMillis()
val timeStarted = StartTime.Current(current)
val prevRecords = recordInteractor.getAllPrev(current)
typeIds.forEachIndexed { index, id ->
startTimer(
typeId = id,
tagIds = emptyList(),
comment = "",
timeStarted = timeStarted,
prevRecords = PrevRecords.Records(prevRecords),
// Update only on last.
updateNotificationSwitch = index == typeIds.size - 1,
)
}
}

// TODO test retroactive mode
// TODO test several prev records at the same time, merge accordingly.
// TODO test retroactive multitask
suspend fun startTimer(
typeId: Long,
tagIds: List<Long>,
comment: String,
timeStarted: StartTime = StartTime.TakeCurrent,
prevRecords: PrevRecords = PrevRecords.Load,
updateNotificationSwitch: Boolean = true,
checkDefaultDuration: Boolean = true,
) {
Expand All @@ -90,10 +73,7 @@ class AddRunningRecordMediator @Inject constructor(
}
val retroactiveTrackingMode = prefsInteractor.getRetroactiveTrackingMode()
val actualPrevRecords = if (retroactiveTrackingMode) {
when (prevRecords) {
is PrevRecords.Load -> recordInteractor.getAllPrev(actualTimeStarted)
is PrevRecords.Records -> prevRecords.records
}
recordInteractor.getAllPrev(actualTimeStarted)
} else {
emptyList()
}
Expand All @@ -113,9 +93,12 @@ class AddRunningRecordMediator @Inject constructor(
prevRecords = actualPrevRecords,
)
}
val isMultitaskingAllowedByDefault = prefsInteractor.getAllowMultitasking()
val isMultitaskingAllowed = rulesResult.isMultitaskingAllowed.getValueOrNull()
?: isMultitaskingAllowedByDefault
processMultitasking(
typeId = typeId,
isMultitaskingAllowedByRules = rulesResult.isMultitaskingAllowed,
isMultitaskingAllowed = isMultitaskingAllowed,
splitTime = when (timeStarted) {
is StartTime.Current -> timeStarted.currentTimeStampMs
is StartTime.TakeCurrent -> currentTime
Expand All @@ -138,6 +121,7 @@ class AddRunningRecordMediator @Inject constructor(
tagIds = actualTags,
timeStarted = actualTimeStarted,
updateNotificationSwitch = updateNotificationSwitch,
isMultitaskingAllowed = isMultitaskingAllowed,
)
if (retroactiveTrackingMode) {
addRetroactiveModeInternal(startParams, actualPrevRecords)
Expand Down Expand Up @@ -165,6 +149,7 @@ class AddRunningRecordMediator @Inject constructor(
comment = comment,
tagIds = tagIds,
updateNotificationSwitch = true,
isMultitaskingAllowed = true,
),
checkDefaultDuration = false,
)
Expand All @@ -188,9 +173,13 @@ class AddRunningRecordMediator @Inject constructor(
) {
val type = recordTypeInteractor.get(params.typeId) ?: return

processRetroactiveMultitasking(
params = params,
prevRecords = prevRecords,
)

if (type.defaultDuration > 0L) {
val newTimeStarted = prevRecords.firstOrNull()?.timeEnded
?: (params.timeStarted - type.defaultDuration * 1000)
val newTimeStarted = params.timeStarted - type.defaultDuration * 1000
addInstantRecord(
params = params.copy(timeStarted = newTimeStarted),
type = type,
Expand Down Expand Up @@ -307,13 +296,9 @@ class AddRunningRecordMediator @Inject constructor(

private suspend fun processMultitasking(
typeId: Long,
isMultitaskingAllowedByRules: ResultContainer<Boolean>,
isMultitaskingAllowed: Boolean,
splitTime: Long,
) {
val isMultitaskingAllowedByDefault = prefsInteractor.getAllowMultitasking()
val isMultitaskingAllowed = isMultitaskingAllowedByRules.getValueOrNull()
?: isMultitaskingAllowedByDefault

// Stop running records if multitasking is disabled.
if (!isMultitaskingAllowed) {
// Widgets will update on adding.
Expand All @@ -330,6 +315,36 @@ class AddRunningRecordMediator @Inject constructor(
}
}

private suspend fun processRetroactiveMultitasking(
params: StartParams,
prevRecords: List<Record>,
) {
if (!params.isMultitaskingAllowed) return

val recordTypesMap = recordTypeInteractor.getAll().associateBy(RecordType::id)
val mergedRecord = getPrevRecordToMergeWith(params.typeId, prevRecords)

// Extend prev records to current time.
prevRecords.filter {
// Skip record that would be merge.
it.id != mergedRecord?.id
}.filter {
// Skip records with default duration.
val thisType = recordTypesMap[it.typeId]
thisType != null && thisType.defaultDuration == 0L
}.map { prevRecord ->
recordInteractor.updateTimeEnded(
recordId = prevRecord.id,
timeEnded = params.timeStarted,
)
prevRecord.typeId
}.let {
updateExternalViewsInteractor.onRecordTimeEndedChange(
typeIds = it,
)
}
}

private suspend fun getAllTags(
typeId: Long,
tagIds: List<Long>,
Expand All @@ -352,16 +367,12 @@ class AddRunningRecordMediator @Inject constructor(
val comment: String,
val tagIds: List<Long>,
val updateNotificationSwitch: Boolean,
val isMultitaskingAllowed: Boolean,
)

sealed interface StartTime {
data class Current(val currentTimeStampMs: Long) : StartTime
data class Timestamp(val timestampMs: Long) : StartTime
object TakeCurrent : StartTime
}

sealed interface PrevRecords {
data class Records(val records: List<Record>) : PrevRecords
object Load : PrevRecords
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ class RecordInteractor @Inject constructor(
updateTags(recordId, tagIds)
}

suspend fun updateTimeEnded(recordId: Long, timeEnded: Long) {
recordRepo.updateTimeEnded(
recordId = recordId,
timeEnded = timeEnded,
)
}

suspend fun remove(id: Long) {
recordToRecordTagRepo.removeAllByRecordId(id)
recordRepo.remove(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ class UpdateExternalViewsInteractor @Inject constructor(
)
}

suspend fun onRecordTimeEndedChange(
typeIds: List<Long>,
) {
runUpdates(
Update.GoalReschedule(typeIds),
)
}

suspend fun onInstantRecordAdd() {
runUpdates(
Update.Wear,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ interface RecordRepo {
comment: String,
)

suspend fun updateTimeEnded(recordId: Long, timeEnded: Long)

suspend fun remove(id: Long)

suspend fun removeByType(typeId: Long)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ fun createRecordTypeAdapterDelegate(
itemIsChecked = item.isChecked.orFalse()
itemCompleteIsAnimated = true
itemIsComplete = item.isComplete
val newItemScale = if (item.isSelected) 1.1f else 1.0f
scaleX = newItemScale
scaleY = newItemScale
getCheckmarkOutline().itemIsFiltered = item.itemIsFiltered
onItemClick?.let { setOnClickWith(item, it) }
onItemLongClick?.let { setOnLongClick { it(item, mapOf(this to transitionName)) } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ data class RecordTypeViewData(
val isChecked: Boolean? = null,
val itemIsFiltered: Boolean = false,
val isComplete: Boolean = false,
val isSelected: Boolean = false,
) : ViewHolderType {

override fun getUniqueId(): Long = id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(

suspend fun getViewData(
completeTypeIds: Set<Long>,
multitaskingSelectionEnabled: Boolean,
multiSelectedActivityIds: Set<Long>,
): List<ViewHolderType> {
val recordTypes = recordTypeInteractor.getAll()
val recordTypesMap = recordTypes.associateBy(RecordType::id)
Expand All @@ -54,7 +52,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
val showRepeatButton = prefsInteractor.getEnableRepeatButton()
val isPomodoroStarted = prefsInteractor.getPomodoroModeStartedTimestampMs() != 0L
val retroactiveTrackingModeEnabled = prefsInteractor.getRetroactiveTrackingMode()
val allowMultitasking = prefsInteractor.getAllowMultitasking()
val goals = filterGoalsByDayOfWeekInteractor
.execute(recordTypeGoalInteractor.getAllTypeGoals())
.groupBy { it.idData.value }
Expand Down Expand Up @@ -84,9 +81,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
useProportionalMinutes = useProportionalMinutes,
useMilitaryTime = useMilitaryTime,
showSeconds = showSeconds,
allowMultitasking = allowMultitasking,
multitaskingSelectionEnabled = multitaskingSelectionEnabled,
multiSelectedActivityIds = multiSelectedActivityIds,
)
}
runningRecords.isEmpty() -> {
Expand Down Expand Up @@ -146,17 +140,6 @@ class RunningRecordsViewDataInteractor @Inject constructor(
isComplete = it.id in completeTypeIds,
)
}
.map {
if (multitaskingSelectionEnabled) {
val isSelected = it.id in multiSelectedActivityIds
it.copy(
isComplete = isSelected,
isSelected = isSelected,
)
} else {
it
}
}
.let { data ->
mutableListOf<ViewHolderType>().apply {
data.let(::addAll)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ import com.example.util.simpletimetracker.domain.model.RecordTag
import com.example.util.simpletimetracker.domain.model.RecordType
import com.example.util.simpletimetracker.domain.model.RunningRecord
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
import com.example.util.simpletimetracker.feature_base_adapter.divider.DividerViewData
import com.example.util.simpletimetracker.feature_base_adapter.empty.EmptyViewData
import com.example.util.simpletimetracker.feature_base_adapter.hint.HintViewData
import com.example.util.simpletimetracker.feature_base_adapter.hintBig.HintBigViewData
import com.example.util.simpletimetracker.feature_base_adapter.recordFilter.FilterViewData
import com.example.util.simpletimetracker.feature_base_adapter.recordWithHint.RecordWithHintViewData
import com.example.util.simpletimetracker.feature_running_records.R
import com.example.util.simpletimetracker.feature_running_records.model.RunningRecordsFilterType
import javax.inject.Inject

class RunningRecordsViewDataMapper @Inject constructor(
Expand Down Expand Up @@ -65,9 +62,6 @@ class RunningRecordsViewDataMapper @Inject constructor(
useProportionalMinutes: Boolean,
useMilitaryTime: Boolean,
showSeconds: Boolean,
allowMultitasking: Boolean,
multitaskingSelectionEnabled: Boolean,
multiSelectedActivityIds: Set<Long>,
): List<ViewHolderType> {
val result = mutableListOf<ViewHolderType>()

Expand Down Expand Up @@ -125,42 +119,6 @@ class RunningRecordsViewDataMapper @Inject constructor(
paddingTop = 0,
paddingBottom = 0,
)
if (allowMultitasking) {
// TODO test retroactive mode
// TODO test several prev records at the same time, merge accordingly.
// TODO test retroactive multitask
// enable, go to other screen
// enable, go to edit type
// disable by clicking
// disable by removing
result += DividerViewData(3)
result += FilterViewData(
id = 0,
type = RunningRecordsFilterType.EnableMultitaskingSelection,
name = resourceRepo.getString(R.string.multitask_time_name),
color = if (multitaskingSelectionEnabled) {
colorMapper.toActiveColor(isDarkTheme)
} else {
colorMapper.toInactiveColor(isDarkTheme)
},
selected = multitaskingSelectionEnabled,
removeBtnVisible = multitaskingSelectionEnabled,
)
if (multitaskingSelectionEnabled) {
result += FilterViewData(
id = 1,
type = RunningRecordsFilterType.FinishMultitaskingSelection,
name = resourceRepo.getString(R.string.records_filter_select),
color = if (multiSelectedActivityIds.isNotEmpty()) {
colorMapper.toActiveColor(isDarkTheme)
} else {
colorMapper.toInactiveColor(isDarkTheme)
},
selected = false,
removeBtnVisible = false,
)
}
}
}

return result
Expand Down

This file was deleted.

Loading

0 comments on commit 01d9d7e

Please sign in to comment.