Merge pull request #3335 from Bnyro/audio-mini-player

Audio mini player
This commit is contained in:
Bnyro 2023-03-21 19:15:23 +01:00 committed by GitHub
commit a5f44c4e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 398 additions and 216 deletions

View File

@ -18,6 +18,7 @@ import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.enums.PlaylistType
import com.github.libretube.extensions.toID
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.fragments.AudioPlayerFragment
import com.github.libretube.ui.fragments.PlayerFragment
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
@ -117,7 +118,9 @@ object NavigationHelper {
*/
fun startAudioPlayer(context: Context) {
val activity = unwrap(context)
activity.navController.navigate(R.id.audioPlayerFragment)
activity.supportFragmentManager.commitNow {
replace<AudioPlayerFragment>(R.id.container)
}
}
/**

View File

@ -362,7 +362,7 @@ class MainActivity : BaseActivity() {
true
}
R.id.action_audio -> {
navController.navigate(R.id.audioPlayerFragment)
NavigationHelper.startAudioPlayer(this)
true
}
else -> super.onOptionsItemSelected(item)

View File

@ -13,7 +13,10 @@ import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit
import androidx.navigation.fragment.findNavController
import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem
@ -31,14 +34,22 @@ import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.interfaces.AudioPlayerOptions
import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.ui.sheets.PlaybackOptionsSheet
import com.github.libretube.ui.sheets.PlayingQueueSheet
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
import com.github.libretube.util.PlayingQueue
import kotlin.math.abs
class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private lateinit var binding: FragmentAudioPlayerBinding
private lateinit var audioHelper: AudioHelper
private val mainActivity get() = context as MainActivity
private val viewModel: PlayerViewModel by activityViewModels()
// for the transition
private var sId: Int = 0
private var eId: Int = 0
private val onTrackChangeListener: (StreamItem) -> Unit = {
updateStreamInfo()
@ -57,16 +68,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
handleServiceConnection()
}
override fun onServiceDisconnected(arg0: ComponentName) {
val mainActivity = activity as MainActivity
if (mainActivity.navController.currentDestination?.id == R.id.audioPlayerFragment) {
mainActivity.navController.popBackStack()
} else {
mainActivity.navController.backQueue.removeIf {
it.destination.id == R.id.audioPlayerFragment
}
}
}
override fun onServiceDisconnected(arg0: ComponentName) {}
}
override fun onCreate(savedInstanceState: Bundle?) {
@ -91,6 +93,8 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeTransitionLayout()
// select the title TV in order for it to automatically scroll
binding.title.isSelected = true
binding.uploader.isSelected = true
@ -142,7 +146,13 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
binding.close.setOnClickListener {
activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext())
findNavController().popBackStack()
killFragment()
}
binding.miniPlayerClose.setOnClickListener {
activity?.unbindService(connection)
BackgroundHelper.stopBackgroundPlay(requireContext())
killFragment()
}
val listener = AudioPlayerThumbnailListener(requireContext(), this)
@ -155,6 +165,10 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
if (isPaused) playerService?.play() else playerService?.pause()
}
binding.miniPlayerPause.setOnClickListener {
if (isPaused) playerService?.play() else playerService?.pause()
}
// load the stream info into the UI
updateStreamInfo()
@ -164,6 +178,63 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
}
}
private fun killFragment() {
viewModel.isFullscreen.value = false
binding.playerMotionLayout.transitionToEnd()
mainActivity.supportFragmentManager.commit {
remove(this@AudioPlayerFragment)
}
onDestroy()
}
@SuppressLint("ClickableViewAccessibility")
private fun initializeTransitionLayout() {
mainActivity.binding.container.visibility = View.VISIBLE
val mainMotionLayout = mainActivity.binding.mainMotionLayout
binding.playerMotionLayout.addTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionStarted(
motionLayout: MotionLayout?,
startId: Int,
endId: Int
) {
}
override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
mainMotionLayout.progress = abs(progress)
eId = endId
sId = startId
}
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
if (currentId == eId) {
viewModel.isMiniPlayerVisible.value = true
mainMotionLayout.progress = 1F
} else if (currentId == sId) {
viewModel.isMiniPlayerVisible.value = false
mainMotionLayout.progress = 0F
}
}
override fun onTransitionTrigger(
MotionLayout: MotionLayout?,
triggerId: Int,
positive: Boolean,
progress: Float
) {
}
})
binding.playerMotionLayout.progress = 1.toFloat()
binding.playerMotionLayout.transitionToStart()
}
/**
* Load the information from a new stream into the UI
*/
@ -172,6 +243,8 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
current ?: return
binding.title.text = current.title
binding.miniPlayerTitle.text = current.title
binding.uploader.text = current.uploaderName
binding.uploader.setOnClickListener {
NavigationHelper.navigateChannel(requireContext(), current.uploaderUrl?.toID())
@ -188,6 +261,7 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
ImageHelper.getAsync(requireContext(), thumbnailUrl) {
binding.thumbnail.setImageBitmap(it)
binding.miniPlayerThumbnail.setImageBitmap(it)
binding.thumbnail.visibility = View.VISIBLE
binding.progress.visibility = View.GONE
}
@ -232,9 +306,9 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private fun handleServiceConnection() {
playerService?.onIsPlayingChanged = { isPlaying ->
binding.playPause.setIconResource(
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play
)
val iconResource = if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play
binding.playPause.setIconResource(iconResource)
binding.miniPlayerPause.setImageResource(iconResource)
isPaused = !isPlaying
}
initializeSeekBar()

View File

@ -14,7 +14,7 @@ class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeS
MotionLayout(context, attributeSet) {
private val viewToDetectTouch by lazy {
findViewById<View>(R.id.main_container) // TODO move to Attributes
findViewById<View>(R.id.main_container) ?: findViewById(R.id.audio_player_container)
}
private val viewRect = Rect()
private var touchStarted = false

View File

@ -1,204 +1,275 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.github.libretube.ui.views.SingleViewTouchableMotionLayout 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/playerMotionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
app:layoutDescription="@xml/audio_player_scene">
<FrameLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/audio_player_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
android:layout_height="match_parent"
android:background="?android:attr/colorBackground"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/thumbnail"
<LinearLayout
android:id="@+id/audio_player_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@id/audio_player_container"
app:layout_constraintEnd_toEndOf="@id/audio_player_container"
app:layout_constraintStart_toStartOf="@id/audio_player_container"
app:layout_constraintTop_toTopOf="@id/audio_player_container">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Small"
tools:src="@tools:sample/backgrounds/scenic" />
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:id="@+id/volumeControls"
android:layout_width="42dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/controls_layout_bg"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/volume_textView"
style="@style/SwipeControlString"
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:autoSizeTextType="uniform" />
android:layout_marginHorizontal="20dp"
android:layout_marginVertical="10dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Small"
tools:src="@tools:sample/backgrounds/scenic" />
<LinearLayout
android:id="@+id/volumeControls"
android:layout_width="42dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/controls_layout_bg"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="RtlHardcoded">
<TextView
android:id="@+id/volume_textView"
style="@style/SwipeControlString"
android:layout_gravity="center"
app:autoSizeTextType="uniform" />
<ProgressBar
android:id="@+id/volume_progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="7dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_marginVertical="4dp"
android:progressDrawable="@drawable/vertical_progressbar" />
<ImageView
android:id="@+id/volume_imageView"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:contentDescription="@string/volume"
android:src="@drawable/ic_volume_up" />
</LinearLayout>
<ProgressBar
android:id="@+id/volume_progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="7dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_marginVertical="4dp"
android:progressDrawable="@drawable/vertical_progressbar" />
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ImageView
android:id="@+id/volume_imageView"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:contentDescription="@string/volume"
android:src="@drawable/ic_volume_up" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
style="@style/TextViewMarquee"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp" />
<TextView
android:id="@+id/uploader"
style="@style/TextViewMarquee"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="18sp" />
</LinearLayout>
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
style="@style/TextViewMarquee"
<com.google.android.material.slider.Slider
android:id="@+id/time_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp" />
android:layout_marginHorizontal="20dp"
app:labelBehavior="gone" />
<TextView
android:id="@+id/uploader"
style="@style/TextViewMarquee"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="18sp" />
android:paddingHorizontal="20dp">
</LinearLayout>
<TextView
android:id="@+id/current_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
tools:text="00:00" />
<com.google.android.material.slider.Slider
android:id="@+id/time_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
app:labelBehavior="gone" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
tools:text="10:15" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="20dp">
<TextView
android:id="@+id/current_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
tools:text="00:00" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
tools:text="10:15" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="36dp">
<ImageView
android:id="@+id/prev"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginHorizontal="20dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_prev" />
<com.google.android.material.button.MaterialButton
android:id="@+id/play_pause"
android:layout_width="72dp"
android:layout_height="72dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:icon="@drawable/ic_pause"
app:iconSize="24dp"
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Full" />
<ImageView
android:id="@+id/next"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginHorizontal="20dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_next" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Elevated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="30dp"
app:cardCornerRadius="18dp">
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="15dp">
android:layout_marginTop="10dp"
android:layout_marginBottom="36dp">
<ImageView
android:id="@+id/open_queue"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_queue" />
android:id="@+id/prev"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginHorizontal="20dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_prev" />
<com.google.android.material.button.MaterialButton
android:id="@+id/play_pause"
android:layout_width="72dp"
android:layout_height="72dp"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:icon="@drawable/ic_pause"
app:iconSize="24dp"
app:shapeAppearanceOverlay="@style/ShapeAppearance.Material3.Corner.Full" />
<ImageView
android:id="@+id/playback_options"
style="@style/AudioPlayerButton"
android:layout_width="27dp"
android:layout_height="27dp"
android:src="@drawable/ic_speed" />
<ImageView
android:id="@+id/open_video"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_video" />
<ImageView
android:id="@+id/share"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_share" />
<ImageView
android:id="@+id/close"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_close" />
android:id="@+id/next"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginHorizontal="20dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_next" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Elevated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="30dp"
app:cardCornerRadius="18dp">
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="15dp">
<ImageView
android:id="@+id/open_queue"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_queue" />
<ImageView
android:id="@+id/playback_options"
style="@style/AudioPlayerButton"
android:layout_width="27dp"
android:layout_height="27dp"
android:src="@drawable/ic_speed" />
<ImageView
android:id="@+id/open_video"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_video" />
<ImageView
android:id="@+id/share"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_share" />
<ImageView
android:id="@+id/close"
style="@style/AudioPlayerButton"
android:src="@drawable/ic_close" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<LinearLayout
android:id="@+id/miniPlayerControls"
android:layout_width="match_parent"
android:layout_height="54dp"
android:alpha="0"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/audio_player_container"
app:layout_constraintEnd_toEndOf="@id/audio_player_container"
app:layout_constraintStart_toStartOf="@id/audio_player_container"
app:layout_constraintTop_toTopOf="@id/audio_player_container">
<ImageView
android:id="@+id/miniPlayerThumbnail"
android:layout_width="96dp"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp" />
<TextView
android:id="@+id/miniPlayerTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:paddingHorizontal="8dp"
android:paddingVertical="15dp" />
<ImageView
android:id="@+id/miniPlayerPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:src="@drawable/ic_pause" />
<ImageView
android:id="@+id/miniPlayerClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:src="@drawable/ic_close" />
</LinearLayout>
</com.github.libretube.ui.views.SingleViewTouchableMotionLayout>

View File

@ -54,9 +54,4 @@
android:name="com.github.libretube.ui.fragments.DownloadsFragment"
android:label="@string/downloads"
tools:layout="@layout/fragment_downloads" />
<fragment
android:id="@+id/audioPlayerFragment"
android:name="com.github.libretube.ui.fragments.AudioPlayerFragment"
android:label="@string/audio_player"
tools:layout="@layout/fragment_audio_player" />
</navigation>

View File

@ -0,0 +1,67 @@
<?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">
<Transition
android:id="@+id/mini_player_transition"
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="500"
motion:motionInterpolator="easeInOut">
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
motion:framePosition="90"
motion:motionTarget="@+id/miniPlayerControls" />
</KeyFrameSet>
<OnSwipe
motion:dragDirection="dragDown"
motion:dragScale="6"
motion:maxAcceleration="40"
motion:touchAnchorId="@+id/audio_player_container"
motion:touchAnchorSide="bottom" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/audio_player_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/audio_player_container"
android:layout_width="match_parent"
android:layout_height="54dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintVertical_bias="1.0" />
<Constraint
android:id="@+id/audio_player_main"
android:layout_width="0dp"
android:layout_height="1dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@+id/main_container" />
<Constraint
android:id="@+id/miniPlayerControls"
android:layout_width="match_parent"
android:layout_height="54dp"
android:alpha="1"
android:paddingEnd="16dp"
android:visibility="visible"
motion:layout_constraintBottom_toBottomOf="@+id/audio_player_container"
motion:layout_constraintEnd_toEndOf="@id/audio_player_container"
motion:layout_constraintStart_toStartOf="@id/audio_player_container"
motion:layout_constraintTop_toTopOf="@+id/audio_player_container" />
</ConstraintSet>
</MotionScene>

View File

@ -31,34 +31,6 @@
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="@id/main_container"
motion:layout_constraintStart_toStartOf="@id/main_container"
motion:layout_constraintTop_toTopOf="@id/main_container" />
<Constraint
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="@id/main_container"
motion:layout_constraintStart_toStartOf="@id/main_container"
motion:layout_constraintTop_toTopOf="@id/main_container" />
<Constraint
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="@id/main_container"
motion:layout_constraintStart_toStartOf="@id/main_container"
motion:layout_constraintTop_toTopOf="@id/main_container" />
<Constraint
android:id="@+id/player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/main_container"
motion:layout_constraintStart_toStartOf="@id/main_container"
motion:layout_constraintTop_toTopOf="@id/main_container" />
<Constraint
android:id="@+id/player"
android:layout_width="match_parent"