Search Recyclerview layouts

This commit is contained in:
rimthekid 2022-01-20 15:58:59 +04:00
parent f5aebe4b13
commit b03920d816
13 changed files with 365 additions and 54 deletions

View File

@ -12,7 +12,7 @@
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2021-12-17T12:50:01.440166Z" />
<timeTargetWasSelectedWithDropDown value="2022-01-20T11:48:34.927750Z" />
<runningDeviceTargetsSelectedWithDialog>
<Target>
<type value="RUNNING_DEVICE_TARGET" />

3
.idea/misc.xml generated
View File

@ -9,15 +9,18 @@
<entry key="app/src/main/res/layout-land/fragment_player.xml" value="0.1" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="app/src/main/res/layout/activity_player.xml" value="0.1" />
<entry key="app/src/main/res/layout/channel_search_row.xml" value="0.33" />
<entry key="app/src/main/res/layout/exo_styled_player_control_view.xml" value="0.12" />
<entry key="app/src/main/res/layout/fragment_home.xml" value="0.16" />
<entry key="app/src/main/res/layout/fragment_library.xml" value="0.11956521739130435" />
<entry key="app/src/main/res/layout/fragment_player.xml" value="0.1" />
<entry key="app/src/main/res/layout/fragment_search.xml" value="0.25" />
<entry key="app/src/main/res/layout/fragment_subscriptions.xml" value="0.1" />
<entry key="app/src/main/res/layout/playlist_search_row.xml" value="0.33" />
<entry key="app/src/main/res/layout/styled_quality_list.xml" value="0.15520833333333334" />
<entry key="app/src/main/res/layout/styled_quality_list_item.xml" value="0.15520833333333334" />
<entry key="app/src/main/res/layout/trending_row.xml" value="0.33" />
<entry key="app/src/main/res/layout/video_search_row.xml" value="0.25" />
<entry key="app/src/main/res/menu/action_bar.xml" value="0.2" />
<entry key="app/src/main/res/menu/bottom_menu.xml" value="0.15520833333333334" />
<entry key="app/src/main/res/xml-land/player_scene.xml" value="0.13139329805996472" />

View File

@ -13,8 +13,8 @@ import androidx.recyclerview.widget.RecyclerView
import okhttp3.*
import retrofit2.HttpException
import xyz.btcland.libretube.adapters.TrendingAdapter
import java.io.IOException
import java.lang.Exception
// TODO: Rename parameter arguments, choose names that match
@ -54,7 +54,6 @@ class Home : Fragment() {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
recyclerView.layoutManager = GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items))
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
fetchJson(progressbar,recyclerView)
@ -82,31 +81,7 @@ class Home : Fragment() {
}
private fun fetchJson(progressBar: ProgressBar, recyclerView: RecyclerView) {
//val client = OkHttpClient()
fun run() {
/* val request = Request.Builder()
.url("http://piped-api.alefvanoon.xyz/trending?region=US")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val body = response.body!!.string()
println(body)
val gson = GsonBuilder().create()
val itemType = object : TypeToken<List<Video>>() {}.type
val trendingList = gson.fromJson<List<Video>>(body, itemType)
runOnUiThread {
progressBar.visibility = View.GONE
recyclerView.adapter = TrendingAdapter(trendingList)
}
}
}
})*/
lifecycleScope.launchWhenCreated {
val response = try {
RetrofitInstance.api.getTrending("US")
@ -127,7 +102,7 @@ class Home : Fragment() {
run()
}
fun Fragment?.runOnUiThread(action: () -> Unit) {
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity
activity?.runOnUiThread(action)

View File

@ -11,10 +11,13 @@ import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import retrofit2.HttpException
import xyz.btcland.libretube.adapters.SearchAdapter
import java.io.IOException
// TODO: Rename parameter arguments, choose names that match
@ -51,6 +54,8 @@ class SearchFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<RecyclerView>(R.id.search_recycler)
recyclerView.layoutManager = GridLayoutManager(view.context, 1)
val autoTextView = view.findViewById<AutoCompleteTextView>(R.id.autoCompleteTextView)
autoTextView.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(
@ -64,10 +69,10 @@ class SearchFragment : Fragment() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if(s!! != ""){
lifecycleScope.launchWhenCreated {
GlobalScope.launch {
fetchSuggestions(s.toString(), autoTextView)
delay(2000)
fetchSearch(s.toString())
fetchSearch(s.toString(),recyclerView)
}
}
}
@ -77,10 +82,6 @@ class SearchFragment : Fragment() {
}
})
}
private fun fetchSuggestions(query: String, autoTextView: AutoCompleteTextView){
@ -99,7 +100,7 @@ class SearchFragment : Fragment() {
autoTextView.setAdapter(adapter)
}
}
private fun fetchSearch(query: String){
private fun fetchSearch(query: String, recyclerView: RecyclerView){
lifecycleScope.launchWhenCreated {
val response = try {
RetrofitInstance.api.getSearchResults(query, "all")
@ -112,9 +113,12 @@ class SearchFragment : Fragment() {
return@launchWhenCreated
}
if(response.items!!.isNotEmpty()){
print(response!!.items!![0])
runOnUiThread {
recyclerView.adapter = SearchAdapter(response.items)
}
}
}
}
companion object {
/**

View File

@ -0,0 +1,110 @@
package xyz.btcland.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 android.widget.VideoView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import xyz.btcland.libretube.PlayerFragment
import xyz.btcland.libretube.R
import xyz.btcland.libretube.obj.SearchItem
import xyz.btcland.libretube.obj.StreamItem
import xyz.btcland.libretube.videoViews
class SearchAdapter(private val searchItems: List<SearchItem>): RecyclerView.Adapter<CustomViewHolder1>() {
override fun getItemCount(): Int {
return searchItems.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder1 {
val layout = when (viewType) {
0 -> R.layout.video_search_row
1 -> R.layout.channel_search_row
2 -> R.layout.playlist_search_row
else -> throw IllegalArgumentException("Invalid type")
}
val layoutInflater = LayoutInflater.from(parent.context)
val cell = layoutInflater.inflate(layout,parent,false)
return CustomViewHolder1(cell)
}
override fun onBindViewHolder(holder: CustomViewHolder1, position: Int) {
holder.bind(searchItems[position])
}
override fun getItemViewType(position: Int): Int {
return when {
searchItems[position].url!!.startsWith("/watch",false) -> 0
searchItems[position].url!!.startsWith("/channel",false) -> 1
searchItems[position].url!!.startsWith("/playlist",false) -> 2
else -> 3
}
}
}
class CustomViewHolder1(private val v: View): RecyclerView.ViewHolder(v){
private fun bindWatch(item: SearchItem) {
val thumbnailImage = v.findViewById<ImageView>(R.id.search_thumbnail)
Picasso.get().load(item.thumbnail).into(thumbnailImage)
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
Picasso.get().load(item.uploaderAvatar).into(channelImage)
val title = v.findViewById<TextView>(R.id.search_description)
title.text = item.title
val views = v.findViewById<TextView>(R.id.search_views)
views.text = item.views.videoViews() +""+item.uploadedDate
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
channelName.text = item.uploaderName
v.setOnClickListener{
var bundle = Bundle()
bundle.putString("videoId",item.url!!.replace("/watch?v=",""))
var frag = PlayerFragment()
frag.arguments = bundle
val activity = v.context as AppCompatActivity
activity.supportFragmentManager.beginTransaction()
.remove(PlayerFragment())
.commit()
activity.supportFragmentManager.beginTransaction()
.replace(R.id.container, frag)
.commitNow()
}
}
private fun bindChannel(item: SearchItem) {
val channelImage = v.findViewById<ImageView>(R.id.search_channel_image)
Picasso.get().load(item.thumbnail).into(channelImage)
val channelName = v.findViewById<TextView>(R.id.search_channel_name)
channelName.text = item.name
val channelViews = v.findViewById<TextView>(R.id.search_views)
channelViews.text = item.subscribers.videoViews() + "subscribers • "+ item.videos + " videos"
//todo sub button
}
private fun bindPlaylist(item: SearchItem) {
val playlistImage = v.findViewById<ImageView>(R.id.search_thumbnail)
Picasso.get().load(item.thumbnail).into(playlistImage)
val playlistNumber = v.findViewById<TextView>(R.id.search_playlist_number)
playlistNumber.text = item.videos.toString()
val playlistName = v.findViewById<TextView>(R.id.search_description)
playlistName.text = item.name
val playlistChannelName = v.findViewById<TextView>(R.id.search_name)
playlistChannelName.text = item.uploaderName
val playlistVideosNumber = v.findViewById<TextView>(R.id.search_playlist_videos)
playlistVideosNumber.text = item.videos.toString()+" videos"
}
fun bind(searchItem: SearchItem) {
when {
searchItem.url!!.startsWith("/watch",false) -> bindWatch(searchItem)
searchItem.url!!.startsWith("/channel",false) -> bindChannel(searchItem)
searchItem.url!!.startsWith("/playlist",false) -> bindPlaylist(searchItem)
else -> {
}
}
}
}

View File

@ -1,4 +1,4 @@
package xyz.btcland.libretube
package xyz.btcland.libretube.adapters
import android.os.Bundle
import android.view.LayoutInflater
@ -9,7 +9,10 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import xyz.btcland.libretube.PlayerFragment
import xyz.btcland.libretube.R
import xyz.btcland.libretube.obj.StreamItem
import xyz.btcland.libretube.videoViews
class TrendingAdapter(private val videoFeed: List<StreamItem>): RecyclerView.Adapter<CustomViewHolder>() {
override fun getItemCount(): Int {
@ -30,13 +33,11 @@ class TrendingAdapter(private val videoFeed: List<StreamItem>): RecyclerView.Ada
val channelImage = holder.v.findViewById<ImageView>(R.id.channel_image)
channelImage.setOnClickListener{
println("channel clicked")
//TODO
}
Picasso.get().load(trending.thumbnail).into(thumbnailImage)
Picasso.get().load(trending.uploaderAvatar).into(channelImage)
holder.v.setOnClickListener{
//val intent = Intent(holder.v.context, Player::class.java)
//intent.putExtra("videoId",trending.url.replace("/watch?v=",""))
//holder.v.context.startActivity(intent)
var bundle = Bundle()
bundle.putString("videoId",trending.url!!.replace("/watch?v=",""))
var frag = PlayerFragment()

View File

@ -2,9 +2,10 @@ package xyz.btcland.libretube.obj
data class SearchItem(
var url: String?,
var title: String?,
var thumbnail: String?,
var uploaderName: String?,
//Video only attributes
var title: String?,
var uploaderUrl: String?,
var uploaderAvatar: String?,
var uploadedDate: String?,

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,10h12v2L4,12zM4,6h12v2L4,8zM4,14h8v2L4,16zM14,14v6l5,-3z"/>
</vector>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginBottom="16dp"
>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/search_channel_image"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginStart="32dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/search_channel_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:text="TextView"
android:textColor="#000000"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_channel_image"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/search_views"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_channel_image"
app:layout_constraintTop_toBottomOf="@+id/search_channel_name" />
<Button
android:id="@+id/search_sub_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:background="#00FFFFFF"
android:text="@string/subscribe"
android:textColor="#DC1212"
app:layout_constraintStart_toEndOf="@+id/search_channel_image"
app:layout_constraintTop_toBottomOf="@+id/search_views" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -10,33 +10,22 @@
android:id="@+id/autoCompleteTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="7dp"
android:hint="@string/search_hint"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:minHeight="48dp"
app:layout_constraintEnd_toStartOf="@+id/imageView_Search"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView_Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7dp"
android:src="@drawable/ic_search2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_recycler"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginBottom="16dp"
>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".5"/>
<ImageView
android:id="@+id/search_thumbnail"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintEnd_toStartOf="@+id/guideline"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<RelativeLayout
android:layout_width="100dp"
android:layout_height="0dp"
android:background="#CC000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
>
<TextView
android:id="@+id/search_playlist_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10"
android:textColor="#ECE4E4"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
/>
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_playlist"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_below="@+id/search_playlist_number"
/>
</RelativeLayout>
<TextView
android:id="@+id/search_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="2dp"
android:text="TextView"
android:textColor="#000000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_thumbnail"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/search_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_thumbnail"
app:layout_constraintTop_toBottomOf="@+id/search_description" />
<TextView
android:id="@+id/search_playlist_videos"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="TextView"
android:layout_marginStart="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/search_name" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginBottom="16dp"
android:id="@+id/video_search"
>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".5"/>
<ImageView
android:id="@+id/search_thumbnail"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintEnd_toStartOf="@+id/guideline"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<TextView
android:id="@+id/search_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
android:textColor="#000000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_thumbnail"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/search_views"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_thumbnail"
app:layout_constraintTop_toBottomOf="@+id/search_description" />
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/search_channel_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toBottomOf="@+id/search_views" />
<TextView
android:id="@+id/search_channel_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/search_channel_image"
app:layout_constraintTop_toBottomOf="@+id/search_views" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,4 +4,5 @@
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="choose_quality_dialog">Choose Quality:</string>
<string name="search_hint">Search</string>
<string name="subscribe">SUBSCRIBE</string>
</resources>