diff --git a/CHANGELOG.md b/CHANGELOG.md
index e87ad34a1..b6dfbc8b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## [2.0.3] - [Unreleased]
+### Fixed
+- Improve automatic checkmarks for monthly habits (@iSoron, 947)
+- Fix small theme issues (@iSoron)
+- Fix ANR on some Samsung phones (@iSoron, #962)
+
## [2.0.2] - 2021-05-23
### Changed
diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts
index 6017450b5..6062a86f7 100644
--- a/uhabits-android/build.gradle.kts
+++ b/uhabits-android/build.gradle.kts
@@ -37,8 +37,8 @@ android {
compileSdkVersion(30)
defaultConfig {
- versionCode(20002)
- versionName("2.0.2")
+ versionCode(20003)
+ versionName("2.0.3")
minSdkVersion(23)
targetSdkVersion(30)
applicationId("org.isoron.uhabits")
diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt
index b4ff1d5e5..ae1d1f52f 100644
--- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt
+++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt
@@ -36,6 +36,7 @@ class AndroidCanvas : Canvas {
var innerDensity = 1.0
var innerWidth = 0
var innerHeight = 0
+ var mHeight = 15
var paint = Paint().apply {
isAntiAlias = true
@@ -64,11 +65,10 @@ class AndroidCanvas : Canvas {
}
override fun drawText(text: String, x: Double, y: Double) {
- textPaint.getTextBounds(text, 0, text.length, textBounds)
innerCanvas.drawText(
text,
x.toDp(),
- y.toDp() - textBounds.exactCenterY(),
+ y.toDp() + 0.6f * mHeight,
textPaint,
)
}
@@ -126,10 +126,17 @@ class AndroidCanvas : Canvas {
Font.BOLD -> Typeface.DEFAULT_BOLD
Font.FONT_AWESOME -> getFontAwesome(context)
}
+ updateMHeight()
}
override fun setFontSize(size: Double) {
textPaint.textSize = size.toDp()
+ updateMHeight()
+ }
+
+ private fun updateMHeight() {
+ textPaint.getTextBounds("m", 0, 1, textBounds)
+ mHeight = textBounds.height()
}
override fun setStrokeWidth(size: Double) {
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt
index 855adaa84..be9d0eb02 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt
@@ -30,6 +30,7 @@ import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.ThemeSwitcher
import org.isoron.uhabits.core.ui.views.DarkTheme
import org.isoron.uhabits.core.ui.views.LightTheme
+import org.isoron.uhabits.core.ui.views.PureBlackTheme
import org.isoron.uhabits.core.ui.views.Theme
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
@@ -66,7 +67,7 @@ constructor(
}
override fun applyPureBlackTheme() {
- currentTheme = DarkTheme()
+ currentTheme = PureBlackTheme()
context.setTheme(R.style.AppBaseThemeDark_PureBlack)
(context as Activity).window.navigationBarColor =
ContextCompat.getColor(context, R.color.black)
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt
index 0971ffab6..92754ca89 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt
@@ -160,26 +160,28 @@ class FrequencyPickerDialog(
private fun populateViews() {
uncheckAll()
- if (freqNumerator == 1) {
- if (freqDenominator == 1) {
- contentView.everyDayRadioButton.isChecked = true
- } else {
- contentView.everyXDaysRadioButton.isChecked = true
- contentView.everyXDaysTextView.setText(freqDenominator.toString())
- focus(contentView.everyXDaysTextView)
- }
+ if (freqDenominator == 30 || freqDenominator == 31) {
+ contentView.xTimesPerMonthRadioButton.isChecked = true
+ contentView.xTimesPerMonthTextView.setText(freqNumerator.toString())
+ focus(contentView.xTimesPerMonthTextView)
} else {
- if (freqDenominator == 7) {
- contentView.xTimesPerWeekRadioButton.isChecked = true
- contentView.xTimesPerWeekTextView.setText(freqNumerator.toString())
- focus(contentView.xTimesPerWeekTextView)
- } else if (freqDenominator == 30 || freqDenominator == 31) {
- contentView.xTimesPerMonthRadioButton.isChecked = true
- contentView.xTimesPerMonthTextView.setText(freqNumerator.toString())
- focus(contentView.xTimesPerMonthTextView)
+ if (freqNumerator == 1) {
+ if (freqDenominator == 1) {
+ contentView.everyDayRadioButton.isChecked = true
+ } else {
+ contentView.everyXDaysRadioButton.isChecked = true
+ contentView.everyXDaysTextView.setText(freqDenominator.toString())
+ focus(contentView.everyXDaysTextView)
+ }
} else {
- Log.w("FrequencyPickerDialog", "Unknown frequency: $freqNumerator/$freqDenominator")
- contentView.everyDayRadioButton.isChecked = true
+ if (freqDenominator == 7) {
+ contentView.xTimesPerWeekRadioButton.isChecked = true
+ contentView.xTimesPerWeekTextView.setText(freqNumerator.toString())
+ focus(contentView.xTimesPerWeekTextView)
+ } else {
+ Log.w("FrequencyPickerDialog", "Unknown frequency: $freqNumerator/$freqDenominator")
+ contentView.everyDayRadioButton.isChecked = true
+ }
}
}
}
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
index 289caa867..c5e432b1f 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt
@@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.edit
import android.annotation.SuppressLint
import android.content.res.ColorStateList
+import android.content.res.Resources
import android.graphics.Color
import android.os.Bundle
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.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() {
private lateinit var themeSwitcher: AndroidThemeSwitcher
@@ -299,14 +310,7 @@ class EditHabitActivity : AppCompatActivity() {
@SuppressLint("StringFormatMatches")
private fun populateFrequency() {
- binding.booleanFrequencyPicker.text = when {
- 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.booleanFrequencyPicker.text = formatFrequency(freqNum, freqDen, resources)
binding.numericalFrequencyPicker.text = when (freqDen) {
1 -> getString(R.string.every_day)
7 -> getString(R.string.every_week)
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt
index 7b0cc407b..0673017e8 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt
@@ -20,14 +20,13 @@ package org.isoron.uhabits.activities.habits.show.views
import android.annotation.SuppressLint
import android.content.Context
-import android.content.res.Resources
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
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.core.models.Frequency
import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardState
import org.isoron.uhabits.databinding.ShowHabitSubtitleBinding
import org.isoron.uhabits.utils.InterfaceUtils
@@ -49,7 +48,11 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
fun setState(state: SubtitleCardState) {
val color = state.color.toThemedAndroidColor(context)
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.text = state.question
binding.reminderLabel.text = if (reminder != null) {
@@ -72,32 +75,4 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con
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"
- }
}
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
index 7ec0b8485..5df329a95 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
@@ -63,13 +63,14 @@ class PendingIntentFactory
FLAG_UPDATE_CURRENT
)
- fun removeRepetition(habit: Habit): PendingIntent =
+ fun removeRepetition(habit: Habit, timestamp: Timestamp?): PendingIntent =
getBroadcast(
context,
3,
Intent(context, WidgetReceiver::class.java).apply {
action = WidgetReceiver.ACTION_REMOVE_REPETITION
data = Uri.parse(habit.uriString)
+ if (timestamp != null) putExtra("timestamp", timestamp.unixTime)
},
FLAG_UPDATE_CURRENT
)
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
index de1c23d24..04f3d8d92 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
@@ -107,7 +107,7 @@ class AndroidNotificationTray
val removeRepetitionAction = Action(
R.drawable.ic_action_cancel,
context.getString(R.string.no),
- pendingIntents.removeRepetition(habit)
+ pendingIntents.removeRepetition(habit, timestamp)
)
val enterAction = Action(
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt
index 2383b3683..ff743816b 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt
@@ -31,6 +31,7 @@ import android.widget.ListView
import android.widget.TextView
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
+import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.isoron.uhabits.widgets.WidgetUpdater
import java.util.ArrayList
@@ -58,6 +59,7 @@ open class HabitPickerDialog : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val component = (applicationContext as HabitsApplication).component
+ AndroidThemeSwitcher(this, component.preferences).apply()
val habitList = component.habitList
widgetPreferences = component.widgetPreferences
widgetUpdater = component.widgetUpdater
diff --git a/uhabits-android/src/main/res/values/styles.xml b/uhabits-android/src/main/res/values/styles.xml
index 2f8eb6e21..9bba46775 100644
--- a/uhabits-android/src/main/res/values/styles.xml
+++ b/uhabits-android/src/main/res/values/styles.xml
@@ -129,6 +129,7 @@
- @drawable/selected_box
- @color/grey_100
- @color/black
+ - @style/PreferenceThemeOverlay.v14.Material.PureBlack
+
+
+