Skip to content

Commit ff0e748

Browse files
committed
add duration formats for days and minutes
1 parent ff8c497 commit ff0e748

79 files changed

Lines changed: 754 additions & 273 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withClassName
1010
import androidx.test.espresso.matcher.ViewMatchers.withId
1111
import androidx.test.espresso.matcher.ViewMatchers.withText
1212
import androidx.test.ext.junit.runners.AndroidJUnit4
13+
import com.example.util.simpletimetracker.domain.base.DurationFormat
1314
import com.example.util.simpletimetracker.feature_dialogs.dateTime.CustomDatePicker
1415
import com.example.util.simpletimetracker.feature_dialogs.dateTime.CustomTimePicker
1516
import com.example.util.simpletimetracker.utils.BaseUiTest
@@ -80,7 +81,9 @@ class ChangeRecordTest : BaseUiTest() {
8081
var timeEndedPreview = timeEndedTimestamp
8182
.let { timeMapper.formatTime(time = it, useMilitaryTime = true, showSeconds = false) }
8283
var timeRangePreview = (timeEndedTimestamp - timeStartedTimestamp)
83-
.let { timeMapper.formatInterval(interval = it, forceSeconds = false, useProportionalMinutes = false) }
84+
.let {
85+
timeMapper.formatInterval(interval = it, forceSeconds = false, durationFormat = DurationFormat.HOURS)
86+
}
8487

8588
clickOnViewWithText(coreR.string.change_record_comment_field)
8689
typeTextIntoView(changeRecordR.id.etChangeRecordCommentField, comment)
@@ -173,7 +176,9 @@ class ChangeRecordTest : BaseUiTest() {
173176
timeEndedPreview = timeEndedTimestamp
174177
.let { timeMapper.formatTime(time = it, useMilitaryTime = true, showSeconds = false) }
175178
timeRangePreview = (timeEndedTimestamp - timeStartedTimestamp)
176-
.let { timeMapper.formatInterval(interval = it, forceSeconds = false, useProportionalMinutes = false) }
179+
.let {
180+
timeMapper.formatInterval(interval = it, forceSeconds = false, durationFormat = DurationFormat.HOURS)
181+
}
177182

178183
checkViewIsDisplayed(allOf(withId(changeRecordR.id.tvChangeRecordTimeStartedDate), withText(timeStarted.date)))
179184
checkViewIsDisplayed(allOf(withId(changeRecordR.id.tvChangeRecordTimeStartedTime), withText(timeStarted.time)))

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.example.util.simpletimetracker.core.extension.setWeekToFirstDay
2121
import com.example.util.simpletimetracker.core.interactor.LanguageInteractor
2222
import com.example.util.simpletimetracker.domain.language.AppLanguage
2323
import com.example.util.simpletimetracker.domain.activityFilter.model.ActivityFilter
24+
import com.example.util.simpletimetracker.domain.base.DurationFormat
2425
import com.example.util.simpletimetracker.domain.daysOfWeek.model.DayOfWeek
2526
import com.example.util.simpletimetracker.feature_dialogs.dateTime.CustomDatePicker
2627
import com.example.util.simpletimetracker.feature_dialogs.dateTime.CustomTimePicker
@@ -186,7 +187,7 @@ class SettingsTest : BaseUiTest() {
186187
val duration = timeMapper.formatInterval(
187188
interval = interval,
188189
forceSeconds = true,
189-
useProportionalMinutes = false,
190+
durationFormat = DurationFormat.HOURS,
190191
)
191192
val matcher = allOf(
192193
withId(baseR.id.viewRecordItem),

app/src/androidTest/java/com/example/util/simpletimetracker/utils/BaseUiTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.example.util.simpletimetracker.core.mapper.TimeMapper
2020
import com.example.util.simpletimetracker.core.utils.CountingIdlingResourceProvider
2121
import com.example.util.simpletimetracker.core.utils.TestUtils
2222
import com.example.util.simpletimetracker.domain.backup.repo.BackupRepo
23+
import com.example.util.simpletimetracker.domain.base.DurationFormat
2324
import com.example.util.simpletimetracker.domain.complexRule.repo.ComplexRuleRepo
2425
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
2526
import com.example.util.simpletimetracker.domain.recordType.repo.RecordTypeRepo
@@ -180,7 +181,7 @@ open class BaseUiTest {
180181
}
181182

182183
internal fun Long.formatInterval(): String {
183-
return timeMapper.formatInterval(interval = this, forceSeconds = false, useProportionalMinutes = false)
184+
return timeMapper.formatInterval(interval = this, forceSeconds = false, durationFormat = DurationFormat.HOURS)
184185
}
185186

186187
private fun clearData() {

core/common/src/main/java/com/example/util/simpletimetracker/core/mapper/TimeMapper.kt

Lines changed: 59 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.example.util.simpletimetracker.core.extension.shift
77
import com.example.util.simpletimetracker.core.provider.LocaleProvider
88
import com.example.util.simpletimetracker.core.repo.BaseResourceRepo
99
import com.example.util.simpletimetracker.domain.base.CurrentTimestampProvider
10+
import com.example.util.simpletimetracker.domain.base.DurationFormat
1011
import com.example.util.simpletimetracker.domain.daysOfWeek.model.DayOfWeek
1112
import com.example.util.simpletimetracker.domain.extension.orZero
1213
import com.example.util.simpletimetracker.domain.extension.padDuration
@@ -323,6 +324,8 @@ class TimeMapper @Inject constructor(
323324

324325
/**
325326
* @param interval in seconds.
327+
*
328+
* ex. 1h, 1h 1m, 1h 1m 1s, 1h 1s, 1m 1s, 1s.
326329
*/
327330
fun formatDuration(interval: Long): String {
328331
val hourString = resourceRepo.getString(R.string.time_hour)
@@ -471,101 +474,84 @@ class TimeMapper @Inject constructor(
471474

472475
/**
473476
* @param forceSeconds - true 1h 7m 21s, false 1h 7m
474-
* @param useProportionalMinutes - true 1.25h
477+
* @param durationFormat - PROPORTIONAL_MINUTES 1.25h
478+
*
479+
* ex. 1d 0h 0m, 1h 0m, 1s.
475480
*/
476481
fun formatInterval(
477482
interval: Long,
478483
forceSeconds: Boolean,
479-
useProportionalMinutes: Boolean,
484+
durationFormat: DurationFormat,
480485
): String {
486+
val dayString = resourceRepo.getString(R.string.time_day)
481487
val hourString = resourceRepo.getString(R.string.time_hour)
482488
val minuteString = resourceRepo.getString(R.string.time_minute)
483489
val secondString = resourceRepo.getString(R.string.time_second)
484490

485-
val hr: Long = TimeUnit.MILLISECONDS.toHours(
486-
abs(interval),
487-
)
488-
val min: Long = TimeUnit.MILLISECONDS.toMinutes(
489-
abs(interval) - TimeUnit.HOURS.toMillis(hr),
490-
)
491-
val sec: Long = TimeUnit.MILLISECONDS.toSeconds(
492-
abs(interval) - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min),
493-
)
494-
495-
if (useProportionalMinutes) {
496-
return formatIntervalProportional(interval, hr, min)
491+
var intervalLeft = abs(interval)
492+
val days: Long = if (durationFormat == DurationFormat.DAYS) {
493+
TimeUnit.MILLISECONDS.toDays(intervalLeft)
494+
} else {
495+
0
497496
}
498-
499-
val willShowHours: Boolean
500-
val willShowMinutes: Boolean
501-
val willShowSeconds: Boolean
502-
503-
if (forceSeconds) {
504-
willShowHours = hr != 0L
505-
willShowMinutes = willShowHours || min != 0L
506-
willShowSeconds = true
497+
intervalLeft -= TimeUnit.DAYS.toMillis(days)
498+
val hr: Long = if (durationFormat != DurationFormat.MINUTES) {
499+
TimeUnit.MILLISECONDS.toHours(intervalLeft)
507500
} else {
508-
willShowHours = hr != 0L
509-
willShowMinutes = true
510-
willShowSeconds = false
501+
0
511502
}
503+
intervalLeft -= TimeUnit.HOURS.toMillis(hr)
504+
val min: Long = TimeUnit.MILLISECONDS.toMinutes(intervalLeft)
505+
intervalLeft -= TimeUnit.MINUTES.toMillis(min)
506+
val sec: Long = TimeUnit.MILLISECONDS.toSeconds(intervalLeft)
507+
508+
val result = when (durationFormat) {
509+
DurationFormat.PROPORTIONAL_MINUTES -> {
510+
formatIntervalProportional(hr, min)
511+
}
512+
else -> {
513+
val willShowDays = durationFormat == DurationFormat.DAYS && days != 0L
514+
val willShowHours = willShowDays || hr != 0L
515+
516+
val willShowMinutes: Boolean
517+
val willShowSeconds: Boolean
518+
519+
if (forceSeconds) {
520+
willShowMinutes = willShowHours || min != 0L
521+
willShowSeconds = true
522+
} else {
523+
willShowMinutes = true
524+
willShowSeconds = false
525+
}
512526

513-
var res = ""
514-
if (willShowHours) res += "$hr$hourString "
515-
if (willShowMinutes) res += "$min$minuteString"
516-
if (willShowMinutes && willShowSeconds) res += " "
517-
if (willShowSeconds) res += "$sec$secondString"
518-
519-
res = if (interval < 0) "-$res" else res
520-
521-
return res
522-
}
523-
524-
@Suppress("unused")
525-
fun formatIntervalAdjusted(
526-
timeStarted: Long,
527-
timeEnded: Long,
528-
showSeconds: Boolean,
529-
useProportionalMinutes: Boolean,
530-
): String {
531-
val duration = timeEnded - timeStarted
532-
val interval = formatInterval(
533-
interval = duration,
534-
forceSeconds = showSeconds,
535-
useProportionalMinutes = useProportionalMinutes,
536-
)
537-
538-
return if (
539-
showSeconds ||
540-
useProportionalMinutes ||
541-
duration < MINUTES_IN_MILLIS
542-
) {
543-
interval
544-
} else {
545-
val adjustedTimeStarted = timeStarted / MINUTES_IN_MILLIS * MINUTES_IN_MILLIS
546-
val adjustedTimeEnded = timeEnded / MINUTES_IN_MILLIS * MINUTES_IN_MILLIS
547-
val adjustedInterval = formatInterval(
548-
interval = adjustedTimeEnded - adjustedTimeStarted,
549-
forceSeconds = false,
550-
useProportionalMinutes = false,
551-
)
552-
if (adjustedInterval != interval) {
553-
"~$adjustedInterval"
554-
} else {
555-
interval
527+
var res = ""
528+
if (willShowDays) res += "$days$dayString"
529+
if (willShowHours) {
530+
if (res.isNotEmpty()) res += " "
531+
res += "$hr$hourString"
532+
}
533+
if (willShowMinutes) {
534+
if (res.isNotEmpty()) res += " "
535+
res += "$min$minuteString"
536+
}
537+
if (willShowSeconds) {
538+
if (res.isNotEmpty()) res += " "
539+
res += "$sec$secondString"
540+
}
541+
res
556542
}
557543
}
544+
545+
return if (interval < 0) "-$result" else result
558546
}
559547

560-
private fun formatIntervalProportional(interval: Long, hr: Long, min: Long): String {
548+
private fun formatIntervalProportional(hr: Long, min: Long): String {
561549
val hourString = resourceRepo.getString(R.string.time_hour)
562550
val minutesProportion = min / 60f
563551
val proportional = hr + minutesProportion
564552
val proportionalString = "%.2f".format(proportional)
565553

566-
val res = "$proportionalString$hourString"
567-
568-
return if (interval < 0) "-$res" else res
554+
return "$proportionalString$hourString"
569555
}
570556

571557
fun toDayDateTitle(

core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetChangeRecordNavigationParamsInteractor.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.example.util.simpletimetracker.core.interactor
33
import com.example.util.simpletimetracker.core.extension.toParams
44
import com.example.util.simpletimetracker.core.extension.toRecordParams
55
import com.example.util.simpletimetracker.core.mapper.ChangeRecordDateTimeMapper
6+
import com.example.util.simpletimetracker.domain.base.DurationFormat
67
import com.example.util.simpletimetracker.feature_base_adapter.record.RecordViewData
78
import com.example.util.simpletimetracker.feature_base_adapter.runningRecord.RunningRecordViewData
89
import com.example.util.simpletimetracker.navigation.params.screen.ChangeRecordParams
@@ -19,6 +20,7 @@ class GetChangeRecordNavigationParamsInteractor @Inject constructor(
1920
shift: Int,
2021
useMilitaryTimeFormat: Boolean,
2122
showSeconds: Boolean,
23+
durationFormat: DurationFormat,
2224
sharedElements: Pair<Any, String>?,
2325
): ChangeRecordParams {
2426
val preview = ChangeRecordParams.Preview(
@@ -31,12 +33,14 @@ class GetChangeRecordNavigationParamsInteractor @Inject constructor(
3133
field = ChangeRecordDateTimeMapper.Field.Start,
3234
useMilitaryTimeFormat = useMilitaryTimeFormat,
3335
showSeconds = showSeconds,
36+
durationFormat = durationFormat,
3437
).toRecordParams(),
3538
timeEndedDateTime = changeRecordDateTimeMapper.map(
3639
param = ChangeRecordDateTimeMapper.Param.DateTime(item.timeEndedTimestamp),
3740
field = ChangeRecordDateTimeMapper.Field.End,
3841
useMilitaryTimeFormat = useMilitaryTimeFormat,
3942
showSeconds = showSeconds,
43+
durationFormat = durationFormat,
4044
).toRecordParams(),
4145
duration = item.duration,
4246
iconId = item.iconId.toParams(),
@@ -67,6 +71,7 @@ class GetChangeRecordNavigationParamsInteractor @Inject constructor(
6771
from: ChangeRunningRecordParams.From,
6872
useMilitaryTimeFormat: Boolean,
6973
showSeconds: Boolean,
74+
durationFormat: DurationFormat,
7075
sharedElements: Pair<Any, String>?,
7176
): ChangeRunningRecordParams {
7277
val preview = ChangeRunningRecordParams.Preview(
@@ -78,6 +83,7 @@ class GetChangeRecordNavigationParamsInteractor @Inject constructor(
7883
field = ChangeRecordDateTimeMapper.Field.Start,
7984
useMilitaryTimeFormat = useMilitaryTimeFormat,
8085
showSeconds = showSeconds,
86+
durationFormat = durationFormat,
8187
).toRecordParams(),
8288
duration = item.timer,
8389
durationTotal = item.timerTotal,

core/src/main/java/com/example/util/simpletimetracker/core/interactor/GetRunningRecordViewDataMediator.kt

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

33
import com.example.util.simpletimetracker.core.mapper.RunningRecordViewDataMapper
4+
import com.example.util.simpletimetracker.domain.base.DurationFormat
45
import com.example.util.simpletimetracker.domain.recordType.extension.getDaily
56
import com.example.util.simpletimetracker.domain.recordTag.model.RecordTag
67
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
@@ -24,7 +25,7 @@ class GetRunningRecordViewDataMediator @Inject constructor(
2425
totalDurationVisible: Boolean,
2526
isDarkTheme: Boolean,
2627
useMilitaryTime: Boolean,
27-
useProportionalMinutes: Boolean,
28+
durationFormat: DurationFormat,
2829
showSeconds: Boolean,
2930
): RunningRecordViewData {
3031
val dailyCurrent = if ((goals.getDaily() != null && goalsVisible) || totalDurationVisible) {
@@ -42,7 +43,7 @@ class GetRunningRecordViewDataMediator @Inject constructor(
4243
isDarkTheme = isDarkTheme,
4344
useMilitaryTime = useMilitaryTime,
4445
showSeconds = showSeconds,
45-
useProportionalMinutes = useProportionalMinutes,
46+
durationFormat = durationFormat,
4647
nowIconVisible = nowIconVisible,
4748
goalsVisible = goalsVisible,
4849
totalDurationVisible = totalDurationVisible,

core/src/main/java/com/example/util/simpletimetracker/core/interactor/StatisticsMediator.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.example.util.simpletimetracker.core.interactor
33
import com.example.util.simpletimetracker.core.mapper.RecordTagViewDataMapper
44
import com.example.util.simpletimetracker.core.mapper.TimeMapper
55
import com.example.util.simpletimetracker.core.viewData.StatisticsDataHolder
6+
import com.example.util.simpletimetracker.domain.base.DurationFormat
67
import com.example.util.simpletimetracker.domain.base.UNCATEGORIZED_ITEM_ID
78
import com.example.util.simpletimetracker.domain.base.UNTRACKED_ITEM_ID
89
import com.example.util.simpletimetracker.domain.category.interactor.CategoryInteractor
@@ -85,7 +86,7 @@ class StatisticsMediator @Inject constructor(
8586
fun getStatisticsTotalTracked(
8687
statistics: List<Statistics>,
8788
filteredIds: List<Long>,
88-
useProportionalMinutes: Boolean,
89+
durationFormat: DurationFormat,
8990
showSeconds: Boolean,
9091
): String {
9192
val statisticsFiltered = statistics
@@ -94,7 +95,7 @@ class StatisticsMediator @Inject constructor(
9495
return timeMapper.formatInterval(
9596
interval = total,
9697
forceSeconds = showSeconds,
97-
useProportionalMinutes = useProportionalMinutes,
98+
durationFormat = durationFormat,
9899
)
99100
}
100101

core/src/main/java/com/example/util/simpletimetracker/core/mapper/ChangeRecordDateTimeMapper.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.example.util.simpletimetracker.core.mapper
33
import com.example.util.simpletimetracker.core.R
44
import com.example.util.simpletimetracker.core.repo.ResourceRepo
55
import com.example.util.simpletimetracker.core.viewData.ChangeRecordDateTimeState
6+
import com.example.util.simpletimetracker.domain.base.DurationFormat
67
import javax.inject.Inject
78

89
class ChangeRecordDateTimeMapper @Inject constructor(
@@ -15,6 +16,7 @@ class ChangeRecordDateTimeMapper @Inject constructor(
1516
field: Field,
1617
useMilitaryTimeFormat: Boolean,
1718
showSeconds: Boolean,
19+
durationFormat: DurationFormat,
1820
): ChangeRecordDateTimeState {
1921
return ChangeRecordDateTimeState(
2022
hint = when (param) {
@@ -39,7 +41,7 @@ class ChangeRecordDateTimeMapper @Inject constructor(
3941
timeMapper.formatInterval(
4042
interval = param.duration,
4143
forceSeconds = showSeconds,
42-
useProportionalMinutes = false,
44+
durationFormat = durationFormat,
4345
),
4446
)
4547
}

0 commit comments

Comments
 (0)