mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Merge branch 'hotfix/2.0.3' into dev
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# 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
|
## [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")
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AndroidCanvas : Canvas {
|
|||||||
var innerDensity = 1.0
|
var innerDensity = 1.0
|
||||||
var innerWidth = 0
|
var innerWidth = 0
|
||||||
var innerHeight = 0
|
var innerHeight = 0
|
||||||
|
var mHeight = 15
|
||||||
|
|
||||||
var paint = Paint().apply {
|
var paint = Paint().apply {
|
||||||
isAntiAlias = true
|
isAntiAlias = true
|
||||||
@@ -64,11 +65,10 @@ class AndroidCanvas : Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawText(text: String, x: Double, y: Double) {
|
override fun drawText(text: String, x: Double, y: Double) {
|
||||||
textPaint.getTextBounds(text, 0, text.length, textBounds)
|
|
||||||
innerCanvas.drawText(
|
innerCanvas.drawText(
|
||||||
text,
|
text,
|
||||||
x.toDp(),
|
x.toDp(),
|
||||||
y.toDp() - textBounds.exactCenterY(),
|
y.toDp() + 0.6f * mHeight,
|
||||||
textPaint,
|
textPaint,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -126,10 +126,17 @@ class AndroidCanvas : Canvas {
|
|||||||
Font.BOLD -> Typeface.DEFAULT_BOLD
|
Font.BOLD -> Typeface.DEFAULT_BOLD
|
||||||
Font.FONT_AWESOME -> getFontAwesome(context)
|
Font.FONT_AWESOME -> getFontAwesome(context)
|
||||||
}
|
}
|
||||||
|
updateMHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setFontSize(size: Double) {
|
override fun setFontSize(size: Double) {
|
||||||
textPaint.textSize = size.toDp()
|
textPaint.textSize = size.toDp()
|
||||||
|
updateMHeight()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateMHeight() {
|
||||||
|
textPaint.getTextBounds("m", 0, 1, textBounds)
|
||||||
|
mHeight = textBounds.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setStrokeWidth(size: Double) {
|
override fun setStrokeWidth(size: Double) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.isoron.uhabits.core.preferences.Preferences
|
|||||||
import org.isoron.uhabits.core.ui.ThemeSwitcher
|
import org.isoron.uhabits.core.ui.ThemeSwitcher
|
||||||
import org.isoron.uhabits.core.ui.views.DarkTheme
|
import org.isoron.uhabits.core.ui.views.DarkTheme
|
||||||
import org.isoron.uhabits.core.ui.views.LightTheme
|
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.core.ui.views.Theme
|
||||||
import org.isoron.uhabits.inject.ActivityContext
|
import org.isoron.uhabits.inject.ActivityContext
|
||||||
import org.isoron.uhabits.inject.ActivityScope
|
import org.isoron.uhabits.inject.ActivityScope
|
||||||
@@ -66,7 +67,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun applyPureBlackTheme() {
|
override fun applyPureBlackTheme() {
|
||||||
currentTheme = DarkTheme()
|
currentTheme = PureBlackTheme()
|
||||||
context.setTheme(R.style.AppBaseThemeDark_PureBlack)
|
context.setTheme(R.style.AppBaseThemeDark_PureBlack)
|
||||||
(context as Activity).window.navigationBarColor =
|
(context as Activity).window.navigationBarColor =
|
||||||
ContextCompat.getColor(context, R.color.black)
|
ContextCompat.getColor(context, R.color.black)
|
||||||
|
|||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,13 +63,14 @@ class PendingIntentFactory
|
|||||||
FLAG_UPDATE_CURRENT
|
FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
|
||||||
fun removeRepetition(habit: Habit): PendingIntent =
|
fun removeRepetition(habit: Habit, timestamp: Timestamp?): PendingIntent =
|
||||||
getBroadcast(
|
getBroadcast(
|
||||||
context,
|
context,
|
||||||
3,
|
3,
|
||||||
Intent(context, WidgetReceiver::class.java).apply {
|
Intent(context, WidgetReceiver::class.java).apply {
|
||||||
action = WidgetReceiver.ACTION_REMOVE_REPETITION
|
action = WidgetReceiver.ACTION_REMOVE_REPETITION
|
||||||
data = Uri.parse(habit.uriString)
|
data = Uri.parse(habit.uriString)
|
||||||
|
if (timestamp != null) putExtra("timestamp", timestamp.unixTime)
|
||||||
},
|
},
|
||||||
FLAG_UPDATE_CURRENT
|
FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class AndroidNotificationTray
|
|||||||
val removeRepetitionAction = Action(
|
val removeRepetitionAction = Action(
|
||||||
R.drawable.ic_action_cancel,
|
R.drawable.ic_action_cancel,
|
||||||
context.getString(R.string.no),
|
context.getString(R.string.no),
|
||||||
pendingIntents.removeRepetition(habit)
|
pendingIntents.removeRepetition(habit, timestamp)
|
||||||
)
|
)
|
||||||
|
|
||||||
val enterAction = Action(
|
val enterAction = Action(
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.widget.ListView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import org.isoron.uhabits.HabitsApplication
|
import org.isoron.uhabits.HabitsApplication
|
||||||
import org.isoron.uhabits.R
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
||||||
import org.isoron.uhabits.core.preferences.WidgetPreferences
|
import org.isoron.uhabits.core.preferences.WidgetPreferences
|
||||||
import org.isoron.uhabits.widgets.WidgetUpdater
|
import org.isoron.uhabits.widgets.WidgetUpdater
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
@@ -58,6 +59,7 @@ open class HabitPickerDialog : Activity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val component = (applicationContext as HabitsApplication).component
|
val component = (applicationContext as HabitsApplication).component
|
||||||
|
AndroidThemeSwitcher(this, component.preferences).apply()
|
||||||
val habitList = component.habitList
|
val habitList = component.habitList
|
||||||
widgetPreferences = component.widgetPreferences
|
widgetPreferences = component.widgetPreferences
|
||||||
widgetUpdater = component.widgetUpdater
|
widgetUpdater = component.widgetUpdater
|
||||||
|
|||||||
@@ -129,6 +129,7 @@
|
|||||||
<item name="selectedBackground">@drawable/selected_box</item>
|
<item name="selectedBackground">@drawable/selected_box</item>
|
||||||
<item name="textColorAlertDialogListItem">@color/grey_100</item>
|
<item name="textColorAlertDialogListItem">@color/grey_100</item>
|
||||||
<item name="windowBackgroundColor">@color/black</item>
|
<item name="windowBackgroundColor">@color/black</item>
|
||||||
|
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material.PureBlack</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="BaseDialog" parent="Theme.AppCompat.Light.Dialog">
|
<style name="BaseDialog" parent="Theme.AppCompat.Light.Dialog">
|
||||||
@@ -151,6 +152,11 @@
|
|||||||
<item name="palette">@array/darkPalette</item>
|
<item name="palette">@array/darkPalette</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="PreferenceThemeOverlay.v14.Material.PureBlack">
|
||||||
|
<item name="android:background">@color/black</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="WidgetTheme" parent="AppBaseThemeDark">
|
<style name="WidgetTheme" parent="AppBaseThemeDark">
|
||||||
<item name="cardBgColor">@color/grey_850</item>
|
<item name="cardBgColor">@color/grey_850</item>
|
||||||
<item name="contrast0">@color/white</item>
|
<item name="contrast0">@color/white</item>
|
||||||
|
|||||||
@@ -72,10 +72,20 @@ 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
|
||||||
|
if (daysSince2000 < 0) {
|
||||||
|
currYear -= 400
|
||||||
|
currDay -= 146097
|
||||||
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
val currYearLength = if (isLeapYear(currYear)) 366 else 365
|
val currYearLength = if (isLeapYear(currYear)) 366 else 365
|
||||||
if (daysSince2000 < currDay + currYearLength) {
|
if (daysSince2000 < currDay + currYearLength) {
|
||||||
@@ -86,10 +96,8 @@ data class LocalDate(val daysSince2000: Int) {
|
|||||||
currDay += currYearLength
|
currDay += currYearLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var currMonth = 1
|
var currMonth = 1
|
||||||
val monthOffset = if (isLeapYear(currYear)) leapOffset else nonLeapOffset
|
val monthOffset = if (isLeapYear(currYear)) leapOffset else nonLeapOffset
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (daysSince2000 < currDay + monthOffset[currMonth]) {
|
if (daysSince2000 < currDay + monthOffset[currMonth]) {
|
||||||
monthCache = currMonth
|
monthCache = currMonth
|
||||||
@@ -98,7 +106,6 @@ data class LocalDate(val daysSince2000: Int) {
|
|||||||
currMonth++
|
currMonth++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currDay += monthOffset[currMonth - 1]
|
currDay += monthOffset[currMonth - 1]
|
||||||
dayCache = daysSince2000 - currDay + 1
|
dayCache = daysSince2000 - currDay + 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,12 @@ open class DarkTheme : Theme() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PureBlackTheme : DarkTheme() {
|
||||||
|
override val appBackgroundColor = Color(0x000000)
|
||||||
|
override val cardBackgroundColor = Color(0x000000)
|
||||||
|
override val lowContrastTextColor = Color(0x212121)
|
||||||
|
}
|
||||||
|
|
||||||
class WidgetTheme : LightTheme() {
|
class WidgetTheme : LightTheme() {
|
||||||
override val cardBackgroundColor = Color.TRANSPARENT
|
override val cardBackgroundColor = Color.TRANSPARENT
|
||||||
override val highContrastTextColor = Color.WHITE
|
override val highContrastTextColor = Color.WHITE
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker 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, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.platform.gui
|
||||||
|
|
||||||
|
import org.isoron.platform.time.LocalDate
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DatesTest {
|
||||||
|
@Test
|
||||||
|
fun testDatesBefore2000() {
|
||||||
|
val date = LocalDate(-1)
|
||||||
|
assertEquals(date.day, 31)
|
||||||
|
assertEquals(date.month, 12)
|
||||||
|
assertEquals(date.year, 1999)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user