diff --git a/app/build.gradle b/app/build.gradle index d9c17d7..63912ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation project(':client') implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.core:core-splashscreen:1.0.0' - implementation 'com.google.android.material:material:1.4.0' + implementation 'com.google.android.material:material:1.7.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.vectordrawable:vectordrawable:1.1.0' diff --git a/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt b/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt index ac88631..49e6d1f 100644 --- a/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt @@ -5,7 +5,6 @@ import android.app.NotificationManager import android.content.Intent import android.os.Build import android.os.Bundle -import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.preference.PreferenceManager @@ -24,6 +23,7 @@ import com.github.gotify.login.LoginActivity import com.github.gotify.messages.MessagesActivity import com.github.gotify.service.WebSocketService import com.github.gotify.settings.ThemeHelper +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.livinglifetechway.quickpermissionskotlin.runWithPermissions import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsOptions import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsRequest @@ -98,7 +98,7 @@ internal class InitializationActivity : AppCompatActivity() { } private fun dialog(message: String) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setTitle(R.string.oops) .setMessage(message) .setPositiveButton(R.string.retry) { _, _ -> tryAuthenticate() } @@ -176,7 +176,7 @@ internal class InitializationActivity : AppCompatActivity() { } private fun processPermissionRationale(req: QuickPermissionsRequest) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.permissions_denied_temp)) .setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ -> req.proceed() @@ -186,7 +186,7 @@ internal class InitializationActivity : AppCompatActivity() { } private fun processPermissionsPermanentDenied(req: QuickPermissionsRequest) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.permissions_denied_permanent)) .setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ -> req.openAppSettings() diff --git a/app/src/main/kotlin/com/github/gotify/login/AdvancedDialog.kt b/app/src/main/kotlin/com/github/gotify/login/AdvancedDialog.kt index 6a1910d..8c4809f 100644 --- a/app/src/main/kotlin/com/github/gotify/login/AdvancedDialog.kt +++ b/app/src/main/kotlin/com/github/gotify/login/AdvancedDialog.kt @@ -1,11 +1,11 @@ package com.github.gotify.login -import android.app.AlertDialog import android.content.Context import android.view.LayoutInflater import android.widget.CompoundButton import com.github.gotify.R import com.github.gotify.databinding.AdvancedSettingsDialogBinding +import com.google.android.material.dialog.MaterialAlertDialogBuilder internal class AdvancedDialog( private val context: Context, @@ -42,7 +42,7 @@ internal class AdvancedDialog( } else { showRemoveCACertificate(selectedCertificate) } - AlertDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setView(binding.root) .setTitle(R.string.advanced_settings) .setPositiveButton(context.getString(R.string.done), null) diff --git a/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt b/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt index ed84f7b..ac31707 100644 --- a/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt @@ -8,10 +8,7 @@ import android.os.Bundle import android.text.Editable import android.text.TextWatcher import android.view.View -import android.widget.EditText -import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.view.ContextThemeWrapper import com.github.gotify.R import com.github.gotify.SSLSettings import com.github.gotify.Settings @@ -27,10 +24,13 @@ import com.github.gotify.client.api.UserApi import com.github.gotify.client.model.Client import com.github.gotify.client.model.VersionInfo import com.github.gotify.databinding.ActivityLoginBinding +import com.github.gotify.databinding.ClientNameDialogBinding import com.github.gotify.init.InitializationActivity import com.github.gotify.log.Log import com.github.gotify.log.LogsActivity import com.github.gotify.log.UncaughtExceptionHandler +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.textfield.TextInputEditText import okhttp3.HttpUrl import java.security.cert.X509Certificate @@ -59,7 +59,7 @@ internal class LoginActivity : AppCompatActivity() { override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) - binding.gotifyUrl.addTextChangedListener(object : TextWatcher { + binding.gotifyUrlEditext.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { @@ -83,7 +83,7 @@ internal class LoginActivity : AppCompatActivity() { } private fun doCheckUrl() { - val url = binding.gotifyUrl.text.toString().trim().trimEnd('/') + val url = binding.gotifyUrlEditext.text.toString().trim().trimEnd('/') val parsedUrl = HttpUrl.parse(url) if (parsedUrl == null) { Utils.showSnackBar(this, "Invalid URL (include http:// or https://)") @@ -110,7 +110,7 @@ internal class LoginActivity : AppCompatActivity() { } private fun showHttpWarning() { - AlertDialog.Builder(ContextThemeWrapper(this, R.style.AppTheme_Dialog)) + MaterialAlertDialogBuilder(this) .setTitle(R.string.warning) .setCancelable(true) .setMessage(R.string.http_warning) @@ -213,8 +213,8 @@ internal class LoginActivity : AppCompatActivity() { } private fun doLogin() { - val username = binding.username.text.toString() - val password = binding.password.text.toString() + val username = binding.usernameEditext.text.toString() + val password = binding.passwordEditext.text.toString() binding.login.visibility = View.GONE binding.loginProgress.visibility = View.VISIBLE @@ -238,21 +238,23 @@ internal class LoginActivity : AppCompatActivity() { } private fun newClientDialog(client: ApiClient) { - val clientName = EditText(this) - clientName.setText(Build.MODEL) + val clientDialogBinding = ClientNameDialogBinding.inflate(layoutInflater) + val clientDialogEditext = clientDialogBinding.clientNameEditext + clientDialogEditext.setText(Build.MODEL) - AlertDialog.Builder(ContextThemeWrapper(this, R.style.AppTheme_Dialog)) + MaterialAlertDialogBuilder(this) .setTitle(R.string.create_client_title) .setMessage(R.string.create_client_message) - .setView(clientName) - .setPositiveButton(R.string.create, doCreateClient(client, clientName)) + .setView(clientDialogBinding.root) + .setPositiveButton(R.string.create, doCreateClient(client, clientDialogEditext)) .setNegativeButton(R.string.cancel) { _, _ -> onCancelClientDialog() } + .setCancelable(false) .show() } private fun doCreateClient( client: ApiClient, - nameProvider: EditText + nameProvider: TextInputEditText ): DialogInterface.OnClickListener { return DialogInterface.OnClickListener { _, _ -> val newClient = Client().name(nameProvider.text.toString()) diff --git a/app/src/main/kotlin/com/github/gotify/messages/ListMessageAdapter.kt b/app/src/main/kotlin/com/github/gotify/messages/ListMessageAdapter.kt index e36916d..15451ea 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/ListMessageAdapter.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/ListMessageAdapter.kt @@ -101,6 +101,13 @@ internal class ListMessageAdapter( return currentItem.message.id } + // Fix for message not being selectable (https://issuetracker.google.com/issues/37095917) + override fun onViewAttachedToWindow(holder: ViewHolder) { + super.onViewAttachedToWindow(holder) + holder.message.isEnabled = false + holder.message.isEnabled = true + } + class ViewHolder(binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) { lateinit var image: ImageView lateinit var message: TextView diff --git a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt index 78b13bf..5b5704c 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt @@ -16,9 +16,7 @@ import android.view.View import android.widget.ImageButton import android.widget.TextView import androidx.appcompat.app.ActionBarDrawerToggle -import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.view.ContextThemeWrapper import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.GravityCompat @@ -53,6 +51,7 @@ import com.github.gotify.messages.provider.MessageWithImage import com.github.gotify.service.WebSocketService import com.github.gotify.settings.SettingsActivity import com.github.gotify.sharing.ShareActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.navigation.NavigationView import com.google.android.material.snackbar.BaseTransientBottomBar.BaseCallback import com.google.android.material.snackbar.Snackbar @@ -260,7 +259,7 @@ internal class MessagesActivity : startLoading() binding.appBarDrawer.toolbar.subtitle = "" } else if (id == R.id.logout) { - AlertDialog.Builder(ContextThemeWrapper(this, R.style.AppTheme_Dialog)) + MaterialAlertDialogBuilder(this) .setTitle(R.string.logout) .setMessage(getString(R.string.logout_confirm)) .setPositiveButton(R.string.yes) { _, _ -> doLogout() } @@ -523,12 +522,12 @@ internal class MessagesActivity : } } if (item.itemId == R.id.action_delete_app) { - val alert = android.app.AlertDialog.Builder(this) - alert.setTitle(R.string.delete_app) - alert.setMessage(R.string.ack) - alert.setPositiveButton(R.string.yes) { _, _ -> deleteApp(viewModel.appId) } - alert.setNegativeButton(R.string.no, null) - alert.show() + MaterialAlertDialogBuilder(this) + .setTitle(R.string.delete_app) + .setMessage(R.string.ack) + .setPositiveButton(R.string.yes) { _, _ -> deleteApp(viewModel.appId) } + .setNegativeButton(R.string.no, null) + .show() } return super.onContextItemSelected(item) } diff --git a/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt b/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt index fa88d2b..bb4a825 100644 --- a/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/settings/SettingsActivity.kt @@ -1,6 +1,7 @@ package com.github.gotify.settings -import android.app.AlertDialog +import android.app.Dialog +import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener @@ -9,11 +10,13 @@ import android.view.MenuItem import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.preference.ListPreference +import androidx.preference.ListPreferenceDialogFragmentCompat import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceManager import com.github.gotify.R import com.github.gotify.databinding.SettingsActivityBinding +import com.google.android.material.dialog.MaterialAlertDialogBuilder internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeListener { private lateinit var binding: SettingsActivityBinding @@ -64,7 +67,7 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL findPreference(getString(R.string.setting_key_message_layout)) messageLayout?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ -> - AlertDialog.Builder(context) + MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.setting_message_layout_dialog_title) .setMessage(R.string.setting_message_layout_dialog_message) .setPositiveButton( @@ -81,6 +84,24 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL } } + override fun onDisplayPreferenceDialog(preference: Preference) { + if (preference is ListPreference) { + showListPreferenceDialog(preference) + } else { + super.onDisplayPreferenceDialog(preference) + } + } + + private fun showListPreferenceDialog(preference: ListPreference) { + val dialogFragment = MaterialListPreference() + dialogFragment.arguments = Bundle(1).apply { putString("key", preference.key) } + dialogFragment.setTargetFragment(this, 0) + dialogFragment.show( + parentFragmentManager, + "androidx.preference.PreferenceFragment.DIALOG" + ) + } + private fun restartApp() { val packageManager = requireContext().packageManager val packageName = requireContext().packageName @@ -91,4 +112,46 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL Runtime.getRuntime().exit(0) } } + + class MaterialListPreference : ListPreferenceDialogFragmentCompat() { + private var mWhichButtonClicked = 0 + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE + val builder = MaterialAlertDialogBuilder(requireActivity()) + .setTitle(preference.dialogTitle) + .setPositiveButton(preference.positiveButtonText, this) + .setNegativeButton(preference.negativeButtonText, this) + + val contentView = context?.let { onCreateDialogView(it) } + if (contentView != null) { + onBindDialogView(contentView) + builder.setView(contentView) + } else { + builder.setMessage(preference.dialogMessage) + } + onPrepareDialogBuilder(builder) + return builder.create() + } + + override fun onClick(dialog: DialogInterface, which: Int) { + mWhichButtonClicked = which + } + + override fun onDismiss(dialog: DialogInterface) { + onDialogClosedWasCalledFromOnDismiss = true + super.onDismiss(dialog) + } + + private var onDialogClosedWasCalledFromOnDismiss = false + + override fun onDialogClosed(positiveResult: Boolean) { + if (onDialogClosedWasCalledFromOnDismiss) { + onDialogClosedWasCalledFromOnDismiss = false + super.onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE) + } else { + super.onDialogClosed(positiveResult) + } + } + } } diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 1ce90e8..8c23990 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -13,19 +13,18 @@ tools:context=".login.LoginActivity" tools:layout_editor_absoluteY="25dp"> -