diff --git a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt index 1c4086466..cbe237d9c 100644 --- a/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt +++ b/app/src/main/java/com/github/libretube/constants/PreferenceKeys.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index 7925076d5..7ad013a21 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -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() 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 069a51f36..93ef77c57 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 @@ -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 -> diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index ce3a94c3a..fe73fc124 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt index 6d55680ea..d4742b92c 100644 --- a/app/src/main/java/com/github/libretube/util/NavigationHelper.kt +++ b/app/src/main/java/com/github/libretube/util/NavigationHelper.kt @@ -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 */ diff --git a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt index 174891393..995f45bfd 100644 --- a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt +++ b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt @@ -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() } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7da95f877..9c8c18b4e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -431,6 +431,8 @@ Alternative PiP controls Show audio only and skip controls in PiP instead of forward and rewind Audio player + Audio only mode + Turn LibreTube into a music player. Download Service diff --git a/app/src/main/res/xml/general_settings.xml b/app/src/main/res/xml/general_settings.xml index 423f831c8..67b585be7 100644 --- a/app/src/main/res/xml/general_settings.xml +++ b/app/src/main/res/xml/general_settings.xml @@ -23,6 +23,13 @@ + +