ui: add edge-to-edge toggle

Add a toggle for edge-to-edge mode.

Normally we would want to enable edge-to-edge by default (in fact, we
still do). However, some phones (once again, samsung) don't provide
Auxio with actual window insets. As a result, we need to add a toggle
so that it can be disabled on busted devices.

Did you know that even when Auxio has it's edge-to-edge functionality
busted, Samsung Music works just fine? Very interesting.

Resolves #149.
This commit is contained in:
OxygenCobalt 2022-06-07 17:14:02 -06:00
parent bd683ca09a
commit c929357d76
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
6 changed files with 61 additions and 20 deletions

View file

@ -32,6 +32,8 @@ import org.oxycblt.auxio.music.IndexerService
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.system.PlaybackService import org.oxycblt.auxio.playback.system.PlaybackService
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.accent.Accent
import org.oxycblt.auxio.util.getColorSafe
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.systemBarInsetsCompat import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -54,11 +56,13 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setupTheme() val settingsManager = SettingsManager.getInstance()
setupTheme(settingsManager.theme, settingsManager.accent, settingsManager.useBlackTheme)
val binding = ActivityMainBinding.inflate(layoutInflater) val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
applyEdgeToEdgeWindow(binding.root) setupEdgeToEdge(binding.root, settingsManager.edgeToEdge)
logD("Activity created") logD("Activity created")
} }
@ -87,9 +91,12 @@ class MainActivity : AppCompatActivity() {
} }
} }
/**
* Extracts a [Uri] from an intent as long as:
* - The intent is ACTION_VIEW
* - The intent has not already been used.
*/
private fun retrieveViewUri(intent: Intent?): Uri? { private fun retrieveViewUri(intent: Intent?): Uri? {
// If this intent is a valid view intent that has not been used already, give it
// to PlaybackViewModel to be used later.
if (intent != null) { if (intent != null) {
val action = intent.action val action = intent.action
val isConsumed = intent.getBooleanExtra(KEY_INTENT_USED, false) val isConsumed = intent.getBooleanExtra(KEY_INTENT_USED, false)
@ -104,22 +111,18 @@ class MainActivity : AppCompatActivity() {
return null return null
} }
private fun setupTheme() { private fun setupTheme(theme: Int, accent: Accent, useBlackTheme: Boolean) {
val settingsManager = SettingsManager.getInstance()
// Disable theme customization above Android 12, as it's far enough in as a version to // Disable theme customization above Android 12, as it's far enough in as a version to
// the point where most phones should have an automatic option for light/dark theming. // the point where most phones should have an automatic option for light/dark theming.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
AppCompatDelegate.setDefaultNightMode(settingsManager.theme) AppCompatDelegate.setDefaultNightMode(theme)
} else { } else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
} }
val accent = settingsManager.accent
// The black theme has a completely separate set of styles since style attributes cannot // The black theme has a completely separate set of styles since style attributes cannot
// be modified at runtime. // be modified at runtime.
if (isNight && settingsManager.useBlackTheme) { if (isNight && useBlackTheme) {
logD("Applying black theme [accent $accent]") logD("Applying black theme [accent $accent]")
setTheme(accent.blackTheme) setTheme(accent.blackTheme)
} else { } else {
@ -128,8 +131,21 @@ class MainActivity : AppCompatActivity() {
} }
} }
private fun applyEdgeToEdgeWindow(contentView: View) { private fun setupEdgeToEdge(contentView: View, enabled: Boolean) {
WindowCompat.setDecorFitsSystemWindows(window, false) val fitsSystemWindows = !enabled
WindowCompat.setDecorFitsSystemWindows(window, fitsSystemWindows)
if (fitsSystemWindows) {
// Auxio's theme is normally set up to anticipate edge to edge mode being
// enabled. In the case that it is not, we have to update the values during
// runtime.
val controller = WindowCompat.getInsetsController(window, window.decorView)
val black = getColorSafe(android.R.color.black)
window.statusBarColor = black
controller.isAppearanceLightStatusBars = false
window.navigationBarColor = black
controller.isAppearanceLightNavigationBars = false
}
contentView.setOnApplyWindowInsetsListener { view, insets -> contentView.setOnApplyWindowInsetsListener { view, insets ->
val bars = insets.systemBarInsetsCompat val bars = insets.systemBarInsetsCompat

View file

@ -122,6 +122,15 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true true
} }
} }
SettingsManager.KEY_ACCENT -> {
onPreferenceClickListener =
Preference.OnPreferenceClickListener {
AccentDialog().show(childFragmentManager, AccentDialog.TAG)
true
}
summary = context.getString(settingsManager.accent.name)
}
SettingsManager.KEY_BLACK_THEME -> { SettingsManager.KEY_BLACK_THEME -> {
onPreferenceClickListener = onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
@ -132,14 +141,12 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true true
} }
} }
SettingsManager.KEY_ACCENT -> { SettingsManager.KEY_EDGE_TO_EDGE -> {
onPreferenceClickListener = onPreferenceChangeListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceChangeListener { _, _ ->
AccentDialog().show(childFragmentManager, AccentDialog.TAG) requireActivity().recreate()
true true
} }
summary = context.getString(settingsManager.accent.name)
} }
SettingsManager.KEY_LIB_TABS -> { SettingsManager.KEY_LIB_TABS -> {
onPreferenceClickListener = onPreferenceClickListener =

View file

@ -62,6 +62,10 @@ class SettingsManager private constructor(context: Context) :
} }
} }
/** Whether edge-to-edge is enabled. */
val edgeToEdge: Boolean
get() = inner.getBoolean(KEY_EDGE_TO_EDGE, true)
/** /**
* Whether to display the RepeatMode or the shuffle status on the notification. False if repeat, * Whether to display the RepeatMode or the shuffle status on the notification. False if repeat,
* true if shuffle. * true if shuffle.
@ -304,6 +308,7 @@ class SettingsManager private constructor(context: Context) :
const val KEY_THEME = "KEY_THEME2" const val KEY_THEME = "KEY_THEME2"
const val KEY_BLACK_THEME = "KEY_BLACK_THEME" const val KEY_BLACK_THEME = "KEY_BLACK_THEME"
const val KEY_ACCENT = "auxio_accent2" const val KEY_ACCENT = "auxio_accent2"
const val KEY_EDGE_TO_EDGE = "auxio_edge"
const val KEY_LIB_TABS = "auxio_lib_tabs" const val KEY_LIB_TABS = "auxio_lib_tabs"
const val KEY_SHOW_COVERS = "KEY_SHOW_COVERS" const val KEY_SHOW_COVERS = "KEY_SHOW_COVERS"

View file

@ -173,7 +173,10 @@ fun Fragment.launch(
* bit of a dumb hack with [combine], as when we have to combine flows, we often just want to call * bit of a dumb hack with [combine], as when we have to combine flows, we often just want to call
* the same block with both functions, and not do any transformations. * the same block with both functions, and not do any transformations.
*/ */
suspend fun <T1, T2> Flow<T1>.collectWith(other: Flow<T2>, block: suspend (T1, T2) -> Unit) { suspend inline fun <T1, T2> Flow<T1>.collectWith(
other: Flow<T2>,
crossinline block: (T1, T2) -> Unit
) {
combine(this, other) { a, b -> a to b }.collect { block(it.first, it.second) } combine(this, other) { a, b -> a to b }.collect { block(it.first, it.second) }
} }

View file

@ -76,6 +76,8 @@
<string name="set_accent">Color scheme</string> <string name="set_accent">Color scheme</string>
<string name="set_black_mode">Black theme</string> <string name="set_black_mode">Black theme</string>
<string name="set_black_mode_desc">Use a pure-black dark theme</string> <string name="set_black_mode_desc">Use a pure-black dark theme</string>
<string name="set_edge_to_edge">Edge-to-edge</string>
<string name="set_edge_to_edge_desc">May not work on all devices</string>
<string name="set_display">Display</string> <string name="set_display">Display</string>
<string name="set_lib_tabs">Library tabs</string> <string name="set_lib_tabs">Library tabs</string>

View file

@ -27,6 +27,14 @@
app:summary="@string/set_black_mode_desc" app:summary="@string/set_black_mode_desc"
app:title="@string/set_black_mode" /> app:title="@string/set_black_mode" />
<org.oxycblt.auxio.settings.pref.M3SwitchPreference
app:allowDividerBelow="false"
app:defaultValue="true"
app:iconSpaceReserved="false"
app:key="auxio_edge"
app:summary="@string/set_edge_to_edge_desc"
app:title="@string/set_edge_to_edge" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory