Compare commits
16 Commits
53c270ee12
...
release/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
ec1f0c5356
|
|||
|
961fb7618f
|
|||
|
11f726064a
|
|||
| abced92a07 | |||
|
|
eeacc5eef8 | ||
|
|
16c65f19fd | ||
| fc402fd81b | |||
| f7c6bc716c | |||
| 2535347d5a | |||
| 13af054214 | |||
| fcbb586e80 | |||
|
|
428bf42e79 | ||
| 838e13f30c | |||
| 0eae43fe55 | |||
| c0fcd4e763 | |||
| 79e2402c9d |
@@ -7,8 +7,9 @@
|
|||||||
- Allow user to add skips to measurable habits (@kalina559, #1319)
|
- Allow user to add skips to measurable habits (@kalina559, #1319)
|
||||||
- Bring back custom frequencies (x times in y days) (@hiqua, #1079)
|
- Bring back custom frequencies (x times in y days) (@hiqua, #1079)
|
||||||
- Improve number picker (@hiqua, @iSoron, #1082, #1370)
|
- Improve number picker (@hiqua, @iSoron, #1082, #1370)
|
||||||
- Add new checkmark state picker (@iSoron, #1370)
|
- Add new checkmark and number picker (@iSoron, #1370)
|
||||||
- Allow user to import numerical habits from HabitBull (@hiqua, #1278)
|
- Allow user to import numerical habits from HabitBull (@hiqua, #1278)
|
||||||
|
- Add support for Android 13 themed icons (@cheeeeer, #1497)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Hide snooze button Android 12 notifications (@hiqua, #1226)
|
- Hide snooze button Android 12 notifications (@hiqua, #1226)
|
||||||
@@ -20,19 +21,21 @@
|
|||||||
- Add delay after toggling a habit (@hiqua, @kalina559, #1147)
|
- Add delay after toggling a habit (@hiqua, @kalina559, #1147)
|
||||||
- Small theme improvements (@KristianTashkov, #1113)
|
- Small theme improvements (@KristianTashkov, #1113)
|
||||||
- Left-align habit notes (@iSoron)
|
- Left-align habit notes (@iSoron)
|
||||||
|
- Increase target SDK to 31 (@hiqua)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix small dialog buttons (@kalina559, #1096)
|
- Fix small dialog buttons (@kalina559, #1096)
|
||||||
- Fix invalid CSV files (@hiqua, #1177)
|
- Fix invalid CSV files (@hiqua, #1177)
|
||||||
- Fix small issues in calendar chart (@kalina559, #1314)
|
- Fix small issues in calendar chart (@kalina559, #1314)
|
||||||
- Resort habit list after edit (@hiqua, #1350)
|
- Resort habit list after edit (@hiqua, #1350)
|
||||||
|
- Fix marker scaling in frequency display (@eduebernal, #1425)
|
||||||
|
- Fix widgets not working correctly on API 33 (@iSoron, #1488)
|
||||||
|
|
||||||
### Refactoring & Testing
|
### Refactoring & Testing
|
||||||
- Replace raster icons by vector assets (@kalina559)
|
- Replace raster icons by vector assets (@kalina559)
|
||||||
- Remove JVM dependencies from uhabits-core module (@sgallese)
|
- Remove JVM dependencies from uhabits-core module (@sgallese)
|
||||||
- Add various missing tests (@sgallese)
|
- Add various missing tests (@sgallese)
|
||||||
- Upgrade project dependencies (@hiqua, @sgallese)
|
- Upgrade project dependencies (@hiqua, @sgallese)
|
||||||
- Increase target SDK to 31 (@hiqua)
|
|
||||||
|
|
||||||
## [2.0.3] - 2021-08-21
|
## [2.0.3] - 2021-08-21
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 22 KiB |
@@ -119,18 +119,6 @@
|
|||||||
android:value=".activities.habits.list.ListHabitsActivity" />
|
android:value=".activities.habits.list.ListHabitsActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".widgets.activities.NumericalCheckmarkWidgetActivity"
|
|
||||||
android:excludeFromRecents="true"
|
|
||||||
android:exported="true"
|
|
||||||
android:label="NumericalCheckmarkWidget"
|
|
||||||
android:noHistory="true"
|
|
||||||
android:theme="@style/Theme.Transparent">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".notifications.SnoozeDelayPickerActivity"
|
android:name=".notifications.SnoozeDelayPickerActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import org.isoron.uhabits.core.preferences.Preferences
|
|||||||
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome
|
import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome
|
||||||
import org.isoron.uhabits.utils.dimBehind
|
import org.isoron.uhabits.utils.dimBehind
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
import org.isoron.uhabits.utils.dp
|
import org.isoron.uhabits.utils.dp
|
||||||
import org.isoron.uhabits.utils.sres
|
import org.isoron.uhabits.utils.sres
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ class CheckmarkPopup(
|
|||||||
view.unknownBtn.setOnClickListener { onClick(UNKNOWN) }
|
view.unknownBtn.setOnClickListener { onClick(UNKNOWN) }
|
||||||
dialog.setCanceledOnTouchOutside(true)
|
dialog.setCanceledOnTouchOutside(true)
|
||||||
dialog.dimBehind()
|
dialog.dimBehind()
|
||||||
dialog.show()
|
dialog.dismissCurrentAndShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
|
|||||||
@@ -149,8 +149,10 @@ class FrequencyPickerDialog(
|
|||||||
}
|
}
|
||||||
contentView.xTimesPerYDaysRadioButton.isChecked -> {
|
contentView.xTimesPerYDaysRadioButton.isChecked -> {
|
||||||
if (contentView.xTimesPerYDaysXTextView.text.isNotEmpty() && contentView.xTimesPerYDaysYTextView.text.isNotEmpty()) {
|
if (contentView.xTimesPerYDaysXTextView.text.isNotEmpty() && contentView.xTimesPerYDaysYTextView.text.isNotEmpty()) {
|
||||||
numerator = Integer.parseInt(contentView.xTimesPerYDaysXTextView.text.toString())
|
numerator =
|
||||||
denominator = Integer.parseInt(contentView.xTimesPerYDaysYTextView.text.toString())
|
Integer.parseInt(contentView.xTimesPerYDaysXTextView.text.toString())
|
||||||
|
denominator =
|
||||||
|
Integer.parseInt(contentView.xTimesPerYDaysYTextView.text.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package org.isoron.uhabits.activities.common.dialogs
|
package org.isoron.uhabits.activities.common.dialogs
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment
|
import androidx.appcompat.app.AppCompatDialogFragment
|
||||||
import org.isoron.platform.gui.AndroidDataView
|
import org.isoron.platform.gui.AndroidDataView
|
||||||
@@ -49,6 +50,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
|
|||||||
private var onDateClickedListener: OnDateClickedListener? = null
|
private var onDateClickedListener: OnDateClickedListener? = null
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
clearCurrentDialog()
|
||||||
val component = (activity!!.application as HabitsApplication).component
|
val component = (activity!!.application as HabitsApplication).component
|
||||||
commandRunner = component.commandRunner
|
commandRunner = component.commandRunner
|
||||||
habit = component.habitList.getById(arguments!!.getLong("habit"))!!
|
habit = component.habitList.getById(arguments!!.getLong("habit"))!!
|
||||||
@@ -72,12 +74,20 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
|
|||||||
dataView = AndroidDataView(context!!, null)
|
dataView = AndroidDataView(context!!, null)
|
||||||
dataView.view = chart!!
|
dataView.view = chart!!
|
||||||
|
|
||||||
return Dialog(context!!).apply {
|
val dialog = Dialog(context!!).apply {
|
||||||
val metrics = resources.displayMetrics
|
val metrics = resources.displayMetrics
|
||||||
val maxHeight = resources.getDimensionPixelSize(R.dimen.history_editor_max_height)
|
val maxHeight = resources.getDimensionPixelSize(R.dimen.history_editor_max_height)
|
||||||
setContentView(dataView)
|
setContentView(dataView)
|
||||||
window!!.setLayout(metrics.widthPixels, min(metrics.heightPixels, maxHeight))
|
window!!.setLayout(metrics.widthPixels, min(metrics.heightPixels, maxHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentDialog = dialog
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
currentDialog = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -111,4 +121,14 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
|
|||||||
override fun onCommandFinished(command: Command) {
|
override fun onCommandFinished(command: Command) {
|
||||||
refreshData()
|
refreshData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// HistoryEditorDialog handles multiple dialogs on its own,
|
||||||
|
// because sometimes we want it to be shown under another dialog (e.g. NumberPopup)
|
||||||
|
var currentDialog: Dialog? = null
|
||||||
|
fun clearCurrentDialog() {
|
||||||
|
currentDialog?.dismiss()
|
||||||
|
currentDialog = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.isoron.uhabits.core.models.Entry
|
|||||||
import org.isoron.uhabits.core.preferences.Preferences
|
import org.isoron.uhabits.core.preferences.Preferences
|
||||||
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
||||||
import org.isoron.uhabits.utils.dimBehind
|
import org.isoron.uhabits.utils.dimBehind
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
import org.isoron.uhabits.utils.dp
|
import org.isoron.uhabits.utils.dp
|
||||||
import org.isoron.uhabits.utils.requestFocusWithKeyboard
|
import org.isoron.uhabits.utils.requestFocusWithKeyboard
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
@@ -43,6 +44,7 @@ class NumberPopup(
|
|||||||
private val anchor: View,
|
private val anchor: View,
|
||||||
) {
|
) {
|
||||||
var onToggle: (Double, String) -> Unit = { _, _ -> }
|
var onToggle: (Double, String) -> Unit = { _, _ -> }
|
||||||
|
var onDismiss: () -> Unit = {}
|
||||||
private val originalValue = value
|
private val originalValue = value
|
||||||
private lateinit var dialog: Dialog
|
private lateinit var dialog: Dialog
|
||||||
|
|
||||||
@@ -81,6 +83,9 @@ class NumberPopup(
|
|||||||
)
|
)
|
||||||
setBackgroundDrawableResource(android.R.color.transparent)
|
setBackgroundDrawableResource(android.R.color.transparent)
|
||||||
}
|
}
|
||||||
|
dialog.setOnDismissListener {
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
|
||||||
view.value.setOnKeyListener { _, keyCode, event ->
|
view.value.setOnKeyListener { _, keyCode, event ->
|
||||||
if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) {
|
if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) {
|
||||||
@@ -99,7 +104,7 @@ class NumberPopup(
|
|||||||
view.value.requestFocusWithKeyboard()
|
view.value.requestFocusWithKeyboard()
|
||||||
dialog.setCanceledOnTouchOutside(true)
|
dialog.setCanceledOnTouchOutside(true)
|
||||||
dialog.dimBehind()
|
dialog.dimBehind()
|
||||||
dialog.show()
|
dialog.dismissCurrentAndShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class WeekdayPickerDialog :
|
|||||||
.setNegativeButton(
|
.setNegativeButton(
|
||||||
android.R.string.cancel
|
android.R.string.cancel
|
||||||
) { _: DialogInterface?, _: Int -> dismiss() }
|
) { _: DialogInterface?, _: Int -> dismiss() }
|
||||||
|
|
||||||
return builder.create()
|
return builder.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.isoron.uhabits.core.utils.DateUtils.Companion.getShortWeekdayNames
|
|||||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar
|
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar
|
||||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendarWithOffset
|
import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendarWithOffset
|
||||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getWeekdaySequence
|
import org.isoron.uhabits.core.utils.DateUtils.Companion.getWeekdaySequence
|
||||||
|
import org.isoron.uhabits.core.utils.DateUtils.Companion.getWeekdaysInMonth
|
||||||
import org.isoron.uhabits.utils.ColorUtils.mixColors
|
import org.isoron.uhabits.utils.ColorUtils.mixColors
|
||||||
import org.isoron.uhabits.utils.StyledResources
|
import org.isoron.uhabits.utils.StyledResources
|
||||||
import org.isoron.uhabits.utils.toSimpleDataFormat
|
import org.isoron.uhabits.utils.toSimpleDataFormat
|
||||||
@@ -64,6 +65,7 @@ class FrequencyChart : ScrollableChart {
|
|||||||
private lateinit var frequency: HashMap<Timestamp, Array<Int>>
|
private lateinit var frequency: HashMap<Timestamp, Array<Int>>
|
||||||
private var maxFreq = 0
|
private var maxFreq = 0
|
||||||
private var firstWeekday = Calendar.SUNDAY
|
private var firstWeekday = Calendar.SUNDAY
|
||||||
|
private var isNumerical: Boolean = false
|
||||||
|
|
||||||
constructor(context: Context?) : super(context) {
|
constructor(context: Context?) : super(context) {
|
||||||
init()
|
init()
|
||||||
@@ -80,6 +82,11 @@ class FrequencyChart : ScrollableChart {
|
|||||||
postInvalidate()
|
postInvalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setIsNumerical(type: Boolean) {
|
||||||
|
isNumerical = type
|
||||||
|
postInvalidate()
|
||||||
|
}
|
||||||
|
|
||||||
fun setFrequency(frequency: java.util.HashMap<Timestamp, Array<Int>>) {
|
fun setFrequency(frequency: java.util.HashMap<Timestamp, Array<Int>>) {
|
||||||
this.frequency = frequency
|
this.frequency = frequency
|
||||||
maxFreq = getMaxFreq(frequency)
|
maxFreq = getMaxFreq(frequency)
|
||||||
@@ -166,6 +173,7 @@ class FrequencyChart : ScrollableChart {
|
|||||||
|
|
||||||
private fun drawColumn(canvas: Canvas, rect: RectF?, date: GregorianCalendar) {
|
private fun drawColumn(canvas: Canvas, rect: RectF?, date: GregorianCalendar) {
|
||||||
val values = frequency[Timestamp(date)]
|
val values = frequency[Timestamp(date)]
|
||||||
|
val weekDaysInMonth = getWeekdaysInMonth(Timestamp(date))
|
||||||
val rowHeight = rect!!.height() / 8.0f
|
val rowHeight = rect!!.height() / 8.0f
|
||||||
prevRect!!.set(rect)
|
prevRect!!.set(rect)
|
||||||
val localeWeekdayList: Array<Int> = getWeekdaySequence(firstWeekday)
|
val localeWeekdayList: Array<Int> = getWeekdaySequence(firstWeekday)
|
||||||
@@ -174,7 +182,7 @@ class FrequencyChart : ScrollableChart {
|
|||||||
rect.offset(prevRect!!.left, prevRect!!.top + baseSize * j)
|
rect.offset(prevRect!!.left, prevRect!!.top + baseSize * j)
|
||||||
val i = localeWeekdayList[j] % 7
|
val i = localeWeekdayList[j] % 7
|
||||||
if (values != null)
|
if (values != null)
|
||||||
drawMarker(canvas, rect, values[i])
|
drawMarker(canvas, rect, values[i], weekDaysInMonth[i])
|
||||||
rect.offset(0f, rowHeight)
|
rect.offset(0f, rowHeight)
|
||||||
}
|
}
|
||||||
drawFooter(canvas, rect, date)
|
drawFooter(canvas, rect, date)
|
||||||
@@ -222,7 +230,7 @@ class FrequencyChart : ScrollableChart {
|
|||||||
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid!!)
|
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawMarker(canvas: Canvas, rect: RectF?, value: Int?) {
|
private fun drawMarker(canvas: Canvas, rect: RectF?, value: Int?, weekdayFrequency: Int) {
|
||||||
// value can be negative when the entry is skipped
|
// value can be negative when the entry is skipped
|
||||||
val valueCopy = value?.let { max(0, it) }
|
val valueCopy = value?.let { max(0, it) }
|
||||||
|
|
||||||
@@ -230,7 +238,8 @@ class FrequencyChart : ScrollableChart {
|
|||||||
// maximal allowed mark radius
|
// maximal allowed mark radius
|
||||||
val maxRadius = (rect.height() - 2 * padding) / 2.0f
|
val maxRadius = (rect.height() - 2 * padding) / 2.0f
|
||||||
// the real mark radius is scaled down by a factor depending on the maximal frequency
|
// the real mark radius is scaled down by a factor depending on the maximal frequency
|
||||||
val scale = 1.0f / maxFreq * valueCopy!!
|
val scalingFactor = if (isNumerical) maxFreq else weekdayFrequency
|
||||||
|
val scale = 1.0f / scalingFactor * valueCopy!!
|
||||||
val radius = maxRadius * scale
|
val radius = maxRadius * scale
|
||||||
val colorIndex = min((colors.size - 1), ((colors.size - 1) * scale).roundToInt())
|
val colorIndex = min((colors.size - 1), ((colors.size - 1) * scale).roundToInt())
|
||||||
pGraph!!.color = colors[colorIndex]
|
pGraph!!.color = colors[colorIndex]
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import org.isoron.uhabits.core.models.Reminder
|
|||||||
import org.isoron.uhabits.core.models.WeekdayList
|
import org.isoron.uhabits.core.models.WeekdayList
|
||||||
import org.isoron.uhabits.databinding.ActivityEditHabitBinding
|
import org.isoron.uhabits.databinding.ActivityEditHabitBinding
|
||||||
import org.isoron.uhabits.utils.ColorUtils
|
import org.isoron.uhabits.utils.ColorUtils
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
import org.isoron.uhabits.utils.formatTime
|
import org.isoron.uhabits.utils.formatTime
|
||||||
import org.isoron.uhabits.utils.toFormattedString
|
import org.isoron.uhabits.utils.toFormattedString
|
||||||
|
|
||||||
@@ -156,23 +157,23 @@ class EditHabitActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val colorPickerDialogFactory = ColorPickerDialogFactory(this)
|
val colorPickerDialogFactory = ColorPickerDialogFactory(this)
|
||||||
binding.colorButton.setOnClickListener {
|
binding.colorButton.setOnClickListener {
|
||||||
val dialog = colorPickerDialogFactory.create(color, themeSwitcher.currentTheme)
|
val picker = colorPickerDialogFactory.create(color, themeSwitcher.currentTheme)
|
||||||
dialog.setListener { paletteColor ->
|
picker.setListener { paletteColor ->
|
||||||
this.color = paletteColor
|
this.color = paletteColor
|
||||||
updateColors()
|
updateColors()
|
||||||
}
|
}
|
||||||
dialog.show(supportFragmentManager, "colorPicker")
|
picker.dismissCurrentAndShow(supportFragmentManager, "colorPicker")
|
||||||
}
|
}
|
||||||
|
|
||||||
populateFrequency()
|
populateFrequency()
|
||||||
binding.booleanFrequencyPicker.setOnClickListener {
|
binding.booleanFrequencyPicker.setOnClickListener {
|
||||||
val dialog = FrequencyPickerDialog(freqNum, freqDen)
|
val picker = FrequencyPickerDialog(freqNum, freqDen)
|
||||||
dialog.onFrequencyPicked = { num, den ->
|
picker.onFrequencyPicked = { num, den ->
|
||||||
freqNum = num
|
freqNum = num
|
||||||
freqDen = den
|
freqDen = den
|
||||||
populateFrequency()
|
populateFrequency()
|
||||||
}
|
}
|
||||||
dialog.show(supportFragmentManager, "frequencyPicker")
|
picker.dismissCurrentAndShow(supportFragmentManager, "frequencyPicker")
|
||||||
}
|
}
|
||||||
|
|
||||||
populateTargetType()
|
populateTargetType()
|
||||||
@@ -189,7 +190,8 @@ class EditHabitActivity : AppCompatActivity() {
|
|||||||
populateTargetType()
|
populateTargetType()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
builder.show()
|
val dialog = builder.create()
|
||||||
|
dialog.dismissCurrentAndShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.numericalFrequencyPicker.setOnClickListener {
|
binding.numericalFrequencyPicker.setOnClickListener {
|
||||||
@@ -235,7 +237,7 @@ class EditHabitActivity : AppCompatActivity() {
|
|||||||
is24HourMode,
|
is24HourMode,
|
||||||
androidColor
|
androidColor
|
||||||
)
|
)
|
||||||
dialog.show(supportFragmentManager, "timePicker")
|
dialog.dismissCurrentAndShow(supportFragmentManager, "timePicker")
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.reminderDatePicker.setOnClickListener {
|
binding.reminderDatePicker.setOnClickListener {
|
||||||
@@ -247,7 +249,7 @@ class EditHabitActivity : AppCompatActivity() {
|
|||||||
populateReminder()
|
populateReminder()
|
||||||
}
|
}
|
||||||
dialog.setSelectedDays(reminderDays)
|
dialog.setSelectedDays(reminderDays)
|
||||||
dialog.show(supportFragmentManager, "dayPicker")
|
dialog.dismissCurrentAndShow(supportFragmentManager, "dayPicker")
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonSave.setOnClickListener {
|
binding.buttonSave.setOnClickListener {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.list
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@@ -29,6 +30,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import org.isoron.uhabits.BaseExceptionHandler
|
import org.isoron.uhabits.BaseExceptionHandler
|
||||||
import org.isoron.uhabits.HabitsApplication
|
import org.isoron.uhabits.HabitsApplication
|
||||||
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
|
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
|
||||||
|
import org.isoron.uhabits.core.models.Timestamp
|
||||||
import org.isoron.uhabits.core.preferences.Preferences
|
import org.isoron.uhabits.core.preferences.Preferences
|
||||||
import org.isoron.uhabits.core.tasks.TaskRunner
|
import org.isoron.uhabits.core.tasks.TaskRunner
|
||||||
import org.isoron.uhabits.core.ui.ThemeSwitcher.Companion.THEME_DARK
|
import org.isoron.uhabits.core.ui.ThemeSwitcher.Companion.THEME_DARK
|
||||||
@@ -36,11 +38,15 @@ import org.isoron.uhabits.core.utils.MidnightTimer
|
|||||||
import org.isoron.uhabits.database.AutoBackup
|
import org.isoron.uhabits.database.AutoBackup
|
||||||
import org.isoron.uhabits.inject.ActivityContextModule
|
import org.isoron.uhabits.inject.ActivityContextModule
|
||||||
import org.isoron.uhabits.inject.DaggerHabitsActivityComponent
|
import org.isoron.uhabits.inject.DaggerHabitsActivityComponent
|
||||||
|
import org.isoron.uhabits.inject.HabitsActivityComponent
|
||||||
|
import org.isoron.uhabits.inject.HabitsApplicationComponent
|
||||||
import org.isoron.uhabits.utils.restartWithFade
|
import org.isoron.uhabits.utils.restartWithFade
|
||||||
|
|
||||||
class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
||||||
|
|
||||||
var pureBlack: Boolean = false
|
var pureBlack: Boolean = false
|
||||||
|
lateinit var appComponent: HabitsApplicationComponent
|
||||||
|
lateinit var component: HabitsActivityComponent
|
||||||
lateinit var taskRunner: TaskRunner
|
lateinit var taskRunner: TaskRunner
|
||||||
lateinit var adapter: HabitCardListAdapter
|
lateinit var adapter: HabitCardListAdapter
|
||||||
lateinit var rootView: ListHabitsRootView
|
lateinit var rootView: ListHabitsRootView
|
||||||
@@ -59,8 +65,8 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val appComponent = (applicationContext as HabitsApplication).component
|
appComponent = (applicationContext as HabitsApplication).component
|
||||||
val component = DaggerHabitsActivityComponent
|
component = DaggerHabitsActivityComponent
|
||||||
.builder()
|
.builder()
|
||||||
.activityContextModule(ActivityContextModule(this))
|
.activityContextModule(ActivityContextModule(this))
|
||||||
.habitsApplicationComponent(appComponent)
|
.habitsApplicationComponent(appComponent)
|
||||||
@@ -94,11 +100,17 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
|||||||
rootView.postInvalidate()
|
rootView.postInvalidate()
|
||||||
midnightTimer.onResume()
|
midnightTimer.onResume()
|
||||||
taskRunner.run {
|
taskRunner.run {
|
||||||
AutoBackup(this@ListHabitsActivity).run()
|
try {
|
||||||
|
AutoBackup(this@ListHabitsActivity).run()
|
||||||
|
appComponent.widgetUpdater.updateWidgets()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("ListHabitActivity", "TaskRunner failed", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (prefs.theme == THEME_DARK && prefs.isPureBlackEnabled != pureBlack) {
|
if (prefs.theme == THEME_DARK && prefs.isPureBlackEnabled != pureBlack) {
|
||||||
restartWithFade(ListHabitsActivity::class.java)
|
restartWithFade(ListHabitsActivity::class.java)
|
||||||
}
|
}
|
||||||
|
parseIntents()
|
||||||
super.onResume()
|
super.onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,4 +128,26 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
|||||||
super.onActivityResult(request, result, data)
|
super.onActivityResult(request, result, data)
|
||||||
screen.onResult(request, result, data)
|
screen.onResult(request, result, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseIntents() {
|
||||||
|
if (intent == null) return
|
||||||
|
if (intent.action == ACTION_EDIT) {
|
||||||
|
val habitId = intent.extras?.getLong("habit")
|
||||||
|
val timestamp = intent.extras?.getLong("timestamp")
|
||||||
|
if (habitId != null && timestamp != null) {
|
||||||
|
val habit = appComponent.habitList.getById(habitId)!!
|
||||||
|
component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intent = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent?) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
setIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ACTION_EDIT = "org.isoron.uhabits.ACTION_EDIT"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import org.isoron.uhabits.tasks.ImportDataTask
|
|||||||
import org.isoron.uhabits.tasks.ImportDataTaskFactory
|
import org.isoron.uhabits.tasks.ImportDataTaskFactory
|
||||||
import org.isoron.uhabits.utils.copyTo
|
import org.isoron.uhabits.utils.copyTo
|
||||||
import org.isoron.uhabits.utils.currentTheme
|
import org.isoron.uhabits.utils.currentTheme
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
import org.isoron.uhabits.utils.restartWithFade
|
import org.isoron.uhabits.utils.restartWithFade
|
||||||
import org.isoron.uhabits.utils.showMessage
|
import org.isoron.uhabits.utils.showMessage
|
||||||
import org.isoron.uhabits.utils.showSendEmailScreen
|
import org.isoron.uhabits.utils.showSendEmailScreen
|
||||||
@@ -163,7 +164,7 @@ class ListHabitsScreen
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback, quantity: Int) {
|
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback, quantity: Int) {
|
||||||
ConfirmDeleteDialog(activity, callback, quantity).show()
|
ConfirmDeleteDialog(activity, callback, quantity).dismissCurrentAndShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showEditHabitsScreen(selected: List<Habit>) {
|
override fun showEditHabitsScreen(selected: List<Habit>) {
|
||||||
@@ -224,7 +225,7 @@ class ListHabitsScreen
|
|||||||
override fun showColorPicker(defaultColor: PaletteColor, callback: OnColorPickedCallback) {
|
override fun showColorPicker(defaultColor: PaletteColor, callback: OnColorPickedCallback) {
|
||||||
val picker = colorPickerFactory.create(defaultColor, themeSwitcher.currentTheme!!)
|
val picker = colorPickerFactory.create(defaultColor, themeSwitcher.currentTheme!!)
|
||||||
picker.setListener(callback)
|
picker.setListener(callback)
|
||||||
picker.show(activity.supportFragmentManager, "picker")
|
picker.dismissCurrentAndShow(activity.supportFragmentManager, "picker")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showNumberPopup(
|
override fun showNumberPopup(
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter
|
|||||||
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
|
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
|
||||||
import org.isoron.uhabits.intents.IntentFactory
|
import org.isoron.uhabits.intents.IntentFactory
|
||||||
import org.isoron.uhabits.utils.currentTheme
|
import org.isoron.uhabits.utils.currentTheme
|
||||||
|
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||||
import org.isoron.uhabits.utils.showMessage
|
import org.isoron.uhabits.utils.showMessage
|
||||||
import org.isoron.uhabits.utils.showSendFileScreen
|
import org.isoron.uhabits.utils.showSendFileScreen
|
||||||
import org.isoron.uhabits.widgets.WidgetUpdater
|
import org.isoron.uhabits.widgets.WidgetUpdater
|
||||||
@@ -228,7 +229,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback) {
|
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback) {
|
||||||
ConfirmDeleteDialog(this@ShowHabitActivity, callback, 1).show()
|
ConfirmDeleteDialog(this@ShowHabitActivity, callback, 1).dismissCurrentAndShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class FrequencyCardView(context: Context, attrs: AttributeSet) : LinearLayout(co
|
|||||||
fun setState(state: FrequencyCardState) {
|
fun setState(state: FrequencyCardState) {
|
||||||
val androidColor = state.theme.color(state.color).toInt()
|
val androidColor = state.theme.color(state.color).toInt()
|
||||||
binding.frequencyChart.setFrequency(state.frequency)
|
binding.frequencyChart.setFrequency(state.frequency)
|
||||||
|
binding.frequencyChart.setIsNumerical(state.isNumerical)
|
||||||
binding.frequencyChart.setFirstWeekday(state.firstWeekday)
|
binding.frequencyChart.setFirstWeekday(state.firstWeekday)
|
||||||
binding.title.setTextColor(androidColor)
|
binding.title.setTextColor(androidColor)
|
||||||
binding.frequencyChart.setColor(androidColor)
|
binding.frequencyChart.setColor(androidColor)
|
||||||
|
|||||||
@@ -21,11 +21,16 @@ package org.isoron.uhabits.intents
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.PendingIntent.FLAG_IMMUTABLE
|
import android.app.PendingIntent.FLAG_IMMUTABLE
|
||||||
|
import android.app.PendingIntent.FLAG_MUTABLE
|
||||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
import android.app.PendingIntent.getActivity
|
||||||
import android.app.PendingIntent.getBroadcast
|
import android.app.PendingIntent.getBroadcast
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import org.isoron.uhabits.activities.habits.list.ListHabitsActivity
|
||||||
|
import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
|
||||||
import org.isoron.uhabits.core.AppScope
|
import org.isoron.uhabits.core.AppScope
|
||||||
import org.isoron.uhabits.core.models.Habit
|
import org.isoron.uhabits.core.models.Habit
|
||||||
import org.isoron.uhabits.core.models.Timestamp
|
import org.isoron.uhabits.core.models.Timestamp
|
||||||
@@ -87,6 +92,20 @@ class PendingIntentFactory
|
|||||||
)
|
)
|
||||||
.getPendingIntent(0, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)!!
|
.getPendingIntent(0, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)!!
|
||||||
|
|
||||||
|
fun showHabitTemplate(): PendingIntent {
|
||||||
|
return getActivity(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
Intent(context, ShowHabitActivity::class.java),
|
||||||
|
getIntentTemplateFlags()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showHabitFillIn(habit: Habit) =
|
||||||
|
Intent().apply {
|
||||||
|
data = Uri.parse(habit.uriString)
|
||||||
|
}
|
||||||
|
|
||||||
fun showReminder(
|
fun showReminder(
|
||||||
habit: Habit,
|
habit: Habit,
|
||||||
reminderTime: Long?,
|
reminderTime: Long?,
|
||||||
@@ -127,25 +146,6 @@ class PendingIntentFactory
|
|||||||
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
|
||||||
fun setNumericalValue(
|
|
||||||
widgetContext: Context,
|
|
||||||
habit: Habit,
|
|
||||||
numericalValue: Int,
|
|
||||||
timestamp: Long?
|
|
||||||
):
|
|
||||||
PendingIntent =
|
|
||||||
getBroadcast(
|
|
||||||
widgetContext,
|
|
||||||
2,
|
|
||||||
Intent(widgetContext, WidgetReceiver::class.java).apply {
|
|
||||||
data = Uri.parse(habit.uriString)
|
|
||||||
action = WidgetReceiver.ACTION_SET_NUMERICAL_VALUE
|
|
||||||
putExtra("numericalValue", numericalValue)
|
|
||||||
if (timestamp != null) putExtra("timestamp", timestamp)
|
|
||||||
},
|
|
||||||
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
|
||||||
)
|
|
||||||
|
|
||||||
fun updateWidgets(): PendingIntent =
|
fun updateWidgets(): PendingIntent =
|
||||||
getBroadcast(
|
getBroadcast(
|
||||||
context,
|
context,
|
||||||
@@ -155,4 +155,56 @@ class PendingIntentFactory
|
|||||||
},
|
},
|
||||||
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun showNumberPicker(habit: Habit, timestamp: Timestamp): PendingIntent? {
|
||||||
|
return getActivity(
|
||||||
|
context,
|
||||||
|
(habit.id!! % Integer.MAX_VALUE).toInt() + 1,
|
||||||
|
Intent(context, ListHabitsActivity::class.java).apply {
|
||||||
|
action = ListHabitsActivity.ACTION_EDIT
|
||||||
|
putExtra("habit", habit.id)
|
||||||
|
putExtra("timestamp", timestamp.unixTime)
|
||||||
|
},
|
||||||
|
FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showNumberPickerTemplate(): PendingIntent {
|
||||||
|
return getActivity(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
Intent(context, ListHabitsActivity::class.java).apply {
|
||||||
|
action = ListHabitsActivity.ACTION_EDIT
|
||||||
|
},
|
||||||
|
getIntentTemplateFlags()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showNumberPickerFillIn(habit: Habit, timestamp: Timestamp) = Intent().apply {
|
||||||
|
putExtra("habit", habit.id)
|
||||||
|
putExtra("timestamp", timestamp.unixTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIntentTemplateFlags(): Int {
|
||||||
|
var flags = 0
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
flags = flags or FLAG_MUTABLE
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleCheckmarkTemplate(): PendingIntent =
|
||||||
|
getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, WidgetReceiver::class.java).apply {
|
||||||
|
action = WidgetReceiver.ACTION_TOGGLE_REPETITION
|
||||||
|
},
|
||||||
|
getIntentTemplateFlags()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun toggleCheckmarkFillIn(habit: Habit, timestamp: Timestamp) = Intent().apply {
|
||||||
|
data = Uri.parse(habit.uriString)
|
||||||
|
putExtra("timestamp", timestamp.unixTime)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class AndroidNotificationTray
|
|||||||
val enterAction = Action(
|
val enterAction = Action(
|
||||||
R.drawable.ic_action_check,
|
R.drawable.ic_action_check,
|
||||||
context.getString(R.string.enter),
|
context.getString(R.string.enter),
|
||||||
pendingIntents.setNumericalValue(context, habit, 0, null)
|
pendingIntents.showNumberPicker(habit, timestamp)
|
||||||
)
|
)
|
||||||
|
|
||||||
val wearableBg = decodeResource(context.resources, R.drawable.stripe)
|
val wearableBg = decodeResource(context.resources, R.drawable.stripe)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.isoron.uhabits.HabitsApplication
|
|||||||
import org.isoron.uhabits.core.ui.widgets.WidgetBehavior
|
import org.isoron.uhabits.core.ui.widgets.WidgetBehavior
|
||||||
import org.isoron.uhabits.inject.HabitsApplicationComponent
|
import org.isoron.uhabits.inject.HabitsApplicationComponent
|
||||||
import org.isoron.uhabits.intents.IntentParser.CheckmarkIntentData
|
import org.isoron.uhabits.intents.IntentParser.CheckmarkIntentData
|
||||||
import org.isoron.uhabits.widgets.activities.NumericalCheckmarkWidgetActivity
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Android BroadcastReceiver for Loop Habit Tracker.
|
* The Android BroadcastReceiver for Loop Habit Tracker.
|
||||||
@@ -96,15 +95,6 @@ class WidgetReceiver : BroadcastReceiver() {
|
|||||||
data.timestamp
|
data.timestamp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ACTION_SET_NUMERICAL_VALUE -> {
|
|
||||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
|
||||||
val numberSelectorIntent = Intent(context, NumericalCheckmarkWidgetActivity::class.java)
|
|
||||||
numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
||||||
numberSelectorIntent.action = NumericalCheckmarkWidgetActivity.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY
|
|
||||||
parser.copyIntentData(intent, numberSelectorIntent)
|
|
||||||
context.startActivity(numberSelectorIntent)
|
|
||||||
}
|
|
||||||
ACTION_UPDATE_WIDGETS_VALUE -> {
|
ACTION_UPDATE_WIDGETS_VALUE -> {
|
||||||
widgetUpdater.updateWidgets()
|
widgetUpdater.updateWidgets()
|
||||||
widgetUpdater.scheduleStartDayWidgetUpdate()
|
widgetUpdater.scheduleStartDayWidgetUpdate()
|
||||||
@@ -126,7 +116,6 @@ class WidgetReceiver : BroadcastReceiver() {
|
|||||||
const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER"
|
const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER"
|
||||||
const val ACTION_REMOVE_REPETITION = "org.isoron.uhabits.ACTION_REMOVE_REPETITION"
|
const val ACTION_REMOVE_REPETITION = "org.isoron.uhabits.ACTION_REMOVE_REPETITION"
|
||||||
const val ACTION_TOGGLE_REPETITION = "org.isoron.uhabits.ACTION_TOGGLE_REPETITION"
|
const val ACTION_TOGGLE_REPETITION = "org.isoron.uhabits.ACTION_TOGGLE_REPETITION"
|
||||||
const val ACTION_SET_NUMERICAL_VALUE = "org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE"
|
|
||||||
const val ACTION_UPDATE_WIDGETS_VALUE = "org.isoron.uhabits.ACTION_UPDATE_WIDGETS_VALUE"
|
const val ACTION_UPDATE_WIDGETS_VALUE = "org.isoron.uhabits.ACTION_UPDATE_WIDGETS_VALUE"
|
||||||
private const val TAG = "WidgetReceiver"
|
private const val TAG = "WidgetReceiver"
|
||||||
var lastReceivedIntent: Intent? = null
|
var lastReceivedIntent: Intent? = null
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.isoron.uhabits.utils
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
var currentDialog: WeakReference<Dialog> = WeakReference(null)
|
||||||
|
|
||||||
|
fun Dialog.dismissCurrentAndShow() {
|
||||||
|
currentDialog.get()?.dismiss()
|
||||||
|
currentDialog = WeakReference(this)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DialogFragment.dismissCurrentAndShow(fragmentManager: FragmentManager, tag: String) {
|
||||||
|
currentDialog.get()?.dismiss()
|
||||||
|
show(fragmentManager, tag)
|
||||||
|
fragmentManager.executePendingTransactions()
|
||||||
|
currentDialog = WeakReference(this.dialog)
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ open class CheckmarkWidget(
|
|||||||
|
|
||||||
override fun getOnClickPendingIntent(context: Context): PendingIntent? {
|
override fun getOnClickPendingIntent(context: Context): PendingIntent? {
|
||||||
return if (habit.isNumerical) {
|
return if (habit.isNumerical) {
|
||||||
pendingIntentFactory.setNumericalValue(context, habit, 10, null)
|
pendingIntentFactory.showNumberPicker(habit, DateUtils.getToday())
|
||||||
} else {
|
} else {
|
||||||
pendingIntentFactory.toggleCheckmark(habit, null)
|
pendingIntentFactory.toggleCheckmark(habit, null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class FrequencyWidget(
|
|||||||
(widgetView.dataView as FrequencyChart).apply {
|
(widgetView.dataView as FrequencyChart).apply {
|
||||||
setFirstWeekday(firstWeekday)
|
setFirstWeekday(firstWeekday)
|
||||||
setColor(WidgetTheme().color(habit.color).toInt())
|
setColor(WidgetTheme().color(habit.color).toInt())
|
||||||
|
setIsNumerical(habit.isNumerical)
|
||||||
setFrequency(habit.originalEntries.computeWeekdayFrequency(habit.isNumerical))
|
setFrequency(habit.originalEntries.computeWeekdayFrequency(habit.isNumerical))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ class StackWidget(
|
|||||||
StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
||||||
StackWidgetType.getStackWidgetEmptyViewId(widgetType)
|
StackWidgetType.getStackWidgetEmptyViewId(widgetType)
|
||||||
)
|
)
|
||||||
|
remoteViews.setPendingIntentTemplate(
|
||||||
|
StackWidgetType.getStackWidgetAdapterViewId(widgetType),
|
||||||
|
StackWidgetType.getPendingIntentTemplate(pendingIntentFactory, widgetType, habits)
|
||||||
|
)
|
||||||
return remoteViews
|
return remoteViews
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,14 @@ import android.widget.RemoteViewsService
|
|||||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
import android.widget.RemoteViewsService.RemoteViewsFactory
|
||||||
import org.isoron.platform.utils.StringUtils.Companion.splitLongs
|
import org.isoron.platform.utils.StringUtils.Companion.splitLongs
|
||||||
import org.isoron.uhabits.HabitsApplication
|
import org.isoron.uhabits.HabitsApplication
|
||||||
|
import org.isoron.uhabits.R
|
||||||
import org.isoron.uhabits.core.models.Habit
|
import org.isoron.uhabits.core.models.Habit
|
||||||
import org.isoron.uhabits.core.models.HabitNotFoundException
|
import org.isoron.uhabits.core.models.HabitNotFoundException
|
||||||
import org.isoron.uhabits.core.preferences.Preferences
|
import org.isoron.uhabits.core.preferences.Preferences
|
||||||
|
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||||
|
import org.isoron.uhabits.intents.IntentFactory
|
||||||
|
import org.isoron.uhabits.intents.PendingIntentFactory
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels
|
import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
class StackWidgetService : RemoteViewsService() {
|
class StackWidgetService : RemoteViewsService() {
|
||||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||||
@@ -54,7 +57,6 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int
|
|||||||
)
|
)
|
||||||
private val habitIds: LongArray
|
private val habitIds: LongArray
|
||||||
private val widgetType: StackWidgetType
|
private val widgetType: StackWidgetType
|
||||||
private var remoteViews = ArrayList<RemoteViews>()
|
|
||||||
override fun onCreate() {}
|
override fun onCreate() {}
|
||||||
override fun onDestroy() {}
|
override fun onDestroy() {}
|
||||||
override fun getCount(): Int {
|
override fun getCount(): Int {
|
||||||
@@ -85,8 +87,26 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getViewAt(position: Int): RemoteViews? {
|
override fun getViewAt(position: Int): RemoteViews? {
|
||||||
Log.i("StackRemoteViewsFactory", "getViewAt $position")
|
Log.i("StackRemoteViewsFactory", "getViewAt $position started")
|
||||||
return if (0 <= position && position < remoteViews.size) remoteViews[position] else null
|
if (position < 0 || position >= habitIds.size) return null
|
||||||
|
val app = context.applicationContext as HabitsApplication
|
||||||
|
val prefs = app.component.preferences
|
||||||
|
val habitList = app.component.habitList
|
||||||
|
val options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId)
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare()
|
||||||
|
val habits = habitIds.map { habitList.getById(it) ?: throw HabitNotFoundException() }
|
||||||
|
val h = habits[position]
|
||||||
|
val widget = constructWidget(h, prefs)
|
||||||
|
widget.setDimensions(getDimensionsFromOptions(context, options))
|
||||||
|
val landscapeViews = widget.landscapeRemoteViews
|
||||||
|
val portraitViews = widget.portraitRemoteViews
|
||||||
|
val factory = PendingIntentFactory(context, IntentFactory())
|
||||||
|
val intent = StackWidgetType.getIntentFillIn(factory, widgetType, h, habits, getToday())
|
||||||
|
landscapeViews.setOnClickFillInIntent(R.id.button, intent)
|
||||||
|
portraitViews.setOnClickFillInIntent(R.id.button, intent)
|
||||||
|
val remoteViews = RemoteViews(landscapeViews, portraitViews)
|
||||||
|
Log.i("StackRemoteViewsFactory", "getViewAt $position ended")
|
||||||
|
return remoteViews
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun constructWidget(
|
private fun constructWidget(
|
||||||
@@ -131,24 +151,6 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDataSetChanged() {
|
override fun onDataSetChanged() {
|
||||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged started")
|
|
||||||
val app = context.applicationContext as HabitsApplication
|
|
||||||
val prefs = app.component.preferences
|
|
||||||
val habitList = app.component.habitList
|
|
||||||
val options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId)
|
|
||||||
val newRemoteViews = ArrayList<RemoteViews>()
|
|
||||||
if (Looper.myLooper() == null) Looper.prepare()
|
|
||||||
for (id in habitIds) {
|
|
||||||
val h = habitList.getById(id) ?: throw HabitNotFoundException()
|
|
||||||
val widget = constructWidget(h, prefs)
|
|
||||||
widget.setDimensions(getDimensionsFromOptions(context, options))
|
|
||||||
val landscapeViews = widget.landscapeRemoteViews
|
|
||||||
val portraitViews = widget.portraitRemoteViews
|
|
||||||
newRemoteViews.add(RemoteViews(landscapeViews, portraitViews))
|
|
||||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget $id")
|
|
||||||
}
|
|
||||||
remoteViews = newRemoteViews
|
|
||||||
Log.i("StackRemoteViewsFactory", "onDataSetChanged ended")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -18,7 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.isoron.uhabits.widgets
|
package org.isoron.uhabits.widgets
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Intent
|
||||||
import org.isoron.uhabits.R
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.core.models.Habit
|
||||||
|
import org.isoron.uhabits.core.models.Timestamp
|
||||||
|
import org.isoron.uhabits.intents.PendingIntentFactory
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
enum class StackWidgetType(val value: Int) {
|
enum class StackWidgetType(val value: Int) {
|
||||||
@@ -73,5 +78,39 @@ enum class StackWidgetType(val value: Int) {
|
|||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPendingIntentTemplate(
|
||||||
|
factory: PendingIntentFactory,
|
||||||
|
widgetType: StackWidgetType,
|
||||||
|
habits: List<Habit>
|
||||||
|
): PendingIntent {
|
||||||
|
val containsNumerical = habits.any { it.isNumerical }
|
||||||
|
return when (widgetType) {
|
||||||
|
CHECKMARK -> if (containsNumerical) {
|
||||||
|
factory.showNumberPickerTemplate()
|
||||||
|
} else {
|
||||||
|
factory.toggleCheckmarkTemplate()
|
||||||
|
}
|
||||||
|
FREQUENCY, SCORE, HISTORY, STREAKS, TARGET -> factory.showHabitTemplate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIntentFillIn(
|
||||||
|
factory: PendingIntentFactory,
|
||||||
|
widgetType: StackWidgetType,
|
||||||
|
habit: Habit,
|
||||||
|
allHabitsInStackWidget: List<Habit>,
|
||||||
|
timestamp: Timestamp
|
||||||
|
): Intent {
|
||||||
|
val containsNumerical = allHabitsInStackWidget.any { it.isNumerical }
|
||||||
|
return when (widgetType) {
|
||||||
|
CHECKMARK -> if (containsNumerical) {
|
||||||
|
factory.showNumberPickerFillIn(habit, timestamp)
|
||||||
|
} else {
|
||||||
|
factory.toggleCheckmarkFillIn(habit, timestamp)
|
||||||
|
}
|
||||||
|
FREQUENCY, SCORE, HISTORY, STREAKS, TARGET -> factory.showHabitFillIn(habit)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.uhabits.widgets.activities
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import org.isoron.uhabits.HabitsApplication
|
|
||||||
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
|
||||||
import org.isoron.uhabits.activities.common.dialogs.NumberPopup
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
|
||||||
import org.isoron.uhabits.core.ui.widgets.WidgetBehavior
|
|
||||||
import org.isoron.uhabits.core.utils.DateUtils
|
|
||||||
import org.isoron.uhabits.intents.IntentParser
|
|
||||||
import org.isoron.uhabits.utils.SystemUtils
|
|
||||||
import org.isoron.uhabits.widgets.WidgetUpdater
|
|
||||||
|
|
||||||
class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPickerCallback {
|
|
||||||
|
|
||||||
private lateinit var behavior: WidgetBehavior
|
|
||||||
private lateinit var data: IntentParser.CheckmarkIntentData
|
|
||||||
private lateinit var widgetUpdater: WidgetUpdater
|
|
||||||
private lateinit var rootView: View
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
rootView = FrameLayout(this)
|
|
||||||
rootView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
|
||||||
setContentView(rootView)
|
|
||||||
val app = this.applicationContext as HabitsApplication
|
|
||||||
val component = app.component
|
|
||||||
val parser = app.component.intentParser
|
|
||||||
data = parser.parseCheckmarkIntent(intent)
|
|
||||||
behavior = WidgetBehavior(
|
|
||||||
component.habitList,
|
|
||||||
component.commandRunner,
|
|
||||||
component.notificationTray,
|
|
||||||
component.preferences
|
|
||||||
)
|
|
||||||
widgetUpdater = component.widgetUpdater
|
|
||||||
rootView.post {
|
|
||||||
showNumberSelector(this)
|
|
||||||
}
|
|
||||||
SystemUtils.unlockScreen(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNumberPicked(newValue: Double, notes: String) {
|
|
||||||
behavior.setValue(data.habit, data.timestamp, (newValue * 1000).toInt(), notes)
|
|
||||||
widgetUpdater.updateWidgets()
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNumberPickerDismissed() {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNumberSelector(context: Context) {
|
|
||||||
val app = this.applicationContext as HabitsApplication
|
|
||||||
AndroidThemeSwitcher(this, app.component.preferences).apply()
|
|
||||||
val today = DateUtils.getTodayWithOffset()
|
|
||||||
val entry = data.habit.computedEntries.get(today)
|
|
||||||
NumberPopup(
|
|
||||||
context = context,
|
|
||||||
prefs = app.component.preferences,
|
|
||||||
anchor = rootView,
|
|
||||||
notes = entry.notes,
|
|
||||||
value = entry.value / 1000.0,
|
|
||||||
).apply {
|
|
||||||
onToggle = { value, notes ->
|
|
||||||
onNumberPicked(value, notes)
|
|
||||||
finish()
|
|
||||||
overridePendingTransition(0, 0)
|
|
||||||
}
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY = "org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,4 +21,5 @@
|
|||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -25,6 +25,12 @@ class StringUtils {
|
|||||||
|
|
||||||
fun joinLongs(values: LongArray): String = values.joinToString(separator = ",")
|
fun joinLongs(values: LongArray): String = values.joinToString(separator = ",")
|
||||||
|
|
||||||
fun splitLongs(str: String): LongArray = str.split(",").map { it.toLong() }.toLongArray()
|
fun splitLongs(str: String): LongArray {
|
||||||
|
return try {
|
||||||
|
str.split(",").map { it.toLong() }.toLongArray()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
LongArray(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ data class FrequencyCardState(
|
|||||||
val firstWeekday: Int,
|
val firstWeekday: Int,
|
||||||
val frequency: HashMap<Timestamp, Array<Int>>,
|
val frequency: HashMap<Timestamp, Array<Int>>,
|
||||||
val theme: Theme,
|
val theme: Theme,
|
||||||
|
val isNumerical: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
class FrequencyCardPresenter {
|
class FrequencyCardPresenter {
|
||||||
@@ -40,6 +41,7 @@ class FrequencyCardPresenter {
|
|||||||
theme: Theme
|
theme: Theme
|
||||||
) = FrequencyCardState(
|
) = FrequencyCardState(
|
||||||
color = habit.color,
|
color = habit.color,
|
||||||
|
isNumerical = habit.isNumerical,
|
||||||
frequency = habit.originalEntries.computeWeekdayFrequency(
|
frequency = habit.originalEntries.computeWeekdayFrequency(
|
||||||
isNumerical = habit.isNumerical
|
isNumerical = habit.isNumerical
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class BarChart(
|
|||||||
val r = round(barWidth * 0.15)
|
val r = round(barWidth * 0.15)
|
||||||
if (2 * r < barHeight) {
|
if (2 * r < barHeight) {
|
||||||
canvas.fillRect(x, y + r, barWidth, barHeight - r)
|
canvas.fillRect(x, y + r, barWidth, barHeight - r)
|
||||||
canvas.fillRect(x + r, y, barWidth - 2 * r, r)
|
canvas.fillRect(x + r, y, barWidth - 2 * r, r + 1)
|
||||||
canvas.fillCircle(x + r, y + r, r)
|
canvas.fillCircle(x + r, y + r, r)
|
||||||
canvas.fillCircle(x + barWidth - r, y + r, r)
|
canvas.fillCircle(x + barWidth - r, y + r, r)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package org.isoron.uhabits.core.utils
|
package org.isoron.uhabits.core.utils
|
||||||
|
|
||||||
import org.isoron.uhabits.core.models.Timestamp
|
import org.isoron.uhabits.core.models.Timestamp
|
||||||
|
import java.time.YearMonth
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Calendar.DAY_OF_MONTH
|
import java.util.Calendar.DAY_OF_MONTH
|
||||||
import java.util.Calendar.DAY_OF_WEEK
|
import java.util.Calendar.DAY_OF_WEEK
|
||||||
@@ -178,6 +179,26 @@ abstract class DateUtils {
|
|||||||
return getWeekdayNames(GregorianCalendar.SHORT, firstWeekday)
|
return getWeekdayNames(GregorianCalendar.SHORT, firstWeekday)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vector of Int representing the frequency of each weekday in a given month.
|
||||||
|
*
|
||||||
|
* @param startOfMonth a Timestamp representing the beginning of the month.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun getWeekdaysInMonth(startOfMonth: Timestamp): Array<Int> {
|
||||||
|
val month = startOfMonth.toCalendar()[Calendar.MONTH] + 1
|
||||||
|
val year = startOfMonth.toCalendar()[Calendar.YEAR]
|
||||||
|
val weekday = startOfMonth.weekday
|
||||||
|
val monthLength = YearMonth.of(year, month).lengthOfMonth()
|
||||||
|
|
||||||
|
val freq = Array(7) { 0 }
|
||||||
|
for (day in weekday until weekday + monthLength) {
|
||||||
|
freq[day % 7] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return freq
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getToday(): Timestamp = Timestamp(getStartOfToday())
|
fun getToday(): Timestamp = Timestamp(getStartOfToday())
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,31 @@ class DateUtilsTest : BaseUnitTest() {
|
|||||||
assertThat(arrayOf("Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"), equalTo(longWeekdayNames))
|
assertThat(arrayOf("Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"), equalTo(longWeekdayNames))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getWeekdaysInMonth() {
|
||||||
|
val february = GregorianCalendar(2018, Calendar.FEBRUARY, 1)
|
||||||
|
val leapFebruary = GregorianCalendar(2020, Calendar.FEBRUARY, 1)
|
||||||
|
val month = GregorianCalendar(2020, Calendar.APRIL, 1)
|
||||||
|
val longMonth = GregorianCalendar(2020, Calendar.AUGUST, 1)
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
arrayOf(4, 4, 4, 4, 4, 4, 4),
|
||||||
|
equalTo(DateUtils.getWeekdaysInMonth(Timestamp(february)))
|
||||||
|
)
|
||||||
|
assertThat(
|
||||||
|
arrayOf(5, 4, 4, 4, 4, 4, 4),
|
||||||
|
equalTo(DateUtils.getWeekdaysInMonth(Timestamp(leapFebruary)))
|
||||||
|
)
|
||||||
|
assertThat(
|
||||||
|
arrayOf(4, 4, 4, 4, 5, 5, 4),
|
||||||
|
equalTo(DateUtils.getWeekdaysInMonth(Timestamp(month)))
|
||||||
|
)
|
||||||
|
assertThat(
|
||||||
|
arrayOf(5, 5, 5, 4, 4, 4, 4),
|
||||||
|
equalTo(DateUtils.getWeekdaysInMonth(Timestamp(longMonth)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetToday() {
|
fun testGetToday() {
|
||||||
setFixedLocalTime(FIXED_LOCAL_TIME)
|
setFixedLocalTime(FIXED_LOCAL_TIME)
|
||||||
|
|||||||