Merge pull request #3124 from Isira-Seneviratne/Scope_extensions

Use lifecycle coroutine scope extensions.
This commit is contained in:
Bnyro 2023-02-22 10:25:47 +01:00 committed by GitHub
commit a2ce37c8d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 131 additions and 132 deletions

View File

@ -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) {

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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<CommentsPage?>()
@ -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!!)

View File

@ -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

View File

@ -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<BottomSheetItem>
@ -30,19 +32,17 @@ open class BaseBottomSheet : ExpandedBottomSheet() {
binding.optionsRecycler.adapter = BottomSheetAdapter(items, listener)
}
fun setItems(items: List<BottomSheetItem>, listener: ((index: Int) -> Unit)?) = apply {
fun setItems(items: List<BottomSheetItem>, 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<String>, listener: ((index: Int) -> Unit)?) = apply {
this.items = titles.map { BottomSheetItem(it) }
this.listener = { index ->
listener?.invoke(index)
dialog?.dismiss()
}
}
fun setSimpleItems(titles: List<String>, listener: (suspend (index: Int) -> Unit)?) =
setItems(titles.map { BottomSheetItem(it) }, listener)
}

View File

@ -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 {

View File

@ -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()
}
}
}

View File

@ -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) -> {