diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index 02c33d593..88aad0de5 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index afbdd9bb4..e4b03fa03 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -9,15 +9,18 @@
+
+
+
diff --git a/app/src/main/java/xyz/btcland/libretube/Home.kt b/app/src/main/java/xyz/btcland/libretube/Home.kt
index a8a736feb..c54ab6f0e 100644
--- a/app/src/main/java/xyz/btcland/libretube/Home.kt
+++ b/app/src/main/java/xyz/btcland/libretube/Home.kt
@@ -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(R.id.recview)
recyclerView.layoutManager = GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items))
-
val progressbar = view.findViewById(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>() {}.type
- val trendingList = gson.fromJson>(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)
diff --git a/app/src/main/java/xyz/btcland/libretube/SearchFragment.kt b/app/src/main/java/xyz/btcland/libretube/SearchFragment.kt
index d3081651d..311c3a97e 100644
--- a/app/src/main/java/xyz/btcland/libretube/SearchFragment.kt
+++ b/app/src/main/java/xyz/btcland/libretube/SearchFragment.kt
@@ -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(R.id.search_recycler)
+ recyclerView.layoutManager = GridLayoutManager(view.context, 1)
val autoTextView = view.findViewById(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,8 +113,11 @@ class SearchFragment : Fragment() {
return@launchWhenCreated
}
if(response.items!!.isNotEmpty()){
- print(response!!.items!![0])
+ runOnUiThread {
+ recyclerView.adapter = SearchAdapter(response.items)
+ }
}
+
}
}
companion object {
diff --git a/app/src/main/java/xyz/btcland/libretube/adapters/SearchAdapter.kt b/app/src/main/java/xyz/btcland/libretube/adapters/SearchAdapter.kt
new file mode 100644
index 000000000..108d41d58
--- /dev/null
+++ b/app/src/main/java/xyz/btcland/libretube/adapters/SearchAdapter.kt
@@ -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): RecyclerView.Adapter() {
+ 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(R.id.search_thumbnail)
+ Picasso.get().load(item.thumbnail).into(thumbnailImage)
+ val channelImage = v.findViewById(R.id.search_channel_image)
+ Picasso.get().load(item.uploaderAvatar).into(channelImage)
+ val title = v.findViewById(R.id.search_description)
+ title.text = item.title
+ val views = v.findViewById(R.id.search_views)
+ views.text = item.views.videoViews() +" • "+item.uploadedDate
+ val channelName = v.findViewById(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(R.id.search_channel_image)
+ Picasso.get().load(item.thumbnail).into(channelImage)
+ val channelName = v.findViewById(R.id.search_channel_name)
+ channelName.text = item.name
+ val channelViews = v.findViewById(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(R.id.search_thumbnail)
+ Picasso.get().load(item.thumbnail).into(playlistImage)
+ val playlistNumber = v.findViewById(R.id.search_playlist_number)
+ playlistNumber.text = item.videos.toString()
+ val playlistName = v.findViewById(R.id.search_description)
+ playlistName.text = item.name
+ val playlistChannelName = v.findViewById(R.id.search_name)
+ playlistChannelName.text = item.uploaderName
+ val playlistVideosNumber = v.findViewById(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 -> {
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/xyz/btcland/libretube/TrendingAdapter.kt b/app/src/main/java/xyz/btcland/libretube/adapters/TrendingAdapter.kt
similarity index 90%
rename from app/src/main/java/xyz/btcland/libretube/TrendingAdapter.kt
rename to app/src/main/java/xyz/btcland/libretube/adapters/TrendingAdapter.kt
index 8618dde6e..b67bf516b 100644
--- a/app/src/main/java/xyz/btcland/libretube/TrendingAdapter.kt
+++ b/app/src/main/java/xyz/btcland/libretube/adapters/TrendingAdapter.kt
@@ -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): RecyclerView.Adapter() {
override fun getItemCount(): Int {
@@ -30,13 +33,11 @@ class TrendingAdapter(private val videoFeed: List): RecyclerView.Ada
val channelImage = holder.v.findViewById(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()
diff --git a/app/src/main/java/xyz/btcland/libretube/obj/SearchItem.kt b/app/src/main/java/xyz/btcland/libretube/obj/SearchItem.kt
index 16a330e9d..986c21723 100644
--- a/app/src/main/java/xyz/btcland/libretube/obj/SearchItem.kt
+++ b/app/src/main/java/xyz/btcland/libretube/obj/SearchItem.kt
@@ -2,16 +2,17 @@ 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?,
var duration: Long?,
var views: Long?,
var uploaderVerified: Boolean?,
-//Channel and Playlist attributes
+ //Channel and Playlist attributes
var name: String? = null,
var description: String? = null,
var subscribers: Long? = -1,
diff --git a/app/src/main/res/drawable/ic_playlist.xml b/app/src/main/res/drawable/ic_playlist.xml
new file mode 100644
index 000000000..84a357ccf
--- /dev/null
+++ b/app/src/main/res/drawable/ic_playlist.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/channel_search_row.xml b/app/src/main/res/layout/channel_search_row.xml
new file mode 100644
index 000000000..23ab51b9f
--- /dev/null
+++ b/app/src/main/res/layout/channel_search_row.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
index ffe829031..ab6896c98 100644
--- a/app/src/main/res/layout/fragment_search.xml
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -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" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/video_search_row.xml b/app/src/main/res/layout/video_search_row.xml
new file mode 100644
index 000000000..70d83ba51
--- /dev/null
+++ b/app/src/main/res/layout/video_search_row.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 853721ee9..10dd84224 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,4 +4,5 @@
Hello blank fragment
Choose Quality:
Search
+ SUBSCRIBE
\ No newline at end of file