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 + + +