From 50c7bfebba28ea433655eeb28149e33a80d546e0 Mon Sep 17 00:00:00 2001 From: denizk0461 Date: Thu, 4 May 2023 12:26:56 +0200 Subject: [PATCH] Fixed TimePickerFragment.kt crashing on configuration change by parcelising OnTimeSetListener interface - I didn't even know that that was possible tbh; fragments now use childFragmentManager instead of the activity's supportFragmentManager to instantiate bottom sheets --- .../studip/dialog/TimePickerFragment.kt | 42 +++++++++------- .../denizk0461/studip/fragment/AppFragment.kt | 3 +- .../studip/sheet/ScheduleUpdateSheet.kt | 50 +++++++++++++++---- 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt b/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt index 39e9e71..5942412 100644 --- a/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt @@ -4,21 +4,29 @@ import android.app.Dialog import androidx.fragment.app.DialogFragment import android.app.TimePickerDialog import android.os.Bundle +import android.os.Parcelable import android.widget.TimePicker +import com.denizk0461.studip.data.getParcelableCompat /** - * Dialogue used for letting the user pick a timestamp. TODO crashes on config change (multitask) - * - * @param listener listener for when the user finishes setting a time - * @param isEventStart whether the timestamp to be edited is the start of the event + * Dialogue used for letting the user pick a timestamp. */ -class TimePickerFragment( - private val listener: OnTimeSetListener, - private val isEventStart: Boolean, -) : DialogFragment(), TimePickerDialog.OnTimeSetListener { +class TimePickerFragment : DialogFragment(), TimePickerDialog.OnTimeSetListener { + + private lateinit var listener: OnTimeSetListener + private var isEventStart: Boolean = false override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + + // Retrieve listener for when the user finishes setting a time + listener = arguments.getParcelableCompat("interface") + + // Retrieve whether the timestamp to be edited is the start of the event + isEventStart = arguments?.getBoolean("isEventStart") == true + + // Retrieve timestamp to edit val timestampSplit = (arguments?.getString("timestamp") ?: "").split(":") + return TimePickerDialog( activity, this, @@ -28,11 +36,19 @@ class TimePickerFragment( ) } + /** + * Override the implementation of TimePickerDialog#OnTimeSetListener. + */ + override fun onTimeSet(picker: TimePicker?, hours: Int, minutes: Int) { + // Use custom implementation of OnTimeSetListener + listener.onTimeSet(hours, minutes, isEventStart) + } + /** * Custom implementation of TimePickerDialog#OnTimeSetListener that includes a boolean to find * out whether the start or the end timestamp has been edited. */ - interface OnTimeSetListener { + interface OnTimeSetListener : Parcelable { /** * Timestamp has been edited by the user. @@ -43,12 +59,4 @@ class TimePickerFragment( */ fun onTimeSet(hours: Int, minutes: Int, isEventStart: Boolean) } - - /** - * Override the implementation of TimePickerDialog#OnTimeSetListener. - */ - override fun onTimeSet(picker: TimePicker?, hours: Int, minutes: Int) { - // Use custom implementation of OnTimeSetListener - listener.onTimeSet(hours, minutes, isEventStart) - } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/fragment/AppFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/AppFragment.kt index 3c6471c..2d9f93a 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/AppFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/AppFragment.kt @@ -2,7 +2,6 @@ package com.denizk0461.studip.fragment import android.content.Context import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity import com.denizk0461.studip.sheet.AppSheet /** @@ -30,6 +29,6 @@ open class AppFragment : Fragment() { * @param sheet element that will be displayed */ protected fun openBottomSheet(sheet: AppSheet) { - sheet.show((context as FragmentActivity).supportFragmentManager, sheet.javaClass.simpleName) + sheet.show(childFragmentManager, sheet.javaClass.simpleName) } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt index 4a9b89d..e9e5af1 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt @@ -1,6 +1,8 @@ package com.denizk0461.studip.sheet import android.os.Bundle +import android.os.Parcel +import android.os.Parcelable import android.view.View import android.view.ViewGroup import androidx.appcompat.widget.PopupMenu @@ -26,7 +28,7 @@ import com.denizk0461.studip.viewmodel.ScheduleUpdateViewModel /** * Update sheet to allow the user to edit attributes for a specific schedule event. */ -class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePickerFragment.OnTimeSetListener { +class ScheduleUpdateSheet() : AppSheet(R.layout.sheet_schedule_update), TimePickerFragment.OnTimeSetListener { // Editable fields private var timeslotStart = "12:00" @@ -48,6 +50,15 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker // Day the event is scheduled for, default is Monday private var selectedDay = 0 + constructor(parcel: Parcel) : this() { + timeslotStart = parcel.readString() ?: "" + timeslotEnd = parcel.readString() ?: "" + colour = parcel.readInt() + hasClickedDelete = parcel.readByte() != 0.toByte() + isEditing = parcel.readByte() != 0.toByte() + selectedDay = parcel.readInt() + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -274,11 +285,10 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker binding.buttonTimeStart.text = timeslotStart binding.buttonTimeStart.setOnClickListener { // Launch a time picker dialogue to pick a new start timestamp - TimePickerFragment( - this, - true, - ).also { sheet -> + TimePickerFragment().also { sheet -> val bundle = Bundle() + bundle.putParcelable("interface", this) + bundle.putBoolean("isEventStart", true) bundle.putString("timestamp", binding.buttonTimeStart.text.toString()) sheet.arguments = bundle }.show((context as FragmentActivity).supportFragmentManager, "timePicker") @@ -286,11 +296,10 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker binding.buttonTimeEnd.text = timeslotEnd binding.buttonTimeEnd.setOnClickListener { // Launch a time picker dialogue to pick a new end timestamp - TimePickerFragment( - this, - false, - ).also { sheet -> + TimePickerFragment().also { sheet -> val bundle = Bundle() + bundle.putParcelable("interface", this) + bundle.putBoolean("isEventStart", false) bundle.putString("timestamp", binding.buttonTimeEnd.text.toString()) sheet.arguments = bundle }.show((context as FragmentActivity).supportFragmentManager, "timePicker") @@ -398,4 +407,27 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker } else { View.GONE } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(timeslotStart) + parcel.writeString(timeslotEnd) + parcel.writeInt(colour) + parcel.writeByte(if (hasClickedDelete) 1 else 0) + parcel.writeByte(if (isEditing) 1 else 0) + parcel.writeInt(selectedDay) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ScheduleUpdateSheet { + return ScheduleUpdateSheet(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } \ No newline at end of file