playback: make compact playback ui a view
Change CompactPlaybackFragment into a View. This completely fixes the
issue I tried to band-aid in ae39054
. The code is a bit uglier, but
that's tolerable.
This commit is contained in:
parent
ae39054b63
commit
c1e1329c21
13 changed files with 226 additions and 178 deletions
|
@ -28,10 +28,13 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.oxycblt.auxio.databinding.FragmentMainBinding
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.playback.PlaybackBarLayout
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
|
@ -39,8 +42,9 @@ import org.oxycblt.auxio.util.logD
|
|||
* A wrapper around the home fragment that shows the playback fragment and controls
|
||||
* the more high-level navigation features.
|
||||
*/
|
||||
class MainFragment : Fragment() {
|
||||
class MainFragment : Fragment(), PlaybackBarLayout.ActionCallback {
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -63,22 +67,26 @@ class MainFragment : Fragment() {
|
|||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
if (playbackModel.song.value != null) {
|
||||
binding.mainBarLayout.showBar()
|
||||
} else {
|
||||
binding.mainBarLayout.hideBar()
|
||||
}
|
||||
binding.mainBarLayout.setActionCallback(this)
|
||||
|
||||
binding.mainBarLayout.setSong(playbackModel.song.value)
|
||||
binding.mainBarLayout.setPlaying(playbackModel.isPlaying.value!!)
|
||||
binding.mainBarLayout.setPosition(playbackModel.position.value!!)
|
||||
|
||||
playbackModel.song.observe(viewLifecycleOwner) { song ->
|
||||
if (song != null) {
|
||||
binding.mainBarLayout.showBar()
|
||||
} else {
|
||||
binding.mainBarLayout.hideBar()
|
||||
}
|
||||
binding.mainBarLayout.setSong(song)
|
||||
}
|
||||
|
||||
// Initialize music loading. Unlike MainFragment, we can not only do this here on startup
|
||||
// but also show a SnackBar in a reasonable place in this fragment.
|
||||
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
|
||||
binding.mainBarLayout.setPlaying(isPlaying)
|
||||
}
|
||||
|
||||
playbackModel.position.observe(viewLifecycleOwner) { pos ->
|
||||
binding.mainBarLayout.setPosition(pos)
|
||||
}
|
||||
|
||||
// Initialize music loading. Do it here so that it shows on every fragment that this
|
||||
// one contains.
|
||||
musicModel.loadMusic(requireContext())
|
||||
|
||||
// Handle the music loader response.
|
||||
|
@ -132,4 +140,18 @@ class MainFragment : Fragment() {
|
|||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onPlayPauseClick() {
|
||||
playbackModel.invertPlayingStatus()
|
||||
}
|
||||
|
||||
override fun onNavToPlayback() {
|
||||
findNavController().navigate(
|
||||
MainFragmentDirections.actionGoToPlayback()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onNavToItem() {
|
||||
detailModel.navToItem(playbackModel.song.value ?: return)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.util.canScroll
|
||||
import org.oxycblt.auxio.util.resolveAttr
|
||||
import org.oxycblt.auxio.util.resolveDrawable
|
||||
import org.oxycblt.auxio.util.systemBarsCompat
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
|
@ -324,12 +325,14 @@ class FastScrollRecyclerView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
|
||||
val bars = insets.systemBarsCompat
|
||||
|
||||
setPadding(
|
||||
initialPadding.left, initialPadding.top, initialPadding.right,
|
||||
initialPadding.bottom + insets.systemWindowInsetBottom
|
||||
initialPadding.bottom + bars.bottom
|
||||
)
|
||||
|
||||
scrollerPadding.bottom = insets.systemWindowInsetBottom
|
||||
scrollerPadding.bottom = bars.bottom
|
||||
|
||||
return insets
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Auxio Project
|
||||
* CompactPlaybackFragment.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.playback
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.oxycblt.auxio.MainFragmentDirections
|
||||
import org.oxycblt.auxio.databinding.FragmentCompactPlaybackBinding
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/**
|
||||
* A [Fragment] that displays the currently played song at a glance, with some basic controls.
|
||||
* Extends into [PlaybackFragment] when clicked on.
|
||||
*
|
||||
* Instantiation is done by FragmentContainerView, **do not instantiate this fragment manually.**
|
||||
* @author OxygenCobalt
|
||||
* TODO: Add more controls to this view depending on screen width
|
||||
*/
|
||||
class CompactPlaybackFragment : Fragment() {
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val binding = FragmentCompactPlaybackBinding.inflate(inflater)
|
||||
|
||||
// --- UI SETUP ---
|
||||
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
binding.playbackModel = playbackModel
|
||||
binding.executePendingBindings()
|
||||
|
||||
binding.root.apply {
|
||||
setOnClickListener {
|
||||
findNavController().navigate(
|
||||
MainFragmentDirections.actionGoToPlayback()
|
||||
)
|
||||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
detailModel.navToItem(playbackModel.song.value!!)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
playbackModel.song.observe(viewLifecycleOwner) { song ->
|
||||
if (song != null) {
|
||||
logD("Updating song display to ${song.name}")
|
||||
|
||||
binding.song = song
|
||||
binding.playbackProgress.max = song.seconds.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
|
||||
binding.playbackPlayPause.isActivated = isPlaying
|
||||
}
|
||||
|
||||
logD("Fragment Created")
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Auxio Project
|
||||
* CompactPlaybackView.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.RippleDrawable
|
||||
import android.util.AttributeSet
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.ViewCompactPlaybackBinding
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.resolveAttr
|
||||
import org.oxycblt.auxio.util.resolveDrawable
|
||||
|
||||
/**
|
||||
* A view displaying the playback state in a compact manner. This is only meant to be used
|
||||
* by [PlaybackBarLayout].
|
||||
*/
|
||||
class CompactPlaybackView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = -1
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
private val binding = ViewCompactPlaybackBinding.inflate(context.inflater, this, true)
|
||||
private var mCallback: PlaybackBarLayout.ActionCallback? = null
|
||||
|
||||
init {
|
||||
id = R.id.playback_bar
|
||||
|
||||
elevation = resources.getDimensionPixelSize(R.dimen.elevation_normal).toFloat()
|
||||
|
||||
// To get a MaterialShapeDrawable to co-exist with a ripple drawable, we need to layer
|
||||
// this drawable on top of the existing ripple drawable. RippleDrawable actually inherits
|
||||
// LayerDrawable though, so we can do this. However, adding a new drawable layer directly
|
||||
// is only available on API 23+, but we're on API 21. So we create a drawable resource with
|
||||
// an empty drawable with a hard-coded ID, filling the drawable in with a
|
||||
// MaterialShapeDrawable at runtime and allowing this code to work on API 21.
|
||||
background = R.drawable.ui_shape_ripple.resolveDrawable(context).apply {
|
||||
val backgroundDrawable = MaterialShapeDrawable.createWithElevationOverlay(context).apply {
|
||||
elevation = this@CompactPlaybackView.elevation
|
||||
fillColor = ColorStateList.valueOf(R.attr.colorSurface.resolveAttr(context))
|
||||
}
|
||||
|
||||
(this as RippleDrawable).setDrawableByLayerId(
|
||||
android.R.id.background, backgroundDrawable
|
||||
)
|
||||
}
|
||||
|
||||
isClickable = true
|
||||
isFocusable = true
|
||||
|
||||
setOnClickListener {
|
||||
mCallback?.onNavToPlayback()
|
||||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
mCallback?.onNavToItem()
|
||||
true
|
||||
}
|
||||
|
||||
binding.playbackPlayPause.setOnClickListener {
|
||||
mCallback?.onPlayPauseClick()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSong(song: Song) {
|
||||
binding.song = song
|
||||
}
|
||||
|
||||
fun setPlaying(isPlaying: Boolean) {
|
||||
binding.playbackPlayPause.isActivated = isPlaying
|
||||
}
|
||||
|
||||
fun setPosition(position: Long) {
|
||||
if (binding.song == null) {
|
||||
binding.playbackProgress.progress = 0
|
||||
return
|
||||
}
|
||||
|
||||
binding.playbackProgress.progress = position.toInt()
|
||||
}
|
||||
|
||||
fun setCallback(callback: PlaybackBarLayout.ActionCallback) {
|
||||
mCallback = callback
|
||||
}
|
||||
|
||||
fun clearCallback() {
|
||||
mCallback = null
|
||||
}
|
||||
}
|
|
@ -19,25 +19,18 @@
|
|||
package org.oxycblt.auxio.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Insets
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.resolveAttr
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.systemBarsCompat
|
||||
|
||||
/**
|
||||
|
@ -46,9 +39,6 @@ import org.oxycblt.auxio.util.systemBarsCompat
|
|||
* this class was primarily written by me and I plan to expand this layout to become part of
|
||||
* the playback navigation process.
|
||||
*
|
||||
* TODO: Migrate CompactPlaybackFragment to a view. This is okay, as updates can be delivered
|
||||
* via MainFragment and it would fix the issue where the actual layout won't measure until
|
||||
* the fragment is shown.
|
||||
* TODO: Implement animation
|
||||
* TODO: Implement the swipe-up behavior. This needs to occur, as the way the main fragment
|
||||
* saves state results in'
|
||||
|
@ -59,37 +49,18 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
@AttrRes defStyleAttr: Int = 0,
|
||||
@StyleRes defStyleRes: Int = 0
|
||||
) : ViewGroup(context, attrs, defStyleAttr, defStyleRes) {
|
||||
private val barLayout = FrameLayout(context)
|
||||
private val playbackFragment = CompactPlaybackFragment()
|
||||
private val playbackView = CompactPlaybackView(context)
|
||||
private var lastInsets: WindowInsets? = null
|
||||
|
||||
init {
|
||||
addView(barLayout)
|
||||
|
||||
barLayout.apply {
|
||||
id = R.id.main_playback
|
||||
|
||||
elevation = resources.getDimensionPixelSize(R.dimen.elevation_normal).toFloat()
|
||||
addView(playbackView)
|
||||
|
||||
playbackView.apply {
|
||||
(layoutParams as LayoutParams).apply {
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
isBar = true
|
||||
}
|
||||
|
||||
background = MaterialShapeDrawable.createWithElevationOverlay(context).apply {
|
||||
elevation = barLayout.elevation
|
||||
fillColor = ColorStateList.valueOf(R.attr.colorSurface.resolveAttr(context))
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInEditMode) {
|
||||
(context as AppCompatActivity).supportFragmentManager.apply {
|
||||
this
|
||||
.beginTransaction()
|
||||
.replace(R.id.main_playback, playbackFragment)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,15 +72,15 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
|
||||
setMeasuredDimension(widthSize, heightSize)
|
||||
|
||||
val barParams = barLayout.layoutParams as LayoutParams
|
||||
val barParams = playbackView.layoutParams as LayoutParams
|
||||
|
||||
val barWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, barParams.width)
|
||||
val barHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, barParams.height)
|
||||
barLayout.measure(barWidthSpec, barHeightSpec)
|
||||
playbackView.measure(barWidthSpec, barHeightSpec)
|
||||
|
||||
updateWindowInsets()
|
||||
|
||||
val barHeightAdjusted = (barLayout.measuredHeight * barParams.offset).toInt()
|
||||
val barHeightAdjusted = (playbackView.measuredHeight * barParams.offset).toInt()
|
||||
|
||||
val contentWidth = measuredWidth
|
||||
val contentHeight = measuredHeight - barHeightAdjusted
|
||||
|
@ -129,13 +100,13 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||
val barHeight = if (barLayout.isVisible) {
|
||||
barLayout.measuredHeight
|
||||
val barHeight = if (playbackView.isVisible) {
|
||||
playbackView.measuredHeight
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
val barHeightAdjusted = (barHeight * (barLayout.layoutParams as LayoutParams).offset).toInt()
|
||||
val barHeightAdjusted = (barHeight * (playbackView.layoutParams as LayoutParams).offset).toInt()
|
||||
|
||||
for (child in children) {
|
||||
if (child.visibility == View.GONE) continue
|
||||
|
@ -154,7 +125,7 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets {
|
||||
barLayout.updatePadding(bottom = insets.systemBarsCompat.bottom)
|
||||
playbackView.updatePadding(bottom = insets.systemBarsCompat.bottom)
|
||||
|
||||
lastInsets = insets
|
||||
updateWindowInsets()
|
||||
|
@ -162,6 +133,12 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
return insets
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
|
||||
playbackView.clearCallback()
|
||||
}
|
||||
|
||||
private fun updateWindowInsets() {
|
||||
val insets = lastInsets
|
||||
|
||||
|
@ -171,8 +148,8 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun mutateInsets(insets: WindowInsets): WindowInsets {
|
||||
val barParams = barLayout.layoutParams as LayoutParams
|
||||
val childConsumedInset = (barLayout.measuredHeight * barParams.offset).toInt()
|
||||
val barParams = playbackView.layoutParams as LayoutParams
|
||||
val childConsumedInset = (playbackView.measuredHeight * barParams.offset).toInt()
|
||||
|
||||
val bars = insets.systemBarsCompat
|
||||
|
||||
|
@ -194,8 +171,29 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
return insets
|
||||
}
|
||||
|
||||
fun showBar() {
|
||||
val barParams = barLayout.layoutParams as LayoutParams
|
||||
fun setSong(song: Song?) {
|
||||
if (song != null) {
|
||||
showBar()
|
||||
playbackView.setSong(song)
|
||||
} else {
|
||||
hideBar()
|
||||
}
|
||||
}
|
||||
|
||||
fun setPlaying(isPlaying: Boolean) {
|
||||
playbackView.setPlaying(isPlaying)
|
||||
}
|
||||
|
||||
fun setPosition(position: Long) {
|
||||
playbackView.setPosition(position)
|
||||
}
|
||||
|
||||
fun setActionCallback(callback: ActionCallback) {
|
||||
playbackView.setCallback(callback)
|
||||
}
|
||||
|
||||
private fun showBar() {
|
||||
val barParams = playbackView.layoutParams as LayoutParams
|
||||
|
||||
if (barParams.offset == 1f) {
|
||||
return
|
||||
|
@ -210,8 +208,8 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
invalidate()
|
||||
}
|
||||
|
||||
fun hideBar() {
|
||||
val barParams = barLayout.layoutParams as LayoutParams
|
||||
private fun hideBar() {
|
||||
val barParams = playbackView.layoutParams as LayoutParams
|
||||
|
||||
if (barParams.offset == 0f) {
|
||||
return
|
||||
|
@ -260,4 +258,10 @@ class PlaybackBarLayout @JvmOverloads constructor(
|
|||
|
||||
constructor(source: ViewGroup.LayoutParams) : super(source)
|
||||
}
|
||||
|
||||
interface ActionCallback {
|
||||
fun onPlayPauseClick()
|
||||
fun onNavToItem()
|
||||
fun onNavToPlayback()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -419,7 +419,6 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
* Restore playback on startup. This can do one of two things:
|
||||
* - Play a file intent that was given by MainActivity in [playWithUri]
|
||||
* - Restore the last playback state if there is no active file intent.
|
||||
* TODO: Re-add this to HomeFragment once state can be restored
|
||||
*/
|
||||
fun setupPlayback(context: Context) {
|
||||
val intentUri = mIntentUri
|
||||
|
|
|
@ -138,6 +138,10 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int {
|
|||
return color.resolveColor(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve window insets in a version-aware manner. This can be used to apply padding to
|
||||
* a view that properly
|
||||
*/
|
||||
val WindowInsets.systemBarsCompat: Rect get() {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
||||
|
|
14
app/src/main/res/drawable/ui_shape_ripple.xml
Normal file
14
app/src/main/res/drawable/ui_shape_ripple.xml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Hack to make MaterialShapeDrawable cooperate with RippleDrawable. See
|
||||
CompactPlaybackView for more info. -->
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@android:color/white" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle" />
|
||||
</item>
|
||||
</ripple>
|
|
@ -32,7 +32,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
app:layout_role="content"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
tools:listitem="@layout/item_detail" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".playback.CompactPlaybackFragment">
|
||||
tools:context=".playback.CompactPlaybackView">
|
||||
|
||||
<data>
|
||||
|
||||
|
@ -10,19 +10,17 @@
|
|||
name="song"
|
||||
type="org.oxycblt.auxio.music.Song" />
|
||||
|
||||
<variable
|
||||
name="playbackModel"
|
||||
type="org.oxycblt.auxio.playback.PlaybackViewModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<merge
|
||||
android:id="@+id/playback_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/ui_background_ripple"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/playback_cover"
|
||||
|
@ -73,7 +71,6 @@
|
|||
android:src="@drawable/sel_playing_state"
|
||||
android:layout_margin="@dimen/spacing_small"
|
||||
android:contentDescription="@string/desc_play_pause"
|
||||
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -82,12 +79,12 @@
|
|||
android:id="@+id/playback_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/size_stroke_large"
|
||||
android:max="@{(int) song.seconds}"
|
||||
style="@style/Widget.Auxio.ProgressBar"
|
||||
android:progress="@{playbackModel.positionAsProgress}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:progress="70" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</merge>
|
||||
</layout>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main_playback"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:clipToPadding="true"
|
||||
android:elevation="@dimen/elevation_normal"
|
||||
tools:layout="@layout/fragment_compact_playback" />
|
|
@ -4,9 +4,4 @@
|
|||
<attr name="entries" format="reference" />
|
||||
<attr name="entryValues" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<attr format="enum" name="layout_role">
|
||||
<enum name="content" value="0" />
|
||||
<enum name="floating" value="1" />
|
||||
</attr>
|
||||
</resources>
|
|
@ -1,5 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- This is for PlaybackBarLayout -->
|
||||
<item name="playback_bar" type="id" />
|
||||
|
||||
<!-- This is for HomeFragment's AppBarLayout. Explanations for these can be found there. -->
|
||||
<item name="home_song_list" type="id" />
|
||||
<item name="home_album_list" type="id" />
|
||||
|
|
Loading…
Reference in a new issue