Merge pull request #5127 from Bnyro/master

refactor: remove unnecessary repeatOnLifecycle calls
This commit is contained in:
Bnyro 2023-11-07 17:16:33 +01:00 committed by GitHub
commit 2afdb1f359
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 352 additions and 382 deletions

View File

@ -10,9 +10,7 @@ import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.core.view.isGone
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
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.util.TextUtils
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import java.io.IOException
class DownloadDialog : DialogFragment() {
private lateinit var videoId: String
@ -80,23 +78,21 @@ class DownloadDialog : DialogFragment() {
private fun fetchAvailableSources(binding: DialogDownloadBinding) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
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
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getStreams(videoId)
}
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)
}
}

View File

@ -11,9 +11,7 @@ import androidx.core.view.children
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R
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.extensions.setupSubscriptionButton
import com.github.libretube.util.deArrow
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import java.io.IOException
class ChannelFragment : Fragment() {
private var _binding: FragmentChannelBinding? = null
@ -113,115 +111,113 @@ class ChannelFragment : Fragment() {
private fun fetchChannel() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
if (channelId != null) {
RetrofitInstance.api.getChannel(channelId!!)
} else {
RetrofitInstance.api.getChannelByName(channelName!!)
}.apply {
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
val response = try {
withContext(Dispatchers.IO) {
if (channelId != null) {
RetrofitInstance.api.getChannel(channelId!!)
} else {
RetrofitInstance.api.getChannelByName(channelName!!)
}.apply {
relatedStreams = relatedStreams.deArrow()
}
}
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)
} catch (e: IOException) {
_binding?.channelRefresh?.isRefreshing = false
Log.e(TAG(), "IOException, you might not have internet connection")
return@launch
} catch (e: HttpException) {
_binding?.channelRefresh?.isRefreshing = false
Log.e(TAG(), "HttpException, unexpected response")
return@launch
}
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
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!).apply {
relatedStreams = relatedStreams.deArrow()
}
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!).apply {
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
nextPage = response.nextpage
channelAdapter?.insertItems(response.relatedStreams)
isLoading = false
binding.channelRefresh.isRefreshing = false
} catch (e: IOException) {
_binding?.channelRefresh?.isRefreshing = false
Log.e(TAG(), "IOException, you might not have internet connection")
return@launch
} catch (e: HttpException) {
_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
}
}

View File

@ -12,9 +12,7 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -122,146 +120,144 @@ class PlaylistFragment : Fragment() {
private fun fetchPlaylist() {
binding.playlistScrollview.isGone = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
PlaylistsHelper.getPlaylist(playlistId!!)
val response = try {
withContext(Dispatchers.IO) {
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()
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
newPlaylistName?.let {
binding.playlistName.text = it
playlistName = it
}
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
if (isPlaylistToBeDeleted) {
// TODO move back: navController().popBackStack() crashes
return@setFragmentResultListener
}
}
showPlaylistVideos(response)
sheet.show(fragmentManager)
}
// 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
)
binding.playAll.setOnClickListener {
if (playlistFeed.isEmpty()) return@setOnClickListener
NavigationHelper.navigateVideo(
requireContext(),
response.relatedStreams.first().url?.toID(),
playlistId
)
}
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
}
newPlaylistName?.let {
binding.playlistName.text = it
playlistName = it
}
if (isPlaylistToBeDeleted) {
// TODO move back: navController().popBackStack() crashes
return@setFragmentResultListener
if (playlistType == PlaylistType.PUBLIC) {
binding.bookmark.setOnClickListener {
isBookmarked = !isBookmarked
updateBookmarkRes()
lifecycleScope.launch(Dispatchers.IO) {
if (!isBookmarked) {
DatabaseHolder.Database.playlistBookmarkDao()
.deleteById(playlistId!!)
} else {
DatabaseHolder.Database.playlistBookmarkDao()
.insert(response.toPlaylistBookmark(playlistId!!))
}
}
sheet.show(fragmentManager)
}
binding.playAll.setOnClickListener {
} 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(),
response.relatedStreams.first().url?.toID(),
playlistId
queue.first().url?.toID(),
playlistId = playlistId,
keepQueue = true
)
}
if (playlistType == PlaylistType.PUBLIC) {
binding.bookmark.setOnClickListener {
isBookmarked = !isBookmarked
updateBookmarkRes()
lifecycleScope.launch(Dispatchers.IO) {
if (!isBookmarked) {
DatabaseHolder.Database.playlistBookmarkDao()
.deleteById(playlistId!!)
} else {
DatabaseHolder.Database.playlistBookmarkDao()
.insert(response.toPlaylistBookmark(playlistId!!))
}
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)
}
}
} 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)
}
}.show(childFragmentManager)
}
updatePlaylistBookmark(response)
}
updatePlaylistBookmark(response)
}
}
@ -380,26 +376,24 @@ class PlaylistFragment : Fragment() {
isLoading = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
// load locally stored playlists with the auth api
if (playlistType == PlaylistType.PRIVATE) {
RetrofitInstance.authApi.getPlaylistNextPage(playlistId!!, nextPage!!)
} else {
RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!)
}
val response = try {
withContext(Dispatchers.IO) {
// load locally stored playlists with the auth api
if (playlistType == PlaylistType.PRIVATE) {
RetrofitInstance.authApi.getPlaylistNextPage(playlistId!!, nextPage!!)
} else {
RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!)
}
} catch (e: Exception) {
context?.toastFromMainDispatcher(e.localizedMessage.orEmpty())
Log.e(TAG(), e.toString())
return@repeatOnLifecycle
}
nextPage = response.nextpage
playlistAdapter?.updateItems(response.relatedStreams)
isLoading = false
} catch (e: Exception) {
context?.toastFromMainDispatcher(e.localizedMessage.orEmpty())
Log.e(TAG(), e.toString())
return@launch
}
nextPage = response.nextpage
playlistAdapter?.updateItems(response.relatedStreams)
isLoading = false
}
}
}

View File

@ -9,9 +9,7 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.constants.IntentData
@ -74,23 +72,21 @@ class SearchFragment : Fragment() {
private fun fetchSuggestions(query: String) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
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
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getSuggestions(query)
}
} 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
}
}
}

View File

@ -8,9 +8,7 @@ import android.view.ViewGroup
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
@ -114,55 +112,51 @@ class SearchResultFragment : Fragment() {
"${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=$videoId"
} ?: query
repeatOnLifecycle(Lifecycle.State.CREATED) {
view?.let { context?.hideKeyboard(it) }
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getSearchResults(searchQuery, searchFilter).apply {
items = items.deArrow()
}
view?.let { context?.hideKeyboard(it) }
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getSearchResults(searchQuery, searchFilter).apply {
items = items.deArrow()
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
context?.toastFromMainDispatcher(R.string.unknown_error)
return@repeatOnLifecycle
}
val binding = _binding ?: return@repeatOnLifecycle
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
} catch (e: Exception) {
Log.e(TAG(), e.toString())
context?.toastFromMainDispatcher(R.string.unknown_error)
return@launch
}
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() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getSearchResultsNextPage(
query,
searchFilter,
nextPage!!
).apply {
items = items.deArrow()
}
val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getSearchResultsNextPage(
query,
searchFilter,
nextPage!!
).apply {
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)
}
}
}

View File

@ -9,9 +9,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isGone
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
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.util.deArrow
import com.google.android.material.snackbar.Snackbar
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import java.io.IOException
class TrendsFragment : Fragment() {
private var _binding: FragmentTrendsBinding? = null
@ -57,41 +55,39 @@ class TrendsFragment : Fragment() {
private fun fetchTrending() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
val response = try {
withContext(Dispatchers.IO) {
val region = LocaleHelper.getTrendingRegion(requireContext())
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
val response = try {
withContext(Dispatchers.IO) {
val region = LocaleHelper.getTrendingRegion(requireContext())
RetrofitInstance.api.getTrending(region).deArrow()
}
val binding = _binding ?: return@repeatOnLifecycle
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@repeatOnLifecycle
}
binding.recview.adapter = VideosAdapter(response.toMutableList())
binding.recview.layoutManager = VideosAdapter.getLayout(requireContext())
} 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
}
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())
}
}
}