mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Refactor handling of remaining time based triggers
This commit is contained in:
parent
5fd38f8ff1
commit
886ee14029
4 changed files with 113 additions and 75 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2021 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
|
||||
|
@ -57,6 +57,15 @@ data class UserRelatedData(
|
|||
|
||||
val categoryById: Map<String, CategoryRelatedData> by lazy { categories.associateBy { it.category.id } }
|
||||
val timeZone: TimeZone by lazy { user.getTimezone() }
|
||||
val preBlockSwitchPoints: Set<Long> by lazy {
|
||||
mutableSetOf<Long>().also { result ->
|
||||
categories.forEach { category ->
|
||||
category.limitLoginCategories.forEach {
|
||||
if (it.preBlockDuration > 0) result.add(it.preBlockDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// O(n), but saves memory and index building time
|
||||
// additionally a cache
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2021 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
|
||||
|
@ -357,6 +357,77 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
.map { categoryHandlingCache.get(it) }
|
||||
.filter { it.shouldCountTime }
|
||||
|
||||
fun timeToSubtractForCategory(categoryId: String): Int {
|
||||
return if (usedTimeUpdateHelper.getCountedCategoryIds().contains(categoryId)) usedTimeUpdateHelper.getCountedTime() else 0
|
||||
}
|
||||
|
||||
val triggerSync = kotlin.run {
|
||||
var triggerSyncByLimitLoginCategory = false
|
||||
var triggerSyncByTimeOver = false
|
||||
|
||||
categoryHandlingsToCount.forEach { handling ->
|
||||
val category = handling.createdWithCategoryRelatedData.category
|
||||
val categoryId = category.id
|
||||
val timeToSubtractForCategory = timeToSubtractForCategory(categoryId)
|
||||
val nowRemaining = handling.remainingTime ?: return@forEach // category is not limited anymore
|
||||
|
||||
val oldRemainingTime = nowRemaining.includingExtraTime - timeToSubtractForCategory
|
||||
val newRemainingTime = oldRemainingTime - timeToSubtract
|
||||
|
||||
// trigger time warnings
|
||||
if (oldRemainingTime / (1000 * 60) != newRemainingTime / (1000 * 60)) {
|
||||
// eventually show remaining time warning
|
||||
val roundedNewTime = ((newRemainingTime / (1000 * 60)) + 1) * (1000 * 60)
|
||||
val flagIndex = CategoryTimeWarnings.durationToBitIndex[roundedNewTime]
|
||||
|
||||
if (flagIndex != null && category.timeWarnings and (1 shl flagIndex) != 0) {
|
||||
appLogic.platformIntegration.showTimeWarningNotification(
|
||||
title = appLogic.context.getString(R.string.time_warning_not_title, category.title),
|
||||
text = TimeTextUtil.remaining(roundedNewTime.toInt(), appLogic.context)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// check if sync triggered by time over
|
||||
if (oldRemainingTime > 0 && newRemainingTime <= 0) {
|
||||
triggerSyncByTimeOver = true
|
||||
}
|
||||
|
||||
// check if limit login triggered
|
||||
val triggerSyncByLimitLoginCategoryForThisCategory = userRelatedData.preBlockSwitchPoints.let { switchPoints ->
|
||||
if (switchPoints.isEmpty()) false else {
|
||||
val newSessionDuration = handling.remainingSessionDuration?.let { it - timeToSubtractForCategory }
|
||||
|
||||
val limitLoginBySessionDuration = if (newSessionDuration != null) {
|
||||
val oldSessionDuration = newSessionDuration + timeToSubtract
|
||||
|
||||
switchPoints.find { switchPoint -> oldSessionDuration >= switchPoint && newSessionDuration < switchPoint } != null
|
||||
} else false
|
||||
|
||||
val limitLoginByRemainingTime = switchPoints.find { switchPoint -> oldRemainingTime >= switchPoint && newRemainingTime < switchPoint } != null
|
||||
|
||||
limitLoginBySessionDuration || limitLoginByRemainingTime
|
||||
}
|
||||
}
|
||||
|
||||
triggerSyncByLimitLoginCategory = triggerSyncByLimitLoginCategory || triggerSyncByLimitLoginCategoryForThisCategory
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (triggerSyncByTimeOver) {
|
||||
Log.d(LOG_TAG, "trigger sync because the time is over")
|
||||
}
|
||||
|
||||
if (triggerSyncByLimitLoginCategory) {
|
||||
Log.d(LOG_TAG, "trigger sync by the limit login category")
|
||||
}
|
||||
}
|
||||
|
||||
val triggerSync = triggerSyncByLimitLoginCategory || triggerSyncByTimeOver
|
||||
|
||||
triggerSync
|
||||
}
|
||||
|
||||
if (
|
||||
usedTimeUpdateHelper.report(
|
||||
duration = timeToSubtract,
|
||||
|
@ -365,6 +436,10 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
handlings = categoryHandlingsToCount
|
||||
)
|
||||
) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "auto commit used times")
|
||||
}
|
||||
|
||||
val newDeviceAndUserRelatedData = Threads.database.executeAndWait {
|
||||
appLogic.database.derivedDataDao().getUserAndDeviceRelatedDataSync()
|
||||
}
|
||||
|
@ -373,84 +448,30 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
newDeviceAndUserRelatedData?.userRelatedData?.user?.id != deviceAndUSerRelatedData.userRelatedData.user.id ||
|
||||
newDeviceAndUserRelatedData.userRelatedData.categoryById.keys != deviceAndUSerRelatedData.userRelatedData.categoryById.keys
|
||||
) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "restart the loop")
|
||||
}
|
||||
|
||||
// start the loop directly again
|
||||
continue
|
||||
}
|
||||
|
||||
val hasLimitLoginCategories = currentCategoryIds.find { userRelatedData.categoryById[it]?.limitLoginCategories?.isNotEmpty() ?: false } != null
|
||||
|
||||
val previousCategoryHandlings = if (hasLimitLoginCategories) {
|
||||
currentCategoryIds.associateWith { categoryHandlingCache.get(it) }
|
||||
} else null
|
||||
|
||||
reportStatusToCategoryHandlingCache(userRelatedData = newDeviceAndUserRelatedData.userRelatedData)
|
||||
|
||||
val triggerSyncByLimitLoginCategory = if (previousCategoryHandlings != null) {
|
||||
val switchPoints = mutableSetOf<Long>()
|
||||
|
||||
currentCategoryIds.forEach {
|
||||
userRelatedData.categoryById[it]?.let { category ->
|
||||
category.limitLoginCategories.forEach {
|
||||
if (it.preBlockDuration > 0) switchPoints.add(it.preBlockDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentCategoryIds.find { categoryId ->
|
||||
val oldHandling = previousCategoryHandlings[categoryId]!!
|
||||
val newHandling = categoryHandlingCache.get(categoryId)
|
||||
|
||||
switchPoints.find { switchPoint ->
|
||||
(oldHandling.remainingTime != null && oldHandling.remainingTime.includingExtraTime >= switchPoint &&
|
||||
(newHandling.remainingTime != null && newHandling.remainingTime.includingExtraTime < switchPoint)) ||
|
||||
(oldHandling.remainingSessionDuration != null && oldHandling.remainingSessionDuration >= switchPoint &&
|
||||
(newHandling.remainingSessionDuration != null && newHandling.remainingSessionDuration < switchPoint))
|
||||
} != null
|
||||
} != null
|
||||
} else false
|
||||
|
||||
// eventually trigger sync
|
||||
val allCategoriesWithRemainingTimeAfterSubtractingTime = currentCategoryIds.filter { categoryHandlingCache.get(it).hasRemainingTime }
|
||||
val triggerSyncByTimeOver = allCategoriesWithRemainingTimeBeforeAddingUsedTime != allCategoriesWithRemainingTimeAfterSubtractingTime
|
||||
|
||||
val triggerSync = triggerSyncByLimitLoginCategory || triggerSyncByTimeOver
|
||||
|
||||
if (triggerSync) {
|
||||
ApplyActionUtil.applyAppLogicAction(
|
||||
action = ForceSyncAction,
|
||||
appLogic = appLogic,
|
||||
ignoreIfDeviceIsNotConfigured = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val categoriesToCount = categoryHandlingsToCount.map { it.createdWithCategoryRelatedData.category.id }
|
||||
|
||||
fun timeToSubtractForCategory(categoryId: String): Int {
|
||||
return if (usedTimeUpdateHelper.getCountedCategoryIds().contains(categoryId)) usedTimeUpdateHelper.getCountedTime() else 0
|
||||
}
|
||||
|
||||
// trigger time warnings
|
||||
categoriesToCount.forEach { categoryId ->
|
||||
val category = userRelatedData.categoryById[categoryId]!!.category
|
||||
val handling = categoryHandlingCache.get(categoryId)
|
||||
val nowRemaining = handling.remainingTime ?: return@forEach // category is not limited anymore
|
||||
|
||||
val newRemainingTime = nowRemaining.includingExtraTime - timeToSubtractForCategory(categoryId)
|
||||
val oldRemainingTime = newRemainingTime + timeToSubtract
|
||||
|
||||
if (oldRemainingTime / (1000 * 60) != newRemainingTime / (1000 * 60)) {
|
||||
// eventually show remaining time warning
|
||||
val roundedNewTime = ((newRemainingTime / (1000 * 60)) + 1) * (1000 * 60)
|
||||
val flagIndex = CategoryTimeWarnings.durationToBitIndex[roundedNewTime]
|
||||
|
||||
if (flagIndex != null && category.timeWarnings and (1 shl flagIndex) != 0) {
|
||||
appLogic.platformIntegration.showTimeWarningNotification(
|
||||
title = appLogic.context.getString(R.string.time_warning_not_title, category.title),
|
||||
text = TimeTextUtil.remaining(roundedNewTime.toInt(), appLogic.context)
|
||||
)
|
||||
}
|
||||
// trigger sync when required
|
||||
if (triggerSync) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "trigger sync")
|
||||
}
|
||||
|
||||
commitUsedTimeUpdaters()
|
||||
|
||||
ApplyActionUtil.applyAppLogicAction(
|
||||
action = ForceSyncAction,
|
||||
appLogic = appLogic,
|
||||
ignoreIfDeviceIsNotConfigured = true
|
||||
)
|
||||
}
|
||||
|
||||
// show notification
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2021 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
|
||||
|
@ -84,6 +84,10 @@ class UsedTimeUpdateHelper (private val appLogic: AppLogic) {
|
|||
val makeCommit = makeCommitByDifferntHandling || makeCommitByDifferentBaseData || makeCommitByCountedTime
|
||||
|
||||
val madeCommit = if (makeCommit) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(LOG_TAG, "makeCommitByDifferntHandling = $makeCommitByDifferntHandling; makeCommitByDifferentBaseData = $makeCommitByDifferentBaseData; makeCommitByCountedTime = $makeCommitByCountedTime")
|
||||
}
|
||||
|
||||
doCommitPrivate()
|
||||
} else {
|
||||
false
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2021 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
|
||||
|
@ -223,7 +223,11 @@ data class CategoryItselfHandling (
|
|||
else
|
||||
remainingTime.default
|
||||
val maxTimeToAddBySessionDuration = remainingSessionDuration ?: Long.MAX_VALUE
|
||||
val maxTimeToAdd = maxTimeToAddByRegularTime.coerceAtMost(maxTimeToAddBySessionDuration)
|
||||
val maxTimeToAdd = maxTimeToAddByRegularTime.coerceAtMost(maxTimeToAddBySessionDuration).let {
|
||||
// use Long.MAX_VALUE if there is nothing remaining for the case that the blocking does not work
|
||||
// to prevent flushing as often as possible
|
||||
if (it > 0) it else Long.MAX_VALUE
|
||||
}
|
||||
|
||||
val additionalTimeCountingSlots = if (shouldCountTime)
|
||||
regularRelatedRules
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue