From 8092ef289c5cb6e3b4cf21fcaa61348568c62903 Mon Sep 17 00:00:00 2001 From: razeeman Date: Sun, 22 Oct 2023 12:23:48 +0300 Subject: [PATCH] add daily goals visible on type cards on main tab --- .../ChartFilterViewDataInteractor.kt | 1 + .../GetCurrentRecordsDurationInteractor.kt | 67 +++++++++++++++---- .../RecordTypesViewDataInteractor.kt | 11 ++- .../core/mapper/RecordTypeViewDataMapper.kt | 54 ++++++++++++--- .../interactor/ArchiveViewDataInteractor.kt | 3 +- .../recordType/RecordTypeAdapterDelegate.kt | 3 + .../recordType/RecordTypeViewData.kt | 3 +- .../ChangeActivityFilterViewDataInteractor.kt | 3 +- .../ChangeCategoryViewDataInteractor.kt | 6 +- .../dialog/DataEditTypeSelectionViewModel.kt | 1 + .../ArchiveDialogViewDataInteractor.kt | 3 +- .../cardOrder/viewModel/CardOrderViewModel.kt | 11 ++- .../cardSize/mapper/CardSizeViewDataMapper.kt | 7 +- .../DefaultTypesSelectionViewModel.kt | 3 +- .../RecordsFilterViewDataInteractor.kt | 3 +- .../RunningRecordsViewDataInteractor.kt | 18 ++++- .../mapper/RunningRecordsViewDataMapper.kt | 18 ----- .../feature_views/RecordTypeView.kt | 26 +++++++ .../res/drawable/spinner_check_unmarked.xml | 9 +++ .../layout/record_type_view_horizontal.xml | 12 ++++ .../res/layout/record_type_view_layout.xml | 4 +- .../res/layout/record_type_view_vertical.xml | 12 ++++ .../src/main/res/values/attrs.xml | 2 + .../viewModel/WidgetUniversalViewModel.kt | 22 ++++++ 24 files changed, 247 insertions(+), 55 deletions(-) create mode 100644 features/feature_views/src/main/res/drawable/spinner_check_unmarked.xml diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/ChartFilterViewDataInteractor.kt b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/ChartFilterViewDataInteractor.kt index f02338d12..c3547c5d1 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/ChartFilterViewDataInteractor.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/ChartFilterViewDataInteractor.kt @@ -43,6 +43,7 @@ class ChartFilterViewDataInteractor @Inject constructor( isFiltered = type.id in typeIdsFiltered, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, + isChecked = null, ) } .takeUnless { it.isEmpty() } diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetCurrentRecordsDurationInteractor.kt b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetCurrentRecordsDurationInteractor.kt index cc4d4ac40..000dee992 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetCurrentRecordsDurationInteractor.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetCurrentRecordsDurationInteractor.kt @@ -1,11 +1,13 @@ package com.example.util.simpletimetracker.core.interactor -import com.example.util.simpletimetracker.domain.mapper.RangeMapper import com.example.util.simpletimetracker.core.mapper.TimeMapper import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor import com.example.util.simpletimetracker.domain.interactor.RecordInteractor +import com.example.util.simpletimetracker.domain.mapper.RangeMapper import com.example.util.simpletimetracker.domain.model.Range import com.example.util.simpletimetracker.domain.model.RangeLength +import com.example.util.simpletimetracker.domain.model.Record +import com.example.util.simpletimetracker.domain.model.RecordType import com.example.util.simpletimetracker.domain.model.RunningRecord import java.lang.Long.max import javax.inject.Inject @@ -18,27 +20,68 @@ class GetCurrentRecordsDurationInteractor @Inject constructor( ) { suspend fun getDailyCurrent(runningRecord: RunningRecord): Result { - return getRangeCurrent(runningRecord, getRange(RangeLength.Day)) + return getRangeCurrent(runningRecord.id, runningRecord, getRange(RangeLength.Day)) } suspend fun getWeeklyCurrent(runningRecord: RunningRecord): Result { - return getRangeCurrent(runningRecord, getRange(RangeLength.Week)) + return getRangeCurrent(runningRecord.id, runningRecord, getRange(RangeLength.Week)) } suspend fun getMonthlyCurrent(runningRecord: RunningRecord): Result { - return getRangeCurrent(runningRecord, getRange(RangeLength.Month)) + return getRangeCurrent(runningRecord.id, runningRecord, getRange(RangeLength.Month)) + } + + suspend fun getAllDailyCurrents( + typesMap: Map, + runningRecords: List, + ): Map { + val range = getRange(RangeLength.Day) + val rangeRecords = recordInteractor.getFromRange(range) + + return typesMap.map { (typeId, type) -> + typeId to getRangeCurrent( + typeId = typeId, + runningRecord = runningRecords.firstOrNull { it.id == typeId }, + range = range, + rangeRecords = rangeRecords, + ) + }.toMap() } private suspend fun getRangeCurrent( - runningRecord: RunningRecord, - range: Range + typeId: Long, + runningRecord: RunningRecord?, + range: Range, + ): Result { + return getRangeCurrent( + typeId = typeId, + runningRecord = runningRecord, + range = range, + rangeRecords = recordInteractor.getFromRange(range), + ) + } + + private fun getRangeCurrent( + typeId: Long, + runningRecord: RunningRecord?, + range: Range, + rangeRecords: List, ): Result { val current = System.currentTimeMillis() - val currentRunning = current - runningRecord.timeStarted - val currentRunningClamped = current - max(runningRecord.timeStarted, range.timeStarted) + val currentRunning = if (runningRecord != null) { + current - runningRecord.timeStarted + } else { + 0 + } + val currentRunningClamped = if (runningRecord != null) { + current - max(runningRecord.timeStarted, range.timeStarted) + } else { + 0 + } + val currentRunningCount = if (runningRecord != null) 1 else 0 - val records = recordInteractor.getFromRange(range) - .filter { it.typeId == runningRecord.id } + val records = rangeRecords + .filter { it.typeId == typeId } .map { rangeMapper.clampToRange(it, range) } val duration = records .let(rangeMapper::mapToDuration) @@ -47,8 +90,8 @@ class GetCurrentRecordsDurationInteractor @Inject constructor( return Result( range = range, duration = duration + currentRunningClamped, - count = count + 1, // 1 is for current running record. - durationDiffersFromCurrent = duration != 0L || currentRunning != currentRunningClamped + count = count + currentRunningCount, + durationDiffersFromCurrent = duration != 0L || currentRunning != currentRunningClamped, ) } diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/RecordTypesViewDataInteractor.kt b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/RecordTypesViewDataInteractor.kt index db7d7e0e9..61d130a3d 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/interactor/RecordTypesViewDataInteractor.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/interactor/RecordTypesViewDataInteractor.kt @@ -9,7 +9,7 @@ import javax.inject.Inject class RecordTypesViewDataInteractor @Inject constructor( private val prefsInteractor: PrefsInteractor, private val recordTypeInteractor: RecordTypeInteractor, - private val recordTypeViewDataMapper: RecordTypeViewDataMapper + private val recordTypeViewDataMapper: RecordTypeViewDataMapper, ) { suspend fun getTypesViewData(): List { @@ -19,7 +19,14 @@ class RecordTypesViewDataInteractor @Inject constructor( return recordTypeInteractor.getAll() .filter { !it.hidden } .takeUnless { it.isEmpty() } - ?.map { recordTypeViewDataMapper.map(it, numberOfCards, isDarkTheme) } + ?.map { + recordTypeViewDataMapper.map( + recordType = it, + numberOfCards = numberOfCards, + isDarkTheme = isDarkTheme, + isChecked = null, + ) + } ?: recordTypeViewDataMapper.mapToEmpty() } } \ No newline at end of file diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordTypeViewDataMapper.kt b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordTypeViewDataMapper.kt index 2d80a71ff..bd46472a1 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordTypeViewDataMapper.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordTypeViewDataMapper.kt @@ -3,9 +3,14 @@ package com.example.util.simpletimetracker.core.mapper import androidx.annotation.ColorInt import androidx.annotation.StringRes import com.example.util.simpletimetracker.core.R +import com.example.util.simpletimetracker.core.interactor.GetCurrentRecordsDurationInteractor import com.example.util.simpletimetracker.core.repo.ResourceRepo +import com.example.util.simpletimetracker.domain.extension.getDaily +import com.example.util.simpletimetracker.domain.extension.orZero +import com.example.util.simpletimetracker.domain.extension.value import com.example.util.simpletimetracker.domain.model.AppColor import com.example.util.simpletimetracker.domain.model.RecordType +import com.example.util.simpletimetracker.domain.model.RecordTypeGoal import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType import com.example.util.simpletimetracker.feature_base_adapter.empty.EmptyViewData import com.example.util.simpletimetracker.feature_base_adapter.recordType.RecordTypeViewData @@ -17,32 +22,33 @@ class RecordTypeViewDataMapper @Inject constructor( private val iconMapper: IconMapper, private val colorMapper: ColorMapper, private val resourceRepo: ResourceRepo, - private val recordTypeCardSizeMapper: RecordTypeCardSizeMapper + private val recordTypeCardSizeMapper: RecordTypeCardSizeMapper, ) { fun mapToEmpty(): List { return EmptyViewData( - message = resourceRepo.getString(R.string.record_types_empty) + message = resourceRepo.getString(R.string.record_types_empty), ).let(::listOf) } fun map( recordType: RecordType, - isDarkTheme: Boolean + isDarkTheme: Boolean, ): RecordTypeViewData { return RecordTypeViewData( id = recordType.id, name = recordType.name, iconId = iconMapper.mapIcon(recordType.icon), iconColor = colorMapper.toIconColor(isDarkTheme), - color = mapColor(recordType.color, isDarkTheme) + color = mapColor(recordType.color, isDarkTheme), ) } fun map( recordType: RecordType, numberOfCards: Int, - isDarkTheme: Boolean + isDarkTheme: Boolean, + isChecked: Boolean?, ): RecordTypeViewData { return RecordTypeViewData( id = recordType.id, @@ -52,7 +58,8 @@ class RecordTypeViewDataMapper @Inject constructor( color = mapColor(recordType.color, isDarkTheme), width = recordTypeCardSizeMapper.toCardWidth(numberOfCards), height = recordTypeCardSizeMapper.toCardHeight(numberOfCards), - asRow = recordTypeCardSizeMapper.toCardAsRow(numberOfCards) + asRow = recordTypeCardSizeMapper.toCardAsRow(numberOfCards), + isChecked = isChecked, ) } @@ -60,9 +67,15 @@ class RecordTypeViewDataMapper @Inject constructor( recordType: RecordType, numberOfCards: Int, isDarkTheme: Boolean, - isFiltered: Boolean + isFiltered: Boolean, + isChecked: Boolean?, ): RecordTypeViewData { - val default = map(recordType, numberOfCards, isDarkTheme) + val default = map( + recordType = recordType, + numberOfCards = numberOfCards, + isDarkTheme = isDarkTheme, + isChecked = isChecked, + ) return if (isFiltered) { default.copy( @@ -114,6 +127,28 @@ class RecordTypeViewDataMapper @Inject constructor( ) } + fun mapGoalCheckmark( + type: RecordType, + goals: Map>, + allDailyCurrents: Map, + ): Boolean? { + val goal = goals[type.id].orEmpty().getDaily() + val goalValue = when (goal?.type) { + is RecordTypeGoal.Type.Duration -> goal.value * 1000 + is RecordTypeGoal.Type.Count -> goal.value + else -> 0 + } + val dailyCurrent = allDailyCurrents[type.id] + val current = when (goal?.type) { + is RecordTypeGoal.Type.Duration -> dailyCurrent?.duration.orZero() + is RecordTypeGoal.Type.Count -> dailyCurrent?.count.orZero() + else -> 0 + } + val valueLeft = goalValue - current + + return if (goal != null) valueLeft <= 0L else null + } + private fun mapToSpecial( type: RunningRecordTypeSpecialViewData.Type, @StringRes name: Int, @@ -132,7 +167,8 @@ class RecordTypeViewDataMapper @Inject constructor( ) } - @ColorInt private fun mapColor(color: AppColor, isDarkTheme: Boolean): Int { + @ColorInt + private fun mapColor(color: AppColor, isDarkTheme: Boolean): Int { return colorMapper.mapToColorInt(color, isDarkTheme) } } \ No newline at end of file diff --git a/features/feature_archive/src/main/java/com/example/util/simpletimetracker/feature_archive/interactor/ArchiveViewDataInteractor.kt b/features/feature_archive/src/main/java/com/example/util/simpletimetracker/feature_archive/interactor/ArchiveViewDataInteractor.kt index 3dd72478d..7a678dd77 100644 --- a/features/feature_archive/src/main/java/com/example/util/simpletimetracker/feature_archive/interactor/ArchiveViewDataInteractor.kt +++ b/features/feature_archive/src/main/java/com/example/util/simpletimetracker/feature_archive/interactor/ArchiveViewDataInteractor.kt @@ -38,7 +38,8 @@ class ArchiveViewDataInteractor @Inject constructor( recordType = type, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, - isFiltered = false + isFiltered = false, + isChecked = null, ) } diff --git a/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeAdapterDelegate.kt b/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeAdapterDelegate.kt index 8226e6387..00ee4eba0 100644 --- a/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeAdapterDelegate.kt +++ b/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeAdapterDelegate.kt @@ -1,6 +1,7 @@ package com.example.util.simpletimetracker.feature_base_adapter.recordType import androidx.core.view.ViewCompat +import com.example.util.simpletimetracker.domain.extension.orFalse import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBindingAdapterDelegate import com.example.util.simpletimetracker.feature_views.TransitionNames import com.example.util.simpletimetracker.feature_views.extension.dpToPx @@ -32,6 +33,8 @@ fun createRecordTypeAdapterDelegate( itemIconColor = item.iconColor itemIconAlpha = item.iconAlpha itemName = item.name + itemWithCheck = item.isChecked != null + itemIsChecked = item.isChecked.orFalse() onItemClick?.let { setOnClickWith(item, it) } onItemLongClick?.let { setOnLongClick { it(item, mapOf(this to transitionName)) } } if (withTransition) ViewCompat.setTransitionName(this, transitionName) diff --git a/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeViewData.kt b/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeViewData.kt index e5e9c4903..de42ff700 100644 --- a/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeViewData.kt +++ b/features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/recordType/RecordTypeViewData.kt @@ -13,7 +13,8 @@ data class RecordTypeViewData( @ColorInt val color: Int, val width: Int? = null, val height: Int? = null, - val asRow: Boolean = false + val asRow: Boolean = false, + val isChecked: Boolean? = null, ) : ViewHolderType { override fun getUniqueId(): Long = id diff --git a/features/feature_change_activity_filter/src/main/java/com/example/util/simpletimetracker/feature_change_activity_filter/interactor/ChangeActivityFilterViewDataInteractor.kt b/features/feature_change_activity_filter/src/main/java/com/example/util/simpletimetracker/feature_change_activity_filter/interactor/ChangeActivityFilterViewDataInteractor.kt index 44491fb85..556efc5aa 100644 --- a/features/feature_change_activity_filter/src/main/java/com/example/util/simpletimetracker/feature_change_activity_filter/interactor/ChangeActivityFilterViewDataInteractor.kt +++ b/features/feature_change_activity_filter/src/main/java/com/example/util/simpletimetracker/feature_change_activity_filter/interactor/ChangeActivityFilterViewDataInteractor.kt @@ -37,7 +37,8 @@ class ChangeActivityFilterViewDataInteractor @Inject constructor( it.id to recordTypeViewDataMapper.map( recordType = it, numberOfCards = numberOfCards, - isDarkTheme = isDarkTheme + isDarkTheme = isDarkTheme, + isChecked = null, ) } } diff --git a/features/feature_change_category/src/main/java/com/example/util/simpletimetracker/feature_change_category/interactor/ChangeCategoryViewDataInteractor.kt b/features/feature_change_category/src/main/java/com/example/util/simpletimetracker/feature_change_category/interactor/ChangeCategoryViewDataInteractor.kt index ee28f3d47..dbcedf9d1 100644 --- a/features/feature_change_category/src/main/java/com/example/util/simpletimetracker/feature_change_category/interactor/ChangeCategoryViewDataInteractor.kt +++ b/features/feature_change_category/src/main/java/com/example/util/simpletimetracker/feature_change_category/interactor/ChangeCategoryViewDataInteractor.kt @@ -39,7 +39,8 @@ class ChangeCategoryViewDataInteractor @Inject constructor( recordTypeViewDataMapper.map( recordType = it, numberOfCards = numberOfCards, - isDarkTheme = isDarkTheme + isDarkTheme = isDarkTheme, + isChecked = null, ) }.let(viewData::addAll) @@ -51,7 +52,8 @@ class ChangeCategoryViewDataInteractor @Inject constructor( recordTypeViewDataMapper.map( recordType = it, numberOfCards = numberOfCards, - isDarkTheme = isDarkTheme + isDarkTheme = isDarkTheme, + isChecked = null, ) }.let(viewData::addAll) diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt index 154e6749c..46d49ebd3 100644 --- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt @@ -45,6 +45,7 @@ class DataEditTypeSelectionViewModel @Inject constructor( recordType = type, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, + isChecked = null, ) } diff --git a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/archive/interactor/ArchiveDialogViewDataInteractor.kt b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/archive/interactor/ArchiveDialogViewDataInteractor.kt index d00a8bced..df19859b0 100644 --- a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/archive/interactor/ArchiveDialogViewDataInteractor.kt +++ b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/archive/interactor/ArchiveDialogViewDataInteractor.kt @@ -34,7 +34,8 @@ class ArchiveDialogViewDataInteractor @Inject constructor( val item = recordTypeViewDataMapper.map( recordType = type, numberOfCards = numberOfCards, - isDarkTheme = isDarkTheme + isDarkTheme = isDarkTheme, + isChecked = null, ) val recordsCount = recordInteractor.getByType(listOf(typeId)).size val recordTagCount = recordTagInteractor.getByType(typeId).size diff --git a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardOrder/viewModel/CardOrderViewModel.kt b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardOrder/viewModel/CardOrderViewModel.kt index 0993029c1..36fa9c2c3 100644 --- a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardOrder/viewModel/CardOrderViewModel.kt +++ b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardOrder/viewModel/CardOrderViewModel.kt @@ -21,7 +21,7 @@ import javax.inject.Inject class CardOrderViewModel @Inject constructor( private val recordTypeInteractor: RecordTypeInteractor, private val prefsInteractor: PrefsInteractor, - private val recordTypeViewDataMapper: RecordTypeViewDataMapper + private val recordTypeViewDataMapper: RecordTypeViewDataMapper, ) : ViewModel() { lateinit var extra: CardOrderDialogParams @@ -58,7 +58,14 @@ class CardOrderViewModel @Inject constructor( return recordTypeInteractor.getAll(extra.initialOrder) .filter { !it.hidden } .takeUnless { it.isEmpty() } - ?.map { type -> recordTypeViewDataMapper.map(type, numberOfCards, isDarkTheme) } + ?.map { type -> + recordTypeViewDataMapper.map( + recordType = type, + numberOfCards = numberOfCards, + isDarkTheme = isDarkTheme, + isChecked = null, + ) + } ?: recordTypeViewDataMapper.mapToEmpty() } } diff --git a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardSize/mapper/CardSizeViewDataMapper.kt b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardSize/mapper/CardSizeViewDataMapper.kt index 50b08db19..aea951266 100644 --- a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardSize/mapper/CardSizeViewDataMapper.kt +++ b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/cardSize/mapper/CardSizeViewDataMapper.kt @@ -19,7 +19,12 @@ class CardSizeViewDataMapper @Inject constructor( numberOfCards: Int, isDarkTheme: Boolean ): RecordTypeViewData { - return recordTypeViewDataMapper.map(recordType, numberOfCards, isDarkTheme) + return recordTypeViewDataMapper.map( + recordType = recordType, + numberOfCards = numberOfCards, + isDarkTheme = isDarkTheme, + isChecked = null, + ) } fun toToButtonsViewData(numberOfCards: Int): List { diff --git a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/defaultTypesSelection/viewModel/DefaultTypesSelectionViewModel.kt b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/defaultTypesSelection/viewModel/DefaultTypesSelectionViewModel.kt index 95195d725..6cbbf5f62 100644 --- a/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/defaultTypesSelection/viewModel/DefaultTypesSelectionViewModel.kt +++ b/features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/defaultTypesSelection/viewModel/DefaultTypesSelectionViewModel.kt @@ -94,7 +94,8 @@ class DefaultTypesSelectionViewModel @Inject constructor( recordType = recordType, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, - isFiltered = recordType.id in typeIdsFiltered + isFiltered = recordType.id in typeIdsFiltered, + isChecked = null, ) } } diff --git a/features/feature_records_filter/src/main/java/com/example/util/simpletimetracker/feature_records_filter/interactor/RecordsFilterViewDataInteractor.kt b/features/feature_records_filter/src/main/java/com/example/util/simpletimetracker/feature_records_filter/interactor/RecordsFilterViewDataInteractor.kt index cf5e19a8b..e8ab978fb 100644 --- a/features/feature_records_filter/src/main/java/com/example/util/simpletimetracker/feature_records_filter/interactor/RecordsFilterViewDataInteractor.kt +++ b/features/feature_records_filter/src/main/java/com/example/util/simpletimetracker/feature_records_filter/interactor/RecordsFilterViewDataInteractor.kt @@ -307,7 +307,8 @@ class RecordsFilterViewDataInteractor @Inject constructor( recordType = type, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, - isFiltered = type.id !in allSelectedTypeIds + isFiltered = type.id !in allSelectedTypeIds, + isChecked = null, ) } diff --git a/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt b/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt index 34b9f199c..5512a22cc 100644 --- a/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt +++ b/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/interactor/RunningRecordsViewDataInteractor.kt @@ -1,6 +1,7 @@ package com.example.util.simpletimetracker.feature_running_records.interactor import com.example.util.simpletimetracker.core.interactor.ActivityFilterViewDataInteractor +import com.example.util.simpletimetracker.core.interactor.GetCurrentRecordsDurationInteractor import com.example.util.simpletimetracker.core.interactor.GetRunningRecordViewDataMediator import com.example.util.simpletimetracker.core.interactor.RecordRepeatInteractor import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper @@ -28,6 +29,7 @@ class RunningRecordsViewDataInteractor @Inject constructor( private val mapper: RunningRecordsViewDataMapper, private val recordTypeViewDataMapper: RecordTypeViewDataMapper, private val getRunningRecordViewDataMediator: GetRunningRecordViewDataMediator, + private val getCurrentRecordsDurationInteractor: GetCurrentRecordsDurationInteractor, ) { suspend fun getViewData(): List { @@ -44,6 +46,15 @@ class RunningRecordsViewDataInteractor @Inject constructor( val useProportionalMinutes = prefsInteractor.getUseProportionalMinutes() val showFirstEnterHint = recordTypes.filterNot(RecordType::hidden).isEmpty() val showRepeatButton = recordRepeatInteractor.shouldShowButton() + val allDailyCurrents = if (goals.isNotEmpty()) { + getCurrentRecordsDurationInteractor.getAllDailyCurrents( + typesMap = recordTypesMap, + runningRecords = runningRecords, + ) + } else { + // No goals - no need to calculate durations. + emptyMap() + } val runningRecordsViewData = when { showFirstEnterHint -> @@ -91,11 +102,16 @@ class RunningRecordsViewDataInteractor @Inject constructor( activityFilterViewDataInteractor.applyFilter(list, filter) } .map { - mapper.map( + recordTypeViewDataMapper.mapFiltered( recordType = it, isFiltered = it.id in recordTypesRunning, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, + isChecked = recordTypeViewDataMapper.mapGoalCheckmark( + type = it, + goals = goals, + allDailyCurrents = allDailyCurrents, + ), ) } .let { data -> diff --git a/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/mapper/RunningRecordsViewDataMapper.kt b/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/mapper/RunningRecordsViewDataMapper.kt index a4248ebb6..06f113e9a 100644 --- a/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/mapper/RunningRecordsViewDataMapper.kt +++ b/features/feature_running_records/src/main/java/com/example/util/simpletimetracker/feature_running_records/mapper/RunningRecordsViewDataMapper.kt @@ -1,35 +1,17 @@ package com.example.util.simpletimetracker.feature_running_records.mapper -import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper import com.example.util.simpletimetracker.core.repo.ResourceRepo -import com.example.util.simpletimetracker.domain.model.RecordType import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType 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.recordType.RecordTypeViewData import com.example.util.simpletimetracker.feature_running_records.R import javax.inject.Inject class RunningRecordsViewDataMapper @Inject constructor( private val resourceRepo: ResourceRepo, - private val recordTypeViewDataMapper: RecordTypeViewDataMapper, ) { - fun map( - recordType: RecordType, - isFiltered: Boolean, - numberOfCards: Int, - isDarkTheme: Boolean, - ): RecordTypeViewData { - return recordTypeViewDataMapper.mapFiltered( - recordType, - numberOfCards, - isDarkTheme, - isFiltered, - ) - } - fun mapToTypesEmpty(): ViewHolderType { return HintBigViewData( text = resourceRepo.getString( diff --git a/features/feature_views/src/main/java/com/example/util/simpletimetracker/feature_views/RecordTypeView.kt b/features/feature_views/src/main/java/com/example/util/simpletimetracker/feature_views/RecordTypeView.kt index 131c826a4..cd1434734 100644 --- a/features/feature_views/src/main/java/com/example/util/simpletimetracker/feature_views/RecordTypeView.kt +++ b/features/feature_views/src/main/java/com/example/util/simpletimetracker/feature_views/RecordTypeView.kt @@ -8,6 +8,7 @@ import android.view.LayoutInflater import androidx.cardview.widget.CardView import androidx.constraintlayout.widget.ConstraintSet import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import com.example.util.simpletimetracker.feature_views.databinding.RecordTypeViewLayoutBinding import com.example.util.simpletimetracker.feature_views.extension.setMargins import com.example.util.simpletimetracker.feature_views.viewData.RecordTypeIcon @@ -69,6 +70,14 @@ class RecordTypeView @JvmOverloads constructor( itemIsRow = getBoolean(R.styleable.RecordTypeView_itemIsRow, false) } + if (hasValue(R.styleable.RecordTypeView_itemWithCheck)) { + itemWithCheck = getBoolean(R.styleable.RecordTypeView_itemWithCheck, false) + } + + if (hasValue(R.styleable.RecordTypeView_itemIsChecked)) { + itemIsChecked = getBoolean(R.styleable.RecordTypeView_itemIsChecked, false) + } + recycle() } } @@ -110,6 +119,23 @@ class RecordTypeView @JvmOverloads constructor( field = value } + var itemWithCheck: Boolean = false + set(value) { + binding.container.ivRecordTypeItemCheck.isVisible = value + field = value + } + + var itemIsChecked: Boolean = false + set(value) { + val iconResId = if (value) { + R.drawable.spinner_check_mark + } else { + R.drawable.spinner_check_unmarked + } + binding.container.ivRecordTypeItemCheck.setImageResource(iconResId) + field = value + } + private fun changeConstraints(isRow: Boolean) = with(binding.container) { if (isRow) { val setRow = ConstraintSet() diff --git a/features/feature_views/src/main/res/drawable/spinner_check_unmarked.xml b/features/feature_views/src/main/res/drawable/spinner_check_unmarked.xml new file mode 100644 index 000000000..bd79aba57 --- /dev/null +++ b/features/feature_views/src/main/res/drawable/spinner_check_unmarked.xml @@ -0,0 +1,9 @@ + + + diff --git a/features/feature_views/src/main/res/layout/record_type_view_horizontal.xml b/features/feature_views/src/main/res/layout/record_type_view_horizontal.xml index 943920ad1..957f4fc7d 100644 --- a/features/feature_views/src/main/res/layout/record_type_view_horizontal.xml +++ b/features/feature_views/src/main/res/layout/record_type_view_horizontal.xml @@ -59,5 +59,17 @@ app:layout_constraintTop_toTopOf="parent" tools:text="Item very long name" /> + + diff --git a/features/feature_views/src/main/res/layout/record_type_view_layout.xml b/features/feature_views/src/main/res/layout/record_type_view_layout.xml index 4771147a4..3571935a6 100644 --- a/features/feature_views/src/main/res/layout/record_type_view_layout.xml +++ b/features/feature_views/src/main/res/layout/record_type_view_layout.xml @@ -2,8 +2,8 @@ + + diff --git a/features/feature_views/src/main/res/values/attrs.xml b/features/feature_views/src/main/res/values/attrs.xml index 9408f355b..e9ce36ff3 100644 --- a/features/feature_views/src/main/res/values/attrs.xml +++ b/features/feature_views/src/main/res/values/attrs.xml @@ -46,6 +46,8 @@ + + diff --git a/features/feature_widget/src/main/java/com/example/util/simpletimetracker/feature_widget/universal/activity/viewModel/WidgetUniversalViewModel.kt b/features/feature_widget/src/main/java/com/example/util/simpletimetracker/feature_widget/universal/activity/viewModel/WidgetUniversalViewModel.kt index c0777a30b..44540a8b3 100644 --- a/features/feature_widget/src/main/java/com/example/util/simpletimetracker/feature_widget/universal/activity/viewModel/WidgetUniversalViewModel.kt +++ b/features/feature_widget/src/main/java/com/example/util/simpletimetracker/feature_widget/universal/activity/viewModel/WidgetUniversalViewModel.kt @@ -6,14 +6,18 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.util.simpletimetracker.core.extension.set import com.example.util.simpletimetracker.core.interactor.ActivityFilterViewDataInteractor +import com.example.util.simpletimetracker.core.interactor.GetCurrentRecordsDurationInteractor import com.example.util.simpletimetracker.core.interactor.RecordRepeatInteractor import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper import com.example.util.simpletimetracker.domain.interactor.ActivityFilterInteractor import com.example.util.simpletimetracker.domain.interactor.AddRunningRecordMediator import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor +import com.example.util.simpletimetracker.domain.interactor.RecordTypeGoalInteractor import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor import com.example.util.simpletimetracker.domain.interactor.RemoveRunningRecordMediator import com.example.util.simpletimetracker.domain.interactor.RunningRecordInteractor +import com.example.util.simpletimetracker.domain.model.RecordType +import com.example.util.simpletimetracker.domain.model.RecordTypeGoal import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType import com.example.util.simpletimetracker.feature_base_adapter.activityFilter.ActivityFilterViewData import com.example.util.simpletimetracker.feature_base_adapter.divider.DividerViewData @@ -40,6 +44,8 @@ class WidgetUniversalViewModel @Inject constructor( private val widgetUniversalViewDataMapper: WidgetUniversalViewDataMapper, private val recordTypeViewDataMapper: RecordTypeViewDataMapper, private val recordRepeatInteractor: RecordRepeatInteractor, + private val recordTypeGoalInteractor: RecordTypeGoalInteractor, + private val getCurrentRecordsDurationInteractor: GetCurrentRecordsDurationInteractor, ) : ViewModel() { val recordTypes: LiveData> by lazy { @@ -115,9 +121,20 @@ class WidgetUniversalViewModel @Inject constructor( private suspend fun loadRecordTypesViewData(): List { val runningRecords = runningRecordInteractor.getAll() val recordTypes = recordTypeInteractor.getAll() + val recordTypesMap = recordTypes.associateBy(RecordType::id) + val goals = recordTypeGoalInteractor.getAll().groupBy(RecordTypeGoal::typeId) val recordTypesRunning = runningRecords.map { it.id } val numberOfCards = prefsInteractor.getNumberOfCards() val isDarkTheme = prefsInteractor.getDarkMode() + val allDailyCurrents = if (goals.isNotEmpty()) { + getCurrentRecordsDurationInteractor.getAllDailyCurrents( + typesMap = recordTypesMap, + runningRecords = runningRecords, + ) + } else { + // No goals - no need to calculate durations. + emptyMap() + } val filter = activityFilterViewDataInteractor.getFilter() val filtersViewData = activityFilterViewDataInteractor.getFilterViewData( @@ -137,6 +154,11 @@ class WidgetUniversalViewModel @Inject constructor( isFiltered = it.id in recordTypesRunning, numberOfCards = numberOfCards, isDarkTheme = isDarkTheme, + isChecked = recordTypeViewDataMapper.mapGoalCheckmark( + type = it, + goals = goals, + allDailyCurrents = allDailyCurrents, + ), ) } val repeatViewData = recordTypeViewDataMapper.mapToRepeatItem(