diff --git a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
index 1b14b3a..a901d31 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt
@@ -26,7 +26,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.random.Random
-
class AddFragment : DialogFragment() {
private val api = ApiService()
diff --git a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
index 6577ecd..ed8a1ac 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
@@ -563,13 +563,28 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
}
preference.onPreferenceClickListener = OnPreferenceClickListener { _ ->
activity?.let {
- UserFragment().show(it.supportFragmentManager, UserFragment.TAG)
+ UserFragment
+ .newInstance(user.user)
+ .show(it.supportFragmentManager, UserFragment.TAG)
}
true
}
preferenceCategory.addPreference(preference)
}
}
+
+ // Add user
+ val preference = Preference(preferenceScreen.context)
+ preference.title = getString(R.string.settings_users_prefs_user_add)
+ preference.onPreferenceClickListener = OnPreferenceClickListener { _ ->
+ activity?.let {
+ UserFragment
+ .newInstance(user = null)
+ .show(it.supportFragmentManager, UserFragment.TAG)
+ }
+ true
+ }
+ preferenceScreen.addPreference(preference)
}
}
diff --git a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
index b76af6c..96e03fa 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/UserFragment.kt
@@ -3,31 +3,63 @@ package io.heckel.ntfy.ui
import android.app.AlertDialog
import android.app.Dialog
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
class UserFragment : DialogFragment() {
+ private var user: User? = null
+
+ private lateinit var baseUrlView: TextInputEditText
+ private lateinit var usernameView: TextInputEditText
+ private lateinit var passwordView: TextInputEditText
+ private lateinit var positiveButton: Button
+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- if (activity == null) {
- throw IllegalStateException("Activity cannot be null")
+ // Reconstruct user (if it is present in the bundle)
+ val userId = arguments?.getLong(BUNDLE_USER_ID)
+ val baseUrl = arguments?.getString(BUNDLE_BASE_URL)
+ val username = arguments?.getString(BUNDLE_USERNAME)
+ val password = arguments?.getString(BUNDLE_PASSWORD)
+
+ if (userId != null && baseUrl != null && username != null && password != null) {
+ user = User(userId, baseUrl, username, password)
}
// Build root view
val view = requireActivity().layoutInflater.inflate(R.layout.fragment_user_dialog, null)
- val addMode = false // FIXME
- val positiveButtonTextResId = if (addMode) R.string.user_dialog_button_add else R.string.user_dialog_button_save
- val titleText = view.findViewById(R.id.user_dialog_title) as TextView
- titleText.text = if (addMode) {
- getString(R.string.user_dialog_title_add)
+ 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 {
- getString(R.string.user_dialog_title_edit)
+ 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 dialog = AlertDialog.Builder(activity)
+ val builder = AlertDialog.Builder(activity)
.setView(view)
.setPositiveButton(positiveButtonTextResId) { _, _ ->
// This will be overridden below to avoid closing the dialog immediately
@@ -35,23 +67,78 @@ class UserFragment : DialogFragment() {
.setNegativeButton(R.string.user_dialog_button_cancel) { _, _ ->
// This will be overridden below
}
- .setNeutralButton(R.string.user_dialog_button_delete) { _, _ ->
+ if (user != null) {
+ builder.setNeutralButton(R.string.user_dialog_button_delete) { _, _ ->
// This will be overridden below
}
- .create()
+ }
+ val dialog = builder.create()
+ dialog.setOnShowListener {
+ positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
+
+ // Delete button should be red
+ if (user != null) {
+ dialog
+ .getButton(AlertDialog.BUTTON_NEUTRAL)
+ .setTextColor(ContextCompat.getColor(requireContext(), R.color.primaryDangerButtonColor))
+ }
+
+ // 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)
+
+ // 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);
- // Add logic to disable "Subscribe" button on invalid input
- dialog.setOnShowListener {
-
- }
-
return dialog
}
+ private fun validateInput() {
+ val baseUrl = baseUrlView.text?.toString() ?: ""
+ val username = usernameView.text?.toString() ?: ""
+ val password = passwordView.text?.toString() ?: ""
+ if (user == null) {
+ positiveButton.isEnabled = (baseUrl.startsWith("http://") || baseUrl.startsWith("https://"))
+ && username.isNotEmpty() && password.isNotEmpty()
+ } else {
+ positiveButton.isEnabled = username.isNotEmpty() // Unchanged if left blank
+ }
+ }
+
companion object {
const val TAG = "NtfyUserFragment"
+ private const val BUNDLE_USER_ID = "userId"
+ private const val BUNDLE_BASE_URL = "baseUrl"
+ private const val BUNDLE_USERNAME = "username"
+ private const val BUNDLE_PASSWORD = "password"
+
+ fun newInstance(user: User?): UserFragment {
+ val fragment = UserFragment()
+ val args = Bundle()
+ if (user != null) {
+ args.putLong(BUNDLE_USER_ID, user.id)
+ args.putString(BUNDLE_BASE_URL, user.baseUrl)
+ args.putString(BUNDLE_USERNAME, user.username)
+ args.putString(BUNDLE_PASSWORD, user.password)
+ fragment.arguments = args
+ }
+ return fragment
+ }
}
}
diff --git a/app/src/main/res/layout/fragment_user_dialog.xml b/app/src/main/res/layout/fragment_user_dialog.xml
index 3676206..c1905e7 100644
--- a/app/src/main/res/layout/fragment_user_dialog.xml
+++ b/app/src/main/res/layout/fragment_user_dialog.xml
@@ -8,6 +8,13 @@
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:visibility="visible">
+
+
+ android:layout_marginTop="6dp" app:layout_constraintTop_toBottomOf="@id/user_dialog_base_url"/>
Not used by any topics
Used by topic %1$s
Used by topics %1$s
+ Add user
UnifiedPush
Allows other apps to use ntfy as a message distributor. Find out more at unifiedpush.org.
UnifiedPushEnabled
@@ -297,8 +298,12 @@
Add user
Edit user
+ You can add a user here that you can later associate with a specific topic.
+ You may edit username/password for the selected user, or delete it entirely.
+ Server URL
Username
- Password
+ Password
+ Password (unchanged if blank)
Add user
Cancel
Delete user