From 0819e58ddd8b6c06d04b1fe4e458cc0866a96624 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Mon, 15 Aug 2022 09:06:20 +0200 Subject: [PATCH 1/2] don't PiP when paused --- .../main/java/com/github/libretube/fragments/PlayerFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 37407e5e4..cfc4c1474 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration import android.graphics.Rect +import android.media.session.PlaybackState import android.net.Uri import android.os.Build import android.os.Build.VERSION.SDK_INT @@ -1646,7 +1647,7 @@ class PlayerFragment : BaseFragment() { } private fun shouldStartPiP(): Boolean { - if (!pipEnabled) return false + if (!pipEnabled || exoPlayer.playbackState == PlaybackState.STATE_PAUSED) return false val bounds = Rect() binding.playerScrollView.getHitRect(bounds) From 4ec0a98cafa9b2a55e0bfa7bdf0efa8b657a2263 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Mon, 15 Aug 2022 09:41:30 +0200 Subject: [PATCH 2/2] replace globals with viewmodels --- .../main/java/com/github/libretube/Globals.kt | 10 ------- .../main/java/com/github/libretube/MyApp.kt | 15 +++++++--- .../libretube/activities/MainActivity.kt | 18 ++---------- .../libretube/dialogs/AddToPlaylistDialog.kt | 10 ++++--- .../libretube/fragments/LibraryFragment.kt | 16 +++++++--- .../libretube/fragments/PlayerFragment.kt | 29 +++++++++++-------- .../libretube/models/PlayerViewModel.kt | 13 +++++++++ .../libretube/models/PlaylistViewModel.kt | 7 +++++ .../libretube/models/SearchViewModel.kt | 3 +- .../github/libretube/util/ConnectionHelper.kt | 15 ++++++---- 10 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/models/PlayerViewModel.kt create mode 100644 app/src/main/java/com/github/libretube/models/PlaylistViewModel.kt diff --git a/app/src/main/java/com/github/libretube/Globals.kt b/app/src/main/java/com/github/libretube/Globals.kt index 5db9eabea..48fe4a64b 100644 --- a/app/src/main/java/com/github/libretube/Globals.kt +++ b/app/src/main/java/com/github/libretube/Globals.kt @@ -4,19 +4,9 @@ package com.github.libretube * Global variables can be stored here */ object Globals { - // for the player fragment - var IS_FULL_SCREEN = false - var MINI_PLAYER_VISIBLE = false - - // for the data saver mode - var DATA_SAVER_MODE_ENABLED = false - // for downloads var IS_DOWNLOAD_RUNNING = false - // for playlists - var SELECTED_PLAYLIST_ID: String? = null - // history of played videos in the current lifecycle val playingQueue = mutableListOf() } diff --git a/app/src/main/java/com/github/libretube/MyApp.kt b/app/src/main/java/com/github/libretube/MyApp.kt index 353a9ecff..1fbacc843 100644 --- a/app/src/main/java/com/github/libretube/MyApp.kt +++ b/app/src/main/java/com/github/libretube/MyApp.kt @@ -9,14 +9,17 @@ import android.os.StrictMode import android.os.StrictMode.VmPolicy import androidx.preference.PreferenceManager import androidx.work.ExistingPeriodicWorkPolicy +import coil.ImageLoader import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.ObjectMapper +import com.github.libretube.api.CronetHelper import com.github.libretube.api.RetrofitInstance import com.github.libretube.db.DatabaseHolder import com.github.libretube.db.obj.WatchHistoryItem import com.github.libretube.db.obj.WatchPosition import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys +import com.github.libretube.util.ConnectionHelper import com.github.libretube.util.ExceptionHandler import com.github.libretube.util.NotificationHelper @@ -30,7 +33,7 @@ class MyApp : Application() { initializeNotificationChannels() /** - * Set the applicationContext as context for the [PreferenceHelper] + * Initialize the [PreferenceHelper] */ PreferenceHelper.setContext(applicationContext) @@ -40,7 +43,7 @@ class MyApp : Application() { DatabaseHolder.initializeDatabase(this) /** - * bypassing fileUriExposedException, see https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed + * Bypassing fileUriExposedException, see https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed */ val builder = VmPolicy.Builder() StrictMode.setVmPolicy(builder.build()) @@ -48,7 +51,7 @@ class MyApp : Application() { /** * Set the api and the auth api url */ - setRetrofitApiUrls() + initializeRetrofit() /** * Initialize the notification listener in the background @@ -76,7 +79,7 @@ class MyApp : Application() { /** * Set the api urls needed for the [RetrofitInstance] */ - private fun setRetrofitApiUrls() { + private fun initializeRetrofit() { RetrofitInstance.url = PreferenceHelper.getString(PreferenceKeys.FETCH_INSTANCE, PIPED_API_URL) // set auth instance @@ -89,6 +92,10 @@ class MyApp : Application() { } else { RetrofitInstance.url } + CronetHelper.initCronet(this) + ConnectionHelper.imageLoader = ImageLoader.Builder(this) + .callFactory(CronetHelper.callFactory) + .build() } /** diff --git a/app/src/main/java/com/github/libretube/activities/MainActivity.kt b/app/src/main/java/com/github/libretube/activities/MainActivity.kt index 1672b42c3..2c8826c7a 100644 --- a/app/src/main/java/com/github/libretube/activities/MainActivity.kt +++ b/app/src/main/java/com/github/libretube/activities/MainActivity.kt @@ -25,15 +25,13 @@ import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.navigation.ui.setupWithNavController -import coil.ImageLoader -import com.github.libretube.Globals import com.github.libretube.R -import com.github.libretube.api.CronetHelper import com.github.libretube.databinding.ActivityMainBinding import com.github.libretube.dialogs.ErrorDialog import com.github.libretube.extensions.BaseActivity import com.github.libretube.extensions.TAG import com.github.libretube.fragments.PlayerFragment +import com.github.libretube.models.PlayerViewModel import com.github.libretube.models.SearchViewModel import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys @@ -74,17 +72,6 @@ class MainActivity : BaseActivity() { e.printStackTrace() } - CronetHelper.initCronet(this.applicationContext) - ConnectionHelper.imageLoader = ImageLoader.Builder(this.applicationContext) - .callFactory(CronetHelper.callFactory) - .build() - - // save whether the data saver mode is enabled - Globals.DATA_SAVER_MODE_ENABLED = PreferenceHelper.getBoolean( - PreferenceKeys.DATA_SAVER_MODE, - false - ) - // show noInternet Activity if no internet available on app startup if (!ConnectionHelper.isNetworkAvailable(this)) { val noInternetIntent = Intent(this, NoInternetActivity::class.java) @@ -456,7 +443,8 @@ class MainActivity : BaseActivity() { enableTransition(R.id.yt_transition, true) } findViewById(R.id.linLayout).visibility = View.VISIBLE - Globals.IS_FULL_SCREEN = false + val playerViewModel = ViewModelProvider(this)[PlayerViewModel::class.java] + playerViewModel.isFullscreen.value = false requestedOrientation = if (autoRotationEnabled) ActivityInfo.SCREEN_ORIENTATION_USER else ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT } diff --git a/app/src/main/java/com/github/libretube/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/com/github/libretube/dialogs/AddToPlaylistDialog.kt index 671a07ad9..6d840997e 100644 --- a/app/src/main/java/com/github/libretube/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/dialogs/AddToPlaylistDialog.kt @@ -7,12 +7,13 @@ import android.widget.ArrayAdapter import android.widget.Toast import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope -import com.github.libretube.Globals import com.github.libretube.R import com.github.libretube.api.RetrofitInstance import com.github.libretube.databinding.DialogAddtoplaylistBinding import com.github.libretube.extensions.TAG +import com.github.libretube.models.PlaylistViewModel import com.github.libretube.obj.PlaylistId import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.util.ThemeHelper @@ -22,6 +23,7 @@ import java.io.IOException class AddToPlaylistDialog : DialogFragment() { private lateinit var binding: DialogAddtoplaylistBinding + private val viewModel: PlaylistViewModel by activityViewModels() private lateinit var videoId: String private lateinit var token: String @@ -67,17 +69,17 @@ class AddToPlaylistDialog : DialogFragment() { android.R.layout.simple_spinner_dropdown_item ) binding.playlistsSpinner.adapter = arrayAdapter - if (Globals.SELECTED_PLAYLIST_ID != null) { + if (viewModel.lastSelectedPlaylistId != null) { var selectionIndex = 0 response.forEachIndexed { index, playlist -> - if (playlist.id == Globals.SELECTED_PLAYLIST_ID) selectionIndex = index + if (playlist.id == viewModel.lastSelectedPlaylistId) selectionIndex = index } binding.playlistsSpinner.setSelection(selectionIndex) } runOnUiThread { binding.addToPlaylist.setOnClickListener { val index = binding.playlistsSpinner.selectedItemPosition - Globals.SELECTED_PLAYLIST_ID = response[index].id!! + viewModel.lastSelectedPlaylistId = response[index].id!! addToPlaylist( response[index].id!! ) diff --git a/app/src/main/java/com/github/libretube/fragments/LibraryFragment.kt b/app/src/main/java/com/github/libretube/fragments/LibraryFragment.kt index a876c6333..8df79aa2f 100644 --- a/app/src/main/java/com/github/libretube/fragments/LibraryFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/LibraryFragment.kt @@ -6,11 +6,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.github.libretube.Globals import com.github.libretube.R import com.github.libretube.adapters.PlaylistsAdapter import com.github.libretube.api.RetrofitInstance @@ -18,6 +18,7 @@ import com.github.libretube.databinding.FragmentLibraryBinding import com.github.libretube.dialogs.CreatePlaylistDialog import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.TAG +import com.github.libretube.models.PlayerViewModel import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys import retrofit2.HttpException @@ -27,6 +28,7 @@ class LibraryFragment : BaseFragment() { lateinit var token: String private lateinit var binding: FragmentLibraryBinding + val playerViewModel: PlayerViewModel by activityViewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -45,6 +47,12 @@ class LibraryFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + // listen for the mini player state changing + playerViewModel.isMiniPlayerVisible.observe(viewLifecycleOwner) { + updateFABMargin() + } + binding.playlistRecView.layoutManager = LinearLayoutManager(requireContext()) token = PreferenceHelper.getToken() @@ -76,12 +84,12 @@ class LibraryFragment : BaseFragment() { } } - override fun onResume() { + fun updateFABMargin() { // optimize CreatePlaylistFab bottom margin if miniPlayer active + val bottomMargin = if (playerViewModel.isMiniPlayerVisible.value == true) 180 else 64 val layoutParams = binding.createPlaylist.layoutParams as ViewGroup.MarginLayoutParams - layoutParams.bottomMargin = if (Globals.MINI_PLAYER_VISIBLE) 180 else 64 + layoutParams.bottomMargin = bottomMargin binding.createPlaylist.layoutParams = layoutParams - super.onResume() } fun fetchPlaylists() { diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index cfc4c1474..95fdbb90b 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -28,6 +28,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.net.toUri import androidx.core.os.bundleOf import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager @@ -54,6 +55,7 @@ import com.github.libretube.extensions.TAG import com.github.libretube.extensions.await import com.github.libretube.interfaces.DoubleTapInterface import com.github.libretube.interfaces.PlayerOptionsInterface +import com.github.libretube.models.PlayerViewModel import com.github.libretube.obj.ChapterSegment import com.github.libretube.obj.Segment import com.github.libretube.obj.Segments @@ -107,6 +109,7 @@ class PlayerFragment : BaseFragment() { private lateinit var binding: FragmentPlayerBinding private lateinit var playerBinding: ExoStyledPlayerControlViewBinding private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding + private val viewModel: PlayerViewModel by activityViewModels() /** * video information @@ -378,11 +381,11 @@ class PlayerFragment : BaseFragment() { val mainMotionLayout = mainActivity.binding.mainMotionLayout if (currentId == eId) { - Globals.MINI_PLAYER_VISIBLE = true + viewModel.isMiniPlayerVisible.value = true exoPlayerView.useController = false mainMotionLayout.progress = 1F } else if (currentId == sId) { - Globals.MINI_PLAYER_VISIBLE = false + viewModel.isMiniPlayerVisible.value = false exoPlayerView.useController = true mainMotionLayout.progress = 0F } @@ -561,7 +564,7 @@ class PlayerFragment : BaseFragment() { // actions that don't depend on video information private fun initializeOnClickActions(context: Context) { binding.closeImageView.setOnClickListener { - Globals.MINI_PLAYER_VISIBLE = false + viewModel.isMiniPlayerVisible.value = false binding.playerMotionLayout.transitionToEnd() val mainActivity = activity as MainActivity mainActivity.supportFragmentManager.beginTransaction() @@ -569,7 +572,7 @@ class PlayerFragment : BaseFragment() { .commit() } playerBinding.closeImageButton.setOnClickListener { - Globals.MINI_PLAYER_VISIBLE = false + viewModel.isFullscreen.value = false binding.playerMotionLayout.transitionToEnd() val mainActivity = activity as MainActivity mainActivity.supportFragmentManager.beginTransaction() @@ -644,7 +647,7 @@ class PlayerFragment : BaseFragment() { playerBinding.fullscreen.setOnClickListener { // hide player controller exoPlayerView.hideController() - if (!Globals.IS_FULL_SCREEN) { + if (viewModel.isFullscreen.value == false) { // go to fullscreen mode setFullscreen() } else { @@ -737,7 +740,7 @@ class PlayerFragment : BaseFragment() { mainActivity.requestedOrientation = orientation } - Globals.IS_FULL_SCREEN = true + viewModel.isFullscreen.value = true } private fun unsetFullscreen() { @@ -758,7 +761,7 @@ class PlayerFragment : BaseFragment() { mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT } - Globals.IS_FULL_SCREEN = false + viewModel.isFullscreen.value = false } private fun toggleDescription() { @@ -1301,7 +1304,7 @@ class PlayerFragment : BaseFragment() { } playerBinding.chapterLL.visibility = View.VISIBLE playerBinding.chapterLL.setOnClickListener { - if (Globals.IS_FULL_SCREEN) { + if (viewModel.isFullscreen.value!!) { MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.chapters) .setItems(titles.toTypedArray()) { _, index -> @@ -1527,7 +1530,7 @@ class PlayerFragment : BaseFragment() { playerBinding.closeImageButton.visibility = visibility playerBinding.exoTitle.visibility = if (isLocked && - Globals.IS_FULL_SCREEN + viewModel.isFullscreen.value == true ) View.VISIBLE else View.INVISIBLE // disable double tap to seek when the player is locked @@ -1627,7 +1630,7 @@ class PlayerFragment : BaseFragment() { } binding.linLayout.visibility = View.GONE - Globals.IS_FULL_SCREEN = false + viewModel.isFullscreen.value = false } else { // enable exoPlayer controls again exoPlayerView.useController = true @@ -1654,8 +1657,10 @@ class PlayerFragment : BaseFragment() { val backgroundModeRunning = isServiceRunning(requireContext(), BackgroundMode::class.java) - return (binding.playerScrollView.getLocalVisibleRect(bounds) || Globals.IS_FULL_SCREEN) && - (exoPlayer.isPlaying || !backgroundModeRunning) + return ( + binding.playerScrollView.getLocalVisibleRect(bounds) || + viewModel.isFullscreen.value == true + ) && (exoPlayer.isPlaying || !backgroundModeRunning) } private fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean { diff --git a/app/src/main/java/com/github/libretube/models/PlayerViewModel.kt b/app/src/main/java/com/github/libretube/models/PlayerViewModel.kt new file mode 100644 index 000000000..14e707513 --- /dev/null +++ b/app/src/main/java/com/github/libretube/models/PlayerViewModel.kt @@ -0,0 +1,13 @@ +package com.github.libretube.models + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class PlayerViewModel : ViewModel() { + val isMiniPlayerVisible = MutableLiveData().apply { + value = false + } + val isFullscreen = MutableLiveData().apply { + value = false + } +} diff --git a/app/src/main/java/com/github/libretube/models/PlaylistViewModel.kt b/app/src/main/java/com/github/libretube/models/PlaylistViewModel.kt new file mode 100644 index 000000000..633286d42 --- /dev/null +++ b/app/src/main/java/com/github/libretube/models/PlaylistViewModel.kt @@ -0,0 +1,7 @@ +package com.github.libretube.models + +import androidx.lifecycle.ViewModel + +class PlaylistViewModel : ViewModel() { + var lastSelectedPlaylistId: String? = null +} diff --git a/app/src/main/java/com/github/libretube/models/SearchViewModel.kt b/app/src/main/java/com/github/libretube/models/SearchViewModel.kt index 6a6690eb8..c8c46b0ff 100644 --- a/app/src/main/java/com/github/libretube/models/SearchViewModel.kt +++ b/app/src/main/java/com/github/libretube/models/SearchViewModel.kt @@ -4,8 +4,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class SearchViewModel : ViewModel() { - var searchQuery = MutableLiveData() - + val searchQuery = MutableLiveData() fun setQuery(query: String?) { this.searchQuery.value = query } diff --git a/app/src/main/java/com/github/libretube/util/ConnectionHelper.kt b/app/src/main/java/com/github/libretube/util/ConnectionHelper.kt index 6f1e93bb3..f4d15d6f5 100644 --- a/app/src/main/java/com/github/libretube/util/ConnectionHelper.kt +++ b/app/src/main/java/com/github/libretube/util/ConnectionHelper.kt @@ -5,9 +5,12 @@ import android.net.ConnectivityManager import android.widget.ImageView import coil.ImageLoader import coil.load -import com.github.libretube.Globals +import com.github.libretube.preferences.PreferenceHelper +import com.github.libretube.preferences.PreferenceKeys object ConnectionHelper { + lateinit var imageLoader: ImageLoader + fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager @@ -38,13 +41,13 @@ object ConnectionHelper { return connectivityManager.activeNetworkInfo?.isConnected ?: false } - lateinit var imageLoader: ImageLoader - // load an image from a url into an imageView fun loadImage(url: String?, target: ImageView) { // only load the image if the data saver mode is disabled - if (!Globals.DATA_SAVER_MODE_ENABLED) { - target.load(url, imageLoader) - } + val dataSaverModeEnabled = PreferenceHelper.getBoolean( + PreferenceKeys.DATA_SAVER_MODE, + false + ) + if (!dataSaverModeEnabled) target.load(url, imageLoader) } }