mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 01:39:22 +02:00
126 lines
No EOL
5.5 KiB
Kotlin
126 lines
No EOL
5.5 KiB
Kotlin
/*
|
|
* TimeLimit Copyright <C> 2019- 2023 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.model.TimeLimitRule
|
|
import io.timelimit.android.data.model.UsedTimeItem
|
|
|
|
data class RemainingTime(val includingExtraTime: Long, val default: Long) {
|
|
val hasRemainingTime = includingExtraTime > 0
|
|
val usingExtraTime = includingExtraTime > 0 && default == 0L
|
|
|
|
init {
|
|
if (includingExtraTime < 0 || default < 0) {
|
|
throw IllegalStateException("time is < 0")
|
|
}
|
|
|
|
if (includingExtraTime < default) {
|
|
throw IllegalStateException("extra time < default time")
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
fun min(a: RemainingTime?, b: RemainingTime?): RemainingTime? = if (a == null) {
|
|
b
|
|
} else if (b == null) {
|
|
a
|
|
} else {
|
|
RemainingTime(
|
|
includingExtraTime = Math.min(a.includingExtraTime, b.includingExtraTime),
|
|
default = Math.min(a.default, b.default)
|
|
)
|
|
}
|
|
|
|
fun getRulesRelatedToDay(dayOfWeek: Int, minuteOfDay: Int, rules: List<TimeLimitRule>): List<TimeLimitRule> {
|
|
return rules.filter {
|
|
((it.dayMask.toInt() and (1 shl dayOfWeek)) != 0) &&
|
|
minuteOfDay >= it.startMinuteOfDay && minuteOfDay <= it.endMinuteOfDay
|
|
}
|
|
}
|
|
|
|
fun getRemainingTime(dayOfWeek: Int, minuteOfDay: Int, usedTimes: List<UsedTimeItem>, rules: List<TimeLimitRule>, extraTime: Long, firstDayOfWeekAsEpochDay: Int): RemainingTime? {
|
|
if (extraTime < 0) {
|
|
throw IllegalStateException("extra time < 0")
|
|
}
|
|
|
|
val relatedRules = getRulesRelatedToDay(dayOfWeek, minuteOfDay, rules)
|
|
val withoutExtraTime = getRemainingTime(usedTimes, relatedRules, false, firstDayOfWeekAsEpochDay, dayOfWeek)
|
|
val withExtraTime = getRemainingTime(usedTimes, relatedRules, true, firstDayOfWeekAsEpochDay, dayOfWeek)
|
|
|
|
if (withoutExtraTime == null && withExtraTime == null) {
|
|
// no rules
|
|
return null
|
|
} else if (withoutExtraTime != null && withExtraTime != null) {
|
|
// with rules for extra time
|
|
val additionalTimeWithExtraTime = withExtraTime - withoutExtraTime
|
|
|
|
if (additionalTimeWithExtraTime < 0) {
|
|
throw IllegalStateException("additional time with extra time < 0")
|
|
}
|
|
|
|
return RemainingTime(
|
|
includingExtraTime = withoutExtraTime + Math.min(extraTime, additionalTimeWithExtraTime),
|
|
default = withoutExtraTime
|
|
)
|
|
} else if (withoutExtraTime != null) {
|
|
// without rules for extra time
|
|
return RemainingTime(
|
|
includingExtraTime = withoutExtraTime + extraTime,
|
|
default = withoutExtraTime
|
|
)
|
|
} else {
|
|
throw IllegalStateException()
|
|
}
|
|
}
|
|
|
|
private fun getRemainingTime(usedTimes: List<UsedTimeItem>, relatedRules: List<TimeLimitRule>, assumeMaximalExtraTime: Boolean, firstDayOfWeekAsEpochDay: Int, dayOfWeek: Int): Long? {
|
|
return relatedRules.filter { (!assumeMaximalExtraTime) || it.applyToExtraTimeUsage }.map { rule ->
|
|
val usedTime = getUsedTime(
|
|
usedTimes = usedTimes,
|
|
rule = rule,
|
|
firstDayOfWeekAsEpochDay = firstDayOfWeekAsEpochDay,
|
|
dayOfWeekForDailyRule = if (rule.perDay) dayOfWeek else null
|
|
)
|
|
|
|
val maxTime = rule.maximumTimeInMillis
|
|
|
|
(maxTime - usedTime).coerceAtLeast(0)
|
|
}.minOrNull()
|
|
}
|
|
|
|
fun getUsedTime(usedTimes: List<UsedTimeItem>, rule: TimeLimitRule, firstDayOfWeekAsEpochDay: Int, dayOfWeekForDailyRule: Int?): Long {
|
|
val usedTimeByDay = longArrayOf(0, 0, 0, 0, 0, 0, 0)
|
|
|
|
usedTimes.forEach { usedTimeItem ->
|
|
val doesWeekMatch = usedTimeItem.dayOfEpoch >= firstDayOfWeekAsEpochDay && usedTimeItem.dayOfEpoch <= firstDayOfWeekAsEpochDay + 6
|
|
|
|
if (doesWeekMatch) {
|
|
val usedTimeItemDayOfWeek = usedTimeItem.dayOfEpoch - firstDayOfWeekAsEpochDay
|
|
val doesDayMaskMatch = (rule.dayMask.toInt() and (1 shl usedTimeItemDayOfWeek)) != 0
|
|
|
|
val dayMatch = rule.perDay or doesDayMaskMatch
|
|
val hourMatch = rule.startMinuteOfDay <= usedTimeItem.startTimeOfDay && rule.endMinuteOfDay >= usedTimeItem.endTimeOfDay
|
|
|
|
if (dayMatch && hourMatch)
|
|
usedTimeByDay[usedTimeItemDayOfWeek] = usedTimeByDay[usedTimeItemDayOfWeek].coerceAtLeast(usedTimeItem.usedMillis)
|
|
}
|
|
}
|
|
|
|
return if (dayOfWeekForDailyRule == null) usedTimeByDay.sum()
|
|
else usedTimeByDay[dayOfWeekForDailyRule]
|
|
}
|
|
}
|
|
} |