Merge pull request #2694 from Bnyro/master

Add audio only mode
This commit is contained in:
Bnyro 2023-01-14 16:59:43 +01:00 committed by GitHub
commit 0357b736a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 42 deletions

View File

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

View File

@ -10,6 +10,7 @@ import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.core.app.ServiceCompat
import com.fasterxml.jackson.databind.ObjectMapper
@ -24,6 +25,7 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.db.DatabaseHolder.Companion.Database
import com.github.libretube.db.obj.WatchPosition
import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.awaitQuery
import com.github.libretube.extensions.query
import com.github.libretube.extensions.toID
@ -127,7 +129,7 @@ class BackgroundMode : Service() {
*/
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
try {
// clear the playing queue
// reset the playing queue listeners
PlayingQueue.resetToDefaults()
// get the intent arguments
@ -145,6 +147,7 @@ class BackgroundMode : Service() {
if (PlayerHelper.watchPositionsEnabled) updateWatchPosition()
} catch (e: Exception) {
Log.e(TAG(), e.toString())
onDestroy()
}
return super.onStartCommand(intent, flags, startId)
@ -177,23 +180,23 @@ class BackgroundMode : Service() {
RetrofitInstance.api.getStreams(videoId)
}.getOrNull() ?: return@launch
// clear the queue if it shouldn't be kept explicitly
if (!keepQueue) PlayingQueue.clear()
if (PlayingQueue.isEmpty()) updateQueue()
// save the current stream to the queue
streams?.toStreamItem(videoId)?.let {
PlayingQueue.updateCurrent(it)
}
// add the playlist video to the queue
if (PlayingQueue.isEmpty() && !keepQueue) updateQueue()
handler.post {
playAudio(seekToPosition)
}
}
}
private fun playAudio(
seekToPosition: Long
) {
private fun playAudio(seekToPosition: Long) {
initializePlayer()
setMediaItem()

View File

@ -41,6 +41,7 @@ import com.github.libretube.ui.models.SearchViewModel
import com.github.libretube.ui.models.SubscriptionsViewModel
import com.github.libretube.ui.tools.BreakReminder
import com.github.libretube.util.NavBarHelper
import com.github.libretube.util.NavigationHelper
import com.github.libretube.util.NetworkHelper
import com.github.libretube.util.PreferenceHelper
import com.github.libretube.util.ThemeHelper
@ -58,6 +59,8 @@ class MainActivity : BaseActivity() {
lateinit var searchView: SearchView
private lateinit var searchItem: MenuItem
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -381,7 +384,7 @@ class MainActivity : BaseActivity() {
}
if (intent?.getBooleanExtra(IntentData.openAudioPlayer, false) == true) {
navController.navigate(R.id.audioPlayerFragment)
NavigationHelper.startAudioPlayer(this)
return
}
@ -404,7 +407,11 @@ class MainActivity : BaseActivity() {
)
}
intent?.getStringExtra(IntentData.videoId)?.let {
loadVideo(it, intent?.getLongExtra(IntentData.timeStamp, 0L))
NavigationHelper.navigateVideo(
context = this,
videoId = it,
timeStamp = intent?.getLongExtra(IntentData.timeStamp, 0L)
)
}
when (intent?.getStringExtra("fragmentToOpen")) {
@ -419,32 +426,6 @@ class MainActivity : BaseActivity() {
}
}
private fun loadVideo(videoId: String, timeStamp: Long?) {
val bundle = Bundle()
bundle.putString(IntentData.videoId, videoId)
if (timeStamp != null) bundle.putLong(IntentData.timeStamp, timeStamp)
val frag = PlayerFragment()
frag.arguments = bundle
supportFragmentManager.beginTransaction()
.remove(PlayerFragment())
.commit()
supportFragmentManager.beginTransaction()
.replace(R.id.container, frag)
.commitNow()
Handler(Looper.getMainLooper()).postDelayed({
supportFragmentManager.fragments.forEach { fragment ->
(fragment as? PlayerFragment)
?.binding?.playerMotionLayout?.apply {
transitionToEnd()
transitionToStart()
}
}
}, 300)
}
private fun minimizePlayer() {
binding.mainMotionLayout.transitionToEnd()
supportFragmentManager.fragments.forEach { fragment ->

View File

@ -86,6 +86,7 @@ import com.github.libretube.util.BackgroundHelper
import com.github.libretube.util.DashHelper
import com.github.libretube.util.DataSaverMode
import com.github.libretube.util.ImageHelper
import com.github.libretube.util.NavigationHelper
import com.github.libretube.util.NowPlayingNotification
import com.github.libretube.util.PlayerHelper
import com.github.libretube.util.PlayingQueue
@ -349,7 +350,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
BackgroundHelper.stopBackgroundPlay(requireContext())
}
playerBinding.closeImageButton.setOnClickListener {
killFragment()
killPlayerFragment()
}
playerBinding.autoPlay.visibility = View.VISIBLE
@ -476,8 +477,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
true
)
handler.postDelayed({
(activity as MainActivity).navController.navigate(R.id.audioPlayerFragment)
killFragment()
NavigationHelper.startAudioPlayer(requireContext())
killPlayerFragment()
}, 500)
}
@ -1530,7 +1531,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
return exoPlayer.isPlaying && !backgroundModeRunning
}
private fun killFragment() {
private fun killPlayerFragment() {
viewModel.isFullscreen.value = false
binding.playerMotionLayout.transitionToEnd()
val mainActivity = activity as MainActivity

View File

@ -6,10 +6,13 @@ import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.github.libretube.R
import com.github.libretube.constants.IntentData
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
@ -17,6 +20,8 @@ import com.github.libretube.ui.fragments.PlayerFragment
import com.github.libretube.ui.views.SingleViewTouchableMotionLayout
object NavigationHelper {
private val handler = Handler(Looper.getMainLooper())
fun navigateChannel(
context: Context,
channelId: String?
@ -45,20 +50,35 @@ object NavigationHelper {
return correctContext as MainActivity
}
/**
* Navigate to the given video using the other provided parameters as well
* If the audio only mode is enabled, play it in the background, else as a normal video
*/
fun navigateVideo(
context: Context,
videoId: String?,
playlistId: String? = null,
channelId: String? = null,
keepQueue: Boolean = false
keepQueue: Boolean = false,
timeStamp: Long? = null
) {
if (videoId == null) return
if (PreferenceHelper.getBoolean(PreferenceKeys.AUDIO_ONLY_MODE, false)) {
BackgroundHelper.stopBackgroundPlay(context)
BackgroundHelper.playOnBackground(context, videoId.toID(), timeStamp, playlistId, channelId, keepQueue)
handler.postDelayed({
startAudioPlayer(context)
}, 500)
return
}
val bundle = Bundle().apply {
putString(IntentData.videoId, videoId.toID())
putString(IntentData.playlistId, playlistId)
putString(IntentData.channelId, channelId)
putBoolean(IntentData.keepQueue, keepQueue)
timeStamp?.let { putLong(IntentData.timeStamp, it) }
}
val activity = context as AppCompatActivity
@ -89,6 +109,14 @@ object NavigationHelper {
activity.navController.navigate(R.id.playlistFragment, bundle)
}
/**
* Start the audio player fragment
*/
fun startAudioPlayer(context: Context) {
val activity = unwrap(context)
activity.navController.navigate(R.id.audioPlayerFragment)
}
/**
* Needed due to different MainActivity Aliases because of the app icons
*/

View File

@ -25,6 +25,8 @@ object PlayingQueue {
private val onTrackChangedListeners: MutableList<(StreamItem) -> Unit> = mutableListOf()
var repeatQueue: Boolean = false
fun clear() = queue.clear()
fun add(vararg streamItem: StreamItem) {
streamItem.forEach {
if (currentStream != it) {
@ -72,7 +74,7 @@ object PlayingQueue {
it.invoke(streamItem)
}
}
if (!contains(streamItem)) queue.add(streamItem)
if (!contains(streamItem)) queue.add(0, streamItem)
}
fun isNotEmpty() = queue.isNotEmpty()
@ -190,6 +192,5 @@ object PlayingQueue {
repeatQueue = false
onQueueTapListener = {}
onTrackChangedListeners.clear()
queue.clear()
}
}

View File

@ -431,6 +431,8 @@
<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="audio_player">Audio player</string>
<string name="audio_only_mode">Audio only mode</string>
<string name="audio_only_mode_summary">Turn LibreTube into a music player.</string>
<!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string>

View File

@ -23,6 +23,13 @@
<PreferenceCategory app:title="@string/customization">
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_headphones"
android:summary="@string/audio_only_mode_summary"
android:title="@string/audio_only_mode"
app:key="audio_only_mode" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_screen_rotation"