diff --git a/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt b/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt index 794ef2e3a..dc558d02a 100644 --- a/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt +++ b/app/src/main/java/com/github/libretube/helpers/NavigationHelper.kt @@ -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(R.id.container) + } } /** diff --git a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt index ebb151182..0669de1a9 100644 --- a/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/github/libretube/ui/activities/MainActivity.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt index f3a9906c8..1cb7b97e0 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/AudioPlayerFragment.kt @@ -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() diff --git a/app/src/main/java/com/github/libretube/ui/views/SingleViewTouchableMotionLayout.kt b/app/src/main/java/com/github/libretube/ui/views/SingleViewTouchableMotionLayout.kt index b070703e1..64bbdd250 100644 --- a/app/src/main/java/com/github/libretube/ui/views/SingleViewTouchableMotionLayout.kt +++ b/app/src/main/java/com/github/libretube/ui/views/SingleViewTouchableMotionLayout.kt @@ -14,7 +14,7 @@ class SingleViewTouchableMotionLayout(context: Context, attributeSet: AttributeS MotionLayout(context, attributeSet) { private val viewToDetectTouch by lazy { - findViewById(R.id.main_container) // TODO move to Attributes + findViewById(R.id.main_container) ?: findViewById(R.id.audio_player_container) } private val viewRect = Rect() private var touchStarted = false diff --git a/app/src/main/res/layout/fragment_audio_player.xml b/app/src/main/res/layout/fragment_audio_player.xml index eb646c7f4..3c26b1ba3 100644 --- a/app/src/main/res/layout/fragment_audio_player.xml +++ b/app/src/main/res/layout/fragment_audio_player.xml @@ -1,204 +1,275 @@ - + app:layoutDescription="@xml/audio_player_scene"> - + 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" /> - + + + android:layout_height="0dp" + android:layout_weight="1"> - - - + 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:id="@+id/progress" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" /> - + + + + + + + - - - - - - - + android:layout_marginHorizontal="20dp" + app:labelBehavior="gone" /> - + android:paddingHorizontal="20dp"> - + - + - - - - - - - - - - - - - - - - - - - + + android:layout_marginTop="10dp" + android:layout_marginBottom="36dp"> + 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" /> + + - - - - - - + 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" /> - + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav.xml b/app/src/main/res/navigation/nav.xml index 3d64e6c50..d076b0d5a 100644 --- a/app/src/main/res/navigation/nav.xml +++ b/app/src/main/res/navigation/nav.xml @@ -54,9 +54,4 @@ android:name="com.github.libretube.ui.fragments.DownloadsFragment" android:label="@string/downloads" tools:layout="@layout/fragment_downloads" /> - \ No newline at end of file diff --git a/app/src/main/res/xml/audio_player_scene.xml b/app/src/main/res/xml/audio_player_scene.xml new file mode 100644 index 000000000..7a6da1949 --- /dev/null +++ b/app/src/main/res/xml/audio_player_scene.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/player_scene.xml b/app/src/main/res/xml/player_scene.xml index 001769fa1..b1c1ad81e 100644 --- a/app/src/main/res/xml/player_scene.xml +++ b/app/src/main/res/xml/player_scene.xml @@ -31,34 +31,6 @@ - - - -