mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 23:40:33 +05:30
Playlist Fragment
This commit is contained in:
parent
85b3181849
commit
1900e7cd5f
@ -23,9 +23,9 @@ class ChannelFragment : Fragment() {
|
|||||||
|
|
||||||
private var channel_id: String? = null
|
private var channel_id: String? = null
|
||||||
private val TAG = "ChannelFragment"
|
private val TAG = "ChannelFragment"
|
||||||
//lateinit var recyclerView: RecyclerView
|
|
||||||
var nextPage: String? =null
|
var nextPage: String? =null
|
||||||
lateinit var channelAdapter: ChannelAdapter
|
var channelAdapter: ChannelAdapter? = null
|
||||||
|
var isLoading = true
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -69,7 +69,8 @@ class ChannelFragment : Fragment() {
|
|||||||
Log.e(TAG, "HttpException, unexpected response")
|
Log.e(TAG, "HttpException, unexpected response")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
nextPage = response.nextpage!!
|
nextPage = response.nextpage
|
||||||
|
isLoading=false
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
view.findViewById<TextView>(R.id.channel_name).text=response.name
|
view.findViewById<TextView>(R.id.channel_name).text=response.name
|
||||||
view.findViewById<TextView>(R.id.channel_subs).text=response.subscriberCount.videoViews() + " subscribers"
|
view.findViewById<TextView>(R.id.channel_subs).text=response.subscriberCount.videoViews() + " subscribers"
|
||||||
@ -86,7 +87,8 @@ class ChannelFragment : Fragment() {
|
|||||||
if (scrollView.getChildAt(0).bottom
|
if (scrollView.getChildAt(0).bottom
|
||||||
== (scrollView.height + scrollView.scrollY)) {
|
== (scrollView.height + scrollView.scrollY)) {
|
||||||
//scroll view is at bottom
|
//scroll view is at bottom
|
||||||
if(nextPage!=null){
|
if(nextPage!=null && !isLoading){
|
||||||
|
isLoading=true
|
||||||
fetchNextPage()
|
fetchNextPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +116,8 @@ class ChannelFragment : Fragment() {
|
|||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
nextPage = response.nextpage
|
nextPage = response.nextpage
|
||||||
channelAdapter.updateItems(response.relatedStreams!!)
|
channelAdapter?.updateItems(response.relatedStreams!!)
|
||||||
|
isLoading=false
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +130,10 @@ class ChannelFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
val scrollView = view?.findViewById<ScrollView>(R.id.channel_scrollView)
|
||||||
|
scrollView?.viewTreeObserver?.removeOnScrollChangedListener {
|
||||||
|
}
|
||||||
|
channelAdapter=null
|
||||||
view?.findViewById<RecyclerView>(R.id.channel_recView)?.adapter=null
|
view?.findViewById<RecyclerView>(R.id.channel_recView)?.adapter=null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import com.github.libretube.obj.Channel
|
import com.github.libretube.obj.*
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
import com.github.libretube.obj.StreamItem
|
|
||||||
import com.github.libretube.obj.Streams
|
|
||||||
import com.github.libretube.obj.SearchResult
|
|
||||||
|
|
||||||
interface PipedApi {
|
interface PipedApi {
|
||||||
@GET("trending")
|
@GET("trending")
|
||||||
@ -29,4 +26,11 @@ interface PipedApi {
|
|||||||
|
|
||||||
@GET("nextpage/channel/{channelId}")
|
@GET("nextpage/channel/{channelId}")
|
||||||
suspend fun getChannelNextPage(@Path("channelId") channelId: String, @Query("nextpage") nextPage: String): Channel
|
suspend fun getChannelNextPage(@Path("channelId") channelId: String, @Query("nextpage") nextPage: String): Channel
|
||||||
|
|
||||||
|
@GET("playlists/{playlistId}")
|
||||||
|
suspend fun getPlaylist(@Path("playlistId") playlistId: String): Playlist
|
||||||
|
|
||||||
|
@GET("nextpage/playlists/{playlistId}")
|
||||||
|
suspend fun getPlaylistNextPage(@Path("playlistId") playlistId: String, @Query("nextpage") nextPage: String): Playlist
|
||||||
|
|
||||||
}
|
}
|
123
app/src/main/java/com/github/libretube/PlaylistFragment.kt
Normal file
123
app/src/main/java/com/github/libretube/PlaylistFragment.kt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package com.github.libretube
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.ScrollView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.github.libretube.adapters.ChannelAdapter
|
||||||
|
import com.github.libretube.adapters.PlaylistAdapter
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import retrofit2.HttpException
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistFragment : Fragment() {
|
||||||
|
private var playlist_id: String? = null
|
||||||
|
private val TAG = "PlaylistFragment"
|
||||||
|
var nextPage: String? =null
|
||||||
|
var playlistAdapter: PlaylistAdapter? = null
|
||||||
|
var isLoading = true
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
arguments?.let {
|
||||||
|
playlist_id = it.getString("playlist_id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
return inflater.inflate(R.layout.fragment_playlist, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
playlist_id = playlist_id!!.replace("/playlist?list=","")
|
||||||
|
view.findViewById<TextView>(R.id.playlist_name).text=playlist_id
|
||||||
|
val recyclerView = view.findViewById<RecyclerView>(R.id.playlist_recView)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
|
||||||
|
fetchPlaylist(view)
|
||||||
|
}
|
||||||
|
private fun fetchPlaylist(view: View){
|
||||||
|
fun run() {
|
||||||
|
lifecycleScope.launchWhenCreated {
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getPlaylist(playlist_id!!)
|
||||||
|
}catch(e: IOException) {
|
||||||
|
println(e)
|
||||||
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
|
return@launchWhenCreated
|
||||||
|
} catch (e: HttpException) {
|
||||||
|
Log.e(TAG, "HttpException, unexpected response")
|
||||||
|
return@launchWhenCreated
|
||||||
|
}
|
||||||
|
nextPage = response.nextpage
|
||||||
|
isLoading=false
|
||||||
|
runOnUiThread {
|
||||||
|
view.findViewById<TextView>(R.id.playlist_name).text=response.name
|
||||||
|
view.findViewById<TextView>(R.id.playlist_uploader).text=response.uploader
|
||||||
|
view.findViewById<TextView>(R.id.playlist_totVideos).text=response.videos.toString()+" Videos"
|
||||||
|
playlistAdapter = PlaylistAdapter(response.relatedStreams!!.toMutableList())
|
||||||
|
view.findViewById<RecyclerView>(R.id.playlist_recView).adapter = playlistAdapter
|
||||||
|
val scrollView = view.findViewById<ScrollView>(R.id.playlist_scrollview)
|
||||||
|
scrollView.viewTreeObserver
|
||||||
|
.addOnScrollChangedListener {
|
||||||
|
if (scrollView.getChildAt(0).bottom
|
||||||
|
== (scrollView.height + scrollView.scrollY)) {
|
||||||
|
//scroll view is at bottom
|
||||||
|
if(nextPage!=null && !isLoading){
|
||||||
|
isLoading=true
|
||||||
|
fetchNextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//scroll view is not at bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchNextPage(){
|
||||||
|
fun run() {
|
||||||
|
|
||||||
|
lifecycleScope.launchWhenCreated {
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getPlaylistNextPage(playlist_id!!,nextPage!!)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
println(e)
|
||||||
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
|
return@launchWhenCreated
|
||||||
|
} catch (e: HttpException) {
|
||||||
|
Log.e(TAG, "HttpException, unexpected response,"+e.response())
|
||||||
|
return@launchWhenCreated
|
||||||
|
}
|
||||||
|
nextPage = response.nextpage
|
||||||
|
playlistAdapter?.updateItems(response.relatedStreams!!)
|
||||||
|
isLoading=false
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||||
|
this ?: return
|
||||||
|
if (!isAdded) return // Fragment not attached to an Activity
|
||||||
|
activity?.runOnUiThread(action)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.github.libretube.adapters
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.github.libretube.MainActivity
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import com.github.libretube.PlayerFragment
|
||||||
|
import com.github.libretube.R
|
||||||
|
import com.github.libretube.obj.StreamItem
|
||||||
|
import com.github.libretube.videoViews
|
||||||
|
|
||||||
|
class PlaylistAdapter(private val videoFeed: MutableList<StreamItem>): RecyclerView.Adapter<PlaylistViewHolder>() {
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return videoFeed.size
|
||||||
|
}
|
||||||
|
fun updateItems(newItems: List<StreamItem>){
|
||||||
|
videoFeed.addAll(newItems)
|
||||||
|
//println("suck another dick: "+newItems[0].title)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaylistViewHolder {
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
|
val cell = layoutInflater.inflate(R.layout.video_channel_row,parent,false)
|
||||||
|
return PlaylistViewHolder(cell)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PlaylistViewHolder, position: Int) {
|
||||||
|
val streamItem = videoFeed[position]
|
||||||
|
holder.v.findViewById<TextView>(R.id.channel_description).text = streamItem.title
|
||||||
|
holder.v.findViewById<TextView>(R.id.channel_views).text = streamItem.uploaderName
|
||||||
|
val thumbnailImage = holder.v.findViewById<ImageView>(R.id.channel_thumbnail)
|
||||||
|
Picasso.get().load(streamItem.thumbnail).into(thumbnailImage)
|
||||||
|
holder.v.setOnClickListener{
|
||||||
|
var bundle = Bundle()
|
||||||
|
bundle.putString("videoId",streamItem.url!!.replace("/watch?v=",""))
|
||||||
|
var frag = PlayerFragment()
|
||||||
|
frag.arguments = bundle
|
||||||
|
val activity = holder.v.context as AppCompatActivity
|
||||||
|
activity.supportFragmentManager.beginTransaction()
|
||||||
|
.remove(PlayerFragment())
|
||||||
|
.commit()
|
||||||
|
activity.supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.container, frag)
|
||||||
|
.commitNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PlaylistViewHolder(val v: View): RecyclerView.ViewHolder(v){
|
||||||
|
init {
|
||||||
|
}
|
||||||
|
}
|
@ -103,6 +103,12 @@ class CustomViewHolder1(private val v: View): RecyclerView.ViewHolder(v){
|
|||||||
playlistChannelName.text = item.uploaderName
|
playlistChannelName.text = item.uploaderName
|
||||||
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_videos)
|
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_videos)
|
||||||
playlistVideosNumber.text = item.videos.toString()+" videos"
|
playlistVideosNumber.text = item.videos.toString()+" videos"
|
||||||
|
v.setOnClickListener {
|
||||||
|
//playlist clicked
|
||||||
|
val activity = v.context as MainActivity
|
||||||
|
val bundle = bundleOf("playlist_id" to item.url)
|
||||||
|
activity.navController.navigate(R.id.playlistFragment,bundle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(searchItem: SearchItem) {
|
fun bind(searchItem: SearchItem) {
|
||||||
|
@ -8,6 +8,6 @@ data class Playlist(
|
|||||||
var uploader: String? = null,
|
var uploader: String? = null,
|
||||||
var uploaderUrl: String? = null,
|
var uploaderUrl: String? = null,
|
||||||
var uploaderAvatar: String? = null,
|
var uploaderAvatar: String? = null,
|
||||||
var videos: Int = 0,
|
var videos: Int? = 0,
|
||||||
var relatedStreams: List<StreamItem>? = null,
|
var relatedStreams: List<StreamItem>? = null,
|
||||||
)
|
)
|
||||||
|
47
app/src/main/res/layout/fragment_playlist.xml
Normal file
47
app/src/main/res/layout/fragment_playlist.xml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".PlaylistFragment"
|
||||||
|
android:id="@+id/playlist_scrollview">
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playlist_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:padding="8dp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playlist_uploader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playlist_totVideos"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"/>
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:descendantFocusability="blocksDescendants">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/playlist_recView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:nestedScrollingEnabled="false" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</ScrollView>
|
@ -45,4 +45,13 @@
|
|||||||
android:name="channel_id"
|
android:name="channel_id"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/playlistFragment"
|
||||||
|
android:name="com.github.libretube.PlaylistFragment"
|
||||||
|
android:label="fragment_playlist"
|
||||||
|
tools:layout="@layout/fragment_playlist" >
|
||||||
|
<argument
|
||||||
|
android:name="playlist_id"
|
||||||
|
app:argType="string" />
|
||||||
|
</fragment>
|
||||||
</navigation>
|
</navigation>
|
@ -6,7 +6,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.0'
|
classpath 'com.android.tools.build:gradle:7.1.0'
|
||||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0'
|
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
Loading…
x
Reference in New Issue
Block a user