More add dialog changes; we're getting there
This commit is contained in:
parent
88b2576af0
commit
c16282fcae
5 changed files with 186 additions and 70 deletions
|
@ -87,13 +87,7 @@ data class User(
|
||||||
@ColumnInfo(name = "username") val username: String,
|
@ColumnInfo(name = "username") val username: String,
|
||||||
@ColumnInfo(name = "password") val password: String
|
@ColumnInfo(name = "password") val password: String
|
||||||
) {
|
) {
|
||||||
override fun toString(): String {
|
override fun toString(): String = username
|
||||||
return if (baseUrl == "") {
|
|
||||||
username
|
|
||||||
} else {
|
|
||||||
"$username (${shortUrl(baseUrl)})"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(tableName = "Log")
|
@Entity(tableName = "Log")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.heckel.ntfy.ui
|
package io.heckel.ntfy.ui
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -25,6 +26,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
class AddFragment : DialogFragment() {
|
class AddFragment : DialogFragment() {
|
||||||
private val api = ApiService()
|
private val api = ApiService()
|
||||||
|
|
||||||
|
@ -33,6 +35,8 @@ class AddFragment : DialogFragment() {
|
||||||
|
|
||||||
private lateinit var subscribeView: View
|
private lateinit var subscribeView: View
|
||||||
private lateinit var loginView: View
|
private lateinit var loginView: View
|
||||||
|
private lateinit var positiveButton: Button
|
||||||
|
private lateinit var negativeButton: Button
|
||||||
|
|
||||||
// Subscribe page
|
// Subscribe page
|
||||||
private lateinit var subscribeTopicText: TextInputEditText
|
private lateinit var subscribeTopicText: TextInputEditText
|
||||||
|
@ -45,7 +49,6 @@ class AddFragment : DialogFragment() {
|
||||||
private lateinit var subscribeInstantDeliveryDescription: View
|
private lateinit var subscribeInstantDeliveryDescription: View
|
||||||
private lateinit var subscribeProgress: ProgressBar
|
private lateinit var subscribeProgress: ProgressBar
|
||||||
private lateinit var subscribeErrorImage: View
|
private lateinit var subscribeErrorImage: View
|
||||||
private lateinit var subscribeButton: Button
|
|
||||||
|
|
||||||
// Login page
|
// Login page
|
||||||
private lateinit var users: List<User>
|
private lateinit var users: List<User>
|
||||||
|
@ -79,6 +82,7 @@ class AddFragment : DialogFragment() {
|
||||||
|
|
||||||
// Main "pages"
|
// Main "pages"
|
||||||
subscribeView = view.findViewById(R.id.add_dialog_subscribe_view)
|
subscribeView = view.findViewById(R.id.add_dialog_subscribe_view)
|
||||||
|
subscribeView.visibility = View.VISIBLE
|
||||||
loginView = view.findViewById(R.id.add_dialog_login_view)
|
loginView = view.findViewById(R.id.add_dialog_login_view)
|
||||||
loginView.visibility = View.GONE
|
loginView.visibility = View.GONE
|
||||||
|
|
||||||
|
@ -153,8 +157,9 @@ class AddFragment : DialogFragment() {
|
||||||
.map { it.key }
|
.map { it.key }
|
||||||
.filterNot { it == appBaseUrl }
|
.filterNot { it == appBaseUrl }
|
||||||
.sorted()
|
.sorted()
|
||||||
val adapter = ArrayAdapter(requireActivity(), R.layout.fragment_add_dialog_dropdown_item, baseUrls)
|
val activity = activity ?: return@launch // We may have pressed "Cancel"
|
||||||
requireActivity().runOnUiThread {
|
val adapter = ArrayAdapter(activity, R.layout.fragment_add_dialog_dropdown_item, baseUrls)
|
||||||
|
activity.runOnUiThread {
|
||||||
subscribeBaseUrlText.threshold = 1
|
subscribeBaseUrlText.threshold = 1
|
||||||
subscribeBaseUrlText.setAdapter(adapter)
|
subscribeBaseUrlText.setAdapter(adapter)
|
||||||
if (baseUrls.count() == 1) {
|
if (baseUrls.count() == 1) {
|
||||||
|
@ -179,17 +184,41 @@ class AddFragment : DialogFragment() {
|
||||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
loginUsernameText.visibility = View.VISIBLE
|
loginUsernameText.visibility = View.VISIBLE
|
||||||
|
loginUsernameText.isEnabled = true
|
||||||
loginPasswordText.visibility = View.VISIBLE
|
loginPasswordText.visibility = View.VISIBLE
|
||||||
|
loginPasswordText.isEnabled = true
|
||||||
|
if (loginUsernameText.requestFocus()) {
|
||||||
|
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
|
imm?.showSoftInput(loginUsernameText, InputMethodManager.SHOW_IMPLICIT)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
loginUsernameText.visibility = View.GONE
|
loginUsernameText.visibility = View.GONE
|
||||||
|
loginUsernameText.isEnabled = false
|
||||||
loginPasswordText.visibility = View.GONE
|
loginPasswordText.visibility = View.GONE
|
||||||
|
loginPasswordText.isEnabled = false
|
||||||
}
|
}
|
||||||
|
validateInputLoginView()
|
||||||
}
|
}
|
||||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||||
// This should not happen, ha!
|
// This should not happen, ha!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Username/password validation on type
|
||||||
|
val textWatcher = object : TextWatcher {
|
||||||
|
override fun afterTextChanged(s: Editable?) {
|
||||||
|
validateInputLoginView()
|
||||||
|
}
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loginUsernameText.addTextChangedListener(textWatcher)
|
||||||
|
loginPasswordText.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
// Build dialog
|
// Build dialog
|
||||||
val dialog = AlertDialog.Builder(activity)
|
val dialog = AlertDialog.Builder(activity)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
|
@ -197,7 +226,7 @@ class AddFragment : DialogFragment() {
|
||||||
// This will be overridden below to avoid closing the dialog immediately
|
// This will be overridden below to avoid closing the dialog immediately
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
|
.setNegativeButton(R.string.add_dialog_button_cancel) { _, _ ->
|
||||||
dialog?.cancel()
|
// This will be overridden below
|
||||||
}
|
}
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
|
@ -206,15 +235,18 @@ class AddFragment : DialogFragment() {
|
||||||
|
|
||||||
// Add logic to disable "Subscribe" button on invalid input
|
// Add logic to disable "Subscribe" button on invalid input
|
||||||
dialog.setOnShowListener {
|
dialog.setOnShowListener {
|
||||||
subscribeButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
subscribeButton.isEnabled = false
|
positiveButton.isEnabled = false
|
||||||
subscribeButton.setOnClickListener {
|
positiveButton.setOnClickListener {
|
||||||
subscribeButtonClick()
|
positiveButtonClick()
|
||||||
|
}
|
||||||
|
negativeButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||||
|
negativeButton.setOnClickListener {
|
||||||
|
negativeButtonClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
val textWatcher = object : TextWatcher {
|
val textWatcher = object : TextWatcher {
|
||||||
override fun afterTextChanged(s: Editable?) {
|
override fun afterTextChanged(s: Editable?) {
|
||||||
validateInput()
|
validateInputSubscribeView()
|
||||||
}
|
}
|
||||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||||
// Nothing
|
// Nothing
|
||||||
|
@ -242,7 +274,7 @@ class AddFragment : DialogFragment() {
|
||||||
if (subscribeInstantDeliveryCheckbox.isChecked) subscribeInstantDeliveryDescription.visibility = View.VISIBLE
|
if (subscribeInstantDeliveryCheckbox.isChecked) subscribeInstantDeliveryDescription.visibility = View.VISIBLE
|
||||||
else subscribeInstantDeliveryDescription.visibility = View.GONE
|
else subscribeInstantDeliveryDescription.visibility = View.GONE
|
||||||
}
|
}
|
||||||
validateInput()
|
validateInputSubscribeView()
|
||||||
}
|
}
|
||||||
subscribeUseAnotherServerCheckbox.isChecked = this::baseUrls.isInitialized && baseUrls.count() == 1
|
subscribeUseAnotherServerCheckbox.isChecked = this::baseUrls.isInitialized && baseUrls.count() == 1
|
||||||
|
|
||||||
|
@ -253,19 +285,20 @@ class AddFragment : DialogFragment() {
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribeButtonClick() {
|
private fun positiveButtonClick() {
|
||||||
val topic = subscribeTopicText.text.toString()
|
val topic = subscribeTopicText.text.toString()
|
||||||
val baseUrl = getBaseUrl()
|
val baseUrl = getBaseUrl()
|
||||||
if (subscribeView.visibility == View.VISIBLE) {
|
if (subscribeView.visibility == View.VISIBLE) {
|
||||||
checkAnonReadAndMaybeShowLogin(baseUrl, topic)
|
checkAnonReadAndMaybeShowLogin(baseUrl, topic)
|
||||||
} else if (loginView.visibility == View.VISIBLE) {
|
} else if (loginView.visibility == View.VISIBLE) {
|
||||||
checkAuthAndMaybeDismiss(baseUrl, topic)
|
loginAndMaybeDismiss(baseUrl, topic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAnonReadAndMaybeShowLogin(baseUrl: String, topic: String) {
|
private fun checkAnonReadAndMaybeShowLogin(baseUrl: String, topic: String) {
|
||||||
subscribeProgress.visibility = View.VISIBLE
|
subscribeProgress.visibility = View.VISIBLE
|
||||||
subscribeErrorImage.visibility = View.GONE
|
subscribeErrorImage.visibility = View.GONE
|
||||||
|
enableSubscribeView(false)
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
Log.d(TAG, "Checking anonymous read access to topic ${topicUrl(baseUrl, topic)}")
|
Log.d(TAG, "Checking anonymous read access to topic ${topicUrl(baseUrl, topic)}")
|
||||||
try {
|
try {
|
||||||
|
@ -275,29 +308,18 @@ class AddFragment : DialogFragment() {
|
||||||
dismiss(authUserId = null)
|
dismiss(authUserId = null)
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Anonymous access not allowed to topic ${topicUrl(baseUrl, topic)}, showing login dialog")
|
Log.w(TAG, "Anonymous access not allowed to topic ${topicUrl(baseUrl, topic)}, showing login dialog")
|
||||||
requireActivity().runOnUiThread {
|
val activity = activity ?: return@launch // We may have pressed "Cancel"
|
||||||
// Show/hide users dropdown
|
activity.runOnUiThread {
|
||||||
val relevantUsers = users.filter { it.baseUrl == baseUrl }
|
showLoginView(activity, baseUrl)
|
||||||
if (relevantUsers.isEmpty()) {
|
|
||||||
loginUsersSpinner.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
val spinnerEntries = relevantUsers.toMutableList()
|
|
||||||
spinnerEntries.add(0, User(0, "", getString(R.string.add_dialog_login_new_user), ""))
|
|
||||||
loginUsersSpinner.adapter = ArrayAdapter(requireActivity(), R.layout.fragment_add_dialog_dropdown_item, spinnerEntries)
|
|
||||||
loginUsersSpinner.setSelection(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show login page
|
|
||||||
subscribeView.visibility = View.GONE
|
|
||||||
loginProgress.visibility = View.INVISIBLE
|
|
||||||
loginView.visibility = View.VISIBLE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Connection to topic failed: ${e.message}", e)
|
Log.w(TAG, "Connection to topic failed: ${e.message}", e)
|
||||||
requireActivity().runOnUiThread {
|
val activity = activity ?: return@launch // We may have pressed "Cancel"
|
||||||
|
activity.runOnUiThread {
|
||||||
subscribeProgress.visibility = View.GONE
|
subscribeProgress.visibility = View.GONE
|
||||||
subscribeErrorImage.visibility = View.VISIBLE
|
subscribeErrorImage.visibility = View.VISIBLE
|
||||||
|
enableSubscribeView(true)
|
||||||
Toast
|
Toast
|
||||||
.makeText(context, getString(R.string.add_dialog_error_connection_failed, e.message), Toast.LENGTH_LONG)
|
.makeText(context, getString(R.string.add_dialog_error_connection_failed, e.message), Toast.LENGTH_LONG)
|
||||||
.show()
|
.show()
|
||||||
|
@ -306,9 +328,10 @@ class AddFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAuthAndMaybeDismiss(baseUrl: String, topic: String) {
|
private fun loginAndMaybeDismiss(baseUrl: String, topic: String) {
|
||||||
loginProgress.visibility = View.VISIBLE
|
loginProgress.visibility = View.VISIBLE
|
||||||
loginErrorImage.visibility = View.GONE
|
loginErrorImage.visibility = View.GONE
|
||||||
|
enableLoginView(false)
|
||||||
val existingUser = loginUsersSpinner.selectedItem != null && loginUsersSpinner.selectedItem is User && loginUsersSpinner.selectedItemPosition > 0
|
val existingUser = loginUsersSpinner.selectedItem != null && loginUsersSpinner.selectedItem is User && loginUsersSpinner.selectedItemPosition > 0
|
||||||
val user = if (existingUser) {
|
val user = if (existingUser) {
|
||||||
loginUsersSpinner.selectedItem as User
|
loginUsersSpinner.selectedItem as User
|
||||||
|
@ -333,18 +356,22 @@ class AddFragment : DialogFragment() {
|
||||||
dismiss(authUserId = user.id)
|
dismiss(authUserId = user.id)
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Access not allowed for user ${user.username} to topic ${topicUrl(baseUrl, topic)}")
|
Log.w(TAG, "Access not allowed for user ${user.username} to topic ${topicUrl(baseUrl, topic)}")
|
||||||
requireActivity().runOnUiThread {
|
val activity = activity ?: return@launch // We may have pressed "Cancel"
|
||||||
|
activity.runOnUiThread {
|
||||||
loginProgress.visibility = View.GONE
|
loginProgress.visibility = View.GONE
|
||||||
loginErrorImage.visibility = View.VISIBLE
|
loginErrorImage.visibility = View.VISIBLE
|
||||||
|
enableLoginView(true)
|
||||||
Toast
|
Toast
|
||||||
.makeText(context, getString(R.string.add_dialog_login_error_not_authorized), Toast.LENGTH_LONG)
|
.makeText(context, getString(R.string.add_dialog_login_error_not_authorized), Toast.LENGTH_LONG)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
requireActivity().runOnUiThread {
|
val activity = activity ?: return@launch // We may have pressed "Cancel"
|
||||||
|
activity.runOnUiThread {
|
||||||
loginProgress.visibility = View.GONE
|
loginProgress.visibility = View.GONE
|
||||||
loginErrorImage.visibility = View.VISIBLE
|
loginErrorImage.visibility = View.VISIBLE
|
||||||
|
enableLoginView(true)
|
||||||
Toast
|
Toast
|
||||||
.makeText(context, getString(R.string.add_dialog_error_connection_failed, e.message), Toast.LENGTH_LONG)
|
.makeText(context, getString(R.string.add_dialog_error_connection_failed, e.message), Toast.LENGTH_LONG)
|
||||||
.show()
|
.show()
|
||||||
|
@ -353,7 +380,16 @@ class AddFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateInput() = lifecycleScope.launch(Dispatchers.IO) {
|
private fun negativeButtonClick() {
|
||||||
|
if (subscribeView.visibility == View.VISIBLE) {
|
||||||
|
dialog?.cancel()
|
||||||
|
} else if (loginView.visibility == View.VISIBLE) {
|
||||||
|
showSubscribeView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateInputSubscribeView() {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val baseUrl = getBaseUrl()
|
val baseUrl = getBaseUrl()
|
||||||
val topic = subscribeTopicText.text.toString()
|
val topic = subscribeTopicText.text.toString()
|
||||||
val subscription = repository.getSubscription(baseUrl, topic)
|
val subscription = repository.getSubscription(baseUrl, topic)
|
||||||
|
@ -361,23 +397,34 @@ class AddFragment : DialogFragment() {
|
||||||
activity?.let {
|
activity?.let {
|
||||||
it.runOnUiThread {
|
it.runOnUiThread {
|
||||||
if (subscription != null || DISALLOWED_TOPICS.contains(topic)) {
|
if (subscription != null || DISALLOWED_TOPICS.contains(topic)) {
|
||||||
subscribeButton.isEnabled = false
|
positiveButton.isEnabled = false
|
||||||
} else if (subscribeUseAnotherServerCheckbox.isChecked) {
|
} else if (subscribeUseAnotherServerCheckbox.isChecked) {
|
||||||
subscribeButton.isEnabled = topic.isNotBlank()
|
positiveButton.isEnabled = topic.isNotBlank()
|
||||||
&& "[-_A-Za-z0-9]{1,64}".toRegex().matches(topic)
|
&& "[-_A-Za-z0-9]{1,64}".toRegex().matches(topic)
|
||||||
&& baseUrl.isNotBlank()
|
&& baseUrl.isNotBlank()
|
||||||
&& "^https?://.+".toRegex().matches(baseUrl)
|
&& "^https?://.+".toRegex().matches(baseUrl)
|
||||||
} else {
|
} else {
|
||||||
subscribeButton.isEnabled = topic.isNotBlank()
|
positiveButton.isEnabled = topic.isNotBlank()
|
||||||
&& "[-_A-Za-z0-9]{1,64}".toRegex().matches(topic)
|
&& "[-_A-Za-z0-9]{1,64}".toRegex().matches(topic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateInputLoginView() {
|
||||||
|
if (loginUsernameText.visibility == View.GONE) {
|
||||||
|
positiveButton.isEnabled = true
|
||||||
|
} else {
|
||||||
|
positiveButton.isEnabled = (loginUsernameText.text?.isNotEmpty() ?: false)
|
||||||
|
&& (loginPasswordText.text?.isNotEmpty() ?: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun dismiss(authUserId: Long?) {
|
private fun dismiss(authUserId: Long?) {
|
||||||
Log.d(TAG, "Closing dialog and calling onSubscribe handler")
|
Log.d(TAG, "Closing dialog and calling onSubscribe handler")
|
||||||
requireActivity().runOnUiThread {
|
val activity = activity?: return // We may have pressed "Cancel"
|
||||||
|
activity.runOnUiThread {
|
||||||
val topic = subscribeTopicText.text.toString()
|
val topic = subscribeTopicText.text.toString()
|
||||||
val baseUrl = getBaseUrl()
|
val baseUrl = getBaseUrl()
|
||||||
val instant = if (!BuildConfig.FIREBASE_AVAILABLE || subscribeUseAnotherServerCheckbox.isChecked) {
|
val instant = if (!BuildConfig.FIREBASE_AVAILABLE || subscribeUseAnotherServerCheckbox.isChecked) {
|
||||||
|
@ -398,6 +445,77 @@ class AddFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showSubscribeView() {
|
||||||
|
resetSubscribeView()
|
||||||
|
positiveButton.text = getString(R.string.add_dialog_button_subscribe)
|
||||||
|
negativeButton.text = getString(R.string.add_dialog_button_cancel)
|
||||||
|
loginView.visibility = View.GONE
|
||||||
|
subscribeView.visibility = View.VISIBLE
|
||||||
|
if (subscribeTopicText.requestFocus()) {
|
||||||
|
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
|
imm?.showSoftInput(subscribeTopicText, InputMethodManager.SHOW_IMPLICIT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showLoginView(activity: Activity, baseUrl: String) {
|
||||||
|
resetLoginView()
|
||||||
|
loginProgress.visibility = View.INVISIBLE
|
||||||
|
positiveButton.text = getString(R.string.add_dialog_button_login)
|
||||||
|
negativeButton.text = getString(R.string.add_dialog_button_back)
|
||||||
|
subscribeView.visibility = View.GONE
|
||||||
|
loginView.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
// Show/hide dropdown
|
||||||
|
val relevantUsers = users.filter { it.baseUrl == baseUrl }
|
||||||
|
if (relevantUsers.isEmpty()) {
|
||||||
|
loginUsersSpinner.visibility = View.GONE
|
||||||
|
loginUsersSpinner.adapter = ArrayAdapter(activity, R.layout.fragment_add_dialog_dropdown_item, emptyArray<User>())
|
||||||
|
if (loginUsernameText.requestFocus()) {
|
||||||
|
val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
|
imm?.showSoftInput(loginUsernameText, InputMethodManager.SHOW_IMPLICIT)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val spinnerEntries = relevantUsers.toMutableList()
|
||||||
|
spinnerEntries.add(0, User(0, "", getString(R.string.add_dialog_login_new_user), ""))
|
||||||
|
loginUsersSpinner.adapter = ArrayAdapter(activity, R.layout.fragment_add_dialog_dropdown_item, spinnerEntries)
|
||||||
|
loginUsersSpinner.setSelection(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enableSubscribeView(enable: Boolean) {
|
||||||
|
subscribeTopicText.isEnabled = enable
|
||||||
|
subscribeBaseUrlText.isEnabled = enable
|
||||||
|
subscribeInstantDeliveryCheckbox.isEnabled = enable
|
||||||
|
subscribeUseAnotherServerCheckbox.isEnabled = enable
|
||||||
|
positiveButton.isEnabled = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetSubscribeView() {
|
||||||
|
subscribeProgress.visibility = View.GONE
|
||||||
|
subscribeErrorImage.visibility = View.GONE
|
||||||
|
enableSubscribeView(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enableLoginView(enable: Boolean) {
|
||||||
|
loginUsernameText.isEnabled = enable
|
||||||
|
loginPasswordText.isEnabled = enable
|
||||||
|
loginUsersSpinner.isEnabled = enable
|
||||||
|
positiveButton.isEnabled = enable
|
||||||
|
if (enable && loginUsernameText.requestFocus()) {
|
||||||
|
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||||
|
imm?.showSoftInput(loginUsernameText, InputMethodManager.SHOW_IMPLICIT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetLoginView() {
|
||||||
|
loginProgress.visibility = View.GONE
|
||||||
|
loginErrorImage.visibility = View.GONE
|
||||||
|
loginUsersSpinner.visibility = View.VISIBLE
|
||||||
|
loginUsernameText.visibility = View.VISIBLE
|
||||||
|
loginPasswordText.visibility = View.VISIBLE
|
||||||
|
enableLoginView(true)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "NtfyAddFragment"
|
const val TAG = "NtfyAddFragment"
|
||||||
private val DISALLOWED_TOPICS = listOf("docs", "static")
|
private val DISALLOWED_TOPICS = listOf("docs", "static")
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:id="@+id/add_dialog_subscribe_view"
|
android:id="@+id/add_dialog_subscribe_view"
|
||||||
android:visibility="visible">
|
android:visibility="gone">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/add_dialog_title_text"
|
android:id="@+id/add_dialog_title_text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -26,6 +26,15 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/add_dialog_error_image"/>
|
app:layout_constraintEnd_toStartOf="@id/add_dialog_error_image"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:id="@+id/add_dialog_progress"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/add_dialog_error_image"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/add_dialog_description_below"
|
||||||
|
android:indeterminate="true" android:layout_marginBottom="5dp" android:visibility="gone"/>
|
||||||
<TextView
|
<TextView
|
||||||
android:text="@string/add_dialog_description_below"
|
android:text="@string/add_dialog_description_below"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -49,15 +58,6 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_topic_text"
|
app:layout_constraintTop_toBottomOf="@id/add_dialog_topic_text"
|
||||||
android:layout_marginTop="-3dp"/>
|
android:layout_marginTop="-3dp"/>
|
||||||
<ProgressBar
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:id="@+id/add_dialog_progress"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/add_dialog_error_image"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/add_dialog_description_below"
|
|
||||||
android:indeterminate="true" android:layout_marginBottom="5dp" android:visibility="gone"/>
|
|
||||||
<TextView
|
<TextView
|
||||||
android:text="@string/add_dialog_use_another_server_description"
|
android:text="@string/add_dialog_use_another_server_description"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -65,7 +65,8 @@
|
||||||
android:paddingStart="4dp" android:paddingTop="0dp"
|
android:paddingStart="4dp" android:paddingTop="0dp"
|
||||||
android:visibility="gone" app:layout_constraintStart_toStartOf="parent"
|
android:visibility="gone" app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_use_another_server_checkbox"/>
|
app:layout_constraintTop_toBottomOf="@id/add_dialog_use_another_server_checkbox"
|
||||||
|
android:layout_marginTop="-5dp"/>
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense.ExposedDropdownMenu"
|
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense.ExposedDropdownMenu"
|
||||||
android:id="@+id/add_dialog_base_url_layout"
|
android:id="@+id/add_dialog_base_url_layout"
|
||||||
|
@ -139,7 +140,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:id="@+id/add_dialog_login_view"
|
android:id="@+id/add_dialog_login_view"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
>
|
>
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/add_dialog_login_title"
|
android:id="@+id/add_dialog_login_title"
|
||||||
|
@ -164,7 +165,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" android:id="@+id/add_dialog_login_users_spinner"
|
android:layout_height="wrap_content" android:id="@+id/add_dialog_login_users_spinner"
|
||||||
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_description"/>
|
app:layout_constraintTop_toBottomOf="@id/add_dialog_login_description" android:paddingStart="0dp"/>
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/add_dialog_login_username"
|
android:id="@+id/add_dialog_login_username"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -97,6 +97,8 @@
|
||||||
</string>
|
</string>
|
||||||
<string name="add_dialog_button_cancel">Cancel</string>
|
<string name="add_dialog_button_cancel">Cancel</string>
|
||||||
<string name="add_dialog_button_subscribe">Subscribe</string>
|
<string name="add_dialog_button_subscribe">Subscribe</string>
|
||||||
|
<string name="add_dialog_button_back">Back</string>
|
||||||
|
<string name="add_dialog_button_login">Login</string>
|
||||||
<string name="add_dialog_error_connection_failed">Connection failed: %1$s</string>
|
<string name="add_dialog_error_connection_failed">Connection failed: %1$s</string>
|
||||||
<string name="add_dialog_login_error_not_authorized">Login failed. User not authorized.</string>
|
<string name="add_dialog_login_error_not_authorized">Login failed. User not authorized.</string>
|
||||||
<string name="add_dialog_login_new_user">New user</string>
|
<string name="add_dialog_login_new_user">New user</string>
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
* Fix download issues on SDK 29 "Movement not allowed" (#116)
|
* Fix download issues on SDK 29 "Movement not allowed" (#116)
|
||||||
|
* Fix for Android 12 crashes (#124)
|
||||||
|
|
Loading…
Reference in a new issue