Layout and skip+prev functionality

This commit is contained in:
Bnyro 2023-01-13 18:20:00 +01:00
parent c3645cb4d2
commit 59697caebf
10 changed files with 205 additions and 19 deletions

View File

@ -8,7 +8,7 @@ object IntentData {
const val timeStamp = "timeStamp" const val timeStamp = "timeStamp"
const val position = "position" const val position = "position"
const val fileName = "fileName" const val fileName = "fileName"
const val openQueueOnce = "openQueue"
const val keepQueue = "keepQueue" const val keepQueue = "keepQueue"
const val playlistType = "playlistType" const val playlistType = "playlistType"
const val openAudioPlayer = "openAudioPlayer"
} }

View File

@ -93,7 +93,6 @@ object PreferenceKeys {
* Background mode * Background mode
*/ */
const val BACKGROUND_PLAYBACK_SPEED = "background_playback_speed" const val BACKGROUND_PLAYBACK_SPEED = "background_playback_speed"
const val NOTIFICATION_OPEN_QUEUE = "notification_open_queue"
/** /**
* Notifications * Notifications

View File

@ -391,6 +391,11 @@ class MainActivity : BaseActivity() {
startActivity(intent) startActivity(intent)
} }
if (intent?.getBooleanExtra(IntentData.openAudioPlayer, false) == true) {
navController.navigate(R.id.audioPlayerFragment)
return
}
intent?.getStringExtra(IntentData.channelId)?.let { intent?.getStringExtra(IntentData.channelId)?.let {
navController.navigate( navController.navigate(
R.id.channelFragment, R.id.channelFragment,
@ -412,6 +417,7 @@ class MainActivity : BaseActivity() {
intent?.getStringExtra(IntentData.videoId)?.let { intent?.getStringExtra(IntentData.videoId)?.let {
loadVideo(it, intent?.getLongExtra(IntentData.timeStamp, 0L)) loadVideo(it, intent?.getLongExtra(IntentData.timeStamp, 0L))
} }
when (intent?.getStringExtra("fragmentToOpen")) { when (intent?.getStringExtra("fragmentToOpen")) {
"home" -> "home" ->
navController.navigate(R.id.homeFragment) navController.navigate(R.id.homeFragment)
@ -422,10 +428,6 @@ class MainActivity : BaseActivity() {
"library" -> "library" ->
navController.navigate(R.id.libraryFragment) navController.navigate(R.id.libraryFragment)
} }
if (intent?.getBooleanExtra(IntentData.openQueueOnce, false) == true) {
PlayingQueueSheet()
.show(supportFragmentManager)
}
} }
private fun loadVideo(videoId: String, timeStamp: Long?) { private fun loadVideo(videoId: String, timeStamp: Long?) {

View File

@ -0,0 +1,67 @@
package com.github.libretube.ui.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.github.libretube.api.obj.StreamItem
import com.github.libretube.databinding.FragmentAudioPlayerBinding
import com.github.libretube.extensions.toID
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.util.ImageHelper
import com.github.libretube.util.NavigationHelper
import com.github.libretube.util.PlayingQueue
class AudioPlayerFragment : BaseFragment() {
private lateinit var binding: FragmentAudioPlayerBinding
private val onTrackChangeListener: (StreamItem) -> Unit = {
updateStreamInfo()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentAudioPlayerBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.prev.setOnClickListener {
val currentIndex = PlayingQueue.currentIndex()
PlayingQueue.onQueueItemSelected(currentIndex - 1)
}
binding.next.setOnClickListener {
val currentIndex = PlayingQueue.currentIndex()
PlayingQueue.onQueueItemSelected(currentIndex + 1)
}
PlayingQueue.addOnTrackChangedListener(onTrackChangeListener)
updateStreamInfo()
}
private fun updateStreamInfo() {
val current = PlayingQueue.getCurrent()
current ?: return
binding.title.text = current.title
binding.uploader.text = current.uploaderName
binding.uploader.setOnClickListener {
NavigationHelper.navigateChannel(requireContext(), current.uploaderUrl?.toID())
}
ImageHelper.loadImage(current.thumbnail, binding.thumbnail)
}
override fun onDestroy() {
super.onDestroy()
// unregister the listener
PlayingQueue.removeOnTrackChangedListener(onTrackChangeListener)
}
}

View File

@ -75,11 +75,7 @@ class NowPlayingNotification(
// that's the only way to launch back into the previous activity (e.g. the player view // that's the only way to launch back into the previous activity (e.g. the player view
val intent = Intent(context, MainActivity::class.java).apply { val intent = Intent(context, MainActivity::class.java).apply {
if (isBackgroundPlayerNotification) { if (isBackgroundPlayerNotification) {
if (PreferenceHelper.getBoolean(PreferenceKeys.NOTIFICATION_OPEN_QUEUE, true)) { putExtra(IntentData.openAudioPlayer, true)
putExtra(IntentData.openQueueOnce, true)
} else {
putExtra(IntentData.videoId, videoId)
}
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
} }
} }

View File

@ -13,7 +13,16 @@ import kotlinx.coroutines.launch
object PlayingQueue { object PlayingQueue {
private val queue = mutableListOf<StreamItem>() private val queue = mutableListOf<StreamItem>()
private var currentStream: StreamItem? = null private var currentStream: StreamItem? = null
/**
* Listener that gets called when the user selects an item from the queue
*/
private var onQueueTapListener: (StreamItem) -> Unit = {} private var onQueueTapListener: (StreamItem) -> Unit = {}
/**
* Listener that gets called when the current playing video changes
*/
private val onTrackChangedListeners: MutableList<(StreamItem) -> Unit> = mutableListOf()
var repeatQueue: Boolean = false var repeatQueue: Boolean = false
fun add(vararg streamItem: StreamItem) { fun add(vararg streamItem: StreamItem) {
@ -58,6 +67,9 @@ object PlayingQueue {
fun updateCurrent(streamItem: StreamItem) { fun updateCurrent(streamItem: StreamItem) {
currentStream = streamItem currentStream = streamItem
onTrackChangedListeners.forEach {
it.invoke(streamItem)
}
if (!contains(streamItem)) queue.add(streamItem) if (!contains(streamItem)) queue.add(streamItem)
} }
@ -77,6 +89,8 @@ object PlayingQueue {
} }
} }
fun getCurrent(): StreamItem? = currentStream
fun contains(streamItem: StreamItem) = queue.any { it.url?.toID() == streamItem.url?.toID() } fun contains(streamItem: StreamItem) = queue.any { it.url?.toID() == streamItem.url?.toID() }
// only returns a copy of the queue, no write access // only returns a copy of the queue, no write access
@ -162,9 +176,18 @@ object PlayingQueue {
onQueueTapListener = listener onQueueTapListener = listener
} }
fun addOnTrackChangedListener(listener: (StreamItem) -> Unit) {
onTrackChangedListeners.add(listener)
}
fun removeOnTrackChangedListener(listener: (StreamItem) -> Unit) {
onTrackChangedListeners.remove(listener)
}
fun resetToDefaults() { fun resetToDefaults() {
repeatQueue = false repeatQueue = false
onQueueTapListener = {} onQueueTapListener = {}
onTrackChangedListeners.clear()
queue.clear() queue.clear()
} }
} }

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/thumbnail"
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" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textSize="20sp" />
<TextView
android:id="@+id/uploader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp" />
</LinearLayout>
<com.google.android.material.slider.Slider
android:id="@+id/time_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:labelBehavior="gone"
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginVertical="50dp">
<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_play"
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>
</LinearLayout>

View File

@ -54,4 +54,9 @@
android:name="com.github.libretube.ui.fragments.DownloadsFragment" android:name="com.github.libretube.ui.fragments.DownloadsFragment"
android:label="@string/downloads" android:label="@string/downloads"
tools:layout="@layout/fragment_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> </navigation>

View File

@ -430,6 +430,7 @@
<string name="pause">Pause</string> <string name="pause">Pause</string>
<string name="alternative_pip_controls">Alternative PiP controls</string> <string name="alternative_pip_controls">Alternative PiP controls</string>
<string name="alternative_pip_controls_summary">Show audio only and skip controls in PiP instead of forward and rewind</string> <string name="alternative_pip_controls_summary">Show audio only and skip controls in PiP instead of forward and rewind</string>
<string name="audio_player">Audio player</string>
<!-- Notification channel strings --> <!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string> <string name="download_channel_name">Download Service</string>

View File

@ -89,12 +89,6 @@
app:valueFrom="0.2" app:valueFrom="0.2"
app:valueTo="4.0" /> app:valueTo="4.0" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:icon="@drawable/ic_grid"
android:title="@string/open_queue_from_notification"
app:key="notification_open_queue" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>