From 7e12224795baa315d79b1c35ff65abbb87e3af75 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Tue, 23 Mar 2021 22:31:44 -0700 Subject: [PATCH] Update Material Components library. - Introduced the new material date range picker, to be used in the FilterOptionsDialog to select a date range. This was necessary because the old MaterialDatePicker that was used inside DatePickerFragment is no longer available in the latest version of the Material Components library. --- app/build.gradle | 2 +- .../fragments/FilterOptionsDialog.kt | 110 +++++++----------- .../views/DatePickerFragment.kt | 93 --------------- .../views/MyTextInputEditText.kt | 2 +- .../main/res/layout/dialog_filter_options.xml | 2 +- 5 files changed, 46 insertions(+), 163 deletions(-) delete mode 100644 app/src/main/java/cy/agorise/bitsybitshareswallet/views/DatePickerFragment.kt diff --git a/app/build.gradle b/app/build.gradle index 63a2808..9d310f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,7 +78,7 @@ dependencies { // Google implementation 'com.google.zxing:core:3.4.0' implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.google.android.material:material:1.1.0-alpha04' + implementation 'com.google.android.material:material:1.3.0' implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.maps.android:android-maps-utils:0.5' // AAC Lifecycle diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt index df27dfb..e4bb5d1 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/FilterOptionsDialog.kt @@ -11,8 +11,10 @@ import androidx.core.os.ConfigurationCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import com.google.android.material.datepicker.CalendarConstraints +import com.google.android.material.datepicker.DateValidatorPointBackward +import com.google.android.material.datepicker.MaterialDatePicker import com.google.firebase.crashlytics.FirebaseCrashlytics -import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.adapters.BalancesDetailsAdapter import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail import cy.agorise.bitsybitshareswallet.databinding.DialogFilterOptionsBinding @@ -20,7 +22,6 @@ import cy.agorise.bitsybitshareswallet.models.FilterOptions import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Helper import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel -import cy.agorise.bitsybitshareswallet.views.DatePickerFragment import java.text.SimpleDateFormat import java.util.* import kotlin.collections.ArrayList @@ -30,15 +31,11 @@ import kotlin.collections.ArrayList * Creates a Dialog that communicates with {@link TransactionsActivity} to give it parameters about * how to filter the list of Transactions */ -class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListener { +class FilterOptionsDialog : DialogFragment() { - companion object { - private const val TAG = "FilterOptionsDialog" - - const val KEY_FILTER_OPTIONS = "key_filter_options" - - const val START_DATE_PICKER = 0 - const val END_DATE_PICKER = 1 + // Container Fragment must implement this interface + interface OnFilterOptionsSelectedListener { + fun onFilterOptionsSelected(filterOptions: FilterOptions) } private val viewModel: BalanceDetailViewModel by viewModels() @@ -61,44 +58,6 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen private lateinit var mCurrency: Currency - override fun onDateSet(which: Int, timestamp: Long) { - when (which) { - START_DATE_PICKER -> { - mFilterOptions.startDate = timestamp - - updateDateTextViews() - } - END_DATE_PICKER -> { - mFilterOptions.endDate = timestamp - - // Make sure there is at least one moth difference between start and end time - val calendar = Calendar.getInstance() - calendar.timeInMillis = mFilterOptions.endDate - calendar.add(Calendar.MONTH, -1) - - val tmpTime = calendar.timeInMillis - - if (tmpTime < mFilterOptions.startDate) - mFilterOptions.startDate = tmpTime - - updateDateTextViews() - } - } - } - - private fun updateDateTextViews() { - var date = Date(mFilterOptions.startDate) - binding.tvStartDate.text = dateFormat.format(date) - - date = Date(mFilterOptions.endDate) - binding.tvEndDate.text = dateFormat.format(date) - } - - // Container Fragment must implement this interface - interface OnFilterOptionsSelectedListener { - fun onFilterOptionsSelected(filterOptions: FilterOptions) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -136,9 +95,9 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen } binding.cbDateRange.isChecked = mFilterOptions.dateRangeAll - binding.tvStartDate.setOnClickListener(mDateClickListener) + binding.tvStartDate.setOnClickListener { showDateRangePicker() } - binding.tvEndDate.setOnClickListener(mDateClickListener) + binding.tvEndDate.setOnClickListener { showDateRangePicker() } updateDateTextViews() @@ -220,27 +179,38 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen } } - private val mDateClickListener = View.OnClickListener { v -> - val calendar = Calendar.getInstance() + private fun updateDateTextViews() { + var date = Date(mFilterOptions.startDate) + binding.tvStartDate.text = dateFormat.format(date) - // Variable used to select that date on the calendar - var currentTime = calendar.timeInMillis - var maxTime = currentTime + date = Date(mFilterOptions.endDate) + binding.tvEndDate.text = dateFormat.format(date) + } - var which = -1 - if (v.id == R.id.tvStartDate) { - which = START_DATE_PICKER - currentTime = mFilterOptions.startDate - calendar.timeInMillis = mFilterOptions.endDate - calendar.add(Calendar.MONTH, -1) - maxTime = calendar.timeInMillis - } else if (v.id == R.id.tvEndDate) { - which = END_DATE_PICKER - currentTime = mFilterOptions.endDate + private fun showDateRangePicker() { + // Makes only dates until today selectable. + val constraintsBuilder = + CalendarConstraints.Builder() + .setValidator(DateValidatorPointBackward.now()) + + val dateRangePicker = + MaterialDatePicker.Builder.dateRangePicker() + .setSelection( + androidx.core.util.Pair( + mFilterOptions.startDate, + mFilterOptions.endDate + ) + ) + .setCalendarConstraints(constraintsBuilder.build()) + .build() + + dateRangePicker.addOnPositiveButtonClickListener { + mFilterOptions.startDate = it.first!! // This is safe cause these should never be null + mFilterOptions.endDate = it.second!! + updateDateTextViews() } - val datePickerFragment = DatePickerFragment.newInstance(which, currentTime, maxTime) - datePickerFragment.show(childFragmentManager, "date-picker") + dateRangePicker.show(childFragmentManager, "date-picker") } private fun validateFields() { @@ -283,4 +253,10 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen mCallback!!.onFilterOptionsSelected(mFilterOptions) dismiss() } + + companion object { + private const val TAG = "FilterOptionsDialog" + + const val KEY_FILTER_OPTIONS = "key_filter_options" + } } \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/views/DatePickerFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/views/DatePickerFragment.kt deleted file mode 100644 index 92aaa75..0000000 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/views/DatePickerFragment.kt +++ /dev/null @@ -1,93 +0,0 @@ -package cy.agorise.bitsybitshareswallet.views - -import android.app.DatePickerDialog -import android.app.Dialog -import android.os.Bundle -import android.widget.DatePicker -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.Fragment -import com.google.android.material.picker.MaterialDatePickerDialog -import java.util.* - -/** - * Lets the user select a Date and communicates the selection back to the parent fragment - * using the OnDateSetListener interface, which has to be implemented by the parent. - */ -class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener { - - companion object { - const val TAG = "DatePickerFragment" - - const val KEY_WHICH = "key_which" - const val KEY_CURRENT = "key_current" - const val KEY_MAX = "key_max" - - fun newInstance(which: Int, currentTime: Long, maxTime: Long): DatePickerFragment { - val f = DatePickerFragment() - val bundle = Bundle() - bundle.putInt(KEY_WHICH, which) - bundle.putLong(KEY_CURRENT, currentTime) - bundle.putLong(KEY_MAX, maxTime) - f.arguments = bundle - return f - } - } - - /** - * Callback used to communicate the date selection back to the parent - */ - private var mCallback: OnDateSetListener? = null - - private var which: Int = 0 - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - which = arguments!!.getInt(KEY_WHICH) - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - onAttachToParentFragment(parentFragment) - - val currentTime = arguments!!.getLong(KEY_CURRENT) - val maxTime = arguments!!.getLong(KEY_MAX) - - // Use the current date as the default date in the picker - val calendar = Calendar.getInstance() - calendar.timeInMillis = currentTime - - val year = calendar.get(Calendar.YEAR) - val month = calendar.get(Calendar.MONTH) - val day = calendar.get(Calendar.DAY_OF_MONTH) - - // Create a new instance of DatePickerDialog and return it - val datePicker = MaterialDatePickerDialog(activity!!, this, year, month, day) - - // Set maximum date allowed to today - datePicker.datePicker.maxDate = maxTime - - return datePicker - } - - override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) { - val calendar = GregorianCalendar() - calendar.set(year, month, day) - mCallback?.onDateSet(which, calendar.time.time) - } - - /** - * Attaches the current [DialogFragment] to its [Fragment] parent, to initialize the - * [OnDateSetListener] interface - */ - private fun onAttachToParentFragment(fragment: Fragment?) { - try { - mCallback = fragment as OnDateSetListener - } catch (e: ClassCastException) { - throw ClassCastException("$fragment must implement OnDateSetListener") - } - } - - // Container Activity must implement this interface - interface OnDateSetListener { - fun onDateSet(which: Int, timestamp: Long) - } -} \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/views/MyTextInputEditText.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/views/MyTextInputEditText.kt index 0012e44..20ea8d2 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/views/MyTextInputEditText.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/views/MyTextInputEditText.kt @@ -13,7 +13,7 @@ import cy.agorise.bitsybitshareswallet.utils.hideKeyboard * A TextInputEditText that hides the keyboard when the focus is removed from it and also lets you * use actions ("Done", "Go", etc.) on multi-line edits. */ -class MyTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){ +class MyTextInputEditText(context: Context, attrs: AttributeSet?) : TextInputEditText(context, attrs){ override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? { val connection = super.onCreateInputConnection(outAttrs) diff --git a/app/src/main/res/layout/dialog_filter_options.xml b/app/src/main/res/layout/dialog_filter_options.xml index 510b0d8..b20725c 100644 --- a/app/src/main/res/layout/dialog_filter_options.xml +++ b/app/src/main/res/layout/dialog_filter_options.xml @@ -138,7 +138,7 @@ -