mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-13 22:00:30 +05:30
Merge pull request #5127 from Bnyro/master
refactor: remove unnecessary repeatOnLifecycle calls
This commit is contained in:
commit
2afdb1f359
@ -10,9 +10,7 @@ import android.widget.ArrayAdapter
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
import com.github.libretube.api.obj.PipedStream
|
import com.github.libretube.api.obj.PipedStream
|
||||||
@ -27,11 +25,11 @@ import com.github.libretube.helpers.PreferenceHelper
|
|||||||
import com.github.libretube.parcelable.DownloadData
|
import com.github.libretube.parcelable.DownloadData
|
||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import java.io.IOException
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class DownloadDialog : DialogFragment() {
|
class DownloadDialog : DialogFragment() {
|
||||||
private lateinit var videoId: String
|
private lateinit var videoId: String
|
||||||
@ -80,23 +78,21 @@ class DownloadDialog : DialogFragment() {
|
|||||||
|
|
||||||
private fun fetchAvailableSources(binding: DialogDownloadBinding) {
|
private fun fetchAvailableSources(binding: DialogDownloadBinding) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
RetrofitInstance.api.getStreams(videoId)
|
||||||
RetrofitInstance.api.getStreams(videoId)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
println(e)
|
|
||||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
|
||||||
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
} catch (e: HttpException) {
|
|
||||||
Log.e(TAG(), "HttpException, unexpected response")
|
|
||||||
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
}
|
||||||
initDownloadOptions(binding, response)
|
} catch (e: IOException) {
|
||||||
|
println(e)
|
||||||
|
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||||
|
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
||||||
|
return@launch
|
||||||
|
} catch (e: HttpException) {
|
||||||
|
Log.e(TAG(), "HttpException, unexpected response")
|
||||||
|
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
|
||||||
|
return@launch
|
||||||
}
|
}
|
||||||
|
initDownloadOptions(binding, response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,7 @@ import androidx.core.view.children
|
|||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
@ -34,11 +32,11 @@ import com.github.libretube.ui.adapters.VideosAdapter
|
|||||||
import com.github.libretube.ui.dialogs.ShareDialog
|
import com.github.libretube.ui.dialogs.ShareDialog
|
||||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
import java.io.IOException
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class ChannelFragment : Fragment() {
|
class ChannelFragment : Fragment() {
|
||||||
private var _binding: FragmentChannelBinding? = null
|
private var _binding: FragmentChannelBinding? = null
|
||||||
@ -113,115 +111,113 @@ class ChannelFragment : Fragment() {
|
|||||||
|
|
||||||
private fun fetchChannel() {
|
private fun fetchChannel() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
if (channelId != null) {
|
||||||
if (channelId != null) {
|
RetrofitInstance.api.getChannel(channelId!!)
|
||||||
RetrofitInstance.api.getChannel(channelId!!)
|
} else {
|
||||||
} else {
|
RetrofitInstance.api.getChannelByName(channelName!!)
|
||||||
RetrofitInstance.api.getChannelByName(channelName!!)
|
}.apply {
|
||||||
}.apply {
|
relatedStreams = relatedStreams.deArrow()
|
||||||
relatedStreams = relatedStreams.deArrow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
_binding?.channelRefresh?.isRefreshing = false
|
|
||||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
} catch (e: HttpException) {
|
|
||||||
_binding?.channelRefresh?.isRefreshing = false
|
|
||||||
Log.e(TAG(), "HttpException, unexpected response")
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
|
||||||
|
|
||||||
// needed if the channel gets loaded by the ID
|
|
||||||
channelId = response.id
|
|
||||||
channelName = response.name
|
|
||||||
val shareData = ShareData(currentChannel = response.name)
|
|
||||||
|
|
||||||
onScrollEnd = {
|
|
||||||
fetchChannelNextPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
val channelId = channelId ?: return@repeatOnLifecycle
|
|
||||||
// fetch and update the subscription status
|
|
||||||
isSubscribed = SubscriptionHelper.isSubscribed(channelId)
|
|
||||||
if (isSubscribed == null) return@repeatOnLifecycle
|
|
||||||
|
|
||||||
binding.channelSubscribe.setupSubscriptionButton(
|
|
||||||
channelId,
|
|
||||||
channelName,
|
|
||||||
binding.notificationBell
|
|
||||||
)
|
|
||||||
|
|
||||||
binding.channelShare.setOnClickListener {
|
|
||||||
val bundle = bundleOf(
|
|
||||||
IntentData.id to channelId.toID(),
|
|
||||||
IntentData.shareObjectType to ShareObjectType.CHANNEL,
|
|
||||||
IntentData.shareData to shareData
|
|
||||||
)
|
|
||||||
val newShareDialog = ShareDialog()
|
|
||||||
newShareDialog.arguments = bundle
|
|
||||||
newShareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage = response.nextpage
|
|
||||||
isLoading = false
|
|
||||||
binding.channelRefresh.isRefreshing = false
|
|
||||||
|
|
||||||
binding.channelScrollView.isVisible = true
|
|
||||||
binding.channelName.text = response.name
|
|
||||||
if (response.verified) {
|
|
||||||
binding.channelName.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
R.drawable.ic_verified,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
binding.channelSubs.text = resources.getString(
|
|
||||||
R.string.subscribers,
|
|
||||||
response.subscriberCount.formatShort()
|
|
||||||
)
|
|
||||||
if (response.description.orEmpty().isBlank()) {
|
|
||||||
binding.channelDescription.isGone = true
|
|
||||||
} else {
|
|
||||||
binding.channelDescription.text = response.description.orEmpty().trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.channelDescription.setOnClickListener {
|
|
||||||
(it as TextView).apply {
|
|
||||||
it.maxLines = if (it.maxLines == Int.MAX_VALUE) 2 else Int.MAX_VALUE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
ImageHelper.loadImage(response.bannerUrl, binding.channelBanner)
|
_binding?.channelRefresh?.isRefreshing = false
|
||||||
ImageHelper.loadImage(response.avatarUrl, binding.channelImage)
|
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||||
|
return@launch
|
||||||
binding.channelImage.setOnClickListener {
|
} catch (e: HttpException) {
|
||||||
NavigationHelper.openImagePreview(
|
_binding?.channelRefresh?.isRefreshing = false
|
||||||
requireContext(),
|
Log.e(TAG(), "HttpException, unexpected response")
|
||||||
response.avatarUrl ?: return@setOnClickListener
|
return@launch
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.channelBanner.setOnClickListener {
|
|
||||||
NavigationHelper.openImagePreview(
|
|
||||||
requireContext(),
|
|
||||||
response.bannerUrl ?: return@setOnClickListener
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// recyclerview of the videos by the channel
|
|
||||||
channelAdapter = VideosAdapter(
|
|
||||||
response.relatedStreams.toMutableList(),
|
|
||||||
forceMode = VideosAdapter.Companion.ForceMode.CHANNEL
|
|
||||||
)
|
|
||||||
binding.channelRecView.adapter = channelAdapter
|
|
||||||
|
|
||||||
setupTabs(response.tabs)
|
|
||||||
}
|
}
|
||||||
|
val binding = _binding ?: return@launch
|
||||||
|
|
||||||
|
// needed if the channel gets loaded by the ID
|
||||||
|
channelId = response.id
|
||||||
|
channelName = response.name
|
||||||
|
val shareData = ShareData(currentChannel = response.name)
|
||||||
|
|
||||||
|
onScrollEnd = {
|
||||||
|
fetchChannelNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
val channelId = channelId ?: return@launch
|
||||||
|
// fetch and update the subscription status
|
||||||
|
isSubscribed = SubscriptionHelper.isSubscribed(channelId)
|
||||||
|
if (isSubscribed == null) return@launch
|
||||||
|
|
||||||
|
binding.channelSubscribe.setupSubscriptionButton(
|
||||||
|
channelId,
|
||||||
|
channelName,
|
||||||
|
binding.notificationBell
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.channelShare.setOnClickListener {
|
||||||
|
val bundle = bundleOf(
|
||||||
|
IntentData.id to channelId.toID(),
|
||||||
|
IntentData.shareObjectType to ShareObjectType.CHANNEL,
|
||||||
|
IntentData.shareData to shareData
|
||||||
|
)
|
||||||
|
val newShareDialog = ShareDialog()
|
||||||
|
newShareDialog.arguments = bundle
|
||||||
|
newShareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPage = response.nextpage
|
||||||
|
isLoading = false
|
||||||
|
binding.channelRefresh.isRefreshing = false
|
||||||
|
|
||||||
|
binding.channelScrollView.isVisible = true
|
||||||
|
binding.channelName.text = response.name
|
||||||
|
if (response.verified) {
|
||||||
|
binding.channelName.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
R.drawable.ic_verified,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.channelSubs.text = resources.getString(
|
||||||
|
R.string.subscribers,
|
||||||
|
response.subscriberCount.formatShort()
|
||||||
|
)
|
||||||
|
if (response.description.orEmpty().isBlank()) {
|
||||||
|
binding.channelDescription.isGone = true
|
||||||
|
} else {
|
||||||
|
binding.channelDescription.text = response.description.orEmpty().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.channelDescription.setOnClickListener {
|
||||||
|
(it as TextView).apply {
|
||||||
|
it.maxLines = if (it.maxLines == Int.MAX_VALUE) 2 else Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageHelper.loadImage(response.bannerUrl, binding.channelBanner)
|
||||||
|
ImageHelper.loadImage(response.avatarUrl, binding.channelImage)
|
||||||
|
|
||||||
|
binding.channelImage.setOnClickListener {
|
||||||
|
NavigationHelper.openImagePreview(
|
||||||
|
requireContext(),
|
||||||
|
response.avatarUrl ?: return@setOnClickListener
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.channelBanner.setOnClickListener {
|
||||||
|
NavigationHelper.openImagePreview(
|
||||||
|
requireContext(),
|
||||||
|
response.bannerUrl ?: return@setOnClickListener
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// recyclerview of the videos by the channel
|
||||||
|
channelAdapter = VideosAdapter(
|
||||||
|
response.relatedStreams.toMutableList(),
|
||||||
|
forceMode = VideosAdapter.Companion.ForceMode.CHANNEL
|
||||||
|
)
|
||||||
|
binding.channelRecView.adapter = channelAdapter
|
||||||
|
|
||||||
|
setupTabs(response.tabs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,29 +288,27 @@ class ChannelFragment : Fragment() {
|
|||||||
binding.channelRefresh.isRefreshing = true
|
binding.channelRefresh.isRefreshing = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!).apply {
|
||||||
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!).apply {
|
relatedStreams = relatedStreams.deArrow()
|
||||||
relatedStreams = relatedStreams.deArrow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
|
||||||
_binding?.channelRefresh?.isRefreshing = false
|
|
||||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
} catch (e: HttpException) {
|
|
||||||
_binding?.channelRefresh?.isRefreshing = false
|
|
||||||
Log.e(TAG(), "HttpException, unexpected response," + e.response())
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
}
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
} catch (e: IOException) {
|
||||||
|
_binding?.channelRefresh?.isRefreshing = false
|
||||||
nextPage = response.nextpage
|
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||||
channelAdapter?.insertItems(response.relatedStreams)
|
return@launch
|
||||||
isLoading = false
|
} catch (e: HttpException) {
|
||||||
binding.channelRefresh.isRefreshing = false
|
_binding?.channelRefresh?.isRefreshing = false
|
||||||
|
Log.e(TAG(), "HttpException, unexpected response," + e.response())
|
||||||
|
return@launch
|
||||||
}
|
}
|
||||||
|
val binding = _binding ?: return@launch
|
||||||
|
|
||||||
|
nextPage = response.nextpage
|
||||||
|
channelAdapter?.insertItems(response.relatedStreams)
|
||||||
|
isLoading = false
|
||||||
|
binding.channelRefresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@ -122,146 +120,144 @@ class PlaylistFragment : Fragment() {
|
|||||||
private fun fetchPlaylist() {
|
private fun fetchPlaylist() {
|
||||||
binding.playlistScrollview.isGone = true
|
binding.playlistScrollview.isGone = true
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
PlaylistsHelper.getPlaylist(playlistId!!)
|
||||||
PlaylistsHelper.getPlaylist(playlistId!!)
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val binding = _binding ?: return@launch
|
||||||
|
|
||||||
|
playlistFeed = response.relatedStreams.toMutableList()
|
||||||
|
binding.playlistScrollview.isVisible = true
|
||||||
|
nextPage = response.nextpage
|
||||||
|
playlistName = response.name
|
||||||
|
isLoading = false
|
||||||
|
ImageHelper.loadImage(response.thumbnailUrl, binding.thumbnail)
|
||||||
|
binding.playlistProgress.isGone = true
|
||||||
|
binding.playlistName.text = response.name
|
||||||
|
|
||||||
|
binding.playlistName.setOnClickListener {
|
||||||
|
binding.playlistName.maxLines =
|
||||||
|
if (binding.playlistName.maxLines == 2) Int.MAX_VALUE else 2
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.playlistInfo.text = getChannelAndVideoString(response, response.videos)
|
||||||
|
binding.playlistInfo.setOnClickListener {
|
||||||
|
(context as MainActivity).navController.navigate(
|
||||||
|
R.id.channelFragment,
|
||||||
|
bundleOf(IntentData.channelId to response.uploaderUrl?.toID())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.playlistDescription.text = response.description
|
||||||
|
// hide playlist description text view if not provided
|
||||||
|
binding.playlistDescription.isGone = response.description.orEmpty().isBlank()
|
||||||
|
|
||||||
|
binding.playlistDescription.let { textView ->
|
||||||
|
textView.setOnClickListener {
|
||||||
|
textView.maxLines =
|
||||||
|
if (textView.maxLines == Int.MAX_VALUE) 3 else Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showPlaylistVideos(response)
|
||||||
|
|
||||||
|
// show playlist options
|
||||||
|
binding.optionsMenu.setOnClickListener {
|
||||||
|
val sheet = PlaylistOptionsBottomSheet()
|
||||||
|
sheet.arguments = bundleOf(
|
||||||
|
IntentData.playlistId to playlistId.orEmpty(),
|
||||||
|
IntentData.playlistName to playlistName.orEmpty(),
|
||||||
|
IntentData.playlistType to playlistType
|
||||||
|
)
|
||||||
|
|
||||||
|
val fragmentManager = (context as BaseActivity).supportFragmentManager
|
||||||
|
fragmentManager.setFragmentResultListener(
|
||||||
|
PlaylistOptionsBottomSheet.PLAYLIST_OPTIONS_REQUEST_KEY,
|
||||||
|
(context as BaseActivity)
|
||||||
|
) { _, resultBundle ->
|
||||||
|
val newPlaylistDescription =
|
||||||
|
resultBundle.getString(IntentData.playlistDescription)
|
||||||
|
val newPlaylistName =
|
||||||
|
resultBundle.getString(IntentData.playlistName)
|
||||||
|
val isPlaylistToBeDeleted =
|
||||||
|
resultBundle.getBoolean(IntentData.playlistTask)
|
||||||
|
|
||||||
|
newPlaylistDescription?.let {
|
||||||
|
binding.playlistDescription.text = it
|
||||||
|
response.description = it
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
|
||||||
|
|
||||||
playlistFeed = response.relatedStreams.toMutableList()
|
newPlaylistName?.let {
|
||||||
binding.playlistScrollview.isVisible = true
|
binding.playlistName.text = it
|
||||||
nextPage = response.nextpage
|
playlistName = it
|
||||||
playlistName = response.name
|
}
|
||||||
isLoading = false
|
|
||||||
ImageHelper.loadImage(response.thumbnailUrl, binding.thumbnail)
|
|
||||||
binding.playlistProgress.isGone = true
|
|
||||||
binding.playlistName.text = response.name
|
|
||||||
|
|
||||||
binding.playlistName.setOnClickListener {
|
if (isPlaylistToBeDeleted) {
|
||||||
binding.playlistName.maxLines =
|
// TODO move back: navController().popBackStack() crashes
|
||||||
if (binding.playlistName.maxLines == 2) Int.MAX_VALUE else 2
|
return@setFragmentResultListener
|
||||||
}
|
|
||||||
|
|
||||||
binding.playlistInfo.text = getChannelAndVideoString(response, response.videos)
|
|
||||||
binding.playlistInfo.setOnClickListener {
|
|
||||||
(context as MainActivity).navController.navigate(
|
|
||||||
R.id.channelFragment,
|
|
||||||
bundleOf(IntentData.channelId to response.uploaderUrl?.toID())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.playlistDescription.text = response.description
|
|
||||||
// hide playlist description text view if not provided
|
|
||||||
binding.playlistDescription.isGone = response.description.orEmpty().isBlank()
|
|
||||||
|
|
||||||
binding.playlistDescription.let { textView ->
|
|
||||||
textView.setOnClickListener {
|
|
||||||
textView.maxLines =
|
|
||||||
if (textView.maxLines == Int.MAX_VALUE) 3 else Int.MAX_VALUE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showPlaylistVideos(response)
|
sheet.show(fragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
// show playlist options
|
binding.playAll.setOnClickListener {
|
||||||
binding.optionsMenu.setOnClickListener {
|
if (playlistFeed.isEmpty()) return@setOnClickListener
|
||||||
val sheet = PlaylistOptionsBottomSheet()
|
NavigationHelper.navigateVideo(
|
||||||
sheet.arguments = bundleOf(
|
requireContext(),
|
||||||
IntentData.playlistId to playlistId.orEmpty(),
|
response.relatedStreams.first().url?.toID(),
|
||||||
IntentData.playlistName to playlistName.orEmpty(),
|
playlistId
|
||||||
IntentData.playlistType to playlistType
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
val fragmentManager = (context as BaseActivity).supportFragmentManager
|
if (playlistType == PlaylistType.PUBLIC) {
|
||||||
fragmentManager.setFragmentResultListener(
|
binding.bookmark.setOnClickListener {
|
||||||
PlaylistOptionsBottomSheet.PLAYLIST_OPTIONS_REQUEST_KEY,
|
isBookmarked = !isBookmarked
|
||||||
(context as BaseActivity)
|
updateBookmarkRes()
|
||||||
) { _, resultBundle ->
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val newPlaylistDescription =
|
if (!isBookmarked) {
|
||||||
resultBundle.getString(IntentData.playlistDescription)
|
DatabaseHolder.Database.playlistBookmarkDao()
|
||||||
val newPlaylistName =
|
.deleteById(playlistId!!)
|
||||||
resultBundle.getString(IntentData.playlistName)
|
} else {
|
||||||
val isPlaylistToBeDeleted =
|
DatabaseHolder.Database.playlistBookmarkDao()
|
||||||
resultBundle.getBoolean(IntentData.playlistTask)
|
.insert(response.toPlaylistBookmark(playlistId!!))
|
||||||
|
|
||||||
newPlaylistDescription?.let {
|
|
||||||
binding.playlistDescription.text = it
|
|
||||||
response.description = it
|
|
||||||
}
|
|
||||||
|
|
||||||
newPlaylistName?.let {
|
|
||||||
binding.playlistName.text = it
|
|
||||||
playlistName = it
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPlaylistToBeDeleted) {
|
|
||||||
// TODO move back: navController().popBackStack() crashes
|
|
||||||
return@setFragmentResultListener
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sheet.show(fragmentManager)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
binding.playAll.setOnClickListener {
|
// private playlist, means shuffle is possible because all videos are received at once
|
||||||
|
binding.bookmark.setIconResource(R.drawable.ic_shuffle)
|
||||||
|
binding.bookmark.text = getString(R.string.shuffle)
|
||||||
|
binding.bookmark.setOnClickListener {
|
||||||
if (playlistFeed.isEmpty()) return@setOnClickListener
|
if (playlistFeed.isEmpty()) return@setOnClickListener
|
||||||
|
val queue = playlistFeed.shuffled()
|
||||||
|
PlayingQueue.resetToDefaults()
|
||||||
|
PlayingQueue.add(*queue.toTypedArray())
|
||||||
NavigationHelper.navigateVideo(
|
NavigationHelper.navigateVideo(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
response.relatedStreams.first().url?.toID(),
|
queue.first().url?.toID(),
|
||||||
playlistId
|
playlistId = playlistId,
|
||||||
|
keepQueue = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
binding.sortContainer.isGone = false
|
||||||
if (playlistType == PlaylistType.PUBLIC) {
|
binding.sortTV.text = sortOptions[selectedSortOrder]
|
||||||
binding.bookmark.setOnClickListener {
|
binding.sortContainer.setOnClickListener {
|
||||||
isBookmarked = !isBookmarked
|
BaseBottomSheet().apply {
|
||||||
updateBookmarkRes()
|
setSimpleItems(sortOptions.toList()) { index ->
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
selectedSortOrder = index
|
||||||
if (!isBookmarked) {
|
binding.sortTV.text = sortOptions[index]
|
||||||
DatabaseHolder.Database.playlistBookmarkDao()
|
showPlaylistVideos(response)
|
||||||
.deleteById(playlistId!!)
|
|
||||||
} else {
|
|
||||||
DatabaseHolder.Database.playlistBookmarkDao()
|
|
||||||
.insert(response.toPlaylistBookmark(playlistId!!))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}.show(childFragmentManager)
|
||||||
} else {
|
|
||||||
// private playlist, means shuffle is possible because all videos are received at once
|
|
||||||
binding.bookmark.setIconResource(R.drawable.ic_shuffle)
|
|
||||||
binding.bookmark.text = getString(R.string.shuffle)
|
|
||||||
binding.bookmark.setOnClickListener {
|
|
||||||
if (playlistFeed.isEmpty()) return@setOnClickListener
|
|
||||||
val queue = playlistFeed.shuffled()
|
|
||||||
PlayingQueue.resetToDefaults()
|
|
||||||
PlayingQueue.add(*queue.toTypedArray())
|
|
||||||
NavigationHelper.navigateVideo(
|
|
||||||
requireContext(),
|
|
||||||
queue.first().url?.toID(),
|
|
||||||
playlistId = playlistId,
|
|
||||||
keepQueue = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
binding.sortContainer.isGone = false
|
|
||||||
binding.sortTV.text = sortOptions[selectedSortOrder]
|
|
||||||
binding.sortContainer.setOnClickListener {
|
|
||||||
BaseBottomSheet().apply {
|
|
||||||
setSimpleItems(sortOptions.toList()) { index ->
|
|
||||||
selectedSortOrder = index
|
|
||||||
binding.sortTV.text = sortOptions[index]
|
|
||||||
showPlaylistVideos(response)
|
|
||||||
}
|
|
||||||
}.show(childFragmentManager)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePlaylistBookmark(response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePlaylistBookmark(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,26 +376,24 @@ class PlaylistFragment : Fragment() {
|
|||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
// load locally stored playlists with the auth api
|
||||||
// load locally stored playlists with the auth api
|
if (playlistType == PlaylistType.PRIVATE) {
|
||||||
if (playlistType == PlaylistType.PRIVATE) {
|
RetrofitInstance.authApi.getPlaylistNextPage(playlistId!!, nextPage!!)
|
||||||
RetrofitInstance.authApi.getPlaylistNextPage(playlistId!!, nextPage!!)
|
} else {
|
||||||
} else {
|
RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!)
|
||||||
RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
context?.toastFromMainDispatcher(e.localizedMessage.orEmpty())
|
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
nextPage = response.nextpage
|
context?.toastFromMainDispatcher(e.localizedMessage.orEmpty())
|
||||||
playlistAdapter?.updateItems(response.relatedStreams)
|
Log.e(TAG(), e.toString())
|
||||||
isLoading = false
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextPage = response.nextpage
|
||||||
|
playlistAdapter?.updateItems(response.relatedStreams)
|
||||||
|
isLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,7 @@ import androidx.core.view.isGone
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -74,23 +72,21 @@ class SearchFragment : Fragment() {
|
|||||||
|
|
||||||
private fun fetchSuggestions(query: String) {
|
private fun fetchSuggestions(query: String) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
RetrofitInstance.api.getSuggestions(query)
|
||||||
RetrofitInstance.api.getSuggestions(query)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
|
||||||
// only load the suggestions if the input field didn't get cleared yet
|
|
||||||
val suggestionsAdapter = SearchSuggestionsAdapter(
|
|
||||||
response.reversed(),
|
|
||||||
(activity as MainActivity).searchView
|
|
||||||
)
|
|
||||||
if (isAdded && !viewModel.searchQuery.value.isNullOrEmpty()) {
|
|
||||||
binding.suggestionsRecycler.adapter = suggestionsAdapter
|
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
// only load the suggestions if the input field didn't get cleared yet
|
||||||
|
val suggestionsAdapter = SearchSuggestionsAdapter(
|
||||||
|
response.reversed(),
|
||||||
|
(activity as MainActivity).searchView
|
||||||
|
)
|
||||||
|
if (isAdded && !viewModel.searchQuery.value.isNullOrEmpty()) {
|
||||||
|
binding.suggestionsRecycler.adapter = suggestionsAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
@ -114,55 +112,51 @@ class SearchResultFragment : Fragment() {
|
|||||||
"${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=$videoId"
|
"${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=$videoId"
|
||||||
} ?: query
|
} ?: query
|
||||||
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
view?.let { context?.hideKeyboard(it) }
|
||||||
view?.let { context?.hideKeyboard(it) }
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
RetrofitInstance.api.getSearchResults(searchQuery, searchFilter).apply {
|
||||||
RetrofitInstance.api.getSearchResults(searchQuery, searchFilter).apply {
|
items = items.deArrow()
|
||||||
items = items.deArrow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
context?.toastFromMainDispatcher(R.string.unknown_error)
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
Log.e(TAG(), e.toString())
|
||||||
searchAdapter = SearchAdapter(timeStamp = timeStamp ?: 0)
|
context?.toastFromMainDispatcher(R.string.unknown_error)
|
||||||
binding.searchRecycler.adapter = searchAdapter
|
return@launch
|
||||||
searchAdapter.submitList(response.items)
|
|
||||||
|
|
||||||
binding.searchResultsLayout.isVisible = true
|
|
||||||
binding.progress.isGone = true
|
|
||||||
binding.noSearchResult.isVisible = response.items.isEmpty()
|
|
||||||
|
|
||||||
nextPage = response.nextpage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val binding = _binding ?: return@launch
|
||||||
|
searchAdapter = SearchAdapter(timeStamp = timeStamp ?: 0)
|
||||||
|
binding.searchRecycler.adapter = searchAdapter
|
||||||
|
searchAdapter.submitList(response.items)
|
||||||
|
|
||||||
|
binding.searchResultsLayout.isVisible = true
|
||||||
|
binding.progress.isGone = true
|
||||||
|
binding.noSearchResult.isVisible = response.items.isEmpty()
|
||||||
|
|
||||||
|
nextPage = response.nextpage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchNextSearchItems() {
|
private fun fetchNextSearchItems() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
RetrofitInstance.api.getSearchResultsNextPage(
|
||||||
RetrofitInstance.api.getSearchResultsNextPage(
|
query,
|
||||||
query,
|
searchFilter,
|
||||||
searchFilter,
|
nextPage!!
|
||||||
nextPage!!
|
).apply {
|
||||||
).apply {
|
items = items.deArrow()
|
||||||
items = items.deArrow()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
|
||||||
nextPage = response.nextpage
|
|
||||||
if (response.items.isNotEmpty()) {
|
|
||||||
searchAdapter.submitList(searchAdapter.currentList + response.items)
|
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
nextPage = response.nextpage
|
||||||
|
if (response.items.isNotEmpty()) {
|
||||||
|
searchAdapter.submitList(searchAdapter.currentList + response.items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
import com.github.libretube.databinding.FragmentTrendsBinding
|
import com.github.libretube.databinding.FragmentTrendsBinding
|
||||||
@ -21,11 +19,11 @@ import com.github.libretube.ui.activities.SettingsActivity
|
|||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import java.io.IOException
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class TrendsFragment : Fragment() {
|
class TrendsFragment : Fragment() {
|
||||||
private var _binding: FragmentTrendsBinding? = null
|
private var _binding: FragmentTrendsBinding? = null
|
||||||
@ -57,41 +55,39 @@ class TrendsFragment : Fragment() {
|
|||||||
|
|
||||||
private fun fetchTrending() {
|
private fun fetchTrending() {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
val response = try {
|
||||||
val response = try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val region = LocaleHelper.getTrendingRegion(requireContext())
|
||||||
val region = LocaleHelper.getTrendingRegion(requireContext())
|
RetrofitInstance.api.getTrending(region).deArrow()
|
||||||
RetrofitInstance.api.getTrending(region).deArrow()
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
println(e)
|
|
||||||
Log.e(TAG(), "IOException, you might not have internet connection")
|
|
||||||
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
} catch (e: HttpException) {
|
|
||||||
Log.e(TAG(), "HttpException, unexpected response")
|
|
||||||
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
println(e)
|
||||||
binding.homeRefresh.isRefreshing = false
|
Log.e(TAG(), "IOException, you might not have internet connection")
|
||||||
binding.progressBar.isGone = true
|
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
||||||
|
return@launch
|
||||||
// show a [SnackBar] if there are no trending videos available
|
} catch (e: HttpException) {
|
||||||
if (response.isEmpty()) {
|
Log.e(TAG(), "HttpException, unexpected response")
|
||||||
Snackbar.make(binding.root, R.string.change_region, Snackbar.LENGTH_LONG)
|
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
|
||||||
.setAction(R.string.settings) {
|
return@launch
|
||||||
val settingsIntent = Intent(context, SettingsActivity::class.java)
|
|
||||||
startActivity(settingsIntent)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
return@repeatOnLifecycle
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.recview.adapter = VideosAdapter(response.toMutableList())
|
|
||||||
binding.recview.layoutManager = VideosAdapter.getLayout(requireContext())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val binding = _binding ?: return@launch
|
||||||
|
binding.homeRefresh.isRefreshing = false
|
||||||
|
binding.progressBar.isGone = true
|
||||||
|
|
||||||
|
// show a [SnackBar] if there are no trending videos available
|
||||||
|
if (response.isEmpty()) {
|
||||||
|
Snackbar.make(binding.root, R.string.change_region, Snackbar.LENGTH_LONG)
|
||||||
|
.setAction(R.string.settings) {
|
||||||
|
val settingsIntent = Intent(context, SettingsActivity::class.java)
|
||||||
|
startActivity(settingsIntent)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.recview.adapter = VideosAdapter(response.toMutableList())
|
||||||
|
binding.recview.layoutManager = VideosAdapter.getLayout(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user