Don't make AddFragment crash when screen is rotated
This commit is contained in:
parent
c3f9cfbb13
commit
b40176c9f4
3 changed files with 92 additions and 73 deletions
|
@ -2,9 +2,11 @@ package io.heckel.ntfy.ui
|
|||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
|
@ -12,10 +14,15 @@ import androidx.fragment.app.DialogFragment
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.data.Database
|
||||
import io.heckel.ntfy.data.Repository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
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 baseUrlText: TextInputEditText
|
||||
private lateinit var useAnotherServerCheckbox: CheckBox
|
||||
|
@ -25,81 +32,96 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
|
|||
private lateinit var instantDeliveryDescription: View
|
||||
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 {
|
||||
return activity?.let {
|
||||
// Build root view
|
||||
val view = requireActivity().layoutInflater.inflate(R.layout.add_dialog_fragment, null)
|
||||
topicNameText = view.findViewById(R.id.add_dialog_topic_text) as TextInputEditText
|
||||
baseUrlText = view.findViewById(R.id.add_dialog_base_url_text) as TextInputEditText
|
||||
instantDeliveryBox = view.findViewById(R.id.add_dialog_instant_delivery_box)
|
||||
instantDeliveryCheckbox = view.findViewById(R.id.add_dialog_instant_delivery_checkbox) as CheckBox
|
||||
instantDeliveryDescription = view.findViewById(R.id.add_dialog_instant_delivery_description)
|
||||
useAnotherServerCheckbox = view.findViewById(R.id.add_dialog_use_another_server_checkbox) as CheckBox
|
||||
useAnotherServerDescription = view.findViewById(R.id.add_dialog_use_another_server_description)
|
||||
if (activity == null) {
|
||||
throw IllegalStateException("Activity cannot be null")
|
||||
}
|
||||
|
||||
// Build dialog
|
||||
val alert = AlertDialog.Builder(it)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.add_dialog_button_subscribe) { _, _ ->
|
||||
val topic = topicNameText.text.toString()
|
||||
val baseUrl = getBaseUrl()
|
||||
val instant = if (useAnotherServerCheckbox.isChecked) true else instantDeliveryCheckbox.isChecked
|
||||
onSubscribe(topic, baseUrl, instant)
|
||||
}
|
||||
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
|
||||
dialog?.cancel()
|
||||
}
|
||||
.create()
|
||||
// Dependencies
|
||||
val database = Database.getInstance(activity!!.applicationContext)
|
||||
repository = Repository.getInstance(database.subscriptionDao(), database.notificationDao())
|
||||
|
||||
// Add logic to disable "Subscribe" button on invalid input
|
||||
alert.setOnShowListener {
|
||||
val dialog = it as AlertDialog
|
||||
// Build root view
|
||||
val view = requireActivity().layoutInflater.inflate(R.layout.add_dialog_fragment, null)
|
||||
topicNameText = view.findViewById(R.id.add_dialog_topic_text) as TextInputEditText
|
||||
baseUrlText = view.findViewById(R.id.add_dialog_base_url_text) as TextInputEditText
|
||||
instantDeliveryBox = view.findViewById(R.id.add_dialog_instant_delivery_box)
|
||||
instantDeliveryCheckbox = view.findViewById(R.id.add_dialog_instant_delivery_checkbox) as CheckBox
|
||||
instantDeliveryDescription = view.findViewById(R.id.add_dialog_instant_delivery_description)
|
||||
useAnotherServerCheckbox = view.findViewById(R.id.add_dialog_use_another_server_checkbox) as CheckBox
|
||||
useAnotherServerDescription = view.findViewById(R.id.add_dialog_use_another_server_description)
|
||||
|
||||
subscribeButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
subscribeButton.isEnabled = false
|
||||
// Build dialog
|
||||
val alert = AlertDialog.Builder(activity)
|
||||
.setView(view)
|
||||
.setPositiveButton(R.string.add_dialog_button_subscribe) { _, _ ->
|
||||
val topic = topicNameText.text.toString()
|
||||
val baseUrl = getBaseUrl()
|
||||
val instant = if (useAnotherServerCheckbox.isChecked) true else instantDeliveryCheckbox.isChecked
|
||||
subscribeListener.onSubscribe(topic, baseUrl, instant)
|
||||
}
|
||||
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
|
||||
dialog?.cancel()
|
||||
}
|
||||
.create()
|
||||
|
||||
val textWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
validateInput()
|
||||
}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
// Nothing
|
||||
}
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
// Nothing
|
||||
}
|
||||
}
|
||||
topicNameText.addTextChangedListener(textWatcher)
|
||||
baseUrlText.addTextChangedListener(textWatcher)
|
||||
instantDeliveryCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) instantDeliveryDescription.visibility = View.VISIBLE
|
||||
else instantDeliveryDescription.visibility = View.GONE
|
||||
}
|
||||
useAnotherServerCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
useAnotherServerDescription.visibility = View.VISIBLE
|
||||
baseUrlText.visibility = View.VISIBLE
|
||||
instantDeliveryBox.visibility = View.GONE
|
||||
instantDeliveryDescription.visibility = View.GONE
|
||||
} else {
|
||||
useAnotherServerDescription.visibility = View.GONE
|
||||
baseUrlText.visibility = View.GONE
|
||||
instantDeliveryBox.visibility = View.VISIBLE
|
||||
if (instantDeliveryCheckbox.isChecked) instantDeliveryDescription.visibility = View.VISIBLE
|
||||
else instantDeliveryDescription.visibility = View.GONE
|
||||
}
|
||||
// Add logic to disable "Subscribe" button on invalid input
|
||||
alert.setOnShowListener {
|
||||
val dialog = it as AlertDialog
|
||||
|
||||
subscribeButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
subscribeButton.isEnabled = false
|
||||
|
||||
val textWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
validateInput()
|
||||
}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
// Nothing
|
||||
}
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
// Nothing
|
||||
}
|
||||
}
|
||||
topicNameText.addTextChangedListener(textWatcher)
|
||||
baseUrlText.addTextChangedListener(textWatcher)
|
||||
instantDeliveryCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) instantDeliveryDescription.visibility = View.VISIBLE
|
||||
else instantDeliveryDescription.visibility = View.GONE
|
||||
}
|
||||
useAnotherServerCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
useAnotherServerDescription.visibility = View.VISIBLE
|
||||
baseUrlText.visibility = View.VISIBLE
|
||||
instantDeliveryBox.visibility = View.GONE
|
||||
instantDeliveryDescription.visibility = View.GONE
|
||||
} else {
|
||||
useAnotherServerDescription.visibility = View.GONE
|
||||
baseUrlText.visibility = View.GONE
|
||||
instantDeliveryBox.visibility = View.VISIBLE
|
||||
if (instantDeliveryCheckbox.isChecked) instantDeliveryDescription.visibility = View.VISIBLE
|
||||
else instantDeliveryDescription.visibility = View.GONE
|
||||
}
|
||||
validateInput()
|
||||
}
|
||||
}
|
||||
|
||||
alert
|
||||
} ?: throw IllegalStateException("Activity cannot be null")
|
||||
return alert
|
||||
}
|
||||
|
||||
private fun validateInput() = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val baseUrl = getBaseUrl()
|
||||
val topic = topicNameText.text.toString()
|
||||
val subscription = viewModel.get(baseUrl, topic)
|
||||
val subscription = repository.getSubscription(baseUrl, topic)
|
||||
|
||||
activity?.let {
|
||||
it.runOnUiThread {
|
||||
|
@ -127,8 +149,6 @@ class AddFragment(private val viewModel: SubscriptionsViewModel, private val onS
|
|||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance() {
|
||||
// ... make it not crash
|
||||
}
|
||||
const val TAG = "NtfyAffFragment"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit
|
|||
import kotlin.random.Random
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity(), ActionMode.Callback {
|
||||
class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.SubscribeListener {
|
||||
private val viewModel by viewModels<SubscriptionsViewModel> {
|
||||
SubscriptionsViewModelFactory((application as Application).repository)
|
||||
}
|
||||
|
@ -152,12 +152,11 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
|
|||
}
|
||||
|
||||
private fun onSubscribeButtonClick() {
|
||||
val newFragment = AddFragment(viewModel, ::onSubscribe)
|
||||
newFragment
|
||||
.show(supportFragmentManager, "AddFragment")
|
||||
val newFragment = AddFragment()
|
||||
newFragment.show(supportFragmentManager, AddFragment.TAG)
|
||||
}
|
||||
|
||||
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)}")
|
||||
|
||||
// Add subscription to database
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<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"
|
||||
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"
|
||||
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"
|
||||
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_copy_url" android:title="@string/detail_menu_copy_url"/>
|
||||
<item android:id="@+id/detail_menu_unsubscribe" android:title="@string/detail_menu_unsubscribe"/>
|
||||
|
|
Loading…
Reference in a new issue