Heavily improve dialogs

Both improve and use dialogs
- The AlertDialog style now properly colors dialogs with the primary coler
- The accent & blacklist dialogs are now based on AlertDialog for their buttons, reducing layout complexity
This commit is contained in:
OxygenCobalt 2021-03-28 18:44:58 -06:00
parent 53ec1aa8a5
commit 4d92df7896
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 72 additions and 122 deletions

View file

@ -4,6 +4,9 @@ import android.net.Uri
// --- MUSIC MODELS ---
// TODO: Implement some kind of hash system, removing the need to redundant names but alsow without the volitility of id
// They need to be completely unique, however, and from whatever information I have about them.
/**
* The base data object for all music.
* @property id The ID that is assigned to this object
@ -51,7 +54,7 @@ data class Song(
val album: Album get() = requireNotNull(mAlbum)
val seconds = duration / 1000
val formattedDuration: String = seconds.toDuration()
val formattedDuration = seconds.toDuration()
fun linkAlbum(album: Album) {
if (mAlbum == null) {

View file

@ -4,13 +4,13 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import org.oxycblt.auxio.databinding.DialogAccentBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.settings.ui.LifecycleDialog
import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.inflater
import org.oxycblt.auxio.ui.toColor
/**
@ -38,25 +38,11 @@ class AccentDialog : LifecycleDialog() {
adapter = AccentAdapter(pendingAccent) { accent ->
pendingAccent = accent
updateAccent(binding)
updateAccent()
}
}
binding.accentConfirm.setOnClickListener {
if (pendingAccent != Accent.get()) {
settingsManager.accent = pendingAccent
requireActivity().recreate()
}
dismiss()
}
binding.accentCancel.setOnClickListener {
dismiss()
}
updateAccent(binding)
updateAccent()
logD("Dialog created.")
@ -69,11 +55,28 @@ class AccentDialog : LifecycleDialog() {
outState.putInt(KEY_PENDING_ACCENT, ACCENTS.indexOf(pendingAccent))
}
private fun updateAccent(binding: DialogAccentBinding) {
override fun onConfigDialog(builder: AlertDialog.Builder) {
builder.setPositiveButton(android.R.string.ok) { _, _ ->
if (pendingAccent != Accent.get()) {
settingsManager.accent = pendingAccent
requireActivity().recreate()
}
dismiss()
}
// Negative button just dismisses, no need for a listener.
builder.setNegativeButton(android.R.string.cancel, null)
}
private fun updateAccent() {
val accentColor = pendingAccent.color.toColor(requireContext())
binding.accentCancel.setTextColor(accentColor)
binding.accentConfirm.setTextColor(accentColor)
(requireDialog() as AlertDialog).apply {
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
}
}
companion object {

View file

@ -10,6 +10,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
@ -19,9 +20,7 @@ import org.oxycblt.auxio.databinding.DialogBlacklistBinding
import org.oxycblt.auxio.logD
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.ui.LifecycleDialog
import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.createToast
import org.oxycblt.auxio.ui.toColor
import kotlin.system.exitProcess
/**
@ -42,43 +41,30 @@ class BlacklistDialog : LifecycleDialog() {
): View {
val binding = DialogBlacklistBinding.inflate(inflater)
val launcher = registerForActivityResult(
ActivityResultContracts.OpenDocumentTree(), ::addDocTreePath
)
val accent = Accent.get().color.toColor(requireContext())
val adapter = BlacklistEntryAdapter { path ->
blacklistModel.removePath(path)
}
val launcher = registerForActivityResult(
ActivityResultContracts.OpenDocumentTree(), ::addDocTreePath
)
// --- UI SETUP ---
binding.blacklistRecycler.adapter = adapter
// Dialogs don't know how to into theming, so I have to manually set the accent color
// to each of the buttons since the overall fragment theme is Neutral.
binding.blacklistAdd.apply {
setTextColor(accent)
// Now that the dialog exists, we get the view manually when the dialog is shown
// and override its click-listener so that the dialog does not auto-dismiss when we
// click the "Add"/"Save" buttons. This prevents the dialog from disappearing in the former
// and the app from crashing in the latter.
val dialog = requireDialog() as AlertDialog
setOnClickListener {
// showFileDialog()
dialog.setOnShowListener {
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)?.setOnClickListener {
launcher.launch(null)
}
}
binding.blacklistCancel.apply {
setTextColor(accent)
setOnClickListener {
dismiss()
}
}
binding.blacklistConfirm.apply {
setTextColor(accent)
setOnClickListener {
dialog.getButton(AlertDialog.BUTTON_POSITIVE)?.setOnClickListener {
if (blacklistModel.isModified()) {
saveAndRestart()
} else {
@ -107,6 +93,13 @@ class BlacklistDialog : LifecycleDialog() {
blacklistModel.loadDatabasePaths()
}
override fun onConfigDialog(builder: AlertDialog.Builder) {
// Dont set the click listener here, we do some custom black magic in onCreateView instead.
builder.setNeutralButton(R.string.label_add, null)
builder.setPositiveButton(R.string.label_save, null)
builder.setNegativeButton(android.R.string.cancel, null)
}
private fun addDocTreePath(uri: Uri?) {
uri ?: return

View file

@ -5,15 +5,19 @@ import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.oxycblt.auxio.R
/**
* [DialogFragment] that replicates the Fragment lifecycle in regards to [AlertDialog], which
* doesn't seem to set the view from onCreateView correctly.
* A wrapper around [DialogFragment] that allows the usage of the standard Auxio lifecycle
* override [onCreateView] and [onDestroyView], but with a proper dialog being created.
*/
abstract class LifecycleDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return MaterialAlertDialogBuilder(requireActivity(), theme).create()
val builder = AlertDialog.Builder(requireActivity(), R.style.Theme_CustomDialog)
onConfigDialog(builder)
return builder.create()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -21,4 +25,6 @@ abstract class LifecycleDialog : DialogFragment() {
(requireDialog() as AlertDialog).setView(view)
}
protected open fun onConfigDialog(builder: AlertDialog.Builder) {}
}

View file

@ -36,28 +36,5 @@
tools:itemCount="18"
tools:listitem="@layout/item_accent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:padding="@dimen/padding_small">
<Button
android:id="@+id/accent_cancel"
style="@style/Widget.Button.Dialog"
android:layout_marginEnd="@dimen/margin_small"
android:text="@android:string/cancel"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/accent_confirm" />
<Button
android:id="@+id/accent_confirm"
style="@style/Widget.Button.Dialog"
android:text="@android:string/ok"
app:layout_constraintBottom_toBottomOf="@+id/accent_cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/accent_cancel" />
</LinearLayout>
</LinearLayout>
</layout>

View file

@ -44,37 +44,5 @@
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorSecondary" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="@dimen/padding_small">
<Button
android:id="@+id/blacklist_cancel"
style="@style/Widget.Button.Dialog"
android:layout_marginEnd="@dimen/padding_small"
android:text="@android:string/cancel"
app:layout_constraintEnd_toStartOf="@+id/blacklist_confirm"
app:layout_constraintTop_toTopOf="@+id/blacklist_add" />
<Button
android:id="@+id/blacklist_confirm"
style="@style/Widget.Button.Dialog"
android:text="@string/label_save"
app:layout_constraintBottom_toBottomOf="@+id/blacklist_cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/blacklist_cancel" />
<Button
android:id="@+id/blacklist_add"
style="@style/Widget.Button.Dialog"
android:text="@string/label_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</layout>

View file

@ -104,6 +104,7 @@
<string name="error_load_failed">Laden die Musik fehlgeschlagen</string>
<string name="error_no_perms">Auxio braucht Berechtigung, zu lesen deine Musikbibliothek</string>
<string name="error_no_browser">Link könnte nicht geöffnet werden</string>
<string name="error_bad_dir">Das Verzeichnis ist nicht gestützt</string>
<!-- Hint Namespace | EditText Hints -->
<string name="hint_search_library">Durchsuche deine Musikbibliothek…</string>

View file

@ -79,11 +79,10 @@
</style>
<!-- Custom Dialog EntryNames -->
<style name="Theme.CustomDialog" parent="Theme.MaterialComponents.DayNight.Dialog">
<item name="colorBackgroundFloating">@color/background</item>
<style name="Theme.CustomDialog" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<item name="android:windowTitleStyle">@style/TextAppearance.Dialog.Title</item>
<item name="colorPrimary">@color/control_color</item>
<item name="colorSecondary">@color/control_color</item>
<item name="colorBackgroundFloating">@color/background</item>
<item name="buttonBarButtonStyle">@style/Widget.Button.Dialog</item>
<item name="dialogCornerRadius">0dp</item>
<item name="colorControlHighlight">@color/selection_color</item>
</style>
@ -93,6 +92,17 @@
<item name="android:fontFamily">@font/inter_exbold</item>
</style>
<!-- Style for dialog buttons -->
<style name="Widget.Button.Dialog" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
<item name="android:layout_height">@dimen/height_dialog_button</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:paddingStart">@dimen/padding_mid_small</item>
<item name="android:paddingEnd">@dimen/padding_mid_small</item>
<item name="android:minWidth">@dimen/width_dialog_button_min</item>
<item name="android:textColor">?attr/colorPrimary</item>
<item name="android:fontFamily">@font/inter_semibold</item>
</style>
<!-- Style for the general item background -->
<style name="ItemSurroundings">
<item name="android:layout_width">match_parent</item>
@ -217,15 +227,4 @@
<item name="android:scaleType">fitCenter</item>
<item name="android:padding">@dimen/padding_medium</item>
</style>
<!-- Style for dialog buttons -->
<style name="Widget.Button.Dialog" parent="Widget.AppCompat.Button">
<item name="android:layout_height">@dimen/height_dialog_button</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:paddingStart">@dimen/padding_mid_small</item>
<item name="android:paddingEnd">@dimen/padding_mid_small</item>
<item name="android:minWidth">@dimen/width_dialog_button_min</item>
<item name="android:background">@drawable/ui_ripple</item>
<item name="android:fontFamily">@font/inter_semibold</item>
</style>
</resources>