mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-15 13:38:52 -06:00
Skip days implemented. Scores not correct yet
This commit is contained in:
@@ -38,11 +38,12 @@ open class EntryList {
|
||||
|
||||
/**
|
||||
* Returns the entry corresponding to the given timestamp. If no entry with such timestamp
|
||||
* has been previously added, returns Entry(timestamp, UNKNOWN).
|
||||
* has been previously added, returns Entry(timestamp, UNKNOWN). or Entry(timestamp, SKIP) if
|
||||
* skip days are enabled and that day is to be skipped
|
||||
*/
|
||||
@Synchronized
|
||||
open fun get(timestamp: Timestamp): Entry {
|
||||
return entriesByTimestamp[timestamp] ?: Entry(timestamp, UNKNOWN)
|
||||
open fun get(timestamp: Timestamp, skipDays: Boolean = false, skipDaysList: WeekdayList = WeekdayList.NO_DAY): Entry {
|
||||
return entriesByTimestamp[timestamp] ?: if (skipDays && skipDaysList.isDayTrue(timestamp.weekday)) Entry(timestamp, SKIP) else Entry(timestamp, UNKNOWN)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,12 +52,12 @@ open class EntryList {
|
||||
* included.
|
||||
*/
|
||||
@Synchronized
|
||||
open fun getByInterval(from: Timestamp, to: Timestamp): List<Entry> {
|
||||
open fun getByInterval(from: Timestamp, to: Timestamp, skipDays: Boolean = false, skipDaysList: WeekdayList = WeekdayList.NO_DAY): List<Entry> {
|
||||
val result = mutableListOf<Entry>()
|
||||
if (from.isNewerThan(to)) return result
|
||||
var current = to
|
||||
while (current >= from) {
|
||||
result.add(get(current))
|
||||
result.add(get(current, skipDays, skipDaysList))
|
||||
current = current.minus(1)
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -20,7 +20,7 @@ package org.isoron.uhabits.core.models
|
||||
|
||||
data class Frequency(
|
||||
var numerator: Int,
|
||||
var denominator: Int
|
||||
var denominator: Int,
|
||||
) {
|
||||
init {
|
||||
if (numerator == denominator) {
|
||||
|
||||
@@ -25,6 +25,8 @@ data class Habit(
|
||||
var color: PaletteColor = PaletteColor(8),
|
||||
var description: String = "",
|
||||
var frequency: Frequency = Frequency.DAILY,
|
||||
var skipDays: Boolean = false,
|
||||
var skipDaysList: WeekdayList = WeekdayList.NO_DAY,
|
||||
var id: Long? = null,
|
||||
var isArchived: Boolean = false,
|
||||
var name: String = "",
|
||||
@@ -90,6 +92,8 @@ data class Habit(
|
||||
scores.recompute(
|
||||
frequency = frequency,
|
||||
isNumerical = isNumerical,
|
||||
skipDays = skipDays,
|
||||
skipDaysList = skipDaysList,
|
||||
numericalHabitType = targetType,
|
||||
targetValue = targetValue,
|
||||
computedEntries = computedEntries,
|
||||
@@ -108,6 +112,8 @@ data class Habit(
|
||||
this.color = other.color
|
||||
this.description = other.description
|
||||
this.frequency = other.frequency
|
||||
this.skipDays = other.skipDays
|
||||
this.skipDaysList = other.skipDaysList
|
||||
// this.id should not be copied
|
||||
this.isArchived = other.isArchived
|
||||
this.name = other.name
|
||||
@@ -128,6 +134,8 @@ data class Habit(
|
||||
if (color != other.color) return false
|
||||
if (description != other.description) return false
|
||||
if (frequency != other.frequency) return false
|
||||
if (skipDays != other.skipDays) return false
|
||||
if (skipDaysList != other.skipDaysList) return false
|
||||
if (id != other.id) return false
|
||||
if (isArchived != other.isArchived) return false
|
||||
if (name != other.name) return false
|
||||
@@ -147,6 +155,7 @@ data class Habit(
|
||||
var result = color.hashCode()
|
||||
result = 31 * result + description.hashCode()
|
||||
result = 31 * result + frequency.hashCode()
|
||||
result = 31 * result + skipDaysList.hashCode()
|
||||
result = 31 * result + (id?.hashCode() ?: 0)
|
||||
result = 31 * result + isArchived.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
|
||||
@@ -68,6 +68,8 @@ class ScoreList {
|
||||
fun recompute(
|
||||
frequency: Frequency,
|
||||
isNumerical: Boolean,
|
||||
skipDays: Boolean,
|
||||
skipDaysList: WeekdayList,
|
||||
numericalHabitType: NumericalHabitType,
|
||||
targetValue: Double,
|
||||
computedEntries: EntryList,
|
||||
@@ -79,7 +81,7 @@ class ScoreList {
|
||||
var numerator = frequency.numerator
|
||||
var denominator = frequency.denominator
|
||||
val freq = frequency.toDouble()
|
||||
val values = computedEntries.getByInterval(from, to).map { it.value }.toIntArray()
|
||||
val values = computedEntries.getByInterval(from, to, skipDays, skipDaysList).map { it.value }.toIntArray()
|
||||
val isAtMost = numericalHabitType == NumericalHabitType.AT_MOST
|
||||
|
||||
// For non-daily boolean habits, we double the numerator and the denominator to smooth
|
||||
|
||||
@@ -38,6 +38,13 @@ class WeekdayList {
|
||||
this.weekdays = Arrays.copyOf(weekdays, 7)
|
||||
}
|
||||
|
||||
constructor(addDays: BooleanArray, removeDays: BooleanArray) {
|
||||
weekdays = BooleanArray(7)
|
||||
for (i in 0..6) {
|
||||
weekdays[i] = addDays[i] && !removeDays[i]
|
||||
}
|
||||
}
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() {
|
||||
for (d in weekdays) if (d) return false
|
||||
@@ -58,6 +65,10 @@ class WeekdayList {
|
||||
return packedList
|
||||
}
|
||||
|
||||
fun isDayTrue(dayNum: Int): Boolean {
|
||||
return weekdays[dayNum]
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
@@ -73,5 +84,6 @@ class WeekdayList {
|
||||
|
||||
companion object {
|
||||
val EVERY_DAY = WeekdayList(127)
|
||||
val NO_DAY = WeekdayList(booleanArrayOf(false, false, false, false, false, false, false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.EntryList
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.models.WeekdayList
|
||||
import org.isoron.uhabits.core.models.sqlite.records.EntryRecord
|
||||
|
||||
class SQLiteEntryList(database: Database) : EntryList() {
|
||||
@@ -43,14 +44,13 @@ class SQLiteEntryList(database: Database) : EntryList() {
|
||||
isLoaded = true
|
||||
}
|
||||
|
||||
override fun get(timestamp: Timestamp): Entry {
|
||||
override fun get(timestamp: Timestamp, skipDays: Boolean, skipDaysList: WeekdayList): Entry {
|
||||
loadRecords()
|
||||
return super.get(timestamp)
|
||||
return super.get(timestamp, skipDays, skipDaysList)
|
||||
}
|
||||
|
||||
override fun getByInterval(from: Timestamp, to: Timestamp): List<Entry> {
|
||||
override fun getByInterval(from: Timestamp, to: Timestamp, skipDays: Boolean, skipDaysList: WeekdayList): List<Entry> {
|
||||
loadRecords()
|
||||
return super.getByInterval(from, to)
|
||||
return super.getByInterval(from, to, skipDays, skipDaysList)
|
||||
}
|
||||
|
||||
override fun add(entry: Entry) {
|
||||
|
||||
@@ -49,6 +49,12 @@ class HabitRecord {
|
||||
@field:Column(name = "freq_den")
|
||||
var freqDen: Int? = null
|
||||
|
||||
@field:Column(name = "skip_days")
|
||||
var skipDays: Int? = null
|
||||
|
||||
@field:Column(name = "skip_days_list")
|
||||
var skipDaysList: Int? = null
|
||||
|
||||
@field:Column
|
||||
var color: Int? = null
|
||||
|
||||
@@ -105,6 +111,8 @@ class HabitRecord {
|
||||
val (numerator, denominator) = model.frequency
|
||||
freqNum = numerator
|
||||
freqDen = denominator
|
||||
skipDays = if (model.skipDays) 1 else 0
|
||||
skipDaysList = model.skipDaysList.toInteger()
|
||||
reminderDays = 0
|
||||
reminderMin = null
|
||||
reminderHour = null
|
||||
@@ -122,6 +130,8 @@ class HabitRecord {
|
||||
habit.description = description!!
|
||||
habit.question = question!!
|
||||
habit.frequency = Frequency(freqNum!!, freqDen!!)
|
||||
habit.skipDays = (skipDays!! == 1)
|
||||
habit.skipDaysList = WeekdayList(skipDaysList!!)
|
||||
habit.color = PaletteColor(color!!)
|
||||
habit.isArchived = archived != 0
|
||||
habit.type = HabitType.fromInt(type!!)
|
||||
|
||||
@@ -311,7 +311,9 @@ class HabitCardListCache @Inject constructor(
|
||||
newData.scores[habit.id] = habit.scores[today].value
|
||||
val list: MutableList<Int> = ArrayList()
|
||||
val notes: MutableList<String> = ArrayList()
|
||||
for ((_, value, note) in habit.computedEntries.getByInterval(dateFrom, today)) {
|
||||
val skipDays = habit.skipDays
|
||||
val skipDaysList = habit.skipDaysList
|
||||
for ((_, value, note) in habit.computedEntries.getByInterval(dateFrom, today, skipDays, skipDaysList)) {
|
||||
list.add(value)
|
||||
notes.add(note)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
if (habit.type == HabitType.NUMERICAL) {
|
||||
val oldValue = entry.value.toDouble() / 1000
|
||||
screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String, x: Float, y: Float ->
|
||||
val value = (newValue * 1000).roundToInt()
|
||||
val value = if (habit.skipDays && habit.skipDaysList.isDayTrue(timestamp.weekday)) 3 else (newValue * 1000).roundToInt()
|
||||
|
||||
if (newValue != oldValue) {
|
||||
if (
|
||||
(habit.targetType == AT_LEAST && newValue >= habit.targetValue) ||
|
||||
|
||||
@@ -5,6 +5,8 @@ create table Habits (
|
||||
description text,
|
||||
freq_den integer,
|
||||
freq_num integer,
|
||||
skip_days integer,
|
||||
skip_days_list integer,
|
||||
highlight integer,
|
||||
name text,
|
||||
position integer,
|
||||
|
||||
Reference in New Issue
Block a user