mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
commit
594017f3a2
@ -3,6 +3,8 @@ package com.github.libretube.api
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
|
import com.github.libretube.api.obj.StreamItem
|
||||||
|
import com.github.libretube.api.obj.Subscription
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||||
import com.github.libretube.db.obj.LocalSubscription
|
import com.github.libretube.db.obj.LocalSubscription
|
||||||
@ -131,4 +133,28 @@ object SubscriptionHelper {
|
|||||||
val localSubscriptions = getLocalSubscriptions()
|
val localSubscriptions = getLocalSubscriptions()
|
||||||
return localSubscriptions.joinToString(",") { it.channelId }
|
return localSubscriptions.joinToString(",") { it.channelId }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getSubscriptions(): List<Subscription> {
|
||||||
|
return if (PreferenceHelper.getToken() != "") {
|
||||||
|
RetrofitInstance.authApi.subscriptions(
|
||||||
|
PreferenceHelper.getToken()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RetrofitInstance.authApi.unauthenticatedSubscriptions(
|
||||||
|
getFormattedLocalSubscriptions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getFeed(): List<StreamItem> {
|
||||||
|
return if (PreferenceHelper.getToken() != "") {
|
||||||
|
RetrofitInstance.authApi.getFeed(
|
||||||
|
PreferenceHelper.getToken()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RetrofitInstance.authApi.getUnauthenticatedFeed(
|
||||||
|
getFormattedLocalSubscriptions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ class VideosAdapter(
|
|||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
||||||
val layoutInflater = LayoutInflater.from(parent.context)
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
return when {
|
return when {
|
||||||
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED, ForceMode.HOME) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
||||||
forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false))
|
forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false))
|
||||||
PreferenceHelper.getBoolean(
|
PreferenceHelper.getBoolean(
|
||||||
PreferenceKeys.ALTERNATIVE_VIDEOS_LAYOUT,
|
PreferenceKeys.ALTERNATIVE_VIDEOS_LAYOUT,
|
||||||
@ -83,11 +83,14 @@ class VideosAdapter(
|
|||||||
|
|
||||||
// Trending layout
|
// Trending layout
|
||||||
holder.trendingRowBinding?.apply {
|
holder.trendingRowBinding?.apply {
|
||||||
if (forceMode == ForceMode.RELATED) {
|
// set a fixed width for better visuals
|
||||||
val params = root.layoutParams
|
val params = root.layoutParams
|
||||||
params.width = (180).toDp(root.context.resources).toInt()
|
when (forceMode) {
|
||||||
root.layoutParams = params
|
ForceMode.RELATED -> params.width = (180).toDp(root.context.resources).toInt()
|
||||||
|
ForceMode.HOME -> params.width = (250).toDp(root.context.resources).toInt()
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
|
root.layoutParams = params
|
||||||
|
|
||||||
textViewTitle.text = video.title
|
textViewTitle.text = video.title
|
||||||
textViewChannel.text =
|
textViewChannel.text =
|
||||||
@ -168,7 +171,8 @@ class VideosAdapter(
|
|||||||
TRENDING,
|
TRENDING,
|
||||||
ROW,
|
ROW,
|
||||||
CHANNEL,
|
CHANNEL,
|
||||||
RELATED
|
RELATED,
|
||||||
|
HOME
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLayout(context: Context): LayoutManager {
|
fun getLayout(context: Context): LayoutManager {
|
||||||
|
@ -4,25 +4,27 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
|
import com.github.libretube.api.RetrofitInstance
|
||||||
|
import com.github.libretube.api.SubscriptionHelper
|
||||||
import com.github.libretube.databinding.FragmentHomeBinding
|
import com.github.libretube.databinding.FragmentHomeBinding
|
||||||
|
import com.github.libretube.extensions.toastFromMainThread
|
||||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
import com.github.libretube.ui.base.BaseFragment
|
import com.github.libretube.ui.base.BaseFragment
|
||||||
import com.github.libretube.ui.models.HomeModel
|
import com.github.libretube.ui.extensions.withMaxSize
|
||||||
import com.github.libretube.util.LocaleHelper
|
import com.github.libretube.util.LocaleHelper
|
||||||
|
import com.github.libretube.util.PreferenceHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class HomeFragment : BaseFragment() {
|
class HomeFragment : BaseFragment() {
|
||||||
private lateinit var binding: FragmentHomeBinding
|
private lateinit var binding: FragmentHomeBinding
|
||||||
private val viewModel: HomeModel by activityViewModels()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -48,42 +50,55 @@ class HomeFragment : BaseFragment() {
|
|||||||
findNavController().navigate(R.id.libraryFragment)
|
findNavController().navigate(R.id.libraryFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.refresh.setOnRefreshListener {
|
||||||
|
binding.refresh.isRefreshing = true
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
viewModel.fetchHome(requireContext(), LocaleHelper.getTrendingRegion(requireContext()))
|
fetchHome(LocaleHelper.getTrendingRegion(requireContext()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.feed.observe(viewLifecycleOwner) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
binding.featuredTV.visibility = View.VISIBLE
|
fetchHome(LocaleHelper.getTrendingRegion(requireContext()))
|
||||||
binding.featuredRV.visibility = View.VISIBLE
|
}
|
||||||
binding.progress.visibility = View.GONE
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchHome(trendingRegion: String) {
|
||||||
|
val token = PreferenceHelper.getToken()
|
||||||
|
runOrError {
|
||||||
|
val feed = SubscriptionHelper.getFeed().withMaxSize(20)
|
||||||
|
if (feed.isEmpty()) return@runOrError
|
||||||
|
runOnUiThread {
|
||||||
|
makeVisible(binding.featuredRV, binding.featuredTV)
|
||||||
binding.featuredRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
binding.featuredRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
binding.featuredRV.adapter = VideosAdapter(
|
binding.featuredRV.adapter = VideosAdapter(
|
||||||
it.toMutableList(),
|
feed.toMutableList(),
|
||||||
childFragmentManager,
|
childFragmentManager,
|
||||||
forceMode = VideosAdapter.Companion.ForceMode.RELATED
|
forceMode = VideosAdapter.Companion.ForceMode.HOME
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.trending.observe(viewLifecycleOwner) {
|
runOrError {
|
||||||
if (it.isEmpty()) return@observe
|
val trending = RetrofitInstance.api.getTrending(trendingRegion).withMaxSize(10)
|
||||||
binding.trendingTV.visibility = View.VISIBLE
|
if (trending.isEmpty()) return@runOrError
|
||||||
binding.trendingRV.visibility = View.VISIBLE
|
runOnUiThread {
|
||||||
binding.progress.visibility = View.GONE
|
makeVisible(binding.trendingRV, binding.trendingTV)
|
||||||
binding.trendingRV.layoutManager = GridLayoutManager(context, 2)
|
binding.trendingRV.layoutManager = GridLayoutManager(context, 2)
|
||||||
binding.trendingRV.adapter = VideosAdapter(
|
binding.trendingRV.adapter = VideosAdapter(
|
||||||
it.toMutableList(),
|
trending.toMutableList(),
|
||||||
childFragmentManager,
|
childFragmentManager,
|
||||||
forceMode = VideosAdapter.Companion.ForceMode.TRENDING
|
forceMode = VideosAdapter.Companion.ForceMode.TRENDING
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.playlists.observe(viewLifecycleOwner) {
|
runOrError {
|
||||||
if (it.isEmpty()) return@observe
|
val playlists = RetrofitInstance.authApi.getUserPlaylists(token).withMaxSize(20)
|
||||||
binding.playlistsRV.visibility = View.VISIBLE
|
if (playlists.isEmpty()) return@runOrError
|
||||||
binding.playlistsTV.visibility = View.VISIBLE
|
runOnUiThread {
|
||||||
binding.progress.visibility = View.GONE
|
makeVisible(binding.playlistsRV, binding.playlistsTV)
|
||||||
binding.playlistsRV.layoutManager = LinearLayoutManager(context)
|
binding.playlistsRV.layoutManager = LinearLayoutManager(context)
|
||||||
binding.playlistsRV.adapter = PlaylistsAdapter(it.toMutableList(), childFragmentManager)
|
binding.playlistsRV.adapter = PlaylistsAdapter(playlists.toMutableList(), childFragmentManager)
|
||||||
binding.playlistsRV.adapter?.registerAdapterDataObserver(object :
|
binding.playlistsRV.adapter?.registerAdapterDataObserver(object :
|
||||||
RecyclerView.AdapterDataObserver() {
|
RecyclerView.AdapterDataObserver() {
|
||||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||||
@ -97,3 +112,23 @@ class HomeFragment : BaseFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun runOrError(action: suspend () -> Unit) {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
action.invoke()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.localizedMessage?.let { context?.toastFromMainThread(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeVisible(vararg views: View) {
|
||||||
|
views.forEach {
|
||||||
|
it.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
binding.progress.visibility = View.GONE
|
||||||
|
binding.scroll.visibility = View.VISIBLE
|
||||||
|
binding.refresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
package com.github.libretube.ui.models
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.github.libretube.api.RetrofitInstance
|
|
||||||
import com.github.libretube.api.obj.Playlists
|
|
||||||
import com.github.libretube.api.obj.StreamItem
|
|
||||||
import com.github.libretube.extensions.toastFromMainThread
|
|
||||||
import com.github.libretube.ui.extensions.withMaxSize
|
|
||||||
import com.github.libretube.util.PreferenceHelper
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class HomeModel : ViewModel() {
|
|
||||||
val feed = MutableLiveData<List<StreamItem>>()
|
|
||||||
var trending = MutableLiveData<List<StreamItem>>()
|
|
||||||
val playlists = MutableLiveData<List<Playlists>>()
|
|
||||||
|
|
||||||
suspend fun fetchHome(context: Context, trendingRegion: String) {
|
|
||||||
val token = PreferenceHelper.getToken()
|
|
||||||
val appContext = context.applicationContext
|
|
||||||
runOrError(appContext) {
|
|
||||||
if (trending.value.isNullOrEmpty()) {
|
|
||||||
trending.postValue(
|
|
||||||
RetrofitInstance.api.getTrending(trendingRegion).withMaxSize(10)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runOrError(appContext) {
|
|
||||||
if (feed.value.isNullOrEmpty()) {
|
|
||||||
feed.postValue(
|
|
||||||
RetrofitInstance.authApi.getFeed(token).withMaxSize(20)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runOrError(appContext) {
|
|
||||||
if (token == "" || !playlists.value.isNullOrEmpty()) return@runOrError
|
|
||||||
playlists.postValue(
|
|
||||||
RetrofitInstance.authApi.getUserPlaylists(token).withMaxSize(20)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun runOrError(context: Context, action: suspend () -> Unit) {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
|
||||||
try {
|
|
||||||
action.invoke()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.localizedMessage?.let { context.toastFromMainThread(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,8 +3,9 @@ package com.github.libretube.ui.models
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.github.libretube.api.RetrofitInstance
|
|
||||||
import com.github.libretube.api.SubscriptionHelper
|
import com.github.libretube.api.SubscriptionHelper
|
||||||
|
import com.github.libretube.api.obj.StreamItem
|
||||||
|
import com.github.libretube.api.obj.Subscription
|
||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.util.PreferenceHelper
|
import com.github.libretube.util.PreferenceHelper
|
||||||
@ -17,26 +18,18 @@ class SubscriptionsViewModel : ViewModel() {
|
|||||||
value = false
|
value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var videoFeed = MutableLiveData<List<com.github.libretube.api.obj.StreamItem>?>().apply {
|
var videoFeed = MutableLiveData<List<StreamItem>?>().apply {
|
||||||
value = null
|
value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscriptions = MutableLiveData<List<com.github.libretube.api.obj.Subscription>?>().apply {
|
var subscriptions = MutableLiveData<List<Subscription>?>().apply {
|
||||||
value = null
|
value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchFeed() {
|
fun fetchFeed() {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val videoFeed = try {
|
val videoFeed = try {
|
||||||
if (PreferenceHelper.getToken() != "") {
|
SubscriptionHelper.getFeed()
|
||||||
RetrofitInstance.authApi.getFeed(
|
|
||||||
PreferenceHelper.getToken()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RetrofitInstance.authApi.getUnauthenticatedFeed(
|
|
||||||
SubscriptionHelper.getFormattedLocalSubscriptions()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
errorResponse.postValue(true)
|
errorResponse.postValue(true)
|
||||||
Log.e(TAG(), e.toString())
|
Log.e(TAG(), e.toString())
|
||||||
@ -53,15 +46,7 @@ class SubscriptionsViewModel : ViewModel() {
|
|||||||
fun fetchSubscriptions() {
|
fun fetchSubscriptions() {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val subscriptions = try {
|
val subscriptions = try {
|
||||||
if (PreferenceHelper.getToken() != "") {
|
SubscriptionHelper.getSubscriptions()
|
||||||
RetrofitInstance.authApi.subscriptions(
|
|
||||||
PreferenceHelper.getToken()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RetrofitInstance.authApi.unauthenticatedSubscriptions(
|
|
||||||
SubscriptionHelper.getFormattedLocalSubscriptions()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
errorResponse.postValue(true)
|
errorResponse.postValue(true)
|
||||||
Log.e(TAG(), e.toString())
|
Log.e(TAG(), e.toString())
|
||||||
|
@ -10,7 +10,6 @@ import androidx.core.app.NotificationManagerCompat
|
|||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
|
||||||
import com.github.libretube.api.SubscriptionHelper
|
import com.github.libretube.api.SubscriptionHelper
|
||||||
import com.github.libretube.constants.PUSH_CHANNEL_ID
|
import com.github.libretube.constants.PUSH_CHANNEL_ID
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
@ -82,16 +81,9 @@ class NotificationWorker(appContext: Context, parameters: WorkerParameters) :
|
|||||||
private fun checkForNewStreams(): Boolean {
|
private fun checkForNewStreams(): Boolean {
|
||||||
var success = true
|
var success = true
|
||||||
|
|
||||||
val token = PreferenceHelper.getToken()
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val task = async {
|
val task = async {
|
||||||
if (token != "") {
|
SubscriptionHelper.getFeed()
|
||||||
RetrofitInstance.authApi.getFeed(token)
|
|
||||||
} else {
|
|
||||||
RetrofitInstance.authApi.getUnauthenticatedFeed(
|
|
||||||
SubscriptionHelper.getFormattedLocalSubscriptions()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// fetch the users feed
|
// fetch the users feed
|
||||||
val videoFeed = try {
|
val videoFeed = try {
|
||||||
|
@ -9,7 +9,14 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<com.github.libretube.ui.views.CustomSwipeToRefresh
|
||||||
|
android:id="@+id/refresh"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
android:id="@+id/scroll"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
@ -68,4 +75,6 @@
|
|||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
</com.github.libretube.ui.views.CustomSwipeToRefresh>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
Loading…
x
Reference in New Issue
Block a user