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 --- // --- 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. * The base data object for all music.
* @property id The ID that is assigned to this object * @property id The ID that is assigned to this object
@ -51,7 +54,7 @@ data class Song(
val album: Album get() = requireNotNull(mAlbum) val album: Album get() = requireNotNull(mAlbum)
val seconds = duration / 1000 val seconds = duration / 1000
val formattedDuration: String = seconds.toDuration() val formattedDuration = seconds.toDuration()
fun linkAlbum(album: Album) { fun linkAlbum(album: Album) {
if (mAlbum == null) { if (mAlbum == null) {

View file

@ -4,13 +4,13 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import org.oxycblt.auxio.databinding.DialogAccentBinding import org.oxycblt.auxio.databinding.DialogAccentBinding
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.settings.ui.LifecycleDialog import org.oxycblt.auxio.settings.ui.LifecycleDialog
import org.oxycblt.auxio.ui.ACCENTS import org.oxycblt.auxio.ui.ACCENTS
import org.oxycblt.auxio.ui.Accent import org.oxycblt.auxio.ui.Accent
import org.oxycblt.auxio.ui.inflater
import org.oxycblt.auxio.ui.toColor import org.oxycblt.auxio.ui.toColor
/** /**
@ -38,25 +38,11 @@ class AccentDialog : LifecycleDialog() {
adapter = AccentAdapter(pendingAccent) { accent -> adapter = AccentAdapter(pendingAccent) { accent ->
pendingAccent = accent pendingAccent = accent
updateAccent(binding) updateAccent()
} }
} }
binding.accentConfirm.setOnClickListener { updateAccent()
if (pendingAccent != Accent.get()) {
settingsManager.accent = pendingAccent
requireActivity().recreate()
}
dismiss()
}
binding.accentCancel.setOnClickListener {
dismiss()
}
updateAccent(binding)
logD("Dialog created.") logD("Dialog created.")
@ -69,11 +55,28 @@ class AccentDialog : LifecycleDialog() {
outState.putInt(KEY_PENDING_ACCENT, ACCENTS.indexOf(pendingAccent)) 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()) val accentColor = pendingAccent.color.toColor(requireContext())
binding.accentCancel.setTextColor(accentColor) (requireDialog() as AlertDialog).apply {
binding.accentConfirm.setTextColor(accentColor) getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
}
} }
companion object { companion object {

View file

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

View file

@ -5,15 +5,19 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment 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 * A wrapper around [DialogFragment] that allows the usage of the standard Auxio lifecycle
* doesn't seem to set the view from onCreateView correctly. * override [onCreateView] and [onDestroyView], but with a proper dialog being created.
*/ */
abstract class LifecycleDialog : DialogFragment() { abstract class LifecycleDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 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?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -21,4 +25,6 @@ abstract class LifecycleDialog : DialogFragment() {
(requireDialog() as AlertDialog).setView(view) (requireDialog() as AlertDialog).setView(view)
} }
protected open fun onConfigDialog(builder: AlertDialog.Builder) {}
} }

View file

@ -36,28 +36,5 @@
tools:itemCount="18" tools:itemCount="18"
tools:listitem="@layout/item_accent" /> 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> </LinearLayout>
</layout> </layout>

View file

@ -44,37 +44,5 @@
android:textAppearance="?android:attr/textAppearanceLarge" android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorSecondary" /> 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> </LinearLayout>
</layout> </layout>

View file

@ -104,6 +104,7 @@
<string name="error_load_failed">Laden die Musik fehlgeschlagen</string> <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_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_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 --> <!-- Hint Namespace | EditText Hints -->
<string name="hint_search_library">Durchsuche deine Musikbibliothek…</string> <string name="hint_search_library">Durchsuche deine Musikbibliothek…</string>

View file

@ -79,11 +79,10 @@
</style> </style>
<!-- Custom Dialog EntryNames --> <!-- Custom Dialog EntryNames -->
<style name="Theme.CustomDialog" parent="Theme.MaterialComponents.DayNight.Dialog"> <style name="Theme.CustomDialog" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<item name="colorBackgroundFloating">@color/background</item>
<item name="android:windowTitleStyle">@style/TextAppearance.Dialog.Title</item> <item name="android:windowTitleStyle">@style/TextAppearance.Dialog.Title</item>
<item name="colorPrimary">@color/control_color</item> <item name="colorBackgroundFloating">@color/background</item>
<item name="colorSecondary">@color/control_color</item> <item name="buttonBarButtonStyle">@style/Widget.Button.Dialog</item>
<item name="dialogCornerRadius">0dp</item> <item name="dialogCornerRadius">0dp</item>
<item name="colorControlHighlight">@color/selection_color</item> <item name="colorControlHighlight">@color/selection_color</item>
</style> </style>
@ -93,6 +92,17 @@
<item name="android:fontFamily">@font/inter_exbold</item> <item name="android:fontFamily">@font/inter_exbold</item>
</style> </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 for the general item background -->
<style name="ItemSurroundings"> <style name="ItemSurroundings">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
@ -217,15 +227,4 @@
<item name="android:scaleType">fitCenter</item> <item name="android:scaleType">fitCenter</item>
<item name="android:padding">@dimen/padding_medium</item> <item name="android:padding">@dimen/padding_medium</item>
</style> </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> </resources>