Improve automatic checkmarks for monthly habits

Fixes #947
pull/1033/head
Alinson S. Xavier 4 years ago
parent 2163a2b93b
commit 33468bfc1c
No known key found for this signature in database
GPG Key ID: DCA0DAD4D2F58624

@ -1,5 +1,9 @@
# Changelog # Changelog
## [2.0.3] - [Unreleased]
### Fixed
- Improve automatic checkmarks for monthly habits (@iSoron, 947)
## [2.0.2] - 2021-05-23 ## [2.0.2] - 2021-05-23
### Changed ### Changed

@ -37,8 +37,8 @@ android {
compileSdkVersion(30) compileSdkVersion(30)
defaultConfig { defaultConfig {
versionCode(20002) versionCode(20003)
versionName("2.0.2") versionName("2.0.3")
minSdkVersion(23) minSdkVersion(23)
targetSdkVersion(30) targetSdkVersion(30)
applicationId("org.isoron.uhabits") applicationId("org.isoron.uhabits")

@ -160,26 +160,28 @@ class FrequencyPickerDialog(
private fun populateViews() { private fun populateViews() {
uncheckAll() uncheckAll()
if (freqNumerator == 1) { if (freqDenominator == 30 || freqDenominator == 31) {
if (freqDenominator == 1) { contentView.xTimesPerMonthRadioButton.isChecked = true
contentView.everyDayRadioButton.isChecked = true contentView.xTimesPerMonthTextView.setText(freqNumerator.toString())
} else { focus(contentView.xTimesPerMonthTextView)
contentView.everyXDaysRadioButton.isChecked = true
contentView.everyXDaysTextView.setText(freqDenominator.toString())
focus(contentView.everyXDaysTextView)
}
} else { } else {
if (freqDenominator == 7) { if (freqNumerator == 1) {
contentView.xTimesPerWeekRadioButton.isChecked = true if (freqDenominator == 1) {
contentView.xTimesPerWeekTextView.setText(freqNumerator.toString()) contentView.everyDayRadioButton.isChecked = true
focus(contentView.xTimesPerWeekTextView) } else {
} else if (freqDenominator == 30 || freqDenominator == 31) { contentView.everyXDaysRadioButton.isChecked = true
contentView.xTimesPerMonthRadioButton.isChecked = true contentView.everyXDaysTextView.setText(freqDenominator.toString())
contentView.xTimesPerMonthTextView.setText(freqNumerator.toString()) focus(contentView.everyXDaysTextView)
focus(contentView.xTimesPerMonthTextView) }
} else { } else {
Log.w("FrequencyPickerDialog", "Unknown frequency: $freqNumerator/$freqDenominator") if (freqDenominator == 7) {
contentView.everyDayRadioButton.isChecked = true contentView.xTimesPerWeekRadioButton.isChecked = true
contentView.xTimesPerWeekTextView.setText(freqNumerator.toString())
focus(contentView.xTimesPerWeekTextView)
} else {
Log.w("FrequencyPickerDialog", "Unknown frequency: $freqNumerator/$freqDenominator")
contentView.everyDayRadioButton.isChecked = true
}
} }
} }
} }

@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.edit
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.text.Html import android.text.Html
@ -59,6 +60,16 @@ import org.isoron.uhabits.utils.formatTime
import org.isoron.uhabits.utils.toFormattedString import org.isoron.uhabits.utils.toFormattedString
import org.isoron.uhabits.utils.toThemedAndroidColor import org.isoron.uhabits.utils.toThemedAndroidColor
fun formatFrequency(freqNum: Int, freqDen: Int, resources: Resources) = when {
freqNum == 1 && (freqDen == 30 || freqDen == 31) -> resources.getString(R.string.every_month)
freqDen == 30 || freqDen == 31 -> resources.getString(R.string.x_times_per_month, freqNum)
freqNum == 1 && freqDen == 1 -> resources.getString(R.string.every_day)
freqNum == 1 && freqDen == 7 -> resources.getString(R.string.every_week)
freqNum == 1 && freqDen > 1 -> resources.getString(R.string.every_x_days, freqDen)
freqDen == 7 -> resources.getString(R.string.x_times_per_week, freqNum)
else -> "$freqNum/$freqDen"
}
class EditHabitActivity : AppCompatActivity() { class EditHabitActivity : AppCompatActivity() {
private lateinit var themeSwitcher: AndroidThemeSwitcher private lateinit var themeSwitcher: AndroidThemeSwitcher
@ -299,14 +310,7 @@ class EditHabitActivity : AppCompatActivity() {
@SuppressLint("StringFormatMatches") @SuppressLint("StringFormatMatches")
private fun populateFrequency() { private fun populateFrequency() {
binding.booleanFrequencyPicker.text = when { binding.booleanFrequencyPicker.text = formatFrequency(freqNum, freqDen, resources)
freqNum == 1 && freqDen == 1 -> getString(R.string.every_day)
freqNum == 1 && freqDen == 7 -> getString(R.string.every_week)
freqNum == 1 && freqDen > 1 -> getString(R.string.every_x_days, freqDen)
freqDen == 7 -> getString(R.string.x_times_per_week, freqNum)
freqDen == 30 || freqDen == 31 -> getString(R.string.x_times_per_month, freqNum)
else -> "$freqNum/$freqDen"
}
binding.numericalFrequencyPicker.text = when (freqDen) { binding.numericalFrequencyPicker.text = when (freqDen) {
1 -> getString(R.string.every_day) 1 -> getString(R.string.every_day)
7 -> getString(R.string.every_week) 7 -> getString(R.string.every_week)

@ -20,14 +20,13 @@ package org.isoron.uhabits.activities.habits.show.views
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.LinearLayout import android.widget.LinearLayout
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.activities.habits.edit.formatFrequency
import org.isoron.uhabits.activities.habits.list.views.toShortString import org.isoron.uhabits.activities.habits.list.views.toShortString
import org.isoron.uhabits.core.models.Frequency
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState
import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding
import org.isoron.uhabits.utils.InterfaceUtils import org.isoron.uhabits.utils.InterfaceUtils
@ -49,7 +48,11 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
fun setState(state: SubtitleCardState) { fun setState(state: SubtitleCardState) {
val color = state.color.toThemedAndroidColor(context) val color = state.color.toThemedAndroidColor(context)
val reminder = state.reminder val reminder = state.reminder
binding.frequencyLabel.text = state.frequency.format(resources) binding.frequencyLabel.text = formatFrequency(
state.frequency.numerator,
state.frequency.denominator,
resources,
)
binding.questionLabel.setTextColor(color) binding.questionLabel.setTextColor(color)
binding.questionLabel.text = state.question binding.questionLabel.text = state.question
binding.reminderLabel.text = if (reminder != null) { binding.reminderLabel.text = if (reminder != null) {
@ -72,32 +75,4 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
postInvalidate() postInvalidate()
} }
@SuppressLint("StringFormatMatches")
private fun Frequency.format(resources: Resources): String {
val num = this.numerator
val den = this.denominator
if (num == den) {
return resources.getString(R.string.every_day)
}
if (den == 7) {
return resources.getString(R.string.x_times_per_week, num)
}
if (den == 30 || den == 31) {
return resources.getString(R.string.x_times_per_month, num)
}
if (num == 1) {
if (den == 7) {
return resources.getString(R.string.every_week)
}
if (den % 7 == 0) {
return resources.getString(R.string.every_x_weeks, den / 7)
}
if (den == 30 || den == 31) {
return resources.getString(R.string.every_month)
}
return resources.getString(R.string.every_x_days, den)
}
return "$num/$den"
}
} }

@ -72,6 +72,13 @@ data class LocalDate(val daysSince2000: Int) {
return dayCache return dayCache
} }
val monthLength: Int
get() = when (month) {
4, 6, 9, 11 -> 30
2 -> if (isLeapYear(year)) 29 else 28
else -> 31
}
private fun updateYearMonthDayCache() { private fun updateYearMonthDayCache() {
var currYear = 2000 var currYear = 2000
var currDay = 0 var currDay = 0

@ -248,8 +248,17 @@ open class EntryList {
for (i in num - 1 until filtered.size) { for (i in num - 1 until filtered.size) {
val (begin, _) = filtered[i] val (begin, _) = filtered[i]
val (center, _) = filtered[i - num + 1] val (center, _) = filtered[i - num + 1]
if (begin.daysUntil(center) < den) { var size = den
val end = begin.plus(den - 1) if (den == 30 || den == 31) {
val beginDate = begin.toLocalDate()
size = if (beginDate.day == beginDate.monthLength) {
beginDate.plus(1).monthLength
} else {
beginDate.monthLength
}
}
if (begin.daysUntil(center) < size) {
val end = begin.plus(size - 1)
intervals.add(Interval(begin, center, end)) intervals.add(Interval(begin, center, end))
} }
} }

Loading…
Cancel
Save