From f5432def3119708dd318cf42ede25a9731a29f77 Mon Sep 17 00:00:00 2001 From: Albert Vaca Cintora Date: Mon, 1 Apr 2024 23:55:53 +0200 Subject: [PATCH] Use Material 3 date and time pickers, with some style tweaks FIXES: #53 --- .../org/kde/bettercounter/ui/ChartHolder.kt | 28 +++++----- .../kde/bettercounter/ui/DateTimePicker.kt | 53 ++++++++++++------- .../kde/bettercounter/ui/EntryViewHolder.kt | 8 +-- app/src/main/res/values/styles.xml | 36 +++++++++++++ 4 files changed, 90 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/org/kde/bettercounter/ui/ChartHolder.kt b/app/src/main/java/org/kde/bettercounter/ui/ChartHolder.kt index f93b520..cbbb4ae 100644 --- a/app/src/main/java/org/kde/bettercounter/ui/ChartHolder.kt +++ b/app/src/main/java/org/kde/bettercounter/ui/ChartHolder.kt @@ -1,7 +1,7 @@ package org.kde.bettercounter.ui -import android.content.Context import android.view.Gravity +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.PopupMenu import androidx.recyclerview.widget.RecyclerView import org.kde.bettercounter.R @@ -19,7 +19,7 @@ import java.util.Date import java.util.Locale class ChartHolder( - private val context: Context, + private val activity: AppCompatActivity, private val binding: FragmentChartBinding, ) : RecyclerView.ViewHolder(binding.root) { @@ -36,9 +36,9 @@ class ChartHolder( Interval.LIFETIME -> throw IllegalStateException("Interval not valid as a chart display interval") } val dateString = dateFormat.format(rangeStart.time) - binding.chartName.text = context.resources.getQuantityString(R.plurals.chart_title, entries.size, dateString, entries.size) + binding.chartName.text = activity.resources.getQuantityString(R.plurals.chart_title, entries.size, dateString, entries.size) binding.chartName.setOnClickListener { view -> - val popupMenu = PopupMenu(context, view, Gravity.END) + val popupMenu = PopupMenu(activity, view, Gravity.END) popupMenu.menuInflater.inflate(R.menu.popup_menu, popupMenu.menu) popupMenu.setOnMenuItemClickListener { menuItem -> menuItem.isChecked = true @@ -62,7 +62,7 @@ class ChartHolder( popupMenu.show() } binding.chartName.setOnLongClickListener { - showDatePicker(context, rangeStart, onDateChange) + showDatePicker(activity, rangeStart, onDateChange) true } @@ -70,14 +70,14 @@ class ChartHolder( val goalLine = computeGoalLine(counter, interval) // Chart - binding.chart.setDataBucketized(entries, rangeStart, interval, counter.color.toColorForChart(context), goalLine) + binding.chart.setDataBucketized(entries, rangeStart, interval, counter.color.toColorForChart(activity), goalLine) // Stats val periodAverage = getPeriodAverageString(counter, entries, rangeStart, rangeEnd) val lifetimeAverage = getLifetimeAverageString(counter) - binding.chartAverage.text = context.getString(R.string.stats_averages, periodAverage, lifetimeAverage) + binding.chartAverage.text = activity.getString(R.string.stats_averages, periodAverage, lifetimeAverage) if (binding.chartAverage.lineCount > 1) { - binding.chartAverage.text = context.getString(R.string.stats_averages_multiline, periodAverage, lifetimeAverage) + binding.chartAverage.text = activity.getString(R.string.stats_averages_multiline, periodAverage, lifetimeAverage) } } @@ -97,7 +97,7 @@ class ChartHolder( private fun getLifetimeAverageString(counter: CounterSummary): String { if (counter.totalCount == 0) { - return context.getString(R.string.stats_average_n_a) + return activity.getString(R.string.stats_average_n_a) } val beginRange = counter.leastRecent!! @@ -111,7 +111,7 @@ class ChartHolder( private fun getPeriodAverageString(counter: CounterSummary, intervalEntries: List, rangeStart: Calendar, rangeEnd: Calendar): String { if (intervalEntries.isEmpty()) { - return context.getString(R.string.stats_average_n_a) + return activity.getString(R.string.stats_average_n_a) } // Hack so to use the end of this interval and not at the beginning of the next, @@ -135,9 +135,9 @@ class ChartHolder( val days = ChronoUnit.DAYS.count(startDate, endDate) val avgPerDay = count.toFloat() / days return if (avgPerDay > 1) { - context.getString(R.string.stats_average_per_day, avgPerDay) + activity.getString(R.string.stats_average_per_day, avgPerDay) } else { - context.getString(R.string.stats_average_every_days, 1 / avgPerDay) + activity.getString(R.string.stats_average_every_days, 1 / avgPerDay) } } @@ -145,9 +145,9 @@ class ChartHolder( val hours = ChronoUnit.HOURS.count(startDate, endDate) val avgPerHour = count.toFloat() / hours return if (avgPerHour > 1) { - context.getString(R.string.stats_average_per_hour, avgPerHour) + activity.getString(R.string.stats_average_per_hour, avgPerHour) } else { - context.getString(R.string.stats_average_every_hours, 1 / avgPerHour) + activity.getString(R.string.stats_average_every_hours, 1 / avgPerHour) } } } diff --git a/app/src/main/java/org/kde/bettercounter/ui/DateTimePicker.kt b/app/src/main/java/org/kde/bettercounter/ui/DateTimePicker.kt index 822eae3..3566e01 100644 --- a/app/src/main/java/org/kde/bettercounter/ui/DateTimePicker.kt +++ b/app/src/main/java/org/kde/bettercounter/ui/DateTimePicker.kt @@ -1,30 +1,47 @@ package org.kde.bettercounter.ui +import android.app.Activity import android.app.DatePickerDialog import android.app.TimePickerDialog import android.content.Context import android.text.format.DateFormat +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.datepicker.CalendarConstraints +import com.google.android.material.datepicker.MaterialDatePicker +import com.google.android.material.timepicker.MaterialTimePicker +import com.google.android.material.timepicker.TimeFormat import java.util.Calendar +import java.util.Date -fun showDateTimePicker(context: Context, initialDateTime: Calendar, callback: (Calendar) -> Unit) { +fun showDateTimePicker(activity: AppCompatActivity, initialDateTime: Calendar, callback: (Calendar) -> Unit) { val initialHour = initialDateTime.get(Calendar.HOUR_OF_DAY) val initialMinute = initialDateTime.get(Calendar.MINUTE) - val use24HourClock = DateFormat.is24HourFormat(context) - showDatePicker(context, initialDateTime) { cal -> - TimePickerDialog(context, { _, hour, minute -> - cal.set(Calendar.MINUTE, minute) - cal.set(Calendar.HOUR_OF_DAY, hour) - callback(cal) - }, initialHour, initialMinute, use24HourClock).show() - }} + val timeFormat = if (DateFormat.is24HourFormat(activity)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H + showDatePicker(activity, initialDateTime) { cal -> + MaterialTimePicker.Builder() + .setTimeFormat(timeFormat) + .setHour(initialHour) + .setMinute(initialMinute) + .setInputMode(MaterialTimePicker.INPUT_MODE_CLOCK) + .build().apply { + addOnPositiveButtonClickListener { + cal.set(Calendar.MINUTE, minute) + cal.set(Calendar.HOUR_OF_DAY, hour) + callback(cal) + } + }.show(activity.supportFragmentManager, "timePicker") + } +} -fun showDatePicker(context: Context, initialDateTime: Calendar, callback: (Calendar) -> Unit) { - val initialYear = initialDateTime.get(Calendar.YEAR) - val initialMonth = initialDateTime.get(Calendar.MONTH) - val initialDay = initialDateTime.get(Calendar.DAY_OF_MONTH) - DatePickerDialog(context, { _, year, month, day -> - val cal = Calendar.getInstance() - cal.set(year, month, day) - callback(cal) - }, initialYear, initialMonth, initialDay).show() +fun showDatePicker(activity: AppCompatActivity, initialDateTime: Calendar, callback: (Calendar) -> Unit) { + MaterialDatePicker.Builder.datePicker() + .setSelection(initialDateTime.timeInMillis) + .build().apply { + addOnPositiveButtonClickListener { + val cal = Calendar.getInstance() + cal.timeInMillis = it + callback(cal) + } + } + .show(activity.supportFragmentManager, "datePicker") } diff --git a/app/src/main/java/org/kde/bettercounter/ui/EntryViewHolder.kt b/app/src/main/java/org/kde/bettercounter/ui/EntryViewHolder.kt index 5a6ec25..a1f0cbb 100644 --- a/app/src/main/java/org/kde/bettercounter/ui/EntryViewHolder.kt +++ b/app/src/main/java/org/kde/bettercounter/ui/EntryViewHolder.kt @@ -1,8 +1,10 @@ package org.kde.bettercounter.ui +import android.app.Activity import android.content.Context import android.view.Gravity import android.view.HapticFeedbackConstants +import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import io.github.douglasjunior.androidSimpleTooltip.SimpleTooltip @@ -14,7 +16,7 @@ import org.kde.bettercounter.persistence.Tutorial import java.util.Calendar class EntryViewHolder( - private val context: Context, + private val activity: AppCompatActivity, val binding: FragmentEntryBinding, private var viewModel: ViewModel, private val touchHelper: ItemTouchHelper, @@ -27,7 +29,7 @@ class EntryViewHolder( viewModel.incrementCounter(counter.name) if (!viewModel.isTutorialShown(Tutorial.PICKDATE)) { viewModel.setTutorialShown(Tutorial.PICKDATE) - SimpleTooltip.Builder(context) + SimpleTooltip.Builder(activity) .anchorView(binding.increaseButton) .text(R.string.tutorial_pickdate) .gravity(Gravity.BOTTOM) @@ -38,7 +40,7 @@ class EntryViewHolder( } } binding.increaseButton.setOnLongClickListener { - showDateTimePicker(context, Calendar.getInstance()) { pickedDateTime -> + showDateTimePicker(activity, Calendar.getInstance()) { pickedDateTime -> viewModel.incrementCounter(counter.name, pickedDateTime.time) } true diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8c220fc..62f9b8a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -18,6 +18,8 @@ @color/colorDarkBackground + + @color/colorLightBackground @color/colorAccent @@ -25,6 +27,9 @@ false true + + @style/ThemeOverlay.App.MaterialTimePicker + @style/ThemeOverlay.App.MaterialCalendar @style/ThemeOverlay.App.MaterialAlertDialog @@ -32,11 +37,42 @@ + + + + + + + + + + + + + +