diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt index b422068c4..26a954c3b 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/AddToPlaylistDialog.kt @@ -18,8 +18,6 @@ import com.github.libretube.extensions.toastFromMainThread import com.github.libretube.ui.models.PlaylistViewModel import com.github.libretube.util.PlayingQueue import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch /** @@ -76,34 +74,35 @@ class AddToPlaylistDialog( binding.addToPlaylist.setOnClickListener { val index = binding.playlistsSpinner.selectedItemPosition viewModel.lastSelectedPlaylistId = response[index].id!! - addToPlaylist(response[index].id!!) - dialog?.dismiss() + dialog?.hide() + lifecycleScope.launch { + addToPlaylist(response[index].id!!) + dialog?.dismiss() + } } } } } - private fun addToPlaylist(playlistId: String) { + private suspend fun addToPlaylist(playlistId: String) { val appContext = context?.applicationContext ?: return - CoroutineScope(Dispatchers.IO).launch { - val streams = when { - videoId != null -> listOf( - RetrofitInstance.api.getStreams(videoId).toStreamItem(videoId) - ) - else -> PlayingQueue.getStreams() - } - - val success = try { - PlaylistsHelper.addToPlaylist(playlistId, *streams.toTypedArray()) - } catch (e: Exception) { - Log.e(TAG(), e.toString()) - appContext.toastFromMainThread(R.string.unknown_error) - return@launch - } - appContext.toastFromMainThread( - if (success) R.string.added_to_playlist else R.string.fail + val streams = when { + videoId != null -> listOf( + RetrofitInstance.api.getStreams(videoId).toStreamItem(videoId) ) + else -> PlayingQueue.getStreams() } + + val success = try { + PlaylistsHelper.addToPlaylist(playlistId, *streams.toTypedArray()) + } catch (e: Exception) { + Log.e(TAG(), e.toString()) + appContext.toastFromMainThread(R.string.unknown_error) + return + } + appContext.toastFromMainThread( + if (success) R.string.added_to_playlist else R.string.fail + ) } private fun Fragment?.runOnUiThread(action: () -> Unit) { diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt index 0f8000fc1..eb76d7f8a 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt @@ -4,12 +4,12 @@ import android.app.Dialog import android.os.Bundle import android.widget.Toast import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope import com.github.libretube.R import com.github.libretube.api.PlaylistsHelper import com.github.libretube.databinding.DialogCreatePlaylistBinding import com.github.libretube.extensions.toastFromMainThread import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -28,17 +28,19 @@ class CreatePlaylistDialog( val appContext = context?.applicationContext playlistUrl?.queryParameter("list")?.let { - CoroutineScope(Dispatchers.IO).launch { - val playlistId = PlaylistsHelper.clonePlaylist(requireContext(), it)?.also { - withContext(Dispatchers.Main) { - onSuccess.invoke() - } + lifecycleScope.launch { + requireDialog().hide() + val playlistId = withContext(Dispatchers.IO) { + PlaylistsHelper.clonePlaylist(requireContext(), it) + } + if (playlistId != null) { + onSuccess() } appContext?.toastFromMainThread( if (playlistId != null) R.string.playlistCloned else R.string.server_error ) + dismiss() } - dismiss() } ?: run { Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show() } @@ -53,16 +55,16 @@ class CreatePlaylistDialog( binding.createNewPlaylist.setOnClickListener(null) val listName = binding.playlistName.text.toString() if (listName != "") { - CoroutineScope(Dispatchers.IO).launch { - val playlistId = PlaylistsHelper.createPlaylist( - listName, - requireContext().applicationContext - ) - withContext(Dispatchers.Main) { - if (playlistId != null) onSuccess.invoke() + lifecycleScope.launch { + requireDialog().hide() + val playlistId = withContext(Dispatchers.IO) { + PlaylistsHelper.createPlaylist(listName, requireContext()) } + if (playlistId != null) { + onSuccess() + } + dismiss() } - dismiss() } else { Toast.makeText(context, R.string.emptyPlaylistName, Toast.LENGTH_LONG).show() } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/RenamePlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/RenamePlaylistDialog.kt index 15ba841d5..e3125104b 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/RenamePlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/RenamePlaylistDialog.kt @@ -1,20 +1,22 @@ package com.github.libretube.ui.dialogs import android.app.Dialog +import android.content.DialogInterface import android.os.Bundle import android.text.InputType import android.util.Log import android.widget.Toast import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope import com.github.libretube.R import com.github.libretube.api.PlaylistsHelper import com.github.libretube.databinding.DialogTextPreferenceBinding import com.github.libretube.extensions.TAG import com.github.libretube.extensions.toastFromMainThread import com.google.android.material.dialog.MaterialAlertDialogBuilder -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class RenamePlaylistDialog( private val playlistId: String, @@ -29,34 +31,42 @@ class RenamePlaylistDialog( return MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.renamePlaylist) .setView(binding.root) - .setPositiveButton(R.string.okay) { _, _ -> - val input = binding.input.text.toString() - if (input == "") { - Toast.makeText( - context, - R.string.emptyPlaylistName, - Toast.LENGTH_SHORT - ).show() - return@setPositiveButton - } - if (input == currentPlaylistName) return@setPositiveButton - val appContext = requireContext().applicationContext - CoroutineScope(Dispatchers.IO).launch { - val success = try { - PlaylistsHelper.renamePlaylist(playlistId, binding.input.text.toString()) - } catch (e: Exception) { - Log.e(TAG(), e.toString()) - e.localizedMessage?.let { appContext.toastFromMainThread(it) } - return@launch + .setPositiveButton(R.string.okay, null) + .setNegativeButton(R.string.cancel, null) + .show() + .apply { + getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener { + val input = binding.input.text.toString() + if (input == "") { + Toast.makeText( + context, + R.string.emptyPlaylistName, + Toast.LENGTH_SHORT + ).show() + return@setOnClickListener } - if (success) { - appContext.toastFromMainThread(R.string.success) - } else { - appContext.toastFromMainThread(R.string.server_error) + if (input == currentPlaylistName) return@setOnClickListener + val appContext = requireContext().applicationContext + + lifecycleScope.launch { + requireDialog().hide() + val success = try { + withContext(Dispatchers.IO) { + PlaylistsHelper.renamePlaylist(playlistId, input) + } + } catch (e: Exception) { + Log.e(TAG(), e.toString()) + e.localizedMessage?.let { appContext.toastFromMainThread(it) } + return@launch + } + if (success) { + appContext.toastFromMainThread(R.string.success) + } else { + appContext.toastFromMainThread(R.string.server_error) + } + dismiss() } } } - .setNegativeButton(R.string.cancel, null) - .show() } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt index 343163f27..328146d1d 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.github.libretube.api.JsonHelper import com.github.libretube.api.RetrofitInstance @@ -19,7 +20,6 @@ import com.github.libretube.extensions.TAG import com.github.libretube.ui.adapters.CommentsAdapter import com.github.libretube.ui.extensions.filterNonEmptyComments import com.github.libretube.ui.models.CommentsViewModel -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -89,7 +89,7 @@ class CommentsRepliesFragment : Fragment() { nextPage: String, onFinished: (CommentsPage) -> Unit ) { - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope.launch(Dispatchers.IO) { if (isLoading) return@launch isLoading = true repliesPage = try { 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 06c7657db..787e352b0 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 @@ -109,7 +109,6 @@ import java.io.IOException import java.util.* import java.util.concurrent.Executors import kotlin.math.abs -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -656,7 +655,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions { } if (PlayingQueue.isEmpty()) { - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope.launch(Dispatchers.IO) { if (playlistId != null) { PlayingQueue.insertPlaylist(playlistId!!, streams.toStreamItem(videoId!!)) } else if (channelId != null) { @@ -721,7 +720,7 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions { * fetch the segments for SponsorBlock */ private fun fetchSponsorBlockSegments() { - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope.launch(Dispatchers.IO) { runCatching { val categories = PlayerHelper.getSponsorBlockCategories() if (categories.isEmpty()) return@runCatching diff --git a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt index 33d6c2fb1..becb96b71 100644 --- a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt +++ b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt @@ -3,16 +3,15 @@ package com.github.libretube.ui.models import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.CommentsPage import com.github.libretube.extensions.TAG import com.github.libretube.ui.extensions.filterNonEmptyComments -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class CommentsViewModel : ViewModel() { - private val scope = CoroutineScope(Dispatchers.IO) private var isLoading = false val commentsPage = MutableLiveData() @@ -25,7 +24,7 @@ class CommentsViewModel : ViewModel() { fun fetchComments() { videoId ?: return - scope.launch { + viewModelScope.launch(Dispatchers.IO) { isLoading = true val response = try { RetrofitInstance.api.getComments(videoId!!) @@ -42,7 +41,7 @@ class CommentsViewModel : ViewModel() { fun fetchNextComments() { if (isLoading || nextPage == null || videoId == null) return - scope.launch { + viewModelScope.launch(Dispatchers.IO) { isLoading = true val response = try { RetrofitInstance.api.getCommentsNextPage(videoId!!, nextPage!!) diff --git a/app/src/main/java/com/github/libretube/ui/preferences/MainSettings.kt b/app/src/main/java/com/github/libretube/ui/preferences/MainSettings.kt index 4641fe33e..46f329822 100644 --- a/app/src/main/java/com/github/libretube/ui/preferences/MainSettings.kt +++ b/app/src/main/java/com/github/libretube/ui/preferences/MainSettings.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.annotation.StringRes import androidx.fragment.app.Fragment import androidx.fragment.app.commitNow +import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import com.github.libretube.BuildConfig import com.github.libretube.R @@ -12,9 +13,9 @@ import com.github.libretube.ui.activities.SettingsActivity import com.github.libretube.ui.base.BasePreferenceFragment import com.github.libretube.ui.dialogs.UpdateAvailableDialog import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class MainSettings : BasePreferenceFragment() { override val titleResourceId: Int = R.string.settings @@ -84,10 +85,12 @@ class MainSettings : BasePreferenceFragment() { // checking for update: yes -> dialog, no -> snackBar update?.setOnPreferenceClickListener { - CoroutineScope(Dispatchers.IO).launch { + lifecycleScope.launch { // check for update val updateInfo = try { - RetrofitInstance.externalApi.getUpdateInfo() + withContext(Dispatchers.IO) { + RetrofitInstance.externalApi.getUpdateInfo() + } } catch (e: Exception) { showSnackBar(R.string.unknown_error) return@launch diff --git a/app/src/main/java/com/github/libretube/ui/sheets/BaseBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/BaseBottomSheet.kt index 162e80719..140adc68d 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/BaseBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/BaseBottomSheet.kt @@ -4,10 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.github.libretube.databinding.BottomSheetBinding import com.github.libretube.obj.BottomSheetItem import com.github.libretube.ui.adapters.BottomSheetAdapter +import kotlinx.coroutines.launch open class BaseBottomSheet : ExpandedBottomSheet() { private lateinit var items: List @@ -30,19 +32,17 @@ open class BaseBottomSheet : ExpandedBottomSheet() { binding.optionsRecycler.adapter = BottomSheetAdapter(items, listener) } - fun setItems(items: List, listener: ((index: Int) -> Unit)?) = apply { + fun setItems(items: List, listener: (suspend (index: Int) -> Unit)?) = apply { this.items = items this.listener = { index -> - listener?.invoke(index) - dialog?.dismiss() + lifecycleScope.launch { + dialog?.hide() + listener?.invoke(index) + dismiss() + } } } - fun setSimpleItems(titles: List, listener: ((index: Int) -> Unit)?) = apply { - this.items = titles.map { BottomSheetItem(it) } - this.listener = { index -> - listener?.invoke(index) - dialog?.dismiss() - } - } + fun setSimpleItems(titles: List, listener: (suspend (index: Int) -> Unit)?) = + setItems(titles.map { BottomSheetItem(it) }, listener) } diff --git a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt index eaf86e581..073ca23d5 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt @@ -11,7 +11,8 @@ import com.github.libretube.helpers.BackgroundHelper import com.github.libretube.helpers.NavigationHelper import com.github.libretube.obj.ShareData import com.github.libretube.ui.dialogs.ShareDialog -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext /** * Dialog with different options for a selected video. @@ -41,7 +42,7 @@ class ChannelOptionsBottomSheet( } getString(R.string.play_latest_videos) -> { try { - val channel = runBlocking { + val channel = withContext(Dispatchers.IO) { RetrofitInstance.api.getChannel(channelId) } channel.relatedStreams.firstOrNull()?.url?.toID()?.let { @@ -57,7 +58,7 @@ class ChannelOptionsBottomSheet( } getString(R.string.playOnBackground) -> { try { - val channel = runBlocking { + val channel = withContext(Dispatchers.IO) { RetrofitInstance.api.getChannel(channelId) } channel.relatedStreams.firstOrNull()?.url?.toID()?.let { diff --git a/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt index 61c512a6e..94468f543 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/PlaylistOptionsBottomSheet.kt @@ -8,7 +8,6 @@ import com.github.libretube.db.DatabaseHolder import com.github.libretube.enums.PlaylistType import com.github.libretube.enums.ShareObjectType import com.github.libretube.extensions.awaitQuery -import com.github.libretube.extensions.query import com.github.libretube.extensions.toID import com.github.libretube.extensions.toastFromMainThread import com.github.libretube.helpers.BackgroundHelper @@ -16,10 +15,8 @@ import com.github.libretube.obj.ShareData import com.github.libretube.ui.dialogs.DeletePlaylistDialog import com.github.libretube.ui.dialogs.RenamePlaylistDialog import com.github.libretube.ui.dialogs.ShareDialog -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext class PlaylistOptionsBottomSheet( private val playlistId: String, @@ -55,28 +52,26 @@ class PlaylistOptionsBottomSheet( when (optionsList[which]) { // play the playlist in the background getString(R.string.playOnBackground) -> { - runBlocking { - val playlist = PlaylistsHelper.getPlaylist(playlistId) - if (playlist.relatedStreams.isEmpty()) return@runBlocking + val playlist = withContext(Dispatchers.IO) { + PlaylistsHelper.getPlaylist(playlistId) + } + playlist.relatedStreams.firstOrNull()?.let { BackgroundHelper.playOnBackground( - context = requireContext(), - videoId = playlist.relatedStreams[0].url!!.toID(), + requireContext(), + it.url!!.toID(), playlistId = playlistId ) } } // Clone the playlist to the users Piped account getString(R.string.clonePlaylist) -> { - val appContext = context?.applicationContext - CoroutineScope(Dispatchers.IO).launch { - val playlistId = PlaylistsHelper.clonePlaylist( - requireContext().applicationContext, - playlistId - ) - appContext?.toastFromMainThread( - if (playlistId != null) R.string.playlistCloned else R.string.server_error - ) + val context = requireContext() + val playlistId = withContext(Dispatchers.IO) { + PlaylistsHelper.clonePlaylist(context, playlistId) } + context.toastFromMainThread( + if (playlistId != null) R.string.playlistCloned else R.string.server_error + ) } // share the playlist getString(R.string.share) -> { @@ -87,7 +82,7 @@ class PlaylistOptionsBottomSheet( getString(R.string.deletePlaylist) -> { DeletePlaylistDialog(playlistId, playlistType) { // try to refresh the playlists in the library on deletion success - onDelete.invoke() + onDelete() }.show(parentFragmentManager, null) } getString(R.string.renamePlaylist) -> { @@ -95,22 +90,18 @@ class PlaylistOptionsBottomSheet( .show(parentFragmentManager, null) } else -> { - CoroutineScope(Dispatchers.IO).launch { + withContext(Dispatchers.IO) { if (isBookmarked) { - query { - DatabaseHolder.Database.playlistBookmarkDao() - .deleteById(playlistId) - } + DatabaseHolder.Database.playlistBookmarkDao().deleteById(playlistId) } else { val bookmark = try { RetrofitInstance.api.getPlaylist(playlistId) } catch (e: Exception) { - return@launch + return@withContext }.toPlaylistBookmark(playlistId) DatabaseHolder.Database.playlistBookmarkDao().insertAll(bookmark) } } - dismiss() } } } diff --git a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt index 96b46cfa5..086e132ea 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/VideoOptionsBottomSheet.kt @@ -18,9 +18,8 @@ import com.github.libretube.ui.dialogs.DownloadDialog import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.fragments.SubscriptionsFragment import com.github.libretube.util.PlayingQueue -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * Dialog with different options for a selected video. @@ -75,27 +74,23 @@ class VideoOptionsBottomSheet( shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) } getString(R.string.play_next) -> { - CoroutineScope(Dispatchers.IO).launch { - try { - PlayingQueue.addAsNext( - RetrofitInstance.api.getStreams(videoId) - .toStreamItem(videoId) - ) - } catch (e: Exception) { - e.printStackTrace() + try { + val streamItem = withContext(Dispatchers.IO) { + RetrofitInstance.api.getStreams(videoId).toStreamItem(videoId) } + PlayingQueue.addAsNext(streamItem) + } catch (e: Exception) { + e.printStackTrace() } } getString(R.string.add_to_queue) -> { - CoroutineScope(Dispatchers.IO).launch { - try { - PlayingQueue.add( - RetrofitInstance.api.getStreams(videoId) - .toStreamItem(videoId) - ) - } catch (e: Exception) { - e.printStackTrace() + try { + val streamItem = withContext(Dispatchers.IO) { + RetrofitInstance.api.getStreams(videoId).toStreamItem(videoId) } + PlayingQueue.add(streamItem) + } catch (e: Exception) { + e.printStackTrace() } } getString(R.string.mark_as_watched) -> {