mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-05 10:49:26 +02:00
Improve time counting with nested categories
This commit is contained in:
parent
192b871ae5
commit
a81bc687fb
9 changed files with 325 additions and 306 deletions
|
@ -69,9 +69,6 @@ abstract class UsedTimeDao {
|
||||||
@Query("SELECT * FROM used_time WHERE category_id = :categoryId ORDER BY day_of_epoch DESC")
|
@Query("SELECT * FROM used_time WHERE category_id = :categoryId ORDER BY day_of_epoch DESC")
|
||||||
abstract fun getUsedTimesByCategoryId(categoryId: String): DataSource.Factory<Int, UsedTimeItem>
|
abstract fun getUsedTimesByCategoryId(categoryId: String): DataSource.Factory<Int, UsedTimeItem>
|
||||||
|
|
||||||
@Query("SELECT * FROM used_time WHERE category_id = :categoryId AND day_of_epoch = :dayOfEpoch")
|
|
||||||
abstract fun getUsedTimesByCategoryIdAndDayOfEpoch(categoryId: String, dayOfEpoch: Int): LiveData<UsedTimeItem?>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM used_time WHERE category_id IN (:categoryIds) AND day_of_epoch >= :startingDayOfEpoch AND day_of_epoch <= :endDayOfEpoch")
|
@Query("SELECT * FROM used_time WHERE category_id IN (:categoryIds) AND day_of_epoch >= :startingDayOfEpoch AND day_of_epoch <= :endDayOfEpoch")
|
||||||
abstract fun getUsedTimesByDayAndCategoryIds(categoryIds: List<String>, startingDayOfEpoch: Int, endDayOfEpoch: Int): LiveData<List<UsedTimeItem>>
|
abstract fun getUsedTimesByDayAndCategoryIds(categoryIds: List<String>, startingDayOfEpoch: Int, endDayOfEpoch: Int): LiveData<List<UsedTimeItem>>
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
private val shouldDoAutomaticSignOut = cache.shouldDoAutomaticSignOut
|
private val shouldDoAutomaticSignOut = cache.shouldDoAutomaticSignOut
|
||||||
private val liveDataCaches = cache.liveDataCaches
|
private val liveDataCaches = cache.liveDataCaches
|
||||||
|
|
||||||
private var usedTimeUpdateHelperForegroundApp: UsedTimeItemBatchUpdateHelper? = null
|
private var usedTimeUpdateHelper: UsedTimeUpdateHelper? = null
|
||||||
private var usedTimeUpdateHelperBackgroundPlayback: UsedTimeItemBatchUpdateHelper? = null
|
|
||||||
private var previousMainLogicExecutionTime = 0
|
private var previousMainLogicExecutionTime = 0
|
||||||
private var previousMainLoopEndTime = 0L
|
private var previousMainLoopEndTime = 0L
|
||||||
private val dayChangeTracker = DayChangeTracker(
|
private val dayChangeTracker = DayChangeTracker(
|
||||||
|
@ -140,8 +139,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
val audioPlaybackHandling = BackgroundTaskRestrictionLogicResult()
|
val audioPlaybackHandling = BackgroundTaskRestrictionLogicResult()
|
||||||
|
|
||||||
private suspend fun commitUsedTimeUpdaters() {
|
private suspend fun commitUsedTimeUpdaters() {
|
||||||
usedTimeUpdateHelperForegroundApp?.commit(appLogic)
|
usedTimeUpdateHelper?.forceCommit(appLogic)
|
||||||
usedTimeUpdateHelperBackgroundPlayback?.commit(appLogic)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun backgroundServiceLoop() {
|
private suspend fun backgroundServiceLoop() {
|
||||||
|
@ -281,84 +279,55 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
result = audioPlaybackHandling
|
result = audioPlaybackHandling
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// update used time helper if date does not match
|
||||||
|
if (usedTimeUpdateHelper?.date != nowDate) {
|
||||||
|
usedTimeUpdateHelper?.forceCommit(appLogic)
|
||||||
|
usedTimeUpdateHelper = UsedTimeUpdateHelper(nowDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
val usedTimeUpdateHelper = usedTimeUpdateHelper!!
|
||||||
|
|
||||||
// check times
|
// check times
|
||||||
fun buildUsedTimesSparseArray(items: SparseArray<UsedTimeItem>, categoryId: String): SparseLongArray {
|
fun buildUsedTimesSparseArray(items: SparseArray<UsedTimeItem>, categoryId: String): SparseLongArray {
|
||||||
val a = usedTimeUpdateHelperForegroundApp
|
|
||||||
val b = usedTimeUpdateHelperBackgroundPlayback
|
|
||||||
|
|
||||||
val result = SparseLongArray()
|
val result = SparseLongArray()
|
||||||
|
|
||||||
for (i in 0..6) {
|
for (i in 0..6) {
|
||||||
val usedTimesItem = items[i]?.usedMillis
|
val usedTimesItem = items[i]?.usedMillis ?: 0
|
||||||
|
val timeToAddButNotCommited = usedTimeUpdateHelper.timeToAdd[categoryId] ?: 0
|
||||||
|
|
||||||
if (a?.date?.dayOfWeek == i && a.childCategoryId == categoryId) {
|
result.put(i, usedTimesItem + timeToAddButNotCommited)
|
||||||
result.put(i, a.getTotalUsedTimeChild())
|
|
||||||
} else if (a?.date?.dayOfWeek == i && a.parentCategoryId == categoryId) {
|
|
||||||
result.put(i, a.getTotalUsedTimeParent())
|
|
||||||
} else if (b?.date?.dayOfWeek == i && b.childCategoryId == categoryId) {
|
|
||||||
result.put(i, b.getTotalUsedTimeChild())
|
|
||||||
} else if (b?.date?.dayOfWeek == i && b.parentCategoryId == categoryId) {
|
|
||||||
result.put(i, b.getTotalUsedTimeParent())
|
|
||||||
} else {
|
|
||||||
result.put(i, usedTimesItem ?: 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCachedExtraTimeToSubstract(categoryId: String): Int {
|
suspend fun getRemainingTime(categoryId: String?): RemainingTime? {
|
||||||
val a = usedTimeUpdateHelperForegroundApp
|
|
||||||
val b = usedTimeUpdateHelperBackgroundPlayback
|
|
||||||
|
|
||||||
if (a?.childCategoryId == categoryId || a?.parentCategoryId == categoryId) {
|
|
||||||
return a.getCachedExtraTimeToSubtract()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b?.childCategoryId == categoryId || b?.parentCategoryId == categoryId) {
|
|
||||||
return b.getCachedExtraTimeToSubtract()
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getRemainingTime(categoryId: String?, parentCategoryId: String?): RemainingTime? {
|
|
||||||
categoryId ?: return null
|
categoryId ?: return null
|
||||||
|
|
||||||
val category = categories.find { it.id == categoryId } ?: return null
|
val category = categories.find { it.id == categoryId } ?: return null
|
||||||
val parentCategory = categories.find { it.id == parentCategoryId }
|
|
||||||
|
|
||||||
val rules = timeLimitRules.get(category.id).waitForNonNullValue()
|
val rules = timeLimitRules.get(category.id).waitForNonNullValue()
|
||||||
val parentRules = parentCategory?.let {
|
|
||||||
timeLimitRules.get(it.id).waitForNonNullValue()
|
if (rules.isEmpty()) {
|
||||||
} ?: emptyList()
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
val usedTimes = usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(category.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
val usedTimes = usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(category.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
||||||
val parentUsedTimes = parentCategory?.let {
|
|
||||||
usedTimesOfCategoryAndWeekByFirstDayOfWeek.get(Pair(it.id, nowDate.dayOfEpoch - nowDate.dayOfWeek)).waitForNonNullValue()
|
|
||||||
} ?: SparseArray()
|
|
||||||
|
|
||||||
val remainingChild = RemainingTime.getRemainingTime(
|
return RemainingTime.getRemainingTime(
|
||||||
nowDate.dayOfWeek,
|
nowDate.dayOfWeek,
|
||||||
buildUsedTimesSparseArray(usedTimes, categoryId),
|
buildUsedTimesSparseArray(usedTimes, categoryId),
|
||||||
rules,
|
rules,
|
||||||
Math.max(0, category.extraTimeInMillis - getCachedExtraTimeToSubstract(category.id))
|
Math.max(0, category.extraTimeInMillis - (usedTimeUpdateHelper.extraTimeToSubtract.get(categoryId) ?: 0))
|
||||||
)
|
)
|
||||||
|
|
||||||
val remainingParent = parentCategory?.let {
|
|
||||||
RemainingTime.getRemainingTime(
|
|
||||||
nowDate.dayOfWeek,
|
|
||||||
buildUsedTimesSparseArray(parentUsedTimes, parentCategory.id),
|
|
||||||
parentRules,
|
|
||||||
Math.max(0, parentCategory.extraTimeInMillis - getCachedExtraTimeToSubstract(parentCategory.id))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return RemainingTime.min(remainingChild, remainingParent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val remainingTimeForegroundApp = getRemainingTime(foregroundAppHandling.categoryId, foregroundAppHandling.parentCategoryId)
|
val remainingTimeForegroundAppChild = getRemainingTime(foregroundAppHandling.categoryId)
|
||||||
val remainingTimeBackgroundApp = getRemainingTime(audioPlaybackHandling.categoryId, audioPlaybackHandling.parentCategoryId)
|
val remainingTimeForegroundAppParent = getRemainingTime(foregroundAppHandling.parentCategoryId)
|
||||||
|
val remainingTimeForegroundApp = RemainingTime.min(remainingTimeForegroundAppChild, remainingTimeForegroundAppParent)
|
||||||
|
|
||||||
|
val remainingTimeBackgroundAppChild = getRemainingTime(audioPlaybackHandling.categoryId)
|
||||||
|
val remainingTimeBackgroundAppParent = getRemainingTime(audioPlaybackHandling.parentCategoryId)
|
||||||
|
val remainingTimeBackgroundApp = RemainingTime.min(remainingTimeBackgroundAppChild, remainingTimeBackgroundAppParent)
|
||||||
|
|
||||||
// eventually block
|
// eventually block
|
||||||
if (remainingTimeForegroundApp?.hasRemainingTime == false) {
|
if (remainingTimeForegroundApp?.hasRemainingTime == false) {
|
||||||
|
@ -370,126 +339,75 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update times
|
// update times
|
||||||
suspend fun getUsedTimeItem(categoryId: String?): UsedTimeItem? {
|
val timeToSubtract = Math.min(previousMainLogicExecutionTime, MAX_USED_TIME_PER_ROUND)
|
||||||
categoryId ?: return null
|
|
||||||
|
|
||||||
return cache.usedTimesOfCategoryAndDayOfEpoch.get(categoryId to nowDate.dayOfEpoch).waitForNullableValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
val shouldCountForegroundApp = remainingTimeForegroundApp != null && isScreenOn && remainingTimeForegroundApp.hasRemainingTime
|
val shouldCountForegroundApp = remainingTimeForegroundApp != null && isScreenOn && remainingTimeForegroundApp.hasRemainingTime
|
||||||
val shouldCountBackgroundApp = remainingTimeBackgroundApp != null && remainingTimeBackgroundApp.hasRemainingTime
|
val shouldCountBackgroundApp = remainingTimeBackgroundApp != null && remainingTimeBackgroundApp.hasRemainingTime
|
||||||
val countTwoTypes = shouldCountForegroundApp && shouldCountBackgroundApp
|
|
||||||
val doCategoriesMatch = (
|
|
||||||
foregroundAppHandling.categoryId != null && (
|
|
||||||
foregroundAppHandling.categoryId == audioPlaybackHandling.categoryId ||
|
|
||||||
foregroundAppHandling.categoryId == audioPlaybackHandling.parentCategoryId
|
|
||||||
)
|
|
||||||
) || (
|
|
||||||
foregroundAppHandling.parentCategoryId != null && (
|
|
||||||
foregroundAppHandling.parentCategoryId == audioPlaybackHandling.categoryId ||
|
|
||||||
foregroundAppHandling.parentCategoryId == audioPlaybackHandling.parentCategoryId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val useSingleCounter = countTwoTypes && doCategoriesMatch
|
|
||||||
|
|
||||||
if (useSingleCounter) {
|
val categoriesToCount = mutableSetOf<String>()
|
||||||
val isBackgroundCategoryHigher = audioPlaybackHandling.categoryId != null &&
|
val categoriesToCountExtraTime = mutableSetOf<String>()
|
||||||
audioPlaybackHandling.categoryId == foregroundAppHandling.parentCategoryId
|
|
||||||
|
|
||||||
if (usedTimeUpdateHelperForegroundApp !== usedTimeUpdateHelperBackgroundPlayback) {
|
if (shouldCountForegroundApp) {
|
||||||
if (isBackgroundCategoryHigher) {
|
remainingTimeForegroundAppChild?.let { remainingTime ->
|
||||||
usedTimeUpdateHelperForegroundApp?.commit(appLogic)
|
foregroundAppHandling.categoryId?.let { categoryId ->
|
||||||
usedTimeUpdateHelperForegroundApp = null
|
categoriesToCount.add(categoryId)
|
||||||
} else {
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback?.commit(appLogic)
|
if (remainingTime.usingExtraTime) {
|
||||||
usedTimeUpdateHelperBackgroundPlayback = null
|
categoriesToCountExtraTime.add(categoryId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBackgroundCategoryHigher) {
|
remainingTimeForegroundAppParent?.let { remainingTime ->
|
||||||
usedTimeUpdateHelperBackgroundPlayback = UsedTimeItemBatchUpdateHelper.eventuallyUpdateInstance(
|
foregroundAppHandling.parentCategoryId?.let {
|
||||||
date = nowDate,
|
categoriesToCount.add(it)
|
||||||
childCategoryId = audioPlaybackHandling.categoryId!!,
|
|
||||||
parentCategoryId = audioPlaybackHandling.parentCategoryId,
|
|
||||||
oldInstance = usedTimeUpdateHelperBackgroundPlayback,
|
|
||||||
usedTimeItemForDayChild = getUsedTimeItem(audioPlaybackHandling.categoryId),
|
|
||||||
usedTimeItemForDayParent = getUsedTimeItem(audioPlaybackHandling.parentCategoryId),
|
|
||||||
logic = appLogic
|
|
||||||
)
|
|
||||||
|
|
||||||
usedTimeUpdateHelperForegroundApp = usedTimeUpdateHelperBackgroundPlayback
|
if (remainingTime.usingExtraTime) {
|
||||||
} else {
|
categoriesToCountExtraTime.add(it)
|
||||||
usedTimeUpdateHelperForegroundApp = UsedTimeItemBatchUpdateHelper.eventuallyUpdateInstance(
|
}
|
||||||
date = nowDate,
|
}
|
||||||
childCategoryId = foregroundAppHandling.categoryId!!,
|
|
||||||
parentCategoryId = foregroundAppHandling.parentCategoryId,
|
|
||||||
oldInstance = usedTimeUpdateHelperForegroundApp,
|
|
||||||
usedTimeItemForDayChild = getUsedTimeItem(foregroundAppHandling.categoryId),
|
|
||||||
usedTimeItemForDayParent = getUsedTimeItem(foregroundAppHandling.parentCategoryId),
|
|
||||||
logic = appLogic
|
|
||||||
)
|
|
||||||
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback = usedTimeUpdateHelperForegroundApp
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (shouldCountForegroundApp) {
|
|
||||||
usedTimeUpdateHelperForegroundApp = UsedTimeItemBatchUpdateHelper.eventuallyUpdateInstance(
|
|
||||||
date = nowDate,
|
|
||||||
childCategoryId = foregroundAppHandling.categoryId!!,
|
|
||||||
parentCategoryId = foregroundAppHandling.parentCategoryId,
|
|
||||||
oldInstance = usedTimeUpdateHelperForegroundApp,
|
|
||||||
usedTimeItemForDayChild = getUsedTimeItem(foregroundAppHandling.categoryId),
|
|
||||||
usedTimeItemForDayParent = getUsedTimeItem(foregroundAppHandling.parentCategoryId),
|
|
||||||
logic = appLogic
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
usedTimeUpdateHelperForegroundApp?.commit(appLogic)
|
|
||||||
usedTimeUpdateHelperForegroundApp = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldCountBackgroundApp) {
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback = UsedTimeItemBatchUpdateHelper.eventuallyUpdateInstance(
|
|
||||||
date = nowDate,
|
|
||||||
childCategoryId = audioPlaybackHandling.categoryId!!,
|
|
||||||
parentCategoryId = audioPlaybackHandling.parentCategoryId,
|
|
||||||
oldInstance = usedTimeUpdateHelperBackgroundPlayback,
|
|
||||||
usedTimeItemForDayChild = getUsedTimeItem(audioPlaybackHandling.categoryId),
|
|
||||||
usedTimeItemForDayParent = getUsedTimeItem(audioPlaybackHandling.parentCategoryId),
|
|
||||||
logic = appLogic
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback?.commit(appLogic)
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// count times
|
if (shouldCountBackgroundApp) {
|
||||||
// never save more than a second of used time
|
remainingTimeBackgroundAppChild?.let { remainingTime ->
|
||||||
// FIXME: currently, this uses extra time if the parent or the child category needs it and it subtracts it from both
|
audioPlaybackHandling.categoryId?.let {
|
||||||
val timeToSubtract = Math.min(previousMainLogicExecutionTime, MAX_USED_TIME_PER_ROUND)
|
categoriesToCount.add(it)
|
||||||
|
|
||||||
if (usedTimeUpdateHelperForegroundApp === usedTimeUpdateHelperBackgroundPlayback) {
|
if (remainingTime.usingExtraTime) {
|
||||||
usedTimeUpdateHelperForegroundApp?.addUsedTime(
|
categoriesToCountExtraTime.add(it)
|
||||||
time = timeToSubtract,
|
}
|
||||||
subtractExtraTime = remainingTimeForegroundApp!!.usingExtraTime or remainingTimeBackgroundApp!!.usingExtraTime,
|
}
|
||||||
appLogic = appLogic
|
}
|
||||||
)
|
|
||||||
} else {
|
|
||||||
usedTimeUpdateHelperForegroundApp?.addUsedTime(
|
|
||||||
time = timeToSubtract,
|
|
||||||
subtractExtraTime = remainingTimeForegroundApp!!.usingExtraTime,
|
|
||||||
appLogic = appLogic
|
|
||||||
)
|
|
||||||
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback?.addUsedTime(
|
remainingTimeBackgroundAppParent?.let { remainingTime ->
|
||||||
time = timeToSubtract,
|
audioPlaybackHandling.parentCategoryId?.let {
|
||||||
subtractExtraTime = remainingTimeBackgroundApp!!.usingExtraTime,
|
categoriesToCount.add(it)
|
||||||
appLogic = appLogic
|
|
||||||
)
|
if (remainingTime.usingExtraTime) {
|
||||||
|
categoriesToCountExtraTime.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (categoriesToCount.isNotEmpty()) {
|
||||||
|
categoriesToCount.forEach { categoryId ->
|
||||||
|
usedTimeUpdateHelper.add(
|
||||||
|
categoryId = categoryId,
|
||||||
|
time = timeToSubtract,
|
||||||
|
includingExtraTime = categoriesToCountExtraTime.contains(categoryId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usedTimeUpdateHelper.reportCurrentCategories(categoriesToCount)
|
||||||
|
|
||||||
|
if (usedTimeUpdateHelper.shouldDoAutoCommit) {
|
||||||
|
usedTimeUpdateHelper.forceCommit(appLogic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger time warnings
|
// trigger time warnings
|
||||||
// FIXME: this uses the resulting time, not the time per category
|
|
||||||
fun eventuallyTriggerTimeWarning(remaining: RemainingTime, categoryId: String?) {
|
fun eventuallyTriggerTimeWarning(remaining: RemainingTime, categoryId: String?) {
|
||||||
val category = categories.find { it.id == categoryId } ?: return
|
val category = categories.find { it.id == categoryId } ?: return
|
||||||
val oldRemainingTime = remaining.includingExtraTime
|
val oldRemainingTime = remaining.includingExtraTime
|
||||||
|
@ -509,13 +427,10 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingTimeForegroundApp != null) {
|
remainingTimeForegroundAppChild?.let { eventuallyTriggerTimeWarning(it, foregroundAppHandling.categoryId) }
|
||||||
eventuallyTriggerTimeWarning(remainingTimeForegroundApp, foregroundAppHandling.categoryId)
|
remainingTimeForegroundAppParent?.let { eventuallyTriggerTimeWarning(it, foregroundAppHandling.parentCategoryId) }
|
||||||
}
|
remainingTimeBackgroundAppChild?.let { eventuallyTriggerTimeWarning(it, audioPlaybackHandling.categoryId) }
|
||||||
|
remainingTimeBackgroundAppParent?.let { eventuallyTriggerTimeWarning(it, audioPlaybackHandling.parentCategoryId) }
|
||||||
if (remainingTimeBackgroundApp != null) {
|
|
||||||
eventuallyTriggerTimeWarning(remainingTimeBackgroundApp, foregroundAppHandling.categoryId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// show notification
|
// show notification
|
||||||
fun buildStatusMessageWithCurrentAppTitle(
|
fun buildStatusMessageWithCurrentAppTitle(
|
||||||
|
@ -633,7 +548,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
if (foregroundAppHandling.status == BackgroundTaskLogicAppStatus.ShouldBlock) {
|
if (foregroundAppHandling.status == BackgroundTaskLogicAppStatus.ShouldBlock) {
|
||||||
openLockscreen(foregroundAppPackageName!!, foregroundAppActivityName)
|
openLockscreen(foregroundAppPackageName!!, foregroundAppActivityName)
|
||||||
|
|
||||||
usedTimeUpdateHelperForegroundApp?.commit(appLogic)
|
commitUsedTimeUpdaters()
|
||||||
} else {
|
} else {
|
||||||
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||||
}
|
}
|
||||||
|
@ -641,7 +556,7 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
if (audioPlaybackHandling.status == BackgroundTaskLogicAppStatus.ShouldBlock && audioPlaybackPackageName != null) {
|
if (audioPlaybackHandling.status == BackgroundTaskLogicAppStatus.ShouldBlock && audioPlaybackPackageName != null) {
|
||||||
appLogic.platformIntegration.muteAudioIfPossible(audioPlaybackPackageName)
|
appLogic.platformIntegration.muteAudioIfPossible(audioPlaybackPackageName)
|
||||||
|
|
||||||
usedTimeUpdateHelperBackgroundPlayback?.commit(appLogic)
|
commitUsedTimeUpdaters()
|
||||||
}
|
}
|
||||||
} catch (ex: SecurityException) {
|
} catch (ex: SecurityException) {
|
||||||
// this is handled by an other main loop (with a delay)
|
// this is handled by an other main loop (with a delay)
|
||||||
|
|
|
@ -54,11 +54,6 @@ class BackgroundTaskLogicCache (private val appLogic: AppLogic) {
|
||||||
return appLogic.database.usedTimes().getUsedTimesOfWeek(key.first, key.second)
|
return appLogic.database.usedTimes().getUsedTimesOfWeek(key.first, key.second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val usedTimesOfCategoryAndDayOfEpoch = object: MultiKeyLiveDataCache<UsedTimeItem?, Pair<String, Int>>() {
|
|
||||||
override fun createValue(key: Pair<String, Int>): LiveData<UsedTimeItem?> {
|
|
||||||
return appLogic.database.usedTimes().getUsedTimesByCategoryIdAndDayOfEpoch(key.first, key.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val shouldDoAutomaticSignOut = SingleItemLiveDataCacheWithRequery { -> appLogic.defaultUserLogic.hasAutomaticSignOut()}
|
val shouldDoAutomaticSignOut = SingleItemLiveDataCacheWithRequery { -> appLogic.defaultUserLogic.hasAutomaticSignOut()}
|
||||||
|
|
||||||
val liveDataCaches = LiveDataCaches(arrayOf(
|
val liveDataCaches = LiveDataCaches(arrayOf(
|
||||||
|
@ -68,7 +63,6 @@ class BackgroundTaskLogicCache (private val appLogic: AppLogic) {
|
||||||
appCategories,
|
appCategories,
|
||||||
timeLimitRules,
|
timeLimitRules,
|
||||||
usedTimesOfCategoryAndWeekByFirstDayOfWeek,
|
usedTimesOfCategoryAndWeekByFirstDayOfWeek,
|
||||||
usedTimesOfCategoryAndDayOfEpoch,
|
|
||||||
shouldDoAutomaticSignOut
|
shouldDoAutomaticSignOut
|
||||||
))
|
))
|
||||||
}
|
}
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation version 3 of the License.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package io.timelimit.android.logic
|
|
||||||
|
|
||||||
import io.timelimit.android.data.Database
|
|
||||||
import io.timelimit.android.data.model.UsedTimeItem
|
|
||||||
import io.timelimit.android.date.DateInTimezone
|
|
||||||
import io.timelimit.android.livedata.waitForNullableValue
|
|
||||||
import io.timelimit.android.sync.actions.AddUsedTimeAction
|
|
||||||
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
|
||||||
|
|
||||||
class UsedTimeItemBatchUpdateHelper(
|
|
||||||
val date: DateInTimezone,
|
|
||||||
val childCategoryId: String,
|
|
||||||
val parentCategoryId: String?,
|
|
||||||
var cachedItemChild: UsedTimeItem?,
|
|
||||||
var cachedItemParent: UsedTimeItem?
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
suspend fun eventuallyUpdateInstance(
|
|
||||||
date: DateInTimezone,
|
|
||||||
childCategoryId: String,
|
|
||||||
parentCategoryId: String?,
|
|
||||||
oldInstance: UsedTimeItemBatchUpdateHelper?,
|
|
||||||
usedTimeItemForDayChild: UsedTimeItem?,
|
|
||||||
usedTimeItemForDayParent: UsedTimeItem?,
|
|
||||||
logic: AppLogic
|
|
||||||
): UsedTimeItemBatchUpdateHelper {
|
|
||||||
if (
|
|
||||||
oldInstance != null &&
|
|
||||||
oldInstance.date == date &&
|
|
||||||
oldInstance.childCategoryId == childCategoryId &&
|
|
||||||
oldInstance.parentCategoryId == parentCategoryId
|
|
||||||
) {
|
|
||||||
if (oldInstance.cachedItemChild != usedTimeItemForDayChild) {
|
|
||||||
oldInstance.cachedItemChild = usedTimeItemForDayChild
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldInstance.cachedItemParent != usedTimeItemForDayParent) {
|
|
||||||
oldInstance.cachedItemParent = usedTimeItemForDayParent
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldInstance
|
|
||||||
} else {
|
|
||||||
if (oldInstance != null) {
|
|
||||||
oldInstance.commit(logic)
|
|
||||||
}
|
|
||||||
|
|
||||||
return UsedTimeItemBatchUpdateHelper(
|
|
||||||
date = date,
|
|
||||||
childCategoryId = childCategoryId,
|
|
||||||
parentCategoryId = parentCategoryId,
|
|
||||||
cachedItemChild = usedTimeItemForDayChild,
|
|
||||||
cachedItemParent = usedTimeItemForDayParent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var timeToAdd = 0
|
|
||||||
private var extraTimeToSubtract = 0
|
|
||||||
|
|
||||||
suspend fun addUsedTime(time: Int, subtractExtraTime: Boolean, appLogic: AppLogic) {
|
|
||||||
timeToAdd += time
|
|
||||||
|
|
||||||
if (subtractExtraTime) {
|
|
||||||
extraTimeToSubtract += time
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.max(timeToAdd, extraTimeToSubtract) > 1000 * 10 /* 10 seconds */) {
|
|
||||||
commit(appLogic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTotalUsedTimeChild(): Long = (cachedItemChild?.usedMillis ?: 0) + timeToAdd
|
|
||||||
fun getTotalUsedTimeParent(): Long = (cachedItemParent?.usedMillis ?: 0) + timeToAdd
|
|
||||||
|
|
||||||
fun getCachedExtraTimeToSubtract(): Int {
|
|
||||||
return extraTimeToSubtract
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun queryCurrentStatusFromDatabase(database: Database) {
|
|
||||||
cachedItemChild = database.usedTimes().getUsedTimeItem(childCategoryId, date.dayOfEpoch).waitForNullableValue()
|
|
||||||
cachedItemParent = parentCategoryId?.let {
|
|
||||||
database.usedTimes().getUsedTimeItem(parentCategoryId, date.dayOfEpoch).waitForNullableValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun commit(logic: AppLogic) {
|
|
||||||
if (timeToAdd == 0) {
|
|
||||||
// do nothing
|
|
||||||
} else {
|
|
||||||
ApplyActionUtil.applyAppLogicAction(
|
|
||||||
action = AddUsedTimeAction(
|
|
||||||
categoryId = childCategoryId,
|
|
||||||
timeToAdd = timeToAdd,
|
|
||||||
dayOfEpoch = date.dayOfEpoch,
|
|
||||||
extraTimeToSubtract = extraTimeToSubtract
|
|
||||||
),
|
|
||||||
appLogic = logic,
|
|
||||||
ignoreIfDeviceIsNotConfigured = true
|
|
||||||
)
|
|
||||||
|
|
||||||
timeToAdd = 0
|
|
||||||
extraTimeToSubtract = 0
|
|
||||||
|
|
||||||
queryCurrentStatusFromDatabase(logic.database)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.timelimit.android.logic
|
||||||
|
|
||||||
|
import io.timelimit.android.date.DateInTimezone
|
||||||
|
import io.timelimit.android.sync.actions.AddUsedTimeActionItem
|
||||||
|
import io.timelimit.android.sync.actions.AddUsedTimeActionVersion2
|
||||||
|
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
||||||
|
|
||||||
|
class UsedTimeUpdateHelper (val date: DateInTimezone) {
|
||||||
|
val timeToAdd = mutableMapOf<String, Int>()
|
||||||
|
val extraTimeToSubtract = mutableMapOf<String, Int>()
|
||||||
|
var shouldDoAutoCommit = false
|
||||||
|
|
||||||
|
suspend fun add(categoryId: String, time: Int, includingExtraTime: Boolean) {
|
||||||
|
if (time < 0) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
timeToAdd[categoryId] = (timeToAdd[categoryId] ?: 0) + time
|
||||||
|
|
||||||
|
if (includingExtraTime) {
|
||||||
|
extraTimeToSubtract[categoryId] = (extraTimeToSubtract[categoryId] ?: 0) + time
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeToAdd[categoryId]!! >= 1000 * 10) {
|
||||||
|
shouldDoAutoCommit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reportCurrentCategories(categories: Set<String>) {
|
||||||
|
if (!categories.containsAll(timeToAdd.keys)) {
|
||||||
|
shouldDoAutoCommit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!categories.containsAll(extraTimeToSubtract.keys)) {
|
||||||
|
shouldDoAutoCommit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun forceCommit(appLogic: AppLogic) {
|
||||||
|
if (timeToAdd.isEmpty() && extraTimeToSubtract.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val categoryIds = timeToAdd.keys + extraTimeToSubtract.keys
|
||||||
|
|
||||||
|
ApplyActionUtil.applyAppLogicAction(
|
||||||
|
action = AddUsedTimeActionVersion2(
|
||||||
|
dayOfEpoch = date.dayOfEpoch,
|
||||||
|
items = categoryIds.map { categoryId ->
|
||||||
|
AddUsedTimeActionItem(
|
||||||
|
categoryId = categoryId,
|
||||||
|
timeToAdd = timeToAdd[categoryId] ?: 0,
|
||||||
|
extraTimeToSubtract = extraTimeToSubtract[categoryId] ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
appLogic = appLogic,
|
||||||
|
ignoreIfDeviceIsNotConfigured = true
|
||||||
|
)
|
||||||
|
|
||||||
|
timeToAdd.clear()
|
||||||
|
extraTimeToSubtract.clear()
|
||||||
|
}
|
||||||
|
}
|
|
@ -142,6 +142,82 @@ data class AddUsedTimeAction(val categoryId: String, val dayOfEpoch: Int, val ti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class AddUsedTimeActionVersion2(val dayOfEpoch: Int, val items: List<AddUsedTimeActionItem>): AppLogicAction() {
|
||||||
|
companion object {
|
||||||
|
const val TYPE_VALUE = "ADD_USED_TIME_V2"
|
||||||
|
private const val DAY_OF_EPOCH = "d"
|
||||||
|
private const val ITEMS = "i"
|
||||||
|
|
||||||
|
fun parse(action: JSONObject): AddUsedTimeActionVersion2 = AddUsedTimeActionVersion2(
|
||||||
|
dayOfEpoch = action.getInt(DAY_OF_EPOCH),
|
||||||
|
items = ParseUtils.readObjectArray(action.getJSONArray(ITEMS)).map { AddUsedTimeActionItem.parse(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (dayOfEpoch < 0) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.distinctBy { it.categoryId }.size != items.size) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(writer: JsonWriter) {
|
||||||
|
writer.beginObject()
|
||||||
|
|
||||||
|
writer.name(TYPE).value(TYPE_VALUE)
|
||||||
|
writer.name(DAY_OF_EPOCH).value(dayOfEpoch)
|
||||||
|
|
||||||
|
writer.name(ITEMS).beginArray()
|
||||||
|
items.forEach { it.serialize(writer) }
|
||||||
|
writer.endArray()
|
||||||
|
|
||||||
|
writer.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AddUsedTimeActionItem(val categoryId: String, val timeToAdd: Int, val extraTimeToSubtract: Int) {
|
||||||
|
companion object {
|
||||||
|
private const val CATEGORY_ID = "categoryId"
|
||||||
|
private const val TIME_TO_ADD = "tta"
|
||||||
|
private const val EXTRA_TIME_TO_SUBTRACT = "etts"
|
||||||
|
|
||||||
|
fun parse(item: JSONObject): AddUsedTimeActionItem = AddUsedTimeActionItem(
|
||||||
|
categoryId = item.getString(CATEGORY_ID),
|
||||||
|
timeToAdd = item.getInt(TIME_TO_ADD),
|
||||||
|
extraTimeToSubtract = item.getInt(EXTRA_TIME_TO_SUBTRACT)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
IdGenerator.assertIdValid(categoryId)
|
||||||
|
|
||||||
|
if (timeToAdd < 0) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extraTimeToSubtract < 0) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serialize(writer: JsonWriter) {
|
||||||
|
writer.beginObject()
|
||||||
|
|
||||||
|
writer.name(CATEGORY_ID).value(categoryId)
|
||||||
|
writer.name(TIME_TO_ADD).value(timeToAdd)
|
||||||
|
writer.name(EXTRA_TIME_TO_SUBTRACT).value(extraTimeToSubtract)
|
||||||
|
|
||||||
|
writer.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// data class ClearTemporarilyAllowedAppsAction(val deviceId: String): AppLogicAction(), LocalOnlyAction
|
// data class ClearTemporarilyAllowedAppsAction(val deviceId: String): AppLogicAction(), LocalOnlyAction
|
||||||
|
|
||||||
data class InstalledApp(val packageName: String, val title: String, val isLaunchable: Boolean, val recommendation: AppRecommendation) {
|
data class InstalledApp(val packageName: String, val title: String, val isLaunchable: Boolean, val recommendation: AppRecommendation) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,6 +26,7 @@ object ActionParser {
|
||||||
SignOutAtDeviceAction.TYPE_VALUE -> SignOutAtDeviceAction
|
SignOutAtDeviceAction.TYPE_VALUE -> SignOutAtDeviceAction
|
||||||
UpdateAppActivitiesAction.TYPE_VALUE -> UpdateAppActivitiesAction.parse(action)
|
UpdateAppActivitiesAction.TYPE_VALUE -> UpdateAppActivitiesAction.parse(action)
|
||||||
UpdateDeviceStatusAction.TYPE_VALUE -> UpdateDeviceStatusAction.parse(action)
|
UpdateDeviceStatusAction.TYPE_VALUE -> UpdateDeviceStatusAction.parse(action)
|
||||||
|
AddUsedTimeActionVersion2.TYPE_VALUE -> AddUsedTimeActionVersion2.parse(action)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -106,6 +106,51 @@ object ApplyActionUtil {
|
||||||
database.setTransactionSuccessful()
|
database.setTransactionSuccessful()
|
||||||
syncUtil.requestVeryUnimportantSync()
|
syncUtil.requestVeryUnimportantSync()
|
||||||
|
|
||||||
|
return@executeAndWait
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (action is AddUsedTimeActionVersion2) {
|
||||||
|
val previousAction = database.pendingSyncAction().getLatestUnscheduledActionSync()
|
||||||
|
|
||||||
|
if (previousAction != null && previousAction.type == PendingSyncActionType.AppLogic) {
|
||||||
|
val parsed = ActionParser.parseAppLogicAction(JSONObject(previousAction.encodedAction))
|
||||||
|
|
||||||
|
if (parsed is AddUsedTimeActionVersion2 && parsed.dayOfEpoch == action.dayOfEpoch) {
|
||||||
|
var updatedAction: AddUsedTimeActionVersion2 = parsed
|
||||||
|
|
||||||
|
action.items.forEach { newItem ->
|
||||||
|
val oldItem = updatedAction.items.find { it.categoryId == newItem.categoryId }
|
||||||
|
|
||||||
|
if (oldItem == null) {
|
||||||
|
updatedAction = updatedAction.copy(
|
||||||
|
items = updatedAction.items + listOf(newItem)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val mergedItem = AddUsedTimeActionItem(
|
||||||
|
timeToAdd = oldItem.timeToAdd + newItem.timeToAdd,
|
||||||
|
extraTimeToSubtract = oldItem.extraTimeToSubtract + newItem.extraTimeToSubtract,
|
||||||
|
categoryId = newItem.categoryId
|
||||||
|
)
|
||||||
|
|
||||||
|
updatedAction = updatedAction.copy(
|
||||||
|
items = updatedAction.items.filter { it.categoryId != mergedItem.categoryId } + listOf(mergedItem)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the previous action
|
||||||
|
database.pendingSyncAction().updateEncodedActionSync(
|
||||||
|
sequenceNumber = previousAction.sequenceNumber,
|
||||||
|
action = StringWriter().apply {
|
||||||
|
JsonWriter(this).apply {
|
||||||
|
updatedAction.serialize(this)
|
||||||
|
}
|
||||||
|
}.toString()
|
||||||
|
)
|
||||||
|
|
||||||
|
database.setTransactionSuccessful()
|
||||||
|
syncUtil.requestVeryUnimportantSync()
|
||||||
|
|
||||||
return@executeAndWait
|
return@executeAndWait
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +171,7 @@ object ApplyActionUtil {
|
||||||
userId = ""
|
userId = ""
|
||||||
))
|
))
|
||||||
|
|
||||||
if (action is AddUsedTimeAction) {
|
if (action is AddUsedTimeAction || action is AddUsedTimeActionVersion2) {
|
||||||
syncUtil.requestVeryUnimportantSync()
|
syncUtil.requestVeryUnimportantSync()
|
||||||
} else {
|
} else {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -76,6 +76,37 @@ object LocalDatabaseAppLogicActionDispatcher {
|
||||||
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
is AddUsedTimeActionVersion2 -> {
|
||||||
|
action.items.forEach { item ->
|
||||||
|
database.category().getCategoryByIdSync(item.categoryId)!!
|
||||||
|
|
||||||
|
val updatedRows = database.usedTimes().addUsedTime(
|
||||||
|
categoryId = item.categoryId,
|
||||||
|
timeToAdd = item.timeToAdd,
|
||||||
|
dayOfEpoch = action.dayOfEpoch
|
||||||
|
)
|
||||||
|
|
||||||
|
if (updatedRows == 0) {
|
||||||
|
// create new entry
|
||||||
|
|
||||||
|
database.usedTimes().insertUsedTime(UsedTimeItem(
|
||||||
|
categoryId = item.categoryId,
|
||||||
|
dayOfEpoch = action.dayOfEpoch,
|
||||||
|
usedMillis = item.timeToAdd.toLong()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (item.extraTimeToSubtract != 0) {
|
||||||
|
database.category().subtractCategoryExtraTime(
|
||||||
|
categoryId = item.categoryId,
|
||||||
|
removedExtraTime = item.extraTimeToSubtract
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
null
|
||||||
|
}
|
||||||
is AddInstalledAppsAction -> {
|
is AddInstalledAppsAction -> {
|
||||||
database.app().addAppsSync(
|
database.app().addAppsSync(
|
||||||
action.apps.map {
|
action.apps.map {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue