Fix edge-to-edge bug in landscape
Fix a bug where the drag handles in QueueFragment would be covered up by the navigation bar in edge-to-edge + landscape mode.
This commit is contained in:
parent
28b6edb5d6
commit
fcebfda406
12 changed files with 84 additions and 30 deletions
|
@ -69,12 +69,12 @@ dependencies {
|
||||||
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
def navigation_version = "2.3.1"
|
def navigation_version = "2.3.2"
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
||||||
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
||||||
|
|
||||||
// Media
|
// Media
|
||||||
implementation 'androidx.media:media:1.2.0'
|
implementation 'androidx.media:media:1.2.1'
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
|
@ -104,7 +104,7 @@ dependencies {
|
||||||
ktlint "com.pinterest:ktlint:0.37.2"
|
ktlint "com.pinterest:ktlint:0.37.2"
|
||||||
|
|
||||||
// Memory Leak checking
|
// Memory Leak checking
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
|
||||||
}
|
}
|
||||||
|
|
||||||
task ktlint(type: JavaExec, group: "verification") {
|
task ktlint(type: JavaExec, group: "verification") {
|
||||||
|
|
|
@ -53,6 +53,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun doEdgeToEdgeSetup(binding: ActivityMainBinding) {
|
private fun doEdgeToEdgeSetup(binding: ActivityMainBinding) {
|
||||||
|
// TODO: Add landscape edge-to-edge support
|
||||||
|
|
||||||
window?.apply {
|
window?.apply {
|
||||||
statusBarColor = Color.TRANSPARENT
|
statusBarColor = Color.TRANSPARENT
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,6 @@ class PlaybackStateDatabase(context: Context) :
|
||||||
/**
|
/**
|
||||||
* Read the stored [PlaybackState] from the database, if there is one.
|
* Read the stored [PlaybackState] from the database, if there is one.
|
||||||
* @return The stored [PlaybackState], null if there isn't one,.
|
* @return The stored [PlaybackState], null if there isn't one,.
|
||||||
* @author OxygenCobalt
|
|
||||||
*/
|
*/
|
||||||
fun readState(): PlaybackState? {
|
fun readState(): PlaybackState? {
|
||||||
val database = writableDatabase
|
val database = writableDatabase
|
||||||
|
@ -163,7 +162,6 @@ class PlaybackStateDatabase(context: Context) :
|
||||||
/**
|
/**
|
||||||
* Write a list of [QueueItem]s to the database, clearing the previous queue present.
|
* Write a list of [QueueItem]s to the database, clearing the previous queue present.
|
||||||
* @param queue The list of [QueueItem]s to be written.
|
* @param queue The list of [QueueItem]s to be written.
|
||||||
* @author OxygenCobalt
|
|
||||||
*/
|
*/
|
||||||
fun writeQueue(queue: List<QueueItem>) {
|
fun writeQueue(queue: List<QueueItem>) {
|
||||||
val database = readableDatabase
|
val database = readableDatabase
|
||||||
|
@ -218,7 +216,6 @@ class PlaybackStateDatabase(context: Context) :
|
||||||
/**
|
/**
|
||||||
* Read the database for any [QueueItem]s.
|
* Read the database for any [QueueItem]s.
|
||||||
* @return A list of any stored [QueueItem]s.
|
* @return A list of any stored [QueueItem]s.
|
||||||
* @author OxygenCobalt
|
|
||||||
*/
|
*/
|
||||||
fun readQueue(): List<QueueItem> {
|
fun readQueue(): List<QueueItem> {
|
||||||
val database = readableDatabase
|
val database = readableDatabase
|
||||||
|
|
|
@ -8,7 +8,6 @@ import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.AlbumSongAdapter
|
import org.oxycblt.auxio.detail.adapters.AlbumSongAdapter
|
||||||
|
@ -20,7 +19,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
import org.oxycblt.auxio.ui.createToast
|
import org.oxycblt.auxio.ui.createToast
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
|
||||||
import org.oxycblt.auxio.ui.setupAlbumSongActions
|
import org.oxycblt.auxio.ui.setupAlbumSongActions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,6 @@ import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.ArtistAlbumAdapter
|
import org.oxycblt.auxio.detail.adapters.ArtistAlbumAdapter
|
||||||
|
@ -17,7 +16,6 @@ import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
|
||||||
import org.oxycblt.auxio.ui.setupAlbumActions
|
import org.oxycblt.auxio.ui.setupAlbumActions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,6 @@ import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.GenreArtistAdapter
|
import org.oxycblt.auxio.detail.adapters.GenreArtistAdapter
|
||||||
|
@ -16,7 +15,6 @@ import org.oxycblt.auxio.logD
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.disable
|
import org.oxycblt.auxio.ui.disable
|
||||||
import org.oxycblt.auxio.ui.isLandscape
|
|
||||||
import org.oxycblt.auxio.ui.setupArtistActions
|
import org.oxycblt.auxio.ui.setupArtistActions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -144,7 +144,6 @@ class MusicLoader(
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|
||||||
// Then try to associate any genres with their respective artists.
|
// Then try to associate any genres with their respective artists.
|
||||||
// TODO: This is already querying all genre songs, just move it.
|
|
||||||
for (genre in genres) {
|
for (genre in genres) {
|
||||||
val artistGenreCursor = resolver.query(
|
val artistGenreCursor = resolver.query(
|
||||||
Genres.Members.getContentUri("external", genre.id),
|
Genres.Members.getContentUri("external", genre.id),
|
||||||
|
|
|
@ -84,7 +84,8 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make ellipsizing of song title work
|
// Make ellipsizing of song title work
|
||||||
binding.playbackSong.isSelected = true
|
// Disabled until I can figure out why marquee causes a memory leak.
|
||||||
|
// binding.playbackSong.isSelected = true
|
||||||
|
|
||||||
binding.playbackSeekBar.setOnSeekBarChangeListener(this)
|
binding.playbackSeekBar.setOnSeekBarChangeListener(this)
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Header
|
import org.oxycblt.auxio.music.Header
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackMode
|
import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
|
import org.oxycblt.auxio.settings.SettingsManager
|
||||||
|
import org.oxycblt.auxio.ui.isLandscape
|
||||||
|
import org.oxycblt.auxio.ui.isSystemBarOnBottom
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [Fragment] that contains both the user queue and the next queue, with the ability to
|
* A [Fragment] that contains both the user queue and the next queue, with the ability to
|
||||||
|
@ -35,6 +38,7 @@ class QueueFragment : Fragment() {
|
||||||
): View {
|
): View {
|
||||||
val binding = FragmentQueueBinding.inflate(inflater)
|
val binding = FragmentQueueBinding.inflate(inflater)
|
||||||
|
|
||||||
|
val settingsManager = SettingsManager.getInstance()
|
||||||
val callback = QueueDragCallback(playbackModel)
|
val callback = QueueDragCallback(playbackModel)
|
||||||
val helper = ItemTouchHelper(callback)
|
val helper = ItemTouchHelper(callback)
|
||||||
val queueAdapter = QueueAdapter(helper) {
|
val queueAdapter = QueueAdapter(helper) {
|
||||||
|
@ -45,6 +49,14 @@ class QueueFragment : Fragment() {
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
|
// Band-aid that fixes a bug with landscape edge-to-edge where the queue drag buttons
|
||||||
|
// will be behind the status bar.
|
||||||
|
if (settingsManager.edgeEnabled) {
|
||||||
|
if (isLandscape(resources) && !isSystemBarOnBottom(requireActivity())) {
|
||||||
|
binding.root.rootView.fitsSystemWindows = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.queueToolbar.apply {
|
binding.queueToolbar.apply {
|
||||||
setNavigationOnClickListener {
|
setNavigationOnClickListener {
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
|
@ -53,18 +65,20 @@ class QueueFragment : Fragment() {
|
||||||
// Since QueueFragment doesn't fit system windows, inset padding needs to be
|
// Since QueueFragment doesn't fit system windows, inset padding needs to be
|
||||||
// artificially applied to the Toolbar so that it fits on the main window AND
|
// artificially applied to the Toolbar so that it fits on the main window AND
|
||||||
// so that the elevation doesn't show on the top.
|
// so that the elevation doesn't show on the top.
|
||||||
setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets ->
|
if (!binding.root.rootView.fitsSystemWindows) {
|
||||||
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets ->
|
||||||
insets.getInsets(WindowInsets.Type.systemBars()).top
|
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
} else {
|
insets.getInsets(WindowInsets.Type.systemBars()).top
|
||||||
insets.systemWindowInsetTop
|
} else {
|
||||||
|
insets.systemWindowInsetTop
|
||||||
|
}
|
||||||
|
|
||||||
|
(parent as View).updatePadding(
|
||||||
|
top = top
|
||||||
|
)
|
||||||
|
|
||||||
|
insets
|
||||||
}
|
}
|
||||||
|
|
||||||
(parent as View).updatePadding(
|
|
||||||
top = top
|
|
||||||
)
|
|
||||||
|
|
||||||
insets
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
package org.oxycblt.auxio.ui
|
package org.oxycblt.auxio.ui
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.graphics.Point
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.util.DisplayMetrics
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowInsetsController
|
import android.view.WindowInsetsController
|
||||||
|
import android.view.WindowManager
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
|
@ -31,6 +35,13 @@ import org.oxycblt.auxio.settings.SettingsManager
|
||||||
|
|
||||||
// Functions for managing UI elements [Not Colors]
|
// Functions for managing UI elements [Not Colors]
|
||||||
|
|
||||||
|
object InterfaceUtils {
|
||||||
|
const val NAV_HIDDEN = -1
|
||||||
|
const val NAV_ON_LEFT = 0
|
||||||
|
const val NAV_ON_RIGHT = 1
|
||||||
|
const val NAV_ON_BOTTOM = 2
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a text color to a [MenuItem]
|
* Apply a text color to a [MenuItem]
|
||||||
* @param color The text color that should be applied.
|
* @param color The text color that should be applied.
|
||||||
|
@ -81,6 +92,43 @@ fun Spanned.render(): Spanned {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the system bars are on the bottom.
|
||||||
|
* @return If the system bars are on the bottom, false if no.
|
||||||
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
fun isSystemBarOnBottom(activity: Activity): Boolean {
|
||||||
|
val realPoint = Point()
|
||||||
|
val metrics = DisplayMetrics()
|
||||||
|
|
||||||
|
var width = 0
|
||||||
|
var height = 0
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
activity.display?.let { display ->
|
||||||
|
display.getRealSize(realPoint)
|
||||||
|
|
||||||
|
activity.windowManager.currentWindowMetrics.bounds.also {
|
||||||
|
width = it.width()
|
||||||
|
height = it.height()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).apply {
|
||||||
|
defaultDisplay.getRealSize(realPoint)
|
||||||
|
defaultDisplay.getMetrics(metrics)
|
||||||
|
|
||||||
|
width = metrics.widthPixels
|
||||||
|
height = metrics.heightPixels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val config = activity.resources.configuration
|
||||||
|
val canMove = (width != height && config.smallestScreenWidthDp < 600)
|
||||||
|
|
||||||
|
return (!canMove || width < height)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle transparent system bars. Adapted from Music Player GO
|
* Handle transparent system bars. Adapted from Music Player GO
|
||||||
* (https://github.com/enricocid/Music-Player-GO)
|
* (https://github.com/enricocid/Music-Player-GO)
|
||||||
|
|
|
@ -53,15 +53,16 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_mid_large"
|
android:layout_marginStart="@dimen/margin_mid_large"
|
||||||
android:ellipsize="marquee"
|
android:layout_marginEnd="24dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:fontFamily="@font/inter_semibold"
|
android:fontFamily="@font/inter_semibold"
|
||||||
android:marqueeRepeatLimit="marquee_forever"
|
|
||||||
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
|
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@{song.name}"
|
android:text="@{song.name}"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
|
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
app:layout_constraintStart_toEndOf="@+id/playback_cover"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
|
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
|
|
@ -56,10 +56,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/margin_mid_large"
|
android:layout_marginStart="@dimen/margin_mid_large"
|
||||||
android:layout_marginEnd="@dimen/margin_mid_large"
|
android:layout_marginEnd="@dimen/margin_mid_large"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="end"
|
||||||
android:focusable="true"
|
|
||||||
android:fontFamily="@font/inter_semibold"
|
android:fontFamily="@font/inter_semibold"
|
||||||
android:marqueeRepeatLimit="marquee_forever"
|
|
||||||
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
|
android:onClick="@{() -> playbackModel.navToItem(playbackModel.song)}"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@{song.name}"
|
android:text="@{song.name}"
|
||||||
|
|
Loading…
Reference in a new issue