Skip to content

Commit

Permalink
change do show seconds logic handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Apr 28, 2024
1 parent ef5d6f4 commit 6e75b67
Show file tree
Hide file tree
Showing 23 changed files with 224 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand All @@ -502,6 +512,7 @@ class TimeMapper @Inject constructor(
return res
}

@Suppress("unused")
fun formatIntervalAdjusted(
timeStarted: Long,
timeEnded: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
)
Expand All @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<GetFromRangeKey, List<Record>>(10)
private var getFromRangeByTypeCache = LruCache<GetFromRangeByTypeKey, List<Record>>(1)
private var isEmpty: Boolean? = null
private var showSecondsCache: Boolean? = null
private val mutex: Mutex = Mutex()

override suspend fun isEmpty(): Boolean = mutex.withLockedCache(
Expand All @@ -32,47 +36,47 @@ class RecordRepoImpl @Inject constructor(
afterSourceAccess = { isEmpty = it },
)

override suspend fun getAll(): List<Record> = withContext(Dispatchers.IO) {
override suspend fun getAll(adjusted: Boolean): List<Record> = withContext(Dispatchers.IO) {
logDataAccess("getAll")
recordDao.getAll().map(recordDataLocalMapper::map)
recordDao.getAll().map { mapItem(it, adjusted) }
}

override suspend fun getByType(typeIds: List<Long>): List<Record> = withContext(Dispatchers.IO) {
logDataAccess("getByType")
recordDao.getByType(typeIds).map(recordDataLocalMapper::map)
recordDao.getByType(typeIds).map { mapItem(it) }
}

override suspend fun getByTypeWithAnyComment(typeIds: List<Long>): List<Record> = withContext(Dispatchers.IO) {
logDataAccess("getByTypeWithAnyComment")
recordDao.getByTypeWithAnyComment(typeIds).map(recordDataLocalMapper::map)
recordDao.getByTypeWithAnyComment(typeIds).map { mapItem(it) }
}

override suspend fun searchComment(
text: String,
): List<Record> = withContext(Dispatchers.IO) {
logDataAccess("searchComment")
recordDao.searchComment(text).map(recordDataLocalMapper::map)
recordDao.searchComment(text).map { mapItem(it) }
}

override suspend fun searchByTypeWithComment(
typeIds: List<Long>,
text: String,
): List<Record> = withContext(Dispatchers.IO) {
logDataAccess("searchByTypeWithComment")
recordDao.searchByTypeWithComment(typeIds, text).map(recordDataLocalMapper::map)
recordDao.searchByTypeWithComment(typeIds, text).map { mapItem(it) }
}

override suspend fun searchAnyComments(): List<Record> = 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<Record> {
override suspend fun getFromRange(range: Range, adjusted: Boolean): List<Record> {
val cacheKey = GetFromRangeKey(range)
return mutex.withLockedCache(
logMessage = "getFromRange",
Expand All @@ -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) },
)
Expand All @@ -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<Record> =
withContext(Dispatchers.IO) {
logDataAccess("getPrev")
recordDao.getPrev(timeStarted, limit)
.map(recordDataLocalMapper::map)
}
override suspend fun getPrev(
timeStarted: Long,
limit: Long,
adjusted: Boolean,
): List<Record> = 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() },
)
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -19,4 +22,12 @@ fun <T> List<T>?.orEmpty(): List<T> = this ?: emptyList()
fun <T> List<T>.rotateLeft(n: Int): List<T> = drop(n) + take(n)

fun List<RecordTag>.getFullName(): String =
this.joinToString(separator = ", ") { it.name }
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
Expand Down
Loading

0 comments on commit 6e75b67

Please sign in to comment.