Use MotionLayout to animate bottom sheet opening
This commit is contained in:
parent
b924a0c655
commit
056e3a4d66
|
@ -181,7 +181,7 @@ dependencies {
|
||||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
implementation("com.google.android.material:material:1.8.0")
|
implementation("com.google.android.material:material:1.8.0")
|
||||||
implementation("com.android.support.constraint:constraint-layout:2.0.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
|
|
||||||
implementation("com.google.android.exoplayer:exoplayer-core:2.18.1")
|
implementation("com.google.android.exoplayer:exoplayer-core:2.18.1")
|
||||||
implementation("com.google.android.exoplayer:exoplayer-ui:2.18.1")
|
implementation("com.google.android.exoplayer:exoplayer-ui:2.18.1")
|
||||||
|
|
|
@ -3,6 +3,7 @@ package audio.funkwhale.ffa.activities
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Fragment
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -49,7 +50,6 @@ import audio.funkwhale.ffa.utils.authorize
|
||||||
import audio.funkwhale.ffa.utils.log
|
import audio.funkwhale.ffa.utils.log
|
||||||
import audio.funkwhale.ffa.utils.logError
|
import audio.funkwhale.ffa.utils.logError
|
||||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||||
import audio.funkwhale.ffa.utils.onApi
|
|
||||||
import audio.funkwhale.ffa.utils.toast
|
import audio.funkwhale.ffa.utils.toast
|
||||||
import audio.funkwhale.ffa.utils.wait
|
import audio.funkwhale.ffa.utils.wait
|
||||||
import com.github.kittinunf.fuel.Fuel
|
import com.github.kittinunf.fuel.Fuel
|
||||||
|
@ -60,10 +60,6 @@ import com.google.gson.Gson
|
||||||
import com.preference.PowerPreference
|
import com.preference.PowerPreference
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.channels.consume
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.consumeAsFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.java.KoinJavaComponent.inject
|
import org.koin.java.KoinJavaComponent.inject
|
||||||
|
|
||||||
|
@ -87,32 +83,28 @@ class MainActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
AppContext.init(this)
|
AppContext.init(this)
|
||||||
|
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
binding.nowPlayingBottomSheet.addBottomSheetCallback(
|
(supportFragmentManager.findFragmentById(R.id.now_playing) as NowPlayingFragment).apply {
|
||||||
object : BottomSheetBehavior.BottomSheetCallback() {
|
onDetailsMenuItemClicked { binding.nowPlayingBottomSheet.close() }
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
binding.nowPlayingBottomSheet.addBottomSheetCallback(
|
||||||
// Set the proper margin on the other child
|
object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
val anim = if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||||
ValueAnimator.ofInt(binding.nowPlayingBottomSheet.peekHeight, 0)
|
// Add padding to the main fragment so that player control don't overlap
|
||||||
} else {
|
// artists and albums
|
||||||
ValueAnimator.ofInt(0, binding.nowPlayingBottomSheet.peekHeight)
|
addSiblingFragmentPadding()
|
||||||
}
|
}
|
||||||
|
|
||||||
anim.apply {
|
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||||
duration = 200
|
// Animate the cover and other elements of the bottom sheet
|
||||||
addUpdateListener {
|
onBottomSheetDrag(slideOffset)
|
||||||
val params =
|
|
||||||
binding.navHostFragmentWrapper.layoutParams as CoordinatorLayout.LayoutParams
|
|
||||||
params.setMargins(0, 0, 0, it.animatedValue as Int)
|
|
||||||
}
|
|
||||||
start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
|
addSiblingFragmentPadding()
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
@ -132,8 +124,11 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let {
|
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let {
|
||||||
if(it.queue.isNotEmpty()) binding.nowPlayingBottomSheet.show()
|
if (it.queue.isNotEmpty() && binding.nowPlayingBottomSheet.isHidden) {
|
||||||
else binding.nowPlayingBottomSheet.hide()
|
binding.nowPlayingBottomSheet.show()
|
||||||
|
} else if (it.queue.isEmpty()) {
|
||||||
|
binding.nowPlayingBottomSheet.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Watch the event bus only after to prevent concurrency in displaying the bottom sheet
|
// Watch the event bus only after to prevent concurrency in displaying the bottom sheet
|
||||||
watchEventBus()
|
watchEventBus()
|
||||||
|
@ -265,6 +260,20 @@ class MainActivity : AppCompatActivity() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addSiblingFragmentPadding() {
|
||||||
|
val anim = if (binding.nowPlayingBottomSheet.isHidden) {
|
||||||
|
ValueAnimator.ofInt(binding.nowPlayingBottomSheet.peekHeight, 0)
|
||||||
|
} else {
|
||||||
|
ValueAnimator.ofInt(0, binding.nowPlayingBottomSheet.peekHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
anim.duration = 200
|
||||||
|
anim.addUpdateListener {
|
||||||
|
binding.navHostFragmentWrapper.setPadding(0, 0, 0, it.animatedValue as Int)
|
||||||
|
}
|
||||||
|
anim.start()
|
||||||
|
}
|
||||||
|
|
||||||
private fun launchDialog(fragment: DialogFragment) =
|
private fun launchDialog(fragment: DialogFragment) =
|
||||||
fragment.show(supportFragmentManager.beginTransaction(), "")
|
fragment.show(supportFragmentManager.beginTransaction(), "")
|
||||||
|
|
||||||
|
@ -297,7 +306,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
CommandBus.get().flowWithLifecycle(
|
CommandBus.get().flowWithLifecycle(
|
||||||
this@MainActivity.lifecycle, Lifecycle.State.RESUMED
|
this@MainActivity.lifecycle, Lifecycle.State.RESUMED
|
||||||
).collect { command ->
|
).collect { command ->
|
||||||
when(command) {
|
when (command) {
|
||||||
is Command.StartService -> startService(command.command)
|
is Command.StartService -> startService(command.command)
|
||||||
is Command.RefreshTrack -> refreshTrack(command.track)
|
is Command.RefreshTrack -> refreshTrack(command.track)
|
||||||
is Command.AddToPlaylist -> AddToPlaylistDialog.show(
|
is Command.AddToPlaylist -> AddToPlaylistDialog.show(
|
||||||
|
@ -306,6 +315,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
lifecycleScope,
|
lifecycleScope,
|
||||||
command.tracks
|
command.tracks
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ import audio.funkwhale.ffa.model.Track
|
||||||
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
||||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||||
import audio.funkwhale.ffa.repositories.Repository
|
import audio.funkwhale.ffa.repositories.Repository
|
||||||
import audio.funkwhale.ffa.utils.BottomSheetIneractable
|
|
||||||
import audio.funkwhale.ffa.utils.Command
|
import audio.funkwhale.ffa.utils.Command
|
||||||
import audio.funkwhale.ffa.utils.CommandBus
|
import audio.funkwhale.ffa.utils.CommandBus
|
||||||
import audio.funkwhale.ffa.utils.CoverArt
|
import audio.funkwhale.ffa.utils.CoverArt
|
||||||
|
@ -30,24 +29,17 @@ import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||||
import audio.funkwhale.ffa.utils.toIntOrElse
|
import audio.funkwhale.ffa.utils.toIntOrElse
|
||||||
import audio.funkwhale.ffa.utils.untilNetwork
|
import audio.funkwhale.ffa.utils.untilNetwork
|
||||||
import audio.funkwhale.ffa.viewmodel.NowPlayingViewModel
|
import audio.funkwhale.ffa.viewmodel.NowPlayingViewModel
|
||||||
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.lang.Float.max
|
||||||
|
|
||||||
class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
class NowPlayingFragment: Fragment(R.layout.fragment_now_playing) {
|
||||||
private val binding by lazy { FragmentNowPlayingBinding.bind(requireView()) }
|
private val binding by lazy { FragmentNowPlayingBinding.bind(requireView()) }
|
||||||
private val viewModel by viewModels<NowPlayingViewModel>()
|
private val viewModel by viewModels<NowPlayingViewModel>()
|
||||||
private val favoriteRepository by lazy { FavoritesRepository(requireContext()) }
|
private val favoriteRepository by lazy { FavoritesRepository(requireContext()) }
|
||||||
private val favoritedRepository by lazy { FavoritedRepository(requireContext()) }
|
private val favoritedRepository by lazy { FavoritedRepository(requireContext()) }
|
||||||
|
|
||||||
private val bottomSheet: BottomSheetIneractable? by lazy {
|
private var onDetailsMenuItemClickedCb: () -> Unit = {}
|
||||||
var view = this.view?.parent
|
|
||||||
while (view != null) {
|
|
||||||
if(view is BottomSheetIneractable) return@lazy view
|
|
||||||
view = view.parent
|
|
||||||
}
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
binding.lifecycleOwner = viewLifecycleOwner
|
binding.lifecycleOwner = viewLifecycleOwner
|
||||||
|
@ -83,7 +75,10 @@ class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
||||||
nowPlayingDetailsAddToPlaylist.setOnClickListener { onAddToPlaylist() }
|
nowPlayingDetailsAddToPlaylist.setOnClickListener { onAddToPlaylist() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.nowPlayingDetailsInfo.setOnClickListener { openInfoMenu() }
|
||||||
|
|
||||||
with(binding.header) {
|
with(binding.header) {
|
||||||
|
lifecycleOwner = viewLifecycleOwner
|
||||||
isBuffering = viewModel.isBuffering
|
isBuffering = viewModel.isBuffering
|
||||||
isPlaying = viewModel.isPlaying
|
isPlaying = viewModel.isPlaying
|
||||||
progress = viewModel.progress
|
progress = viewModel.progress
|
||||||
|
@ -100,8 +95,6 @@ class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.nowPlayingDetailsInfo.setOnClickListener { openInfoMenu() }
|
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
CommandBus.get().collect { onCommand(it) }
|
CommandBus.get().collect { onCommand(it) }
|
||||||
}
|
}
|
||||||
|
@ -115,6 +108,14 @@ class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onBottomSheetDrag(value: Float) {
|
||||||
|
binding.nowPlayingRoot.progress = max(value, 0f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDetailsMenuItemClicked(cb: () -> Unit) {
|
||||||
|
onDetailsMenuItemClickedCb = cb
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun toggleRepeatMode() {
|
private fun toggleRepeatMode() {
|
||||||
val cachedRepeatMode = FFACache.getLine(requireContext(), "repeat").toIntOrElse(0)
|
val cachedRepeatMode = FFACache.getLine(requireContext(), "repeat").toIntOrElse(0)
|
||||||
|
@ -170,19 +171,10 @@ class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
||||||
private fun onTrackChange(track: Track?) {
|
private fun onTrackChange(track: Track?) {
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
binding.header.nowPlayingCover.setImageResource(R.drawable.cover)
|
binding.header.nowPlayingCover.setImageResource(R.drawable.cover)
|
||||||
binding.nowPlayingDetailCover.setImageResource(R.drawable.cover)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
CoverArt.withContext(requireContext(), maybeNormalizeUrl(track.album?.cover()))
|
CoverArt.withContext(requireContext(), maybeNormalizeUrl(track.album?.cover()))
|
||||||
.fit()
|
|
||||||
.centerCrop()
|
|
||||||
.into(binding.nowPlayingDetailCover)
|
|
||||||
|
|
||||||
CoverArt.withContext(requireContext(), maybeNormalizeUrl(track.album?.cover()))
|
|
||||||
.fit()
|
|
||||||
.centerCrop()
|
|
||||||
.transform(RoundedCornersTransformation(16, 0))
|
|
||||||
.into(binding.header.nowPlayingCover)
|
.into(binding.header.nowPlayingCover)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +191,7 @@ class NowPlayingFragment : Fragment(R.layout.fragment_now_playing) {
|
||||||
inflate(R.menu.track_info)
|
inflate(R.menu.track_info)
|
||||||
|
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
bottomSheet?.close()
|
onDetailsMenuItemClickedCb()
|
||||||
|
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.track_info_artist -> findNavController().navigate(
|
R.id.track_info_artist -> findNavController().navigate(
|
||||||
|
|
|
@ -2,20 +2,21 @@ package audio.funkwhale.ffa.views
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.content.res.use
|
import androidx.core.content.res.use
|
||||||
import audio.funkwhale.ffa.R
|
import audio.funkwhale.ffa.R
|
||||||
import audio.funkwhale.ffa.utils.BottomSheetIneractable
|
import audio.funkwhale.ffa.utils.BottomSheetIneractable
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
||||||
import com.google.android.material.card.MaterialCardView
|
|
||||||
|
|
||||||
|
|
||||||
class NowPlayingBottomSheet @JvmOverloads constructor(
|
class NowPlayingBottomSheet @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
) : MaterialCardView(context, attrs), BottomSheetIneractable {
|
) : FrameLayout(context, attrs, defStyleAttr), BottomSheetIneractable {
|
||||||
private val behavior = BottomSheetBehavior<NowPlayingBottomSheet>()
|
private val behavior = BottomSheetBehavior<NowPlayingBottomSheet>()
|
||||||
private val targetHeaderId: Int
|
private val targetHeaderId: Int
|
||||||
|
|
||||||
|
@ -27,6 +28,14 @@ class NowPlayingBottomSheet @JvmOverloads constructor(
|
||||||
).use {
|
).use {
|
||||||
it.getResourceId(R.styleable.NowPlaying_target_header, NO_ID)
|
it.getResourceId(R.styleable.NowPlaying_target_header, NO_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put default peek height to actionBarSize so it is not 0
|
||||||
|
val tv = TypedValue()
|
||||||
|
if (context.theme.resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
|
||||||
|
behavior.peekHeight = TypedValue.complexToDimensionPixelSize(
|
||||||
|
tv.data, resources.displayMetrics
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setLayoutParams(params: ViewGroup.LayoutParams?) {
|
override fun setLayoutParams(params: ViewGroup.LayoutParams?) {
|
||||||
|
@ -37,7 +46,7 @@ class NowPlayingBottomSheet @JvmOverloads constructor(
|
||||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
findViewById<View>(targetHeaderId)?.apply {
|
findViewById<View>(targetHeaderId)?.apply {
|
||||||
behavior.setPeekHeight(this.measuredHeight, false)
|
behavior.setPeekHeight(this.height, false)
|
||||||
this.setOnClickListener { this@NowPlayingBottomSheet.toggle() }
|
this.setOnClickListener { this@NowPlayingBottomSheet.toggle() }
|
||||||
} ?: hide()
|
} ?: hide()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,25 @@ package audio.funkwhale.ffa.views
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.widget.AppCompatImageButton
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
|
||||||
|
open class SquareView : View {
|
||||||
|
constructor(context: Context) : super(context)
|
||||||
|
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||||
|
constructor(context: Context, attrs: AttributeSet?, style: Int) : super(context, attrs, style)
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
|
||||||
|
val dimension = if(measuredWidth == 0 && measuredHeight > 0) measuredHeight else measuredWidth
|
||||||
|
|
||||||
|
setMeasuredDimension(dimension, dimension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open class SquareImageView : AppCompatImageView {
|
open class SquareImageView : AppCompatImageView {
|
||||||
constructor(context: Context) : super(context)
|
constructor(context: Context) : super(context)
|
||||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
|
@ -9,9 +9,8 @@
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="@color/surface"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_weight="10">
|
app:layout_constraintBottom_toTopOf="@id/appbar_wrapper">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/nav_host_fragment_wrapper"
|
android:id="@+id/nav_host_fragment_wrapper"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -38,21 +37,13 @@
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
tools:layout="@layout/partial_queue" />
|
tools:layout="@layout/partial_queue" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/appbar_wrapper"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
<audio.funkwhale.ffa.views.NowPlayingBottomSheet
|
<audio.funkwhale.ffa.views.NowPlayingBottomSheet
|
||||||
android:id="@+id/now_playing_bottom_sheet"
|
android:id="@+id/now_playing_bottom_sheet"
|
||||||
style="?attr/bottomSheetStyle"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:cardCornerRadius="3dp"
|
android:background="@color/elevatedSurface"
|
||||||
app:cardElevation="12dp"
|
app:target_header="@id/constraint_layout_placeholder">
|
||||||
app:target_header="@id/header">
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/now_playing"
|
android:id="@+id/now_playing"
|
||||||
android:name="audio.funkwhale.ffa.fragments.NowPlayingFragment"
|
android:name="audio.funkwhale.ffa.fragments.NowPlayingFragment"
|
||||||
|
|
|
@ -3,56 +3,63 @@
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
|
<data>
|
||||||
|
<import type="androidx.lifecycle.LiveData" />
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<import type="android.graphics.drawable.Drawable" />
|
||||||
|
<variable name="isBuffering" type="LiveData<Boolean>" />
|
||||||
|
<variable name="isPlaying" type="LiveData<Boolean>" />
|
||||||
|
<variable name="progress" type="LiveData<Integer>" />
|
||||||
|
<variable name="currentTrackTitle" type="LiveData<String>" />
|
||||||
|
<variable name="currentTrackArtist" type="LiveData<String>" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
android:id="@+id/now_playing_root"
|
android:id="@+id/now_playing_root"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/elevatedSurface">
|
app:layoutDescription="@xml/fragment_now_playing_scene">
|
||||||
|
|
||||||
<include
|
<include android:id="@+id/header" layout="@layout/partial_now_playing_header" />
|
||||||
android:id="@+id/header"
|
|
||||||
layout="@layout/partial_now_playing_header" />
|
|
||||||
|
|
||||||
<audio.funkwhale.ffa.views.SquareImageView
|
<audio.funkwhale.ffa.views.SquareView
|
||||||
android:id="@+id/now_playing_detail_cover"
|
android:id="@+id/detail_image_placeholder"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:scaleType="fitCenter"
|
app:layout_constraintTop_toBottomOf="@id/now_playing_progress"
|
||||||
app:layout_constraintTop_toBottomOf="@id/header"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintDimensionRatio="H,1:1"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:srcCompat="@drawable/cover"
|
/>
|
||||||
tools:src="@tools:sample/avatars" />
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/now_playing_details_info"
|
android:id="@+id/now_playing_details_info"
|
||||||
style="@style/IconButton"
|
style="@style/IconButton"
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_gravity="top|end"
|
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:background="@drawable/circle"
|
android:background="@drawable/circle"
|
||||||
android:contentDescription="@string/alt_track_info"
|
android:contentDescription="@string/alt_track_info"
|
||||||
android:src="@drawable/more"
|
android:src="@drawable/more"
|
||||||
app:layout_constraintEnd_toEndOf="@id/now_playing_detail_cover"
|
app:layout_constraintEnd_toEndOf="@id/detail_image_placeholder"
|
||||||
app:layout_constraintTop_toTopOf="@id/now_playing_detail_cover"
|
app:layout_constraintTop_toTopOf="@id/detail_image_placeholder"
|
||||||
app:tint="@color/controlForeground"
|
app:tint="@color/controlForeground"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/controls"
|
android:id="@+id/controls"
|
||||||
layout="@layout/partial_now_playing_controls"
|
layout="@layout/partial_now_playing_controls"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/header"
|
app:layout_constraintTop_toTopOf="@id/detail_image_placeholder"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/now_playing_detail_cover"
|
app:layout_constraintStart_toEndOf="@id/detail_image_placeholder"
|
||||||
|
android:alpha="0"
|
||||||
|
android:background="@color/elevatedSurface"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -11,11 +11,11 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toTopOf="@id/appbar_wrapper">
|
app:layout_constraintBottom_toTopOf="@id/appbar_wrapper">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/nav_host_fragment_wrapper"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
android:id="@+id/nav_host_fragment_wrapper">
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/nav_host_fragment"
|
android:id="@+id/nav_host_fragment"
|
||||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
|
@ -30,18 +30,17 @@
|
||||||
|
|
||||||
<audio.funkwhale.ffa.views.NowPlayingBottomSheet
|
<audio.funkwhale.ffa.views.NowPlayingBottomSheet
|
||||||
android:id="@+id/now_playing_bottom_sheet"
|
android:id="@+id/now_playing_bottom_sheet"
|
||||||
style="?attr/bottomSheetStyle"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:cardCornerRadius="3dp"
|
android:background="@color/elevatedSurface"
|
||||||
app:cardElevation="12dp"
|
app:target_header="@id/constraint_layout_placeholder">
|
||||||
app:target_header="@id/header">
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/now_playing"
|
android:id="@+id/now_playing"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:name="audio.funkwhale.ffa.fragments.NowPlayingFragment"
|
android:name="audio.funkwhale.ffa.fragments.NowPlayingFragment"
|
||||||
tools:layout="@layout/fragment_now_playing"/>
|
tools:layout="@layout/fragment_now_playing"
|
||||||
|
/>
|
||||||
</audio.funkwhale.ffa.views.NowPlayingBottomSheet>
|
</audio.funkwhale.ffa.views.NowPlayingBottomSheet>
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layout
|
<layout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<data>
|
||||||
|
<import type="androidx.lifecycle.LiveData" />
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<import type="android.graphics.drawable.Drawable" />
|
||||||
|
<variable name="isBuffering" type="LiveData<Boolean>" />
|
||||||
|
<variable name="isPlaying" type="LiveData<Boolean>" />
|
||||||
|
<variable name="progress" type="LiveData<Integer>" />
|
||||||
|
<variable name="currentTrackTitle" type="LiveData<String>" />
|
||||||
|
<variable name="currentTrackArtist" type="LiveData<String>" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
android:id="@+id/now_playing_root"
|
android:id="@+id/now_playing_root"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/elevatedSurface">
|
app:layoutDescription="@xml/fragment_now_playing_scene">
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/header"
|
android:id="@+id/header"
|
||||||
layout="@layout/partial_now_playing_header" />
|
layout="@layout/partial_now_playing_header"
|
||||||
|
/>
|
||||||
|
|
||||||
<audio.funkwhale.ffa.views.SquareImageView
|
<audio.funkwhale.ffa.views.SquareView
|
||||||
android:id="@+id/now_playing_detail_cover"
|
android:id="@+id/detail_image_placeholder"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/header"
|
app:layout_constraintTop_toBottomOf="@id/now_playing_progress"
|
||||||
app:srcCompat="@drawable/cover"
|
|
||||||
tools:src="@tools:sample/avatars"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -27,23 +37,23 @@
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:layout_constraintEnd_toEndOf="@id/now_playing_detail_cover"
|
app:layout_constraintEnd_toEndOf="@id/detail_image_placeholder"
|
||||||
app:layout_constraintTop_toTopOf="@id/now_playing_detail_cover"
|
app:layout_constraintTop_toTopOf="@id/detail_image_placeholder"
|
||||||
style="@style/IconButton"
|
style="@style/IconButton"
|
||||||
android:layout_gravity="top|end"
|
|
||||||
android:background="@drawable/circle"
|
android:background="@drawable/circle"
|
||||||
android:contentDescription="@string/alt_track_info"
|
android:contentDescription="@string/alt_track_info"
|
||||||
android:src="@drawable/more"
|
android:src="@drawable/more"
|
||||||
app:tint="@color/controlForeground" />
|
app:tint="@color/controlForeground"
|
||||||
|
/>
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/controls"
|
android:id="@+id/controls"
|
||||||
layout="@layout/partial_now_playing_controls"
|
layout="@layout/partial_now_playing_controls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/now_playing_detail_cover"
|
app:layout_constraintTop_toBottomOf="@id/detail_image_placeholder"
|
||||||
/>
|
/>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -16,9 +16,11 @@
|
||||||
<variable name="isPlaying" type="LiveData<Boolean>" />
|
<variable name="isPlaying" type="LiveData<Boolean>" />
|
||||||
<variable name="progress" type="LiveData<Integer>" />
|
<variable name="progress" type="LiveData<Integer>" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/current_playing_details_title"
|
android:id="@+id/current_playing_details_title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -84,8 +86,8 @@
|
||||||
android:id="@+id/now_playing_details_progress"
|
android:id="@+id/now_playing_details_progress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:max="100"
|
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
|
android:max="100"
|
||||||
android:progress="@{progress, default=40}"
|
android:progress="@{progress, default=40}"
|
||||||
android:progressBackgroundTint="#cacaca"
|
android:progressBackgroundTint="#cacaca"
|
||||||
android:progressTint="@color/controlForeground"
|
android:progressTint="@color/controlForeground"
|
||||||
|
|
|
@ -14,29 +14,34 @@
|
||||||
<variable name="currentTrackArtist" type="LiveData<String>" />
|
<variable name="currentTrackArtist" type="LiveData<String>" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<merge>
|
||||||
android:layout_width="match_parent"
|
<!-- Placeholder for setting constraints and interacting -->
|
||||||
android:layout_height="?attr/actionBarSize">
|
<View
|
||||||
|
android:id="@+id/constraint_layout_placeholder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
/>
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
android:id="@+id/now_playing_progress"
|
android:id="@+id/now_playing_progress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="@id/constraint_layout_placeholder"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:progress="@{progress, default=40}"
|
android:progress="@{progress, default=40}"
|
||||||
android:progressTint="@color/colorPrimaryDark" />
|
android:progressTint="@color/colorPrimaryDark"
|
||||||
|
/>
|
||||||
|
|
||||||
<audio.funkwhale.ffa.views.SquareImageView
|
<audio.funkwhale.ffa.views.SquareImageView
|
||||||
android:id="@+id/now_playing_cover"
|
android:id="@+id/now_playing_cover"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="@id/constraint_layout_placeholder"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/now_playing_progress"
|
app:layout_constraintTop_toBottomOf="@id/now_playing_progress"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/constraint_layout_placeholder"
|
||||||
app:srcCompat="@drawable/cover"
|
app:srcCompat="@drawable/cover"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars"
|
||||||
|
/>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/now_playing_buffering"
|
android:id="@+id/now_playing_buffering"
|
||||||
|
@ -46,9 +51,8 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/now_playing_cover"
|
app:layout_constraintTop_toTopOf="@id/now_playing_cover"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/now_playing_cover"
|
app:layout_constraintBottom_toBottomOf="@id/now_playing_cover"
|
||||||
app:layout_constraintEnd_toEndOf="@id/now_playing_cover"
|
app:layout_constraintEnd_toEndOf="@id/now_playing_cover"
|
||||||
android:indeterminate="true"
|
android:visibility="@{isBuffering ? View.VISIBLE : View.INVISIBLE, default=invisible}"
|
||||||
android:indeterminateTint="@color/controlForeground"
|
/>
|
||||||
android:visibility="@{isBuffering ? View.VISIBLE : View.INVISIBLE, default=invisible}" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/header_controls"
|
android:id="@+id/header_controls"
|
||||||
|
@ -56,9 +60,10 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintHorizontal_weight="10"
|
app:layout_constraintHorizontal_weight="10"
|
||||||
app:layout_constraintStart_toEndOf="@id/now_playing_cover"
|
app:layout_constraintStart_toEndOf="@id/now_playing_cover"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="@id/constraint_layout_placeholder"
|
||||||
app:layout_constraintTop_toBottomOf="@id/now_playing_progress"
|
app:layout_constraintTop_toBottomOf="@id/now_playing_progress"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="@id/constraint_layout_placeholder"
|
||||||
|
android:background="@color/elevatedSurface"
|
||||||
android:padding="4dp">
|
android:padding="4dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -71,7 +76,8 @@
|
||||||
android:text="@{currentTrackTitle}"
|
android:text="@{currentTrackTitle}"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
tools:text="Supermassive Black Hole" />
|
tools:text="Supermassive Black Hole"
|
||||||
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -82,7 +88,8 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:text="@{currentTrackArtist}"
|
android:text="@{currentTrackArtist}"
|
||||||
tools:text="Muse" />
|
tools:text="Muse"
|
||||||
|
/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/now_playing_toggle"
|
android:id="@+id/now_playing_toggle"
|
||||||
|
@ -91,7 +98,8 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/now_playing_next"
|
app:layout_constraintEnd_toStartOf="@id/now_playing_next"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
app:icon="@{isPlaying ? @drawable/pause : @drawable/play, default=@drawable/play}" />
|
app:icon="@{isPlaying ? @drawable/pause : @drawable/play, default=@drawable/play}"
|
||||||
|
/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/now_playing_next"
|
android:id="@+id/now_playing_next"
|
||||||
|
@ -100,7 +108,9 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
style="@style/IconButton"
|
style="@style/IconButton"
|
||||||
android:contentDescription="@string/control_next"
|
android:contentDescription="@string/control_next"
|
||||||
android:src="@drawable/next" />
|
android:src="@drawable/next"
|
||||||
|
/>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</merge>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MotionScene
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:motion="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/start">
|
||||||
|
<Constraint android:id="@id/now_playing_details_info">
|
||||||
|
<PropertySet android:alpha="0" android:visibility="invisible" />
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/header_controls">
|
||||||
|
<PropertySet android:alpha="1" android:visibility="visible" />
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/constraint_layout_placeholder">
|
||||||
|
<PropertySet android:visibility="visible" />
|
||||||
|
</Constraint>
|
||||||
|
</ConstraintSet>
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/end">
|
||||||
|
<Constraint
|
||||||
|
android:id="@id/now_playing_cover"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@id/detail_image_placeholder"
|
||||||
|
motion:layout_constraintStart_toStartOf="@id/detail_image_placeholder"
|
||||||
|
motion:layout_constraintTop_toBottomOf="@id/detail_image_placeholder"
|
||||||
|
motion:layout_constraintTop_toTopOf="@id/detail_image_placeholder"
|
||||||
|
motion:transitionEasing="accelerate"
|
||||||
|
/>
|
||||||
|
<Constraint android:id="@id/now_playing_progress">
|
||||||
|
<PropertySet android:alpha="0" android:visibility="gone" />
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/header_controls">
|
||||||
|
<PropertySet android:alpha="0" android:visibility="invisible" />
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/constraint_layout_placeholder">
|
||||||
|
<PropertySet android:visibility="invisible" />
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/now_playing_details_info">
|
||||||
|
<PropertySet android:alpha="1" android:visibility="visible"/>
|
||||||
|
</Constraint>
|
||||||
|
<Constraint android:id="@id/controls">
|
||||||
|
<PropertySet android:alpha="1" />
|
||||||
|
</Constraint>
|
||||||
|
</ConstraintSet>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
motion:constraintSetEnd="@id/end"
|
||||||
|
motion:constraintSetStart="@+id/start"
|
||||||
|
>
|
||||||
|
<KeyFrameSet>
|
||||||
|
<KeyPosition
|
||||||
|
motion:percentX="1"
|
||||||
|
motion:framePosition="50"
|
||||||
|
motion:motionTarget="@id/now_playing_cover"
|
||||||
|
motion:curveFit="spline"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0"
|
||||||
|
motion:framePosition="10"
|
||||||
|
motion:motionTarget="@id/header_controls"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyPosition
|
||||||
|
motion:percentX="1"
|
||||||
|
motion:framePosition="50"
|
||||||
|
motion:motionTarget="@id/header_controls"
|
||||||
|
motion:curveFit="spline"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0"
|
||||||
|
motion:framePosition="10"
|
||||||
|
motion:motionTarget="@id/now_playing_progress"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0"
|
||||||
|
motion:framePosition="90"
|
||||||
|
motion:motionTarget="@id/now_playing_details_info"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0"
|
||||||
|
motion:framePosition="90"
|
||||||
|
motion:motionTarget="@id/controls"
|
||||||
|
/>
|
||||||
|
</KeyFrameSet>
|
||||||
|
</Transition>
|
||||||
|
</MotionScene>
|
Loading…
Reference in New Issue