Skip to content

Commit

Permalink
adding retroactive tracking mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Oct 19, 2024
1 parent 5e1d7f4 commit 7b93a7d
Show file tree
Hide file tree
Showing 19 changed files with 327 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ class PrefsRepoImpl @Inject constructor(
KEY_KEEP_STATISTICS_RANGE, false,
)

override var retroactiveTrackingMode: Boolean by prefs.delegate(
KEY_RETROACTIVE_TRACKING_MODE, false
)

override var firstDayOfWeek: Int by prefs.delegate(
KEY_FIRST_DAY_OF_WEEK, firstDayOfWeekDefault,
)
Expand Down Expand Up @@ -548,6 +552,7 @@ class PrefsRepoImpl @Inject constructor(
const val KEY_CSV_EXPORT_CUSTOM_FILENAME = "csvExportCustomFilename"
const val KEY_ICS_EXPORT_CUSTOM_FILENAME = "icsExportCustomFilename"
const val KEY_KEEP_STATISTICS_RANGE = "keepStatisticsRange"
const val KEY_RETROACTIVE_TRACKING_MODE = "retroactiveTrackingMode"
const val KEY_FIRST_DAY_OF_WEEK = "firstDayOfWeek"
const val KEY_START_OF_DAY_SHIFT = "startOfDayShift"
const val KEY_SHOW_UNTRACKED_IN_RECORDS = "showUntrackedInRecords"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companio
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RECORD_TYPES_FILTERED_ON_CHART
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RECORD_TYPES_FILTERED_ON_LIST
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_REPEAT_BUTTON_TYPE
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RETROACTIVE_TRACKING_MODE
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_REVERSE_ORDER_IN_CALENDAR
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_ACTIVITY_FILTERS
import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB
Expand Down Expand Up @@ -155,6 +156,7 @@ class BackupPrefsRepo @Inject constructor(
PrefsProcessor(KEY_CSV_EXPORT_CUSTOM_FILENAME, ::csvExportCustomFileName),
PrefsProcessor(KEY_ICS_EXPORT_CUSTOM_FILENAME, ::icsExportCustomFileName),
PrefsProcessor(KEY_KEEP_STATISTICS_RANGE, ::keepStatisticsRange),
PrefsProcessor(KEY_RETROACTIVE_TRACKING_MODE, ::retroactiveTrackingMode),
PrefsProcessor(KEY_FIRST_DAY_OF_WEEK, ::firstDayOfWeek),
PrefsProcessor(KEY_START_OF_DAY_SHIFT, ::startOfDayShift),
PrefsProcessor(KEY_SHOW_UNTRACKED_IN_RECORDS, ::showUntrackedInRecords),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.example.util.simpletimetracker.domain.interactor

import com.example.util.simpletimetracker.domain.extension.orZero
import com.example.util.simpletimetracker.domain.model.Range
import com.example.util.simpletimetracker.domain.model.Record
import com.example.util.simpletimetracker.domain.model.RecordType
import com.example.util.simpletimetracker.domain.model.ResultContainer
import com.example.util.simpletimetracker.domain.model.RunningRecord
import java.util.concurrent.TimeUnit
import javax.inject.Inject

class AddRunningRecordMediator @Inject constructor(
Expand Down Expand Up @@ -79,15 +81,18 @@ class AddRunningRecordMediator @Inject constructor(
tagIds = actualTags,
comment = comment,
)
addInternal(
StartParams(
typeId = typeId,
comment = comment,
tagIds = actualTags,
timeStarted = timeStarted ?: System.currentTimeMillis(),
updateNotificationSwitch = updateNotificationSwitch,
),
val startParams = StartParams(
typeId = typeId,
comment = comment,
tagIds = actualTags,
timeStarted = timeStarted ?: System.currentTimeMillis(),
updateNotificationSwitch = updateNotificationSwitch,
)
if (prefsInteractor.getRetroactiveTrackingMode()) {
addRetroactiveModeInternal(startParams)
} else {
addInternal(startParams)
}
// Show goal count only on timer start, otherwise it would show on change also.
notificationGoalCountInteractor.checkAndShow(typeId)
pomodoroStartInteractor.checkAndStart(typeId)
Expand Down Expand Up @@ -122,6 +127,25 @@ class AddRunningRecordMediator @Inject constructor(
}
}

private suspend fun addRetroactiveModeInternal(params: StartParams) {
val type = recordTypeInteractor.get(params.typeId) ?: return
val prevRecord = recordInteractor.getPrev(params.timeStarted).firstOrNull()

if (type.defaultDuration > 0L) {
val newTimeStarted = prevRecord?.timeEnded
?: (params.timeStarted - type.defaultDuration * 1000)
addInstantRecord(
params = params.copy(timeStarted = newTimeStarted),
type = type,
)
} else {
addRecordRetroactively(
params = params,
prevRecord = prevRecord,
)
}
}

private suspend fun addRunningRecord(
params: StartParams,
) {
Expand Down Expand Up @@ -165,6 +189,41 @@ class AddRunningRecordMediator @Inject constructor(
}
}

private suspend fun addRecordRetroactively(
params: StartParams,
prevRecord: Record?,
) {
val shouldMergeWithPrevRecord = prevRecord != null &&
prevRecord.typeId == params.typeId &&
prevRecord.tagIds == params.tagIds

val record = if (prevRecord != null && shouldMergeWithPrevRecord) {
Record(
id = prevRecord.id, // Updates existing record.
typeId = params.typeId,
timeStarted = prevRecord.timeStarted,
timeEnded = params.timeStarted,
comment = params.comment,
tagIds = params.tagIds,
)
} else {
val newTimeStarted = prevRecord?.timeEnded
?: (params.timeStarted - TimeUnit.MINUTES.toMillis(5))
Record(
id = 0L, // Creates new record.
typeId = params.typeId,
timeStarted = newTimeStarted,
timeEnded = params.timeStarted,
comment = params.comment,
tagIds = params.tagIds,
)
}
addRecordMediator.add(
record = record,
updateNotificationSwitch = params.updateNotificationSwitch,
)
}

private suspend fun processRules(
typeId: Long,
timeStarted: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,14 @@ class PrefsInteractor @Inject constructor(
prefsRepo.keepStatisticsRange = isEnabled
}

suspend fun getRetroactiveTrackingMode(): Boolean = withContext(Dispatchers.IO) {
prefsRepo.retroactiveTrackingMode
}

suspend fun setRetroactiveTrackingMode(isEnabled: Boolean) = withContext(Dispatchers.IO) {
prefsRepo.retroactiveTrackingMode = isEnabled
}

suspend fun getFirstDayOfWeek(): DayOfWeek = withContext(Dispatchers.IO) {
// Same as in java Calendar
when (prefsRepo.firstDayOfWeek) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ interface PrefsRepo {

var keepStatisticsRange: Boolean

var retroactiveTrackingMode: Boolean

var firstDayOfWeek: Int

var startOfDayShift: Long // in milliseconds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.example.util.simpletimetracker.feature_base_adapter.databinding.ItemR
import com.example.util.simpletimetracker.feature_base_adapter.record.RecordViewData as ViewData

fun createRecordAdapterDelegate(
onItemClick: ((ViewData, Pair<Any, String>) -> Unit),
onItemClick: ((ViewData, Pair<Any, String>) -> Unit) = { _, _ -> },
onItemLongClick: ((ViewData, Pair<Any, String>) -> Unit) = { _, _ -> },
) = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
Binding::inflate,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.util.simpletimetracker.feature_base_adapter.recordWithHint

import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBindingAdapterDelegate
import com.example.util.simpletimetracker.feature_base_adapter.databinding.ItemRecordWithHintLayoutBinding as Binding
import com.example.util.simpletimetracker.feature_base_adapter.recordWithHint.RecordWithHintViewData as ViewData

fun createRecordWithHintAdapterDelegate() = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
Binding::inflate,
) { binding, item, _ ->

with(binding.viewRecordItem) {
item as ViewData

item.record.let { item ->
itemColor = item.color
itemIcon = item.iconId
itemName = item.name
itemTagName = item.tagName
itemTimeStarted = item.timeStarted
itemTimeEnded = item.timeFinished
itemDuration = item.duration
itemComment = item.comment
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.util.simpletimetracker.feature_base_adapter.recordWithHint

import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
import com.example.util.simpletimetracker.feature_base_adapter.record.RecordViewData

data class RecordWithHintViewData(
val record: RecordViewData.Tracked,
) : ViewHolderType {

override fun getUniqueId(): Long = record.id

override fun isValidType(other: ViewHolderType): Boolean =
other is RecordWithHintViewData
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import com.example.util.simpletimetracker.feature_base_adapter.runningRecord.Run

fun createRunningRecordAdapterDelegate(
transitionNamePrefix: String,
onItemClick: ((ViewData, Pair<Any, String>) -> Unit),
onItemClick: ((ViewData, Pair<Any, String>) -> Unit) = { _, _ -> },
onItemLongClick: ((ViewData, Pair<Any, String>) -> Unit) = { _, _ -> },
) = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
Binding::inflate,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<com.example.util.simpletimetracker.feature_views.RecordView
android:id="@+id/viewRecordItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
app:cardElevation="@dimen/record_type_card_elevation"
app:itemTagColor="@color/white_alpha_60"
app:layout_constraintTop_toTopOf="parent"
tools:itemColor="@color/blue_800"
tools:itemDuration="5h 23m 3s"
tools:itemName="Record"
tools:itemTagName="Tag"
tools:itemTimeEnded="11:58"
tools:itemTimeStarted="07:35" />

<Space
android:id="@+id/spaceRecordItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toTopOf="@id/viewRecordItem"
app:layout_constraintStart_toStartOf="@id/viewRecordItem" />

<androidx.cardview.widget.CardView
android:id="@+id/btnRecordItemHint"
style="@style/InputFieldCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardElevation="@dimen/record_type_card_elevation"
app:layout_constraintStart_toStartOf="@id/spaceRecordItem"
app:layout_constraintTop_toTopOf="@id/spaceRecordItem">

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvRecordItemHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?appInputFieldBorder"
android:paddingHorizontal="10dp"
android:paddingVertical="2dp"
android:text="@string/statistics_detail_last_record"
android:textColor="?appTextHintColor"
android:textSize="11sp"
app:autoSizeTextType="none" />

</androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class RecordsFilterFragment :
createRecordsDateDividerAdapterDelegate(),
createRecordTypeAdapterDelegate(viewModel::onRecordTypeClick),
createCategoryAdapterDelegate(viewModel::onCategoryClick),
createRecordAdapterDelegate(viewModel::onRecordClick),
createRecordAdapterDelegate(onItemClick = viewModel::onRecordClick),
createSelectionButtonAdapterDelegate(viewModel::onSelectionButtonClick),
createRecordsFilterCommentAdapterDelegate(viewModel::onCommentChange),
createRecordsFilterButtonAdapterDelegate(viewModel::onInnerFilterButtonClick),
Expand All @@ -94,7 +94,7 @@ class RecordsFilterFragment :
createLoaderAdapterDelegate(),
createEmptyAdapterDelegate(),
createRecordsDateDividerAdapterDelegate(),
createRunningRecordAdapterDelegate("", { _, _ -> }),
createRunningRecordAdapterDelegate(""),
createRecordAdapterDelegate(viewModel::onRecordClick),
createMultitaskRecordAdapterDelegate(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.example.util.simpletimetracker.core.interactor.GetCurrentRecordsDurat
import com.example.util.simpletimetracker.core.interactor.GetRunningRecordViewDataMediator
import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper
import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordTagInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordTypeGoalInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor
Expand All @@ -23,6 +24,7 @@ class RunningRecordsViewDataInteractor @Inject constructor(
private val recordTagInteractor: RecordTagInteractor,
private val recordTypeGoalInteractor: RecordTypeGoalInteractor,
private val runningRecordInteractor: RunningRecordInteractor,
private val recordInteractor: RecordInteractor,
private val activityFilterViewDataInteractor: ActivityFilterViewDataInteractor,
private val mapper: RunningRecordsViewDataMapper,
private val recordTypeViewDataMapper: RecordTypeViewDataMapper,
Expand All @@ -31,6 +33,8 @@ class RunningRecordsViewDataInteractor @Inject constructor(
private val filterGoalsByDayOfWeekInteractor: FilterGoalsByDayOfWeekInteractor,
) {

// TODO RETRO what to do on first start, when there is no prev record?
// TODO RETRO show timers also if any
suspend fun getViewData(
completeTypeIds: Set<Long>,
): List<ViewHolderType> {
Expand All @@ -49,6 +53,7 @@ class RunningRecordsViewDataInteractor @Inject constructor(
val showPomodoroButton = prefsInteractor.getEnablePomodoroMode()
val showRepeatButton = prefsInteractor.getEnableRepeatButton()
val isPomodoroStarted = prefsInteractor.getPomodoroModeStartedTimestampMs() != 0L
val retroactiveTrackingModeEnabled = prefsInteractor.getRetroactiveTrackingMode()
val goals = filterGoalsByDayOfWeekInteractor
.execute(recordTypeGoalInteractor.getAllTypeGoals())
.groupBy { it.idData.value }
Expand All @@ -63,10 +68,26 @@ class RunningRecordsViewDataInteractor @Inject constructor(
}

val runningRecordsViewData = when {
showFirstEnterHint ->
showFirstEnterHint -> {
listOf(mapper.mapToTypesEmpty())
runningRecords.isEmpty() ->
}
retroactiveTrackingModeEnabled -> {
val prevRecord = recordInteractor.getPrev(
timeStarted = System.currentTimeMillis(),
).firstOrNull()
mapper.mapToRetroActiveMode(
typesMap = recordTypesMap,
recordTags = recordTags,
prevRecord = prevRecord,
isDarkTheme = isDarkTheme,
useProportionalMinutes = useProportionalMinutes,
useMilitaryTime = useMilitaryTime,
showSeconds = showSeconds,
)
}
runningRecords.isEmpty() -> {
listOf(mapper.mapToEmpty())
}
else -> {
runningRecords
.sortedByDescending(RunningRecord::timeStarted)
Expand Down
Loading

0 comments on commit 7b93a7d

Please sign in to comment.