Skip to content

Commit 4ccc935

Browse files
committed
account for goal days in statistics detail
1 parent 6943bea commit 4ccc935

File tree

9 files changed

+61
-19
lines changed

9 files changed

+61
-19
lines changed

app/build.gradle.kts

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import com.example.util.simpletimetracker.Base
22
import com.example.util.simpletimetracker.applyAndroidLibrary
3-
import dagger.hilt.android.plugin.util.capitalize
43

54
plugins {
65
alias(libs.plugins.gradleApplication)

app/src/androidTest/java/com/example/util/simpletimetracker/RecordActionsChangeTagTest.kt

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
66
import androidx.test.espresso.matcher.ViewMatchers.withId
77
import androidx.test.espresso.matcher.ViewMatchers.withText
88
import androidx.test.ext.junit.runners.AndroidJUnit4
9-
import com.example.util.simpletimetracker.core.extension.setToStartOfDay
109
import com.example.util.simpletimetracker.utils.BaseUiTest
1110
import com.example.util.simpletimetracker.utils.NavUtils
1211
import com.example.util.simpletimetracker.utils.checkViewDoesNotExist

features/feature_base_adapter/src/main/java/com/example/util/simpletimetracker/feature_base_adapter/runningRecord/RunningRecordAdapterDelegate.kt

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.example.util.simpletimetracker.feature_base_adapter.runningRecord
22

33
import androidx.core.view.ViewCompat
44
import com.example.util.simpletimetracker.domain.extension.orFalse
5-
import com.example.util.simpletimetracker.domain.record.interactor.UpdateRunningRecordFromChangeScreenInteractor.GoalState
65
import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBindingAdapterDelegate
76
import com.example.util.simpletimetracker.feature_base_adapter.runningRecord.GoalTimeViewData.Subtype
87
import com.example.util.simpletimetracker.feature_views.GoalCheckmarkView.CheckState

features/feature_dialogs/src/main/java/com/example/util/simpletimetracker/feature_dialogs/recordQuickActions/interactor/RecordQuickActionsInteractor.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class RecordQuickActionsInteractor @Inject constructor(
3838
newTagIds = getTagsAfterActivityChange(
3939
currentTags = record.tagIds,
4040
newTypeId = newTypeId,
41-
)
41+
),
4242
)
4343
}
4444
is Type.RecordUntracked -> {
@@ -64,7 +64,7 @@ class RecordQuickActionsInteractor @Inject constructor(
6464
newTagIds = getTagsAfterActivityChange(
6565
currentTags = record.tagIds,
6666
newTypeId = newTypeId,
67-
)
67+
),
6868
)
6969
}
7070
}

features/feature_statistics_detail/src/main/java/com/example/util/simpletimetracker/feature_statistics_detail/interactor/StatisticsDetailChartInteractor.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,13 @@ class StatisticsDetailChartInteractor @Inject constructor(
187187
splitSortMode: ChartSplitSortMode,
188188
): List<ChartBarDataDuration> {
189189
fun mapEmpty(): List<ChartBarDataDuration> {
190-
return ranges.map { ChartBarDataDuration(legend = it.legend, durations = listOf(0L to 0)) }
190+
return ranges.map {
191+
ChartBarDataDuration(
192+
rangeStart = it.rangeStart,
193+
legend = it.legend,
194+
durations = listOf(0L to 0),
195+
)
196+
}
191197
}
192198

193199
fun mapRangesToValue(list: List<Range>): Long {
@@ -244,6 +250,7 @@ class StatisticsDetailChartInteractor @Inject constructor(
244250
}
245251

246252
ChartBarDataDuration(
253+
rangeStart = data.rangeStart,
247254
legend = data.legend,
248255
durations = durations,
249256
)

features/feature_statistics_detail/src/main/java/com/example/util/simpletimetracker/feature_statistics_detail/interactor/StatisticsDetailDataDistributionInteractor.kt

+3
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class StatisticsDetailDataDistributionInteractor @Inject constructor(
235235
return when {
236236
statistics.id == UNTRACKED_ITEM_ID -> {
237237
ChartBarDataDuration(
238+
rangeStart = 0, // Not needed.
238239
legend = "",
239240
durations = listOf(
240241
statistics.data.duration to
@@ -244,6 +245,7 @@ class StatisticsDetailDataDistributionInteractor @Inject constructor(
244245
}
245246
statistics.id == UNCATEGORIZED_ITEM_ID -> {
246247
ChartBarDataDuration(
248+
rangeStart = 0,
247249
legend = "",
248250
durations = listOf(
249251
statistics.data.duration to
@@ -253,6 +255,7 @@ class StatisticsDetailDataDistributionInteractor @Inject constructor(
253255
}
254256
dataHolder != null -> {
255257
ChartBarDataDuration(
258+
rangeStart = 0,
256259
legend = "",
257260
durations = listOf(
258261
statistics.data.duration to

features/feature_statistics_detail/src/main/java/com/example/util/simpletimetracker/feature_statistics_detail/interactor/StatisticsDetailGoalsInteractor.kt

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class StatisticsDetailGoalsInteractor @Inject constructor(
121121
useProportionalMinutes = useProportionalMinutes,
122122
showSeconds = showSeconds,
123123
isDarkTheme = isDarkTheme,
124+
startOfDayShift = startOfDayShift,
124125
)
125126

126127
return@withContext StatisticsDetailGoalsCompositeViewData(

features/feature_statistics_detail/src/main/java/com/example/util/simpletimetracker/feature_statistics_detail/mapper/StatisticsDetailViewDataMapper.kt

+41-11
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import com.example.util.simpletimetracker.feature_statistics_detail.viewData.Sta
4646
import com.example.util.simpletimetracker.feature_statistics_detail.viewData.StatisticsDetailPreviewViewData
4747
import com.example.util.simpletimetracker.feature_statistics_detail.viewData.StatisticsDetailSplitGroupingViewData
4848
import com.example.util.simpletimetracker.feature_views.viewData.RecordTypeIcon
49+
import java.util.Calendar
4950
import java.util.concurrent.TimeUnit
5051
import javax.inject.Inject
5152
import kotlin.math.abs
@@ -511,15 +512,15 @@ class StatisticsDetailViewDataMapper @Inject constructor(
511512
}
512513

513514
val average = getAverage(data)
514-
val nonEmptyData = data.filter { it.durations.sumOf { it.first } != 0L }
515+
val nonEmptyData = data.filter { it.totalDuration != 0L }
515516
val averageByNonEmpty = getAverage(nonEmptyData)
516517

517518
val comparisonAverage = getAverage(compareData)
518-
val comparisonNonEmptyData = compareData.filter { it.durations.sumOf { it.first } != 0L }
519+
val comparisonNonEmptyData = compareData.filter { it.totalDuration != 0L }
519520
val comparisonAverageByNonEmpty = getAverage(comparisonNonEmptyData)
520521

521522
val prevAverage = getAverage(prevData)
522-
val prevNonEmptyData = prevData.filter { it.durations.sumOf { it.first } != 0L }
523+
val prevNonEmptyData = prevData.filter { it.totalDuration != 0L }
523524
val prevAverageByNonEmpty = getAverage(prevNonEmptyData)
524525

525526
val title = resourceRepo.getString(
@@ -682,13 +683,17 @@ class StatisticsDetailViewDataMapper @Inject constructor(
682683
)
683684
}
684685

685-
fun mapGoalData(
686+
private fun mapGoalData(
686687
data: List<ChartBarDataDuration>,
687688
goalValue: Long,
688689
goalSubtype: RecordTypeGoal.Subtype,
690+
goalRange: RecordTypeGoal.Range,
691+
goalDaysOfWeek: Set<DayOfWeek>,
689692
isDarkTheme: Boolean,
693+
startOfDayShift: Long,
690694
): List<ChartBarDataDuration> {
691695
if (goalValue == 0L) return emptyList()
696+
val shouldAccountForDays = goalRange is RecordTypeGoal.Range.Daily
692697
val greenColor = resourceRepo.getThemedAttr(R.attr.appPositiveColor, isDarkTheme)
693698
val redColor = resourceRepo.getThemedAttr(R.attr.appNegativeColor, isDarkTheme)
694699
val positiveColor = when (goalSubtype) {
@@ -699,14 +704,30 @@ class StatisticsDetailViewDataMapper @Inject constructor(
699704
is RecordTypeGoal.Subtype.Goal -> redColor
700705
is RecordTypeGoal.Subtype.Limit -> greenColor
701706
}
707+
val calendar = Calendar.getInstance()
708+
val current = System.currentTimeMillis()
702709

703710
return data.map { dataPart ->
704-
val totalDuration = dataPart.durations.sumOf { it.first }
705-
// Show difference from goal value only on days
706-
// when there were records tracked.
707-
val goalDuration = if (totalDuration != 0L) totalDuration - goalValue else 0L
711+
val totalDuration = dataPart.totalDuration
712+
val goalDuration = if (dataPart.rangeStart > current) {
713+
0
714+
} else if (shouldAccountForDays) {
715+
val currentPartDay = timeMapper.getDayOfWeek(
716+
timestamp = dataPart.rangeStart,
717+
calendar = calendar,
718+
startOfDayShift = startOfDayShift,
719+
)
720+
if (currentPartDay in goalDaysOfWeek) {
721+
totalDuration - goalValue
722+
} else {
723+
0
724+
}
725+
} else {
726+
totalDuration - goalValue
727+
}
708728
val color = if (goalDuration >= 0) positiveColor else negativeColor
709729
ChartBarDataDuration(
730+
rangeStart = dataPart.rangeStart,
710731
legend = dataPart.legend,
711732
durations = listOf(goalDuration to color),
712733
)
@@ -772,23 +793,32 @@ class StatisticsDetailViewDataMapper @Inject constructor(
772793
useProportionalMinutes: Boolean,
773794
showSeconds: Boolean,
774795
isDarkTheme: Boolean,
796+
startOfDayShift: Long,
775797
): List<ViewHolderType> {
776798
val goalValue = getGoalValue(chartGoal)
777799
if (goalValue == 0L) return emptyList()
800+
val goalRange = chartGoal?.range ?: return emptyList()
801+
val goalSubtype = chartGoal.subtype
802+
val goalDaysOfWeek = chartGoal.daysOfWeek
778803

779804
val items = mutableListOf<ViewHolderType>()
780-
val goalSubtype = chartGoal?.subtype ?: RecordTypeGoal.Subtype.Goal
781805
val goalData = mapGoalData(
782806
data = data,
783807
goalValue = goalValue,
808+
goalRange = goalRange,
809+
goalDaysOfWeek = goalDaysOfWeek,
784810
goalSubtype = goalSubtype,
785811
isDarkTheme = isDarkTheme,
812+
startOfDayShift = startOfDayShift,
786813
)
787814
val goalChartPrevData = mapGoalData(
788815
data = prevData,
789816
goalValue = goalValue,
817+
goalRange = goalRange,
818+
goalDaysOfWeek = goalDaysOfWeek,
790819
goalSubtype = goalSubtype,
791820
isDarkTheme = isDarkTheme,
821+
startOfDayShift = startOfDayShift,
792822
)
793823
val chartData = mapChartData(
794824
data = goalData,
@@ -886,7 +916,7 @@ class StatisticsDetailViewDataMapper @Inject constructor(
886916
data: List<ChartBarDataDuration>,
887917
): Pair<String, Boolean> {
888918
val isMinutes = data
889-
.maxOfOrNull { barPart -> abs(barPart.durations.sumOf { it.first }) }
919+
.maxOfOrNull { barPart -> abs(barPart.totalDuration) }
890920
.orZero()
891921
.let(TimeUnit.MILLISECONDS::toHours) == 0L
892922

@@ -976,7 +1006,7 @@ class StatisticsDetailViewDataMapper @Inject constructor(
9761006
useProportionalMinutes: Boolean,
9771007
showSeconds: Boolean,
9781008
): List<StatisticsDetailCardInternalViewData> {
979-
val barValues = goalData.map { bar -> bar.durations.sumOf { it.first } }
1009+
val barValues = goalData.map { bar -> bar.totalDuration }
9801010
val negativeValue = barValues.filter { it < 0L }.sum()
9811011
val positiveValue = barValues.filter { it > 0L }.sum()
9821012
val total = negativeValue + positiveValue
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.example.util.simpletimetracker.feature_statistics_detail.model
22

3-
class ChartBarDataDuration(
3+
data class ChartBarDataDuration(
4+
val rangeStart: Long,
45
val legend: String,
56
val durations: List<Pair<Long, Int>>,
6-
)
7+
) {
8+
9+
val totalDuration = durations.sumOf { it.first }
10+
}

0 commit comments

Comments
 (0)