199 lines
7.8 KiB
Kotlin
199 lines
7.8 KiB
Kotlin
package io.heckel.ntfy.ui
|
|
|
|
import android.app.AlertDialog
|
|
import android.app.Dialog
|
|
import android.content.Context
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.text.Editable
|
|
import android.text.TextWatcher
|
|
import android.view.View
|
|
import android.view.WindowManager
|
|
import android.widget.Button
|
|
import android.widget.TextView
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.fragment.app.DialogFragment
|
|
import com.google.android.material.textfield.TextInputEditText
|
|
import io.heckel.ntfy.R
|
|
import io.heckel.ntfy.db.User
|
|
import io.heckel.ntfy.util.validUrl
|
|
|
|
class UserFragment : DialogFragment() {
|
|
private var user: User? = null
|
|
private lateinit var baseUrlsInUse: ArrayList<String>
|
|
private lateinit var listener: UserDialogListener
|
|
|
|
private lateinit var baseUrlView: TextInputEditText
|
|
private lateinit var usernameView: TextInputEditText
|
|
private lateinit var passwordView: TextInputEditText
|
|
private lateinit var positiveButton: Button
|
|
|
|
interface UserDialogListener {
|
|
fun onAddUser(dialog: DialogFragment, user: User)
|
|
fun onUpdateUser(dialog: DialogFragment, user: User)
|
|
fun onDeleteUser(dialog: DialogFragment, baseUrl: String)
|
|
}
|
|
|
|
override fun onAttach(context: Context) {
|
|
super.onAttach(context)
|
|
listener = activity as UserDialogListener
|
|
}
|
|
|
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
// Reconstruct user (if it is present in the bundle)
|
|
val baseUrl = arguments?.getString(BUNDLE_BASE_URL)
|
|
val username = arguments?.getString(BUNDLE_USERNAME)
|
|
val password = arguments?.getString(BUNDLE_PASSWORD)
|
|
|
|
if (baseUrl != null && username != null && password != null) {
|
|
user = User(baseUrl, username, password)
|
|
}
|
|
|
|
// Required for validation
|
|
baseUrlsInUse = arguments?.getStringArrayList(BUNDLE_BASE_URLS_IN_USE) ?: arrayListOf()
|
|
|
|
// Build root view
|
|
val view = requireActivity().layoutInflater.inflate(R.layout.fragment_user_dialog, null)
|
|
|
|
val positiveButtonTextResId = if (user == null) R.string.user_dialog_button_add else R.string.user_dialog_button_save
|
|
val titleView = view.findViewById(R.id.user_dialog_title) as TextView
|
|
val descriptionView = view.findViewById(R.id.user_dialog_description) as TextView
|
|
|
|
baseUrlView = view.findViewById(R.id.user_dialog_base_url)
|
|
usernameView = view.findViewById(R.id.user_dialog_username)
|
|
passwordView = view.findViewById(R.id.user_dialog_password)
|
|
|
|
if (user == null) {
|
|
titleView.text = getString(R.string.user_dialog_title_add)
|
|
descriptionView.text = getString(R.string.user_dialog_description_add)
|
|
baseUrlView.visibility = View.VISIBLE
|
|
passwordView.hint = getString(R.string.user_dialog_password_hint_add)
|
|
} else {
|
|
titleView.text = getString(R.string.user_dialog_title_edit)
|
|
descriptionView.text = getString(R.string.user_dialog_description_edit)
|
|
baseUrlView.visibility = View.GONE
|
|
usernameView.setText(user!!.username)
|
|
passwordView.hint = getString(R.string.user_dialog_password_hint_edit)
|
|
}
|
|
|
|
// Build dialog
|
|
val builder = AlertDialog.Builder(activity)
|
|
.setView(view)
|
|
.setPositiveButton(positiveButtonTextResId) { _, _ ->
|
|
saveClicked()
|
|
}
|
|
.setNegativeButton(R.string.user_dialog_button_cancel) { _, _ ->
|
|
// Do nothing
|
|
}
|
|
if (user != null) {
|
|
builder.setNeutralButton(R.string.user_dialog_button_delete) { _, _ ->
|
|
if (this::listener.isInitialized) {
|
|
listener.onDeleteUser(this, user!!.baseUrl)
|
|
}
|
|
}
|
|
}
|
|
val dialog = builder.create()
|
|
dialog.setOnShowListener {
|
|
positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
|
|
|
// Delete button should be red
|
|
if (user != null) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
dialog
|
|
.getButton(AlertDialog.BUTTON_NEUTRAL)
|
|
.setTextAppearance(R.style.DangerText)
|
|
} else {
|
|
dialog
|
|
.getButton(AlertDialog.BUTTON_NEUTRAL)
|
|
.setTextColor(ContextCompat.getColor(requireContext(), Colors.dangerText(requireContext())))
|
|
}
|
|
}
|
|
|
|
// Validate input when typing
|
|
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
|
|
}
|
|
}
|
|
baseUrlView.addTextChangedListener(textWatcher)
|
|
usernameView.addTextChangedListener(textWatcher)
|
|
passwordView.addTextChangedListener(textWatcher)
|
|
|
|
// Focus
|
|
if (user != null) {
|
|
usernameView.requestFocus()
|
|
if (usernameView.text != null) {
|
|
usernameView.setSelection(usernameView.text!!.length)
|
|
}
|
|
} else {
|
|
baseUrlView.requestFocus()
|
|
}
|
|
|
|
// Validate now!
|
|
validateInput()
|
|
}
|
|
|
|
// Show keyboard when the dialog is shown (see https://stackoverflow.com/a/19573049/1440785)
|
|
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
|
|
|
return dialog
|
|
}
|
|
|
|
private fun saveClicked() {
|
|
if (!this::listener.isInitialized) return
|
|
val baseUrl = baseUrlView.text?.toString() ?: ""
|
|
val username = usernameView.text?.toString() ?: ""
|
|
val password = passwordView.text?.toString() ?: ""
|
|
if (user == null) {
|
|
user = User(baseUrl, username, password)
|
|
listener.onAddUser(this, user!!)
|
|
} else {
|
|
user = if (password.isNotEmpty()) {
|
|
user!!.copy(username = username, password = password)
|
|
} else {
|
|
user!!.copy(username = username)
|
|
}
|
|
listener.onUpdateUser(this, user!!)
|
|
}
|
|
}
|
|
|
|
private fun validateInput() {
|
|
val baseUrl = baseUrlView.text?.toString() ?: ""
|
|
val username = usernameView.text?.toString() ?: ""
|
|
val password = passwordView.text?.toString() ?: ""
|
|
if (user == null) {
|
|
positiveButton.isEnabled = validUrl(baseUrl)
|
|
&& !baseUrlsInUse.contains(baseUrl)
|
|
&& username.isNotEmpty() && password.isNotEmpty()
|
|
} else {
|
|
positiveButton.isEnabled = username.isNotEmpty() // Unchanged if left blank
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
const val TAG = "NtfyUserFragment"
|
|
private const val BUNDLE_BASE_URL = "baseUrl"
|
|
private const val BUNDLE_USERNAME = "username"
|
|
private const val BUNDLE_PASSWORD = "password"
|
|
private const val BUNDLE_BASE_URLS_IN_USE = "baseUrlsInUse"
|
|
|
|
fun newInstance(user: User?, baseUrlsInUse: ArrayList<String>): UserFragment {
|
|
val fragment = UserFragment()
|
|
val args = Bundle()
|
|
args.putStringArrayList(BUNDLE_BASE_URLS_IN_USE, baseUrlsInUse)
|
|
if (user != null) {
|
|
args.putString(BUNDLE_BASE_URL, user.baseUrl)
|
|
args.putString(BUNDLE_USERNAME, user.username)
|
|
args.putString(BUNDLE_PASSWORD, user.password)
|
|
}
|
|
fragment.arguments = args
|
|
return fragment
|
|
}
|
|
}
|
|
}
|