Don't make AddFragment crash when screen is rotated

This commit is contained in:
Philipp Heckel 2021-11-17 20:16:58 -05:00
parent c3f9cfbb13
commit b40176c9f4
3 changed files with 92 additions and 73 deletions

View file

@ -2,9 +2,11 @@ package io.heckel.ntfy.ui
import android.app.AlertDialog import android.app.AlertDialog
import android.app.Dialog import android.app.Dialog
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.Log
import android.view.View import android.view.View
import android.widget.Button import android.widget.Button
import android.widget.CheckBox import android.widget.CheckBox
@ -12,10 +14,15 @@ import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.data.Database
import io.heckel.ntfy.data.Repository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AddFragment(private val viewModel: SubscriptionsViewModel, private val onSubscribe: (topic: String, baseUrl: String, instant: Boolean) -> Unit) : DialogFragment() { class AddFragment : DialogFragment() {
private lateinit var repository: Repository
private lateinit var subscribeListener: SubscribeListener
private lateinit var topicNameText: TextInputEditText private lateinit var topicNameText: TextInputEditText
private lateinit var baseUrlText: TextInputEditText private lateinit var baseUrlText: TextInputEditText
private lateinit var useAnotherServerCheckbox: CheckBox private lateinit var useAnotherServerCheckbox: CheckBox
@ -25,8 +32,24 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
private lateinit var instantDeliveryDescription: View private lateinit var instantDeliveryDescription: View
private lateinit var subscribeButton: Button private lateinit var subscribeButton: Button
interface SubscribeListener {
fun onSubscribe(topic: String, baseUrl: String, instant: Boolean)
}
override fun onAttach(context: Context) {
super.onAttach(context)
subscribeListener = activity as SubscribeListener
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let { if (activity == null) {
throw IllegalStateException("Activity cannot be null")
}
// Dependencies
val database = Database.getInstance(activity!!.applicationContext)
repository = Repository.getInstance(database.subscriptionDao(), database.notificationDao())
// Build root view // Build root view
val view = requireActivity().layoutInflater.inflate(R.layout.add_dialog_fragment, null) val view = requireActivity().layoutInflater.inflate(R.layout.add_dialog_fragment, null)
topicNameText = view.findViewById(R.id.add_dialog_topic_text) as TextInputEditText topicNameText = view.findViewById(R.id.add_dialog_topic_text) as TextInputEditText
@ -38,13 +61,13 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
useAnotherServerDescription = view.findViewById(R.id.add_dialog_use_another_server_description) useAnotherServerDescription = view.findViewById(R.id.add_dialog_use_another_server_description)
// Build dialog // Build dialog
val alert = AlertDialog.Builder(it) val alert = AlertDialog.Builder(activity)
.setView(view) .setView(view)
.setPositiveButton(R.string.add_dialog_button_subscribe) { _, _ -> .setPositiveButton(R.string.add_dialog_button_subscribe) { _, _ ->
val topic = topicNameText.text.toString() val topic = topicNameText.text.toString()
val baseUrl = getBaseUrl() val baseUrl = getBaseUrl()
val instant = if (useAnotherServerCheckbox.isChecked) true else instantDeliveryCheckbox.isChecked val instant = if (useAnotherServerCheckbox.isChecked) true else instantDeliveryCheckbox.isChecked
onSubscribe(topic, baseUrl, instant) subscribeListener.onSubscribe(topic, baseUrl, instant)
} }
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ -> .setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
dialog?.cancel() dialog?.cancel()
@ -92,14 +115,13 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
} }
} }
alert return alert
} ?: throw IllegalStateException("Activity cannot be null")
} }
private fun validateInput() = lifecycleScope.launch(Dispatchers.IO) { private fun validateInput() = lifecycleScope.launch(Dispatchers.IO) {
val baseUrl = getBaseUrl() val baseUrl = getBaseUrl()
val topic = topicNameText.text.toString() val topic = topicNameText.text.toString()
val subscription = viewModel.get(baseUrl, topic) val subscription = repository.getSubscription(baseUrl, topic)
activity?.let { activity?.let {
it.runOnUiThread { it.runOnUiThread {
@ -127,8 +149,6 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
} }
companion object { companion object {
fun newInstance() { const val TAG = "NtfyAffFragment"
// ... make it not crash
}
} }
} }

View file

@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit
import kotlin.random.Random import kotlin.random.Random
class MainActivity : AppCompatActivity(), ActionMode.Callback { class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.SubscribeListener {
private val viewModel by viewModels<SubscriptionsViewModel> { private val viewModel by viewModels<SubscriptionsViewModel> {
SubscriptionsViewModelFactory((application as Application).repository) SubscriptionsViewModelFactory((application as Application).repository)
} }
@ -152,12 +152,11 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
} }
private fun onSubscribeButtonClick() { private fun onSubscribeButtonClick() {
val newFragment = AddFragment(viewModel, ::onSubscribe) val newFragment = AddFragment()
newFragment newFragment.show(supportFragmentManager, AddFragment.TAG)
.show(supportFragmentManager, "AddFragment")
} }
private fun onSubscribe(topic: String, baseUrl: String, instant: Boolean) { override fun onSubscribe(topic: String, baseUrl: String, instant: Boolean) {
Log.d(TAG, "Adding subscription ${topicShortUrl(baseUrl, topic)}") Log.d(TAG, "Adding subscription ${topicShortUrl(baseUrl, topic)}")
// Add subscription to database // Add subscription to database

View file

@ -1,10 +1,10 @@
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/detail_menu_enable_instant" android:title="@string/detail_menu_enable_instant" <item android:id="@+id/detail_menu_enable_instant" android:title="@string/detail_menu_enable_instant"
app:showAsAction="ifRoom|withText" android:icon="@drawable/ic_bolt_outline_white_24dp"/> app:showAsAction="ifRoom" android:icon="@drawable/ic_bolt_outline_white_24dp"/>
<item android:id="@+id/detail_menu_disable_instant" android:title="@string/detail_menu_disable_instant" <item android:id="@+id/detail_menu_disable_instant" android:title="@string/detail_menu_disable_instant"
android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom|withText"/> android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom"/>
<item android:id="@+id/detail_menu_instant_info" android:title="@string/detail_menu_instant_info" <item android:id="@+id/detail_menu_instant_info" android:title="@string/detail_menu_instant_info"
android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom|withText"/> android:icon="@drawable/ic_bolt_white_24dp" app:showAsAction="ifRoom"/>
<item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/> <item android:id="@+id/detail_menu_test" android:title="@string/detail_menu_test"/>
<item android:id="@+id/detail_menu_copy_url" android:title="@string/detail_menu_copy_url"/> <item android:id="@+id/detail_menu_copy_url" android:title="@string/detail_menu_copy_url"/>
<item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/> <item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/>