Playlist Fragment

This commit is contained in:
rimthekid 2022-02-06 17:10:27 +04:00
parent 85b3181849
commit 1900e7cd5f
9 changed files with 266 additions and 12 deletions

View File

@ -23,9 +23,9 @@ class ChannelFragment : Fragment() {
private var channel_id: String? = null
private val TAG = "ChannelFragment"
//lateinit var recyclerView: RecyclerView
var nextPage: String? =null
lateinit var channelAdapter: ChannelAdapter
var channelAdapter: ChannelAdapter? = null
var isLoading = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -69,7 +69,8 @@ class ChannelFragment : Fragment() {
Log.e(TAG, "HttpException, unexpected response")
return@launchWhenCreated
}
nextPage = response.nextpage!!
nextPage = response.nextpage
isLoading=false
runOnUiThread {
view.findViewById<TextView>(R.id.channel_name).text=response.name
view.findViewById<TextView>(R.id.channel_subs).text=response.subscriberCount.videoViews() + " subscribers"
@ -86,7 +87,8 @@ class ChannelFragment : Fragment() {
if (scrollView.getChildAt(0).bottom
== (scrollView.height + scrollView.scrollY)) {
//scroll view is at bottom
if(nextPage!=null){
if(nextPage!=null && !isLoading){
isLoading=true
fetchNextPage()
}
@ -114,7 +116,8 @@ class ChannelFragment : Fragment() {
return@launchWhenCreated
}
nextPage = response.nextpage
channelAdapter.updateItems(response.relatedStreams!!)
channelAdapter?.updateItems(response.relatedStreams!!)
isLoading=false
}
}
@ -127,7 +130,10 @@ class ChannelFragment : Fragment() {
}
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
super.onDestroyView()
}

View File

@ -1,12 +1,9 @@
package com.github.libretube
import com.github.libretube.obj.Channel
import com.github.libretube.obj.*
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
import com.github.libretube.obj.StreamItem
import com.github.libretube.obj.Streams
import com.github.libretube.obj.SearchResult
interface PipedApi {
@GET("trending")
@ -29,4 +26,11 @@ interface PipedApi {
@GET("nextpage/channel/{channelId}")
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
}

View 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)
}
}

View File

@ -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 {
}
}

View File

@ -103,6 +103,12 @@ class CustomViewHolder1(private val v: View): RecyclerView.ViewHolder(v){
playlistChannelName.text = item.uploaderName
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_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) {

View File

@ -8,6 +8,6 @@ data class Playlist(
var uploader: String? = null,
var uploaderUrl: String? = null,
var uploaderAvatar: String? = null,
var videos: Int = 0,
var videos: Int? = 0,
var relatedStreams: List<StreamItem>? = null,
)

View 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>

View File

@ -45,4 +45,13 @@
android:name="channel_id"
app:argType="string" />
</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>

View File

@ -6,7 +6,7 @@ buildscript {
}
dependencies {
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
// in the individual module build.gradle files