diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordViewDataMapper.kt b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordViewDataMapper.kt index 7b54454bd..7df8a73bc 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordViewDataMapper.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/RecordViewDataMapper.kt @@ -46,10 +46,9 @@ class RecordViewDataMapper @Inject constructor( useMilitaryTime = useMilitaryTime, showSeconds = showSeconds, ), - duration = timeMapper.formatIntervalAdjusted( - timeStarted = record.timeStarted, - timeEnded = record.timeEnded, - showSeconds = showSeconds, + duration = timeMapper.formatInterval( + interval = record.duration, + forceSeconds = showSeconds, useProportionalMinutes = useProportionalMinutes, ), iconId = iconMapper.mapIcon(recordType.icon), @@ -83,10 +82,9 @@ class RecordViewDataMapper @Inject constructor( showSeconds = showSeconds, ), timeEndedTimestamp = timeEnded, - duration = timeMapper.formatIntervalAdjusted( - timeStarted = timeStarted, - timeEnded = timeEnded, - showSeconds = showSeconds, + duration = timeMapper.formatInterval( + interval = timeEnded - timeStarted, + forceSeconds = showSeconds, useProportionalMinutes = useProportionalMinutes, ), iconId = RecordTypeIcon.Image(R.drawable.unknown), diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/TimeMapper.kt b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/TimeMapper.kt index 2fff6b056..b57eef589 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/mapper/TimeMapper.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/mapper/TimeMapper.kt @@ -489,9 +489,19 @@ class TimeMapper @Inject constructor( return formatIntervalProportional(hr, min) } - val willShowHours = hr != 0L - val willShowMinutes = willShowHours || min != 0L - val willShowSeconds = (!willShowHours && !willShowMinutes) || forceSeconds + val willShowHours: Boolean + val willShowMinutes: Boolean + val willShowSeconds: Boolean + + if (forceSeconds) { + willShowHours = hr != 0L + willShowMinutes = willShowHours || min != 0L + willShowSeconds = true + } else { + willShowHours = hr != 0L + willShowMinutes = true + willShowSeconds = false + } var res = "" if (willShowHours) res += "$hr$hourString " @@ -502,6 +512,7 @@ class TimeMapper @Inject constructor( return res } + @Suppress("unused") fun formatIntervalAdjusted( timeStarted: Long, timeEnded: Long, diff --git a/core/src/main/java/com/example/util/simpletimetracker/core/sharedViewModel/RemoveRecordViewModel.kt b/core/src/main/java/com/example/util/simpletimetracker/core/sharedViewModel/RemoveRecordViewModel.kt index 532fbaf4b..37b14e8ca 100644 --- a/core/src/main/java/com/example/util/simpletimetracker/core/sharedViewModel/RemoveRecordViewModel.kt +++ b/core/src/main/java/com/example/util/simpletimetracker/core/sharedViewModel/RemoveRecordViewModel.kt @@ -40,7 +40,7 @@ class RemoveRecordViewModel @Inject constructor( (deleteButtonEnabled as MutableLiveData).value = false viewModelScope.launch { if (recordId != 0L) { - val removedRecord = recordInteractor.get(recordId) + val removedRecord = recordInteractor.get(recordId, adjusted = false) val typeId = removedRecord?.typeId val removedName = typeId ?.let { recordTypeInteractor.get(it) } diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/database/RecordDao.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/database/RecordDao.kt index 06d0f9e70..5a6ddf416 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/database/RecordDao.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/database/RecordDao.kt @@ -62,6 +62,13 @@ interface RecordDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(record: RecordDBO): Long + @Query("UPDATE records SET type_id = :typeId, comment = :comment WHERE id = :recordId") + suspend fun update( + recordId: Long, + typeId: Long, + comment: String, + ) + @Query("DELETE FROM records WHERE id = :id") suspend fun delete(id: Long) diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/mapper/RecordDataLocalMapper.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/mapper/RecordDataLocalMapper.kt index 828b8a0b8..ae16d2d67 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/mapper/RecordDataLocalMapper.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/mapper/RecordDataLocalMapper.kt @@ -2,17 +2,22 @@ package com.example.util.simpletimetracker.data_local.mapper import com.example.util.simpletimetracker.data_local.model.RecordDBO import com.example.util.simpletimetracker.data_local.model.RecordWithRecordTagsDBO +import com.example.util.simpletimetracker.domain.extension.dropMillis +import com.example.util.simpletimetracker.domain.extension.dropSeconds import com.example.util.simpletimetracker.domain.model.Record import javax.inject.Inject class RecordDataLocalMapper @Inject constructor() { - fun map(dbo: RecordWithRecordTagsDBO): Record { + fun map( + dbo: RecordWithRecordTagsDBO, + showSeconds: Boolean, + ): Record { return Record( id = dbo.record.id, typeId = dbo.record.typeId, - timeStarted = dbo.record.timeStarted, - timeEnded = dbo.record.timeEnded, + timeStarted = formatSeconds(dbo.record.timeStarted, showSeconds), + timeEnded = formatSeconds(dbo.record.timeEnded, showSeconds), comment = dbo.record.comment, tagIds = dbo.recordTags.map { it.id }, ) @@ -22,10 +27,18 @@ class RecordDataLocalMapper @Inject constructor() { return RecordDBO( id = domain.id, typeId = domain.typeId, - timeStarted = domain.timeStarted, - timeEnded = domain.timeEnded, + timeStarted = formatMillis(domain.timeStarted), + timeEnded = formatMillis(domain.timeEnded), comment = domain.comment, tagId = 0, ) } + + private fun formatSeconds(time: Long, showSeconds: Boolean): Long { + return if (showSeconds) time else time.dropSeconds() + } + + private fun formatMillis(time: Long): Long { + return time.dropMillis() + } } \ No newline at end of file diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/RecordRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/RecordRepoImpl.kt index eaa2f7482..78e952b19 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/RecordRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/RecordRepoImpl.kt @@ -3,8 +3,10 @@ package com.example.util.simpletimetracker.data_local.repo import androidx.collection.LruCache import com.example.util.simpletimetracker.data_local.database.RecordDao import com.example.util.simpletimetracker.data_local.mapper.RecordDataLocalMapper +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.interactor.PrefsInteractor import com.example.util.simpletimetracker.domain.model.Range import com.example.util.simpletimetracker.domain.model.Record import com.example.util.simpletimetracker.domain.repo.RecordRepo @@ -18,11 +20,13 @@ import javax.inject.Singleton class RecordRepoImpl @Inject constructor( private val recordDao: RecordDao, private val recordDataLocalMapper: RecordDataLocalMapper, + private val prefsInteractor: PrefsInteractor, ) : RecordRepo { private var getFromRangeCache = LruCache>(10) private var getFromRangeByTypeCache = LruCache>(1) private var isEmpty: Boolean? = null + private var showSecondsCache: Boolean? = null private val mutex: Mutex = Mutex() override suspend fun isEmpty(): Boolean = mutex.withLockedCache( @@ -32,26 +36,26 @@ class RecordRepoImpl @Inject constructor( afterSourceAccess = { isEmpty = it }, ) - override suspend fun getAll(): List = withContext(Dispatchers.IO) { + override suspend fun getAll(adjusted: Boolean): List = withContext(Dispatchers.IO) { logDataAccess("getAll") - recordDao.getAll().map(recordDataLocalMapper::map) + recordDao.getAll().map { mapItem(it, adjusted) } } override suspend fun getByType(typeIds: List): List = withContext(Dispatchers.IO) { logDataAccess("getByType") - recordDao.getByType(typeIds).map(recordDataLocalMapper::map) + recordDao.getByType(typeIds).map { mapItem(it) } } override suspend fun getByTypeWithAnyComment(typeIds: List): List = withContext(Dispatchers.IO) { logDataAccess("getByTypeWithAnyComment") - recordDao.getByTypeWithAnyComment(typeIds).map(recordDataLocalMapper::map) + recordDao.getByTypeWithAnyComment(typeIds).map { mapItem(it) } } override suspend fun searchComment( text: String, ): List = withContext(Dispatchers.IO) { logDataAccess("searchComment") - recordDao.searchComment(text).map(recordDataLocalMapper::map) + recordDao.searchComment(text).map { mapItem(it) } } override suspend fun searchByTypeWithComment( @@ -59,20 +63,20 @@ class RecordRepoImpl @Inject constructor( text: String, ): List = withContext(Dispatchers.IO) { logDataAccess("searchByTypeWithComment") - recordDao.searchByTypeWithComment(typeIds, text).map(recordDataLocalMapper::map) + recordDao.searchByTypeWithComment(typeIds, text).map { mapItem(it) } } override suspend fun searchAnyComments(): List = withContext(Dispatchers.IO) { logDataAccess("searchAnyComments") - recordDao.searchAnyComments().map(recordDataLocalMapper::map) + recordDao.searchAnyComments().map { mapItem(it) } } - override suspend fun get(id: Long): Record? = withContext(Dispatchers.IO) { + override suspend fun get(id: Long, adjusted: Boolean): Record? = withContext(Dispatchers.IO) { logDataAccess("get") - recordDao.get(id)?.let(recordDataLocalMapper::map) + recordDao.get(id)?.let { mapItem(it, adjusted) } } - override suspend fun getFromRange(range: Range): List { + override suspend fun getFromRange(range: Range, adjusted: Boolean): List { val cacheKey = GetFromRangeKey(range) return mutex.withLockedCache( logMessage = "getFromRange", @@ -81,7 +85,7 @@ class RecordRepoImpl @Inject constructor( recordDao.getFromRange( start = range.timeStarted, end = range.timeEnded, - ).map(recordDataLocalMapper::map) + ).map { mapItem(it, adjusted) } }, afterSourceAccess = { getFromRangeCache.put(cacheKey, it) }, ) @@ -97,35 +101,49 @@ class RecordRepoImpl @Inject constructor( typesIds = typeIds, start = range.timeStarted, end = range.timeEnded, - ).map(recordDataLocalMapper::map) + ).map { mapItem(it) } }, afterSourceAccess = { getFromRangeByTypeCache.put(cacheKey, it) }, ) } - override suspend fun getPrev(timeStarted: Long, limit: Long): List = - withContext(Dispatchers.IO) { - logDataAccess("getPrev") - recordDao.getPrev(timeStarted, limit) - .map(recordDataLocalMapper::map) - } + override suspend fun getPrev( + timeStarted: Long, + limit: Long, + adjusted: Boolean, + ): List = withContext(Dispatchers.IO) { + logDataAccess("getPrev") + recordDao.getPrev(timeStarted, limit).map { mapItem(it, adjusted) } + } - override suspend fun getNext(timeEnded: Long): Record? = - withContext(Dispatchers.IO) { - logDataAccess("getNext") - recordDao.getNext(timeEnded) - ?.let(recordDataLocalMapper::map) - } + override suspend fun getNext( + timeEnded: Long, + adjusted: Boolean, + ): Record? = withContext(Dispatchers.IO) { + logDataAccess("getNext") + recordDao.getNext(timeEnded)?.let { mapItem(it, adjusted) } + } override suspend fun add(record: Record): Long = mutex.withLockedCache( logMessage = "add", accessSource = { - // Drop milliseconds. - val adjustedRecord = record.copy( - timeStarted = record.timeStarted / 1000 * 1000, - timeEnded = record.timeEnded / 1000 * 1000, + recordDao.insert(record.let(recordDataLocalMapper::map)) + }, + afterSourceAccess = { clearCache() }, + ) + + override suspend fun update( + recordId: Long, + typeId: Long, + comment: String, + ) = mutex.withLockedCache( + logMessage = "update", + accessSource = { + recordDao.update( + recordId = recordId, + typeId = typeId, + comment = comment, ) - recordDao.insert(adjustedRecord.let(recordDataLocalMapper::map)) }, afterSourceAccess = { clearCache() }, ) @@ -148,10 +166,25 @@ class RecordRepoImpl @Inject constructor( afterSourceAccess = { clearCache() }, ) - private fun clearCache() { + override fun clearCache() { getFromRangeCache.evictAll() getFromRangeByTypeCache.evictAll() isEmpty = null + showSecondsCache = null + } + + private suspend fun mapItem( + dbo: RecordWithRecordTagsDBO, + adjusted: Boolean = true, + ): Record { + val showSeconds = if (adjusted) { + showSecondsCache ?: prefsInteractor.getShowSeconds() + .also { showSecondsCache = it } + } else { + true + } + + return recordDataLocalMapper.map(dbo, showSeconds) } private data class GetFromRangeByTypeKey( diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt index c6a4d462c..e73a6f32c 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt @@ -91,7 +91,7 @@ class BackupRepoImpl @Inject constructor( it.let(::toBackupString).toByteArray(), ) } - recordRepo.getAll().forEach { + recordRepo.getAll(adjusted = false).forEach { fileOutputStream?.write( it.let(::toBackupString).toByteArray(), ) diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/CsvRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/CsvRepoImpl.kt index 099a758d5..d1c4b1973 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/CsvRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/CsvRepoImpl.kt @@ -68,9 +68,9 @@ class CsvRepoImpl @Inject constructor( // Write data val records = if (range != null) { - recordRepo.getFromRange(range) + recordRepo.getFromRange(range, adjusted = false) } else { - recordRepo.getAll() + recordRepo.getAll(adjusted = false) } records .sortedBy { it.timeStarted } diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/IcsRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/IcsRepoImpl.kt index 1537771ff..c88cce61a 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/IcsRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/IcsRepoImpl.kt @@ -73,9 +73,9 @@ class IcsRepoImpl @Inject constructor( // Write data val records = if (range != null) { - recordRepo.getFromRange(range) + recordRepo.getFromRange(range, adjusted = false) } else { - recordRepo.getAll() + recordRepo.getAll(adjusted = false) } records .sortedBy { it.timeStarted } diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/extension/DomainExtensions.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/extension/DomainExtensions.kt index 5d46f93e5..6b196c751 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/extension/DomainExtensions.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/extension/DomainExtensions.kt @@ -2,6 +2,9 @@ package com.example.util.simpletimetracker.domain.extension import com.example.util.simpletimetracker.domain.model.RecordTag +private const val MINUTE_IN_MILLIS = 60_000 +private const val SECOND_IN_MILLIS = 1_000 + fun Boolean?.orFalse(): Boolean = this ?: false fun Boolean?.orTrue(): Boolean = this ?: true @@ -19,4 +22,12 @@ fun List?.orEmpty(): List = this ?: emptyList() fun List.rotateLeft(n: Int): List = drop(n) + take(n) fun List.getFullName(): String = - this.joinToString(separator = ", ") { it.name } \ No newline at end of file + this.joinToString(separator = ", ") { it.name } + +fun Long.dropSeconds(): Long { + return this / MINUTE_IN_MILLIS * MINUTE_IN_MILLIS +} + +fun Long.dropMillis(): Long { + return this / SECOND_IN_MILLIS * SECOND_IN_MILLIS +} \ No newline at end of file diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/AddRecordMediator.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/AddRecordMediator.kt index 4d04aa2d5..64cb66665 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/AddRecordMediator.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/AddRecordMediator.kt @@ -11,6 +11,7 @@ class AddRecordMediator @Inject constructor( private val widgetInteractor: WidgetInteractor, ) { + // Use unadjusted records to avoid time without seconds overriding time with seconds. suspend fun add( record: Record, ) { diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RecordInteractor.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RecordInteractor.kt index 164f2b3c7..76b8d6901 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RecordInteractor.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RecordInteractor.kt @@ -2,6 +2,7 @@ package com.example.util.simpletimetracker.domain.interactor import com.example.util.simpletimetracker.domain.model.Range import com.example.util.simpletimetracker.domain.model.Record +import com.example.util.simpletimetracker.domain.model.RunningRecord import com.example.util.simpletimetracker.domain.repo.RecordRepo import com.example.util.simpletimetracker.domain.repo.RecordToRecordTagRepo import javax.inject.Inject @@ -16,7 +17,7 @@ class RecordInteractor @Inject constructor( } suspend fun getAll(): List { - return recordRepo.getAll() + return recordRepo.getAll(adjusted = true) } suspend fun getByType(typeIds: List): List { @@ -39,38 +40,43 @@ class RecordInteractor @Inject constructor( return recordRepo.searchAnyComments() } - suspend fun get(id: Long): Record? { - return recordRepo.get(id) + suspend fun get(id: Long, adjusted: Boolean = true): Record? { + return recordRepo.get(id, adjusted) } - suspend fun getPrev(timeStarted: Long, limit: Long): List { - return recordRepo.getPrev(timeStarted, limit) + suspend fun getPrev( + timeStarted: Long, + limit: Long = 1, + adjusted: Boolean = true, + ): List { + return recordRepo.getPrev( + timeStarted = timeStarted, + limit = limit, + adjusted = adjusted, + ) } - suspend fun getNext(timeEnded: Long): Record? { - return recordRepo.getNext(timeEnded) + suspend fun getNext(timeEnded: Long, adjusted: Boolean = true): Record? { + return recordRepo.getNext(timeEnded, adjusted) } - suspend fun getFromRange(range: Range): List { - return recordRepo.getFromRange(range) + suspend fun getFromRange(range: Range, adjusted: Boolean = true): List { + return recordRepo.getFromRange(range, adjusted) } suspend fun getFromRangeByType(typeIds: List, range: Range): List { return recordRepo.getFromRangeByType(typeIds, range) } - suspend fun add( - typeId: Long, - timeStarted: Long, - comment: String, - tagIds: List, + suspend fun addFromRunning( + runningRecord: RunningRecord, ) { Record( - typeId = typeId, - timeStarted = timeStarted, + typeId = runningRecord.id, + timeStarted = runningRecord.timeStarted, timeEnded = System.currentTimeMillis(), - comment = comment, - tagIds = tagIds, + comment = runningRecord.comment, + tagIds = runningRecord.tagIds, ).let { add(it) } @@ -78,12 +84,37 @@ class RecordInteractor @Inject constructor( suspend fun add(record: Record) { val recordId = recordRepo.add(record) - recordToRecordTagRepo.removeAllByRecordId(recordId) - recordToRecordTagRepo.addRecordTags(recordId, record.tagIds) + updateTags(recordId, record.tagIds) + } + + suspend fun update( + recordId: Long, + typeId: Long, + comment: String, + tagIds: List, + ) { + recordRepo.update( + recordId = recordId, + typeId = typeId, + comment = comment, + ) + updateTags(recordId, tagIds) } suspend fun remove(id: Long) { recordToRecordTagRepo.removeAllByRecordId(id) recordRepo.remove(id) } + + fun clearCache() { + recordRepo.clearCache() + } + + private suspend fun updateTags( + recordId: Long, + tagIds: List, + ) { + recordToRecordTagRepo.removeAllByRecordId(recordId) + recordToRecordTagRepo.addRecordTags(recordId, tagIds) + } } \ No newline at end of file diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RemoveRunningRecordMediator.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RemoveRunningRecordMediator.kt index b1bcf14e3..6f7d8a530 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RemoveRunningRecordMediator.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/RemoveRunningRecordMediator.kt @@ -27,12 +27,7 @@ class RemoveRunningRecordMediator @Inject constructor( if (duration > durationToIgnore || durationToIgnore == 0L) { // No need to update widgets and notification because it will be done in running record remove. - recordInteractor.add( - typeId = runningRecord.id, - timeStarted = runningRecord.timeStarted, - comment = runningRecord.comment, - tagIds = runningRecord.tagIds, - ) + recordInteractor.addFromRunning(runningRecord) } activityStartedStoppedBroadcastInteractor.onActivityStopped( typeId = runningRecord.id, diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/mapper/UntrackedRecordMapper.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/mapper/UntrackedRecordMapper.kt index ee521619b..e52181e5b 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/mapper/UntrackedRecordMapper.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/mapper/UntrackedRecordMapper.kt @@ -40,7 +40,7 @@ class UntrackedRecordMapper @Inject constructor( ): Boolean { return if (durationCutoff > 0) { // Filter only untracked records that are longer than a cutoff - duration >= durationCutoff * 1000 + duration > durationCutoff * 1000 } else { true } diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/RecordRepo.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/RecordRepo.kt index b6d0654d8..35c9e96f6 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/RecordRepo.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/RecordRepo.kt @@ -7,7 +7,7 @@ interface RecordRepo { suspend fun isEmpty(): Boolean - suspend fun getAll(): List + suspend fun getAll(adjusted: Boolean): List suspend fun getByType(typeIds: List): List @@ -19,21 +19,33 @@ interface RecordRepo { suspend fun searchAnyComments(): List - suspend fun get(id: Long): Record? + suspend fun get(id: Long, adjusted: Boolean): Record? - suspend fun getFromRange(range: Range): List + suspend fun getFromRange(range: Range, adjusted: Boolean): List suspend fun getFromRangeByType(typeIds: List, range: Range): List - suspend fun getPrev(timeStarted: Long, limit: Long): List + suspend fun getPrev( + timeStarted: Long, + limit: Long, + adjusted: Boolean, + ): List - suspend fun getNext(timeEnded: Long): Record? + suspend fun getNext(timeEnded: Long, adjusted: Boolean): Record? suspend fun add(record: Record): Long + suspend fun update( + recordId: Long, + typeId: Long, + comment: String, + ) + suspend fun remove(id: Long) suspend fun removeByType(typeId: Long) suspend fun clear() + + fun clearCache() } \ No newline at end of file diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/mapper/ChangeRecordViewDataMapper.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/mapper/ChangeRecordViewDataMapper.kt index 84b135b9d..aa9013672 100644 --- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/mapper/ChangeRecordViewDataMapper.kt +++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/mapper/ChangeRecordViewDataMapper.kt @@ -4,6 +4,7 @@ import com.example.util.simpletimetracker.core.mapper.ColorMapper import com.example.util.simpletimetracker.core.mapper.IconMapper import com.example.util.simpletimetracker.core.mapper.TimeMapper import com.example.util.simpletimetracker.core.repo.ResourceRepo +import com.example.util.simpletimetracker.domain.extension.dropSeconds import com.example.util.simpletimetracker.domain.extension.getFullName import com.example.util.simpletimetracker.domain.model.Record import com.example.util.simpletimetracker.domain.model.RecordTag @@ -54,10 +55,13 @@ class ChangeRecordViewDataMapper @Inject constructor( useMilitaryTime = useMilitaryTime, showSeconds = showSeconds, ), - duration = timeMapper.formatIntervalAdjusted( - timeStarted = record.timeStarted, - timeEnded = record.timeEnded, - showSeconds = showSeconds, + duration = timeMapper.formatInterval( + interval = if (showSeconds) { + record.timeEnded - record.timeStarted + } else { + record.timeEnded.dropSeconds() - record.timeStarted.dropSeconds() + }, + forceSeconds = showSeconds, useProportionalMinutes = useProportionalMinutes, ), iconId = recordType?.icon.orEmpty() diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordAdjustDelegate.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordAdjustDelegate.kt index 76837027f..d6e18f361 100644 --- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordAdjustDelegate.kt +++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordAdjustDelegate.kt @@ -262,16 +262,16 @@ class ChangeRecordAdjustDelegateImpl @Inject constructor( adjustNextRecordAvailable: Boolean, ): AdjacentRecords { suspend fun getNext(): Record? { - return recordInteractor.getNext(newTimeEnded) + return recordInteractor.getNext(newTimeEnded, adjusted = false) } val recordRange = Range(timeStarted = newTimeStarted, timeEnded = newTimeEnded) - val adjacentRecords = recordInteractor.getFromRange(recordRange) + val adjacentRecords = recordInteractor.getFromRange(recordRange, adjusted = false) .sortedByDescending { it.timeStarted } val previousRecords = adjacentRecords .filter { it.timeStarted < newTimeStarted && it.timeEnded <= newTimeEnded } - .ifEmpty { recordInteractor.getPrev(newTimeStarted, limit = 1) } + .ifEmpty { recordInteractor.getPrev(newTimeStarted, adjusted = false) } .filter { it.id != recordId } val overlappedRecords = adjacentRecords .filter { it.timeStarted >= newTimeStarted && it.timeEnded <= newTimeEnded } diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt index ec9165808..094593901 100644 --- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt +++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt @@ -634,7 +634,10 @@ abstract class ChangeRecordBaseViewModel( } private suspend fun initializePrevRecord() { - prevRecord = recordInteractor.getPrev(timeStarted = originalTimeStarted, limit = 1).firstOrNull() + prevRecord = recordInteractor.getPrev( + timeStarted = originalTimeStarted, + adjusted = false, + ).firstOrNull() } private suspend fun loadTypesViewData(): List { diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordMergeDelegate.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordMergeDelegate.kt index d40d83d19..ed61b7c90 100644 --- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordMergeDelegate.kt +++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordMergeDelegate.kt @@ -30,7 +30,7 @@ class ChangeRecordMergeDelegateImpl @Inject constructor( newTimeEnded: Long, onMergeComplete: () -> Unit, ) { - // If merge would be available bot only for untracked - add removal of current record + // If merge would be available but only for untracked - add removal of current record prevRecord?.copy( timeEnded = newTimeEnded, )?.let { diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordViewModel.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordViewModel.kt index 3827a346b..7ea099901 100644 --- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordViewModel.kt +++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordViewModel.kt @@ -223,7 +223,7 @@ class ChangeRecordViewModel @Inject constructor( val default = newTimeEnded - ONE_HOUR return if (daysFromToday == 0) { - recordInteractor.getPrev(newTimeEnded, limit = 1) + recordInteractor.getPrev(newTimeEnded, adjusted = false) .firstOrNull() ?.timeEnded ?: default @@ -239,7 +239,7 @@ class ChangeRecordViewModel @Inject constructor( override suspend fun initializePreviewViewData() { when (extra) { is ChangeRecordParams.Tracked -> { - recordInteractor.get((extra as ChangeRecordParams.Tracked).id)?.let { record -> + recordInteractor.get(recordId.orZero(), adjusted = false)?.let { record -> newTypeId = record.typeId.orZero() newTimeStarted = record.timeStarted newTimeEnded = record.timeEnded diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt index f40c4d3d6..d7f0f756f 100644 --- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt @@ -88,14 +88,13 @@ class DateEditChangeInteractor @Inject constructor( oldTypeIds.add(record.typeId) } - // Change activity - record.copy( + // Change record + recordInteractor.update( + recordId = record.id, typeId = finalTypeId, comment = finalComment, tagIds = finalTagIds.toList(), - ).let { - recordInteractor.add(it) - } + ) } if (deleteRecord) { diff --git a/features/feature_notification/src/main/java/com/example/util/simpletimetracker/feature_notification/recordType/interactor/ActivityStartStopFromBroadcastInteractor.kt b/features/feature_notification/src/main/java/com/example/util/simpletimetracker/feature_notification/recordType/interactor/ActivityStartStopFromBroadcastInteractor.kt index 88e09c5dd..e644aee58 100644 --- a/features/feature_notification/src/main/java/com/example/util/simpletimetracker/feature_notification/recordType/interactor/ActivityStartStopFromBroadcastInteractor.kt +++ b/features/feature_notification/src/main/java/com/example/util/simpletimetracker/feature_notification/recordType/interactor/ActivityStartStopFromBroadcastInteractor.kt @@ -80,7 +80,6 @@ class ActivityStartStopFromBroadcastInteractor @Inject constructor( ) { val previousRecord = recordInteractor.getPrev( timeStarted = System.currentTimeMillis(), - limit = 1, ).firstOrNull() ?: return val typeId = previousRecord.typeId val tagId = findTagIdByName(tagName, typeId) diff --git a/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/delegate/SettingsDisplayViewModelDelegate.kt b/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/delegate/SettingsDisplayViewModelDelegate.kt index 94532f1b8..269a4d8bd 100644 --- a/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/delegate/SettingsDisplayViewModelDelegate.kt +++ b/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/delegate/SettingsDisplayViewModelDelegate.kt @@ -7,6 +7,7 @@ import com.example.util.simpletimetracker.core.extension.set import com.example.util.simpletimetracker.domain.extension.flip import com.example.util.simpletimetracker.domain.interactor.NotificationTypeInteractor import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor +import com.example.util.simpletimetracker.domain.interactor.RecordInteractor import com.example.util.simpletimetracker.domain.interactor.WidgetInteractor import com.example.util.simpletimetracker.domain.model.CardOrder import com.example.util.simpletimetracker.domain.model.WidgetTransparencyPercent @@ -29,6 +30,7 @@ class SettingsDisplayViewModelDelegate @Inject constructor( private val notificationTypeInteractor: NotificationTypeInteractor, private val widgetInteractor: WidgetInteractor, private val settingsDisplayViewDataInteractor: SettingsDisplayViewDataInteractor, + private val recordInteractor: RecordInteractor, ) : ViewModelDelegate() { val keepScreenOnCheckbox: LiveData @@ -234,6 +236,9 @@ class SettingsDisplayViewModelDelegate @Inject constructor( delegateScope.launch { val newValue = !prefsInteractor.getShowSeconds() prefsInteractor.setShowSeconds(newValue) + // Force reload from db to trigger seconds drop. + // Main tab updated every second, other tabs updates on visible. + recordInteractor.clearCache() parent?.updateContent() notificationTypeInteractor.updateNotifications() widgetInteractor.updateWidgets(listOf(WidgetType.STATISTICS_CHART))