Merge pull request #3182 from Isira-Seneviratne/Remove_BaseFragment

Remove BaseFragment.
This commit is contained in:
Bnyro 2023-02-26 15:39:25 +01:00 committed by GitHub
commit 9a659d7a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 275 additions and 322 deletions

View File

@ -1,14 +0,0 @@
package com.github.libretube.extensions
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
fun Fragment.launchWhenCreatedIO(block: suspend () -> Unit) {
lifecycleScope.launchWhenCreated {
withContext(Dispatchers.IO) {
block.invoke()
}
}
}

View File

@ -1,10 +0,0 @@
package com.github.libretube.ui.base
import androidx.fragment.app.Fragment
open class BaseFragment : Fragment() {
fun runOnUiThread(action: () -> Unit) {
if (!isAdded) return // Fragment not attached to an Activity
activity?.runOnUiThread(action)
}
}

View File

@ -13,6 +13,7 @@ import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.github.libretube.R
import com.github.libretube.api.obj.StreamItem
@ -27,7 +28,6 @@ import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.obj.ShareData
import com.github.libretube.services.BackgroundMode
import com.github.libretube.ui.activities.MainActivity
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.interfaces.AudioPlayerOptions
import com.github.libretube.ui.listeners.AudioPlayerThumbnailListener
@ -36,7 +36,7 @@ import com.github.libretube.ui.sheets.PlayingQueueSheet
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
import com.github.libretube.util.PlayingQueue
class AudioPlayerFragment : BaseFragment(), AudioPlayerOptions {
class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
private lateinit var binding: FragmentAudioPlayerBinding
private lateinit var audioHelper: AudioHelper

View File

@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.view.children
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R
@ -24,7 +25,6 @@ import com.github.libretube.obj.ChannelTabs
import com.github.libretube.obj.ShareData
import com.github.libretube.ui.adapters.SearchAdapter
import com.github.libretube.ui.adapters.VideosAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.dialogs.ShareDialog
import com.github.libretube.ui.extensions.setupSubscriptionButton
import java.io.IOException
@ -33,7 +33,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.HttpException
class ChannelFragment : BaseFragment() {
class ChannelFragment : Fragment() {
private lateinit var binding: FragmentChannelBinding
private var channelId: String? = null
@ -102,10 +102,12 @@ class ChannelFragment : BaseFragment() {
private fun fetchChannel() {
lifecycleScope.launchWhenCreated {
val response = try {
if (channelId != null) {
RetrofitInstance.api.getChannel(channelId!!)
} else {
RetrofitInstance.api.getChannelByName(channelName!!)
withContext(Dispatchers.IO) {
if (channelId != null) {
RetrofitInstance.api.getChannel(channelId!!)
} else {
RetrofitInstance.api.getChannelByName(channelName!!)
}
}
} catch (e: IOException) {
binding.channelRefresh.isRefreshing = false
@ -129,64 +131,60 @@ class ChannelFragment : BaseFragment() {
isSubscribed = SubscriptionHelper.isSubscribed(channelId!!)
if (isSubscribed == null) return@launchWhenCreated
runOnUiThread {
binding.channelSubscribe.setupSubscriptionButton(
channelId,
channelName,
binding.notificationBell
)
binding.channelSubscribe.setupSubscriptionButton(
channelId,
channelName,
binding.notificationBell
)
binding.channelShare.setOnClickListener {
val shareDialog = ShareDialog(
response.id!!.toID(),
ShareObjectType.CHANNEL,
shareData
)
shareDialog.show(childFragmentManager, ShareDialog::class.java.name)
}
binding.channelShare.setOnClickListener {
val shareDialog = ShareDialog(
response.id!!.toID(),
ShareObjectType.CHANNEL,
shareData
)
shareDialog.show(childFragmentManager, ShareDialog::class.java.name)
}
nextPage = response.nextpage
isLoading = false
binding.channelRefresh.isRefreshing = false
runOnUiThread {
binding.channelScrollView.visibility = View.VISIBLE
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()
binding.channelScrollView.visibility = View.VISIBLE
binding.channelName.text = response.name
if (response.verified) {
binding.channelName.setCompoundDrawablesWithIntrinsicBounds(
0,
0,
R.drawable.ic_verified,
0
)
if (response.description.isBlank()) {
binding.channelDescription.visibility = View.GONE
} else {
binding.channelDescription.text = response.description.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)
// recyclerview of the videos by the channel
channelAdapter = VideosAdapter(
response.relatedStreams.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.CHANNEL
)
binding.channelRecView.adapter = channelAdapter
}
binding.channelSubs.text = resources.getString(
R.string.subscribers,
response.subscriberCount.formatShort()
)
if (response.description.isBlank()) {
binding.channelDescription.visibility = View.GONE
} else {
binding.channelDescription.text = response.description.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)
// recyclerview of the videos by the channel
channelAdapter = VideosAdapter(
response.relatedStreams.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.CHANNEL
)
binding.channelRecView.adapter = channelAdapter
setupTabs(response.tabs)
}

View File

@ -9,6 +9,7 @@ import android.os.IBinder
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -22,7 +23,6 @@ import com.github.libretube.obj.DownloadStatus
import com.github.libretube.receivers.DownloadReceiver
import com.github.libretube.services.DownloadService
import com.github.libretube.ui.adapters.DownloadsAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.viewholders.DownloadsViewHolder
import java.io.File
import kotlinx.coroutines.Dispatchers
@ -31,7 +31,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class DownloadsFragment : BaseFragment() {
class DownloadsFragment : Fragment() {
private lateinit var binding: FragmentDownloadsBinding
private var binder: DownloadService.LocalBinder? = null
private val downloads = mutableListOf<DownloadWithItems>()

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@ -17,19 +18,16 @@ import com.github.libretube.api.SubscriptionHelper
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.databinding.FragmentHomeBinding
import com.github.libretube.db.DatabaseHolder
import com.github.libretube.extensions.launchWhenCreatedIO
import com.github.libretube.helpers.LocaleHelper
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
import com.github.libretube.ui.adapters.PlaylistsAdapter
import com.github.libretube.ui.adapters.VideosAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.models.SubscriptionsViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class HomeFragment : BaseFragment() {
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
private val subscriptionsViewModel: SubscriptionsViewModel by activityViewModels()
@ -70,11 +68,11 @@ class HomeFragment : BaseFragment() {
}
private fun fetchHomeFeed() {
launchWhenCreatedIO {
lifecycleScope.launchWhenCreated {
loadTrending()
loadBookmarks()
}
launchWhenCreatedIO {
lifecycleScope.launchWhenCreated {
loadFeed()
loadPlaylists()
}
@ -83,89 +81,86 @@ class HomeFragment : BaseFragment() {
private suspend fun loadTrending() {
val region = LocaleHelper.getTrendingRegion(requireContext())
val trending = runCatching {
RetrofitInstance.api.getTrending(region).take(10)
}.getOrNull().takeIf { it?.isNotEmpty() == true } ?: return
withContext(Dispatchers.IO) {
RetrofitInstance.api.getTrending(region).take(10)
}
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
runOnUiThread {
makeVisible(binding.trendingRV, binding.trendingTV)
binding.trendingRV.layoutManager = GridLayoutManager(context, 2)
binding.trendingRV.adapter = VideosAdapter(
trending.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.TRENDING
)
}
makeVisible(binding.trendingRV, binding.trendingTV)
binding.trendingRV.layoutManager = GridLayoutManager(context, 2)
binding.trendingRV.adapter = VideosAdapter(
trending.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.TRENDING
)
}
private suspend fun loadFeed() {
val savedFeed = withContext(Dispatchers.Main) {
subscriptionsViewModel.videoFeed.value
}
val savedFeed = subscriptionsViewModel.videoFeed.value
val feed = if (
PreferenceHelper.getBoolean(PreferenceKeys.SAVE_FEED, false) &&
!savedFeed.isNullOrEmpty()
) { savedFeed } else {
runCatching {
SubscriptionHelper.getFeed()
withContext(Dispatchers.IO) {
SubscriptionHelper.getFeed()
}
}.getOrElse { return }
}.takeIf { it.isNotEmpty() }?.take(20) ?: return
}.take(20)
runOnUiThread {
makeVisible(binding.featuredRV, binding.featuredTV)
binding.featuredRV.layoutManager = LinearLayoutManager(
makeVisible(binding.featuredRV, binding.featuredTV)
binding.featuredRV.layoutManager = LinearLayoutManager(
context,
LinearLayoutManager.HORIZONTAL,
false
)
binding.featuredRV.adapter = VideosAdapter(
feed.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.HOME
)
}
private suspend fun loadBookmarks() {
val bookmarkedPlaylists = withContext(Dispatchers.IO) {
DatabaseHolder.Database.playlistBookmarkDao().getAll()
}
if (bookmarkedPlaylists.isNotEmpty()) {
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
binding.bookmarksRV.layoutManager = LinearLayoutManager(
context,
LinearLayoutManager.HORIZONTAL,
false
)
binding.featuredRV.adapter = VideosAdapter(
feed.toMutableList(),
forceMode = VideosAdapter.Companion.ForceMode.HOME
binding.bookmarksRV.adapter = PlaylistBookmarkAdapter(
bookmarkedPlaylists,
PlaylistBookmarkAdapter.Companion.BookmarkMode.HOME
)
}
}
private fun loadBookmarks() {
lifecycleScope.launch {
val bookmarkedPlaylists = withContext(Dispatchers.IO) {
DatabaseHolder.Database.playlistBookmarkDao().getAll()
}
if (bookmarkedPlaylists.isNotEmpty()) {
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
binding.bookmarksRV.layoutManager = LinearLayoutManager(
context,
LinearLayoutManager.HORIZONTAL,
false
)
binding.bookmarksRV.adapter = PlaylistBookmarkAdapter(
bookmarkedPlaylists,
PlaylistBookmarkAdapter.Companion.BookmarkMode.HOME
)
}
}
}
private suspend fun loadPlaylists() {
val playlists = runCatching {
PlaylistsHelper.getPlaylists().take(20)
}.getOrNull().takeIf { it?.isNotEmpty() == true } ?: return
withContext(Dispatchers.IO) {
PlaylistsHelper.getPlaylists().take(20)
}
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
runOnUiThread {
makeVisible(binding.playlistsRV, binding.playlistsTV)
binding.playlistsRV.layoutManager = LinearLayoutManager(context)
binding.playlistsRV.adapter = PlaylistsAdapter(
playlists.toMutableList(),
PlaylistsHelper.getPrivatePlaylistType()
)
binding.playlistsRV.adapter?.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
super.onItemRangeRemoved(positionStart, itemCount)
if (itemCount == 0) {
binding.playlistsRV.visibility = View.GONE
binding.playlistsTV.visibility = View.GONE
}
makeVisible(binding.playlistsRV, binding.playlistsTV)
binding.playlistsRV.layoutManager = LinearLayoutManager(context)
binding.playlistsRV.adapter = PlaylistsAdapter(
playlists.toMutableList(),
PlaylistsHelper.getPrivatePlaylistType()
)
binding.playlistsRV.adapter?.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
super.onItemRangeRemoved(positionStart, itemCount)
if (itemCount == 0) {
binding.playlistsRV.visibility = View.GONE
binding.playlistsTV.visibility = View.GONE
}
})
}
}
})
}
private fun makeVisible(vararg views: View) {

View File

@ -9,6 +9,7 @@ import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@ -25,15 +26,13 @@ import com.github.libretube.helpers.NavBarHelper
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
import com.github.libretube.ui.adapters.PlaylistsAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.dialogs.CreatePlaylistDialog
import com.github.libretube.ui.models.PlayerViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LibraryFragment : BaseFragment() {
class LibraryFragment : Fragment() {
private lateinit var binding: FragmentLibraryBinding
private val playerViewModel: PlayerViewModel by activityViewModels()
@ -118,7 +117,9 @@ class LibraryFragment : BaseFragment() {
binding.playlistRefresh.isRefreshing = true
lifecycleScope.launchWhenCreated {
var playlists = try {
PlaylistsHelper.getPlaylists()
withContext(Dispatchers.IO) {
PlaylistsHelper.getPlaylists()
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
@ -128,10 +129,7 @@ class LibraryFragment : BaseFragment() {
}
if (playlists.isNotEmpty()) {
playlists = when (
PreferenceHelper.getString(
PreferenceKeys.PLAYLISTS_ORDER,
"recent"
)
PreferenceHelper.getString(PreferenceKeys.PLAYLISTS_ORDER, "recent")
) {
"recent" -> playlists
"recent_reversed" -> playlists.reversed()
@ -158,9 +156,7 @@ class LibraryFragment : BaseFragment() {
binding.nothingHere.visibility = View.GONE
binding.playlistRecView.adapter = playlistsAdapter
} else {
runOnUiThread {
binding.nothingHere.visibility = View.VISIBLE
}
binding.nothingHere.visibility = View.VISIBLE
}
}
}

View File

@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View
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.ItemTouchHelper
@ -27,7 +28,6 @@ import com.github.libretube.extensions.toID
import com.github.libretube.helpers.ImageHelper
import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.ui.adapters.PlaylistAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
import com.github.libretube.util.PlayingQueue
@ -35,8 +35,9 @@ import com.github.libretube.util.TextUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
class PlaylistFragment : BaseFragment() {
class PlaylistFragment : Fragment() {
private lateinit var binding: FragmentPlaylistBinding
// general playlist information
@ -104,7 +105,9 @@ class PlaylistFragment : BaseFragment() {
binding.playlistScrollview.visibility = View.GONE
lifecycleScope.launchWhenCreated {
val response = try {
PlaylistsHelper.getPlaylist(playlistId!!)
withContext(Dispatchers.IO) {
PlaylistsHelper.getPlaylist(playlistId!!)
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
return@launchWhenCreated
@ -114,154 +117,151 @@ class PlaylistFragment : BaseFragment() {
nextPage = response.nextpage
playlistName = response.name
isLoading = false
runOnUiThread {
ImageHelper.loadImage(response.thumbnailUrl, binding.thumbnail)
binding.playlistProgress.visibility = View.GONE
binding.playlistName.text = response.name
ImageHelper.loadImage(response.thumbnailUrl, binding.thumbnail)
binding.playlistProgress.visibility = View.GONE
binding.playlistName.text = response.name
binding.playlistName.setOnClickListener {
binding.playlistName.maxLines =
if (binding.playlistName.maxLines == 2) Int.MAX_VALUE else 2
}
binding.playlistName.setOnClickListener {
binding.playlistName.maxLines =
if (binding.playlistName.maxLines == 2) Int.MAX_VALUE else 2
}
binding.playlistInfo.text =
(if (response.uploader != null) response.uploader + TextUtils.SEPARATOR else "") +
binding.playlistInfo.text =
(if (response.uploader != null) response.uploader + TextUtils.SEPARATOR else "") +
getString(R.string.videoCount, response.videos.toString())
// show playlist options
binding.optionsMenu.setOnClickListener {
PlaylistOptionsBottomSheet(playlistId!!, playlistName ?: "", playlistType).show(
childFragmentManager,
PlaylistOptionsBottomSheet::class.java.name
)
}
// show playlist options
binding.optionsMenu.setOnClickListener {
PlaylistOptionsBottomSheet(playlistId!!, playlistName ?: "", playlistType).show(
childFragmentManager,
PlaylistOptionsBottomSheet::class.java.name
)
}
binding.playAll.setOnClickListener {
if (playlistFeed.isEmpty()) return@setOnClickListener
binding.playAll.setOnClickListener {
if (playlistFeed.isEmpty()) return@setOnClickListener
NavigationHelper.navigateVideo(
requireContext(),
response.relatedStreams.first().url?.toID(),
playlistId
)
}
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()
.insertAll(listOf(response.toPlaylistBookmark(playlistId!!)))
}
}
}
} 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 {
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()
.insertAll(listOf(response.toPlaylistBookmark(playlistId!!)))
}
}
}
} 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
playlistAdapter = PlaylistAdapter(
playlistFeed,
playlistId!!,
playlistType
)
// listen for playlist items to become deleted
playlistAdapter!!.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
if (positionStart == 0) {
ImageHelper.loadImage(
playlistFeed.firstOrNull()?.thumbnail ?: "",
binding.thumbnail
)
}
}
playlistAdapter = PlaylistAdapter(
playlistFeed,
playlistId!!,
playlistType
)
// listen for playlist items to become deleted
playlistAdapter!!.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() {
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
if (positionStart == 0) {
ImageHelper.loadImage(
playlistFeed.firstOrNull()?.thumbnail ?: "",
binding.thumbnail
)
}
val info = binding.playlistInfo.text.split(TextUtils.SEPARATOR)
binding.playlistInfo.text = (
val info = binding.playlistInfo.text.split(TextUtils.SEPARATOR)
binding.playlistInfo.text = (
if (info.size == 2) {
info[0] + TextUtils.SEPARATOR
} else {
""
}
) + getString(
R.string.videoCount,
playlistAdapter!!.itemCount.toString()
)
super.onItemRangeRemoved(positionStart, itemCount)
}
})
R.string.videoCount,
playlistAdapter!!.itemCount.toString()
)
super.onItemRangeRemoved(positionStart, itemCount)
}
})
binding.playlistRecView.adapter = playlistAdapter
binding.playlistScrollview.viewTreeObserver
.addOnScrollChangedListener {
if (!binding.playlistScrollview.canScrollVertically(1)) {
if (isLoading) return@addOnScrollChangedListener
binding.playlistRecView.adapter = playlistAdapter
binding.playlistScrollview.viewTreeObserver
.addOnScrollChangedListener {
if (!binding.playlistScrollview.canScrollVertically(1)) {
if (isLoading) return@addOnScrollChangedListener
// append more playlists to the recycler view
if (playlistType != PlaylistType.PUBLIC) {
isLoading = true
playlistAdapter?.showMoreItems()
isLoading = false
} else {
fetchNextPage()
}
// append more playlists to the recycler view
if (playlistType != PlaylistType.PUBLIC) {
isLoading = true
playlistAdapter?.showMoreItems()
isLoading = false
} else {
fetchNextPage()
}
}
// listener for swiping to the left or right
if (playlistType != PlaylistType.PUBLIC) {
val itemTouchCallback = object : ItemTouchHelper.SimpleCallback(
0,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
val position = viewHolder.absoluteAdapterPosition
playlistAdapter!!.removeFromPlaylist(requireContext(), position)
}
}
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
}
// listener for swiping to the left or right
if (playlistType != PlaylistType.PUBLIC) {
val itemTouchCallback = object : ItemTouchHelper.SimpleCallback(
0,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
val position = viewHolder.absoluteAdapterPosition
playlistAdapter!!.removeFromPlaylist(requireContext(), position)
}
}
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
}
lifecycleScope.launch(Dispatchers.IO) {
// update the playlist thumbnail if bookmarked
lifecycleScope.launch(Dispatchers.IO) {
val playlistBookmark = DatabaseHolder.Database.playlistBookmarkDao().getAll()
.firstOrNull { it.playlistId == playlistId }
playlistBookmark?.let {
if (it.thumbnailUrl != response.thumbnailUrl) {
it.thumbnailUrl = response.thumbnailUrl
DatabaseHolder.Database.playlistBookmarkDao().update(it)
}
val playlistBookmark = DatabaseHolder.Database.playlistBookmarkDao().getAll()
.firstOrNull { it.playlistId == playlistId }
playlistBookmark?.let {
if (it.thumbnailUrl != response.thumbnailUrl) {
it.thumbnailUrl = response.thumbnailUrl
DatabaseHolder.Database.playlistBookmarkDao().update(it)
}
}
}

View File

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
@ -19,13 +20,12 @@ import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
import com.github.libretube.ui.adapters.VideosAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.models.SubscriptionsViewModel
import com.github.libretube.ui.sheets.BaseBottomSheet
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
class SubscriptionsFragment : BaseFragment() {
class SubscriptionsFragment : Fragment() {
private lateinit var binding: FragmentSubscriptionsBinding
private val viewModel: SubscriptionsViewModel by activityViewModels()

View File

@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance
@ -15,12 +16,13 @@ import com.github.libretube.extensions.TAG
import com.github.libretube.helpers.LocaleHelper
import com.github.libretube.ui.activities.SettingsActivity
import com.github.libretube.ui.adapters.VideosAdapter
import com.github.libretube.ui.base.BaseFragment
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
import retrofit2.HttpException
class TrendsFragment : BaseFragment() {
class TrendsFragment : Fragment() {
private lateinit var binding: FragmentTrendsBinding
override fun onCreateView(
@ -45,9 +47,11 @@ class TrendsFragment : BaseFragment() {
private fun fetchTrending() {
lifecycleScope.launchWhenCreated {
val response = try {
RetrofitInstance.api.getTrending(
LocaleHelper.getTrendingRegion(requireContext())
)
withContext(Dispatchers.IO) {
RetrofitInstance.api.getTrending(
LocaleHelper.getTrendingRegion(requireContext())
)
}
} catch (e: IOException) {
println(e)
Log.e(TAG(), "IOException, you might not have internet connection")
@ -60,36 +64,20 @@ class TrendsFragment : BaseFragment() {
} finally {
binding.homeRefresh.isRefreshing = false
}
runOnUiThread {
binding.progressBar.visibility = View.GONE
binding.progressBar.visibility = View.GONE
// 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
) {
startActivity(
Intent(
context,
SettingsActivity::class.java
)
)
}
.show()
return@runOnUiThread
}
binding.recview.adapter = VideosAdapter(
response.toMutableList()
)
binding.recview.layoutManager = VideosAdapter.getLayout(requireContext())
// 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) {
startActivity(Intent(context, SettingsActivity::class.java))
}
.show()
return@launchWhenCreated
}
binding.recview.adapter = VideosAdapter(response.toMutableList())
binding.recview.layoutManager = VideosAdapter.getLayout(requireContext())
}
}
}

View File

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.os.postDelayed
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
@ -21,7 +22,6 @@ import com.github.libretube.extensions.dpToPx
import com.github.libretube.helpers.NavigationHelper
import com.github.libretube.helpers.ProxyHelper
import com.github.libretube.ui.adapters.WatchHistoryAdapter
import com.github.libretube.ui.base.BaseFragment
import com.github.libretube.ui.models.PlayerViewModel
import com.github.libretube.util.PlayingQueue
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -29,7 +29,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class WatchHistoryFragment : BaseFragment() {
class WatchHistoryFragment : Fragment() {
private lateinit var binding: FragmentWatchHistoryBinding
private val playerViewModel: PlayerViewModel by activityViewModels()