diff --git a/app/src/main/java/com/github/libretube/PipedApi.kt b/app/src/main/java/com/github/libretube/PipedApi.kt index 94c2a65b5..3442f1d32 100644 --- a/app/src/main/java/com/github/libretube/PipedApi.kt +++ b/app/src/main/java/com/github/libretube/PipedApi.kt @@ -22,6 +22,13 @@ interface PipedApi { @Query("filter") filter: String ): SearchResult + @GET("nextpage/search") + suspend fun getSearchResultsNextPage( + @Query("q") searchQuery: String, + @Query("filter") filter: String, + @Query("nextpage") nextPage: String + ): SearchResult + @GET("suggestions") suspend fun getSuggestions(@Query("query") query: String): List diff --git a/app/src/main/java/com/github/libretube/SearchFragment.kt b/app/src/main/java/com/github/libretube/SearchFragment.kt index 19f96ee23..fc5279753 100644 --- a/app/src/main/java/com/github/libretube/SearchFragment.kt +++ b/app/src/main/java/com/github/libretube/SearchFragment.kt @@ -12,11 +12,10 @@ import android.view.ViewGroup import android.view.WindowManager import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager -import android.widget.ArrayAdapter -import android.widget.AutoCompleteTextView -import android.widget.ImageView +import android.widget.* import android.widget.TextView.* import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContentProviderCompat.requireContext import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager @@ -31,11 +30,13 @@ import kotlinx.coroutines.launch import retrofit2.HttpException import java.io.IOException - -private var selectedFilter = 0 - class SearchFragment : Fragment() { private val TAG = "SearchFragment" + private var selectedFilter = 0 + private var nextPage : String? = null + private lateinit var searchRecView : RecyclerView + private var searchAdapter : SearchAdapter? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { @@ -54,7 +55,7 @@ class SearchFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val recyclerView = view.findViewById(R.id.search_recycler) + searchRecView = view.findViewById(R.id.search_recycler) val autoTextView = view.findViewById(R.id.autoCompleteTextView) @@ -73,7 +74,7 @@ class SearchFragment : Fragment() { }) .setPositiveButton(getString(R.string.okay), DialogInterface.OnClickListener { _, _ -> selectedFilter = tempSelectedItem - fetchSearch(autoTextView.text.toString(), recyclerView) + fetchSearch(autoTextView.text.toString()) }) .setNegativeButton(getString(R.string.cancel), null) .create() @@ -82,7 +83,7 @@ class SearchFragment : Fragment() { //show search history - recyclerView.visibility = GONE + searchRecView.visibility = GONE historyRecycler.visibility = VISIBLE historyRecycler.layoutManager = LinearLayoutManager(view.context) @@ -93,7 +94,7 @@ class SearchFragment : Fragment() { SearchHistoryAdapter(requireContext(), historylist, autoTextView) } - recyclerView.layoutManager = GridLayoutManager(view.context, 1) + searchRecView.layoutManager = GridLayoutManager(view.context, 1) autoTextView.requestFocus() val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager @@ -110,24 +111,30 @@ class SearchFragment : Fragment() { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { if (s!! != "") { - recyclerView.visibility = VISIBLE + searchRecView.visibility = VISIBLE historyRecycler.visibility = GONE - recyclerView.adapter = null + searchRecView.adapter = null + + searchRecView.viewTreeObserver + .addOnScrollChangedListener { + if (!searchRecView.canScrollVertically(1)) { + fetchNextSearchItems(autoTextView.text.toString()) + } + + } GlobalScope.launch { fetchSuggestions(s.toString(), autoTextView) delay(1000) addtohistory(s.toString()) - fetchSearch(s.toString(), recyclerView) + fetchSearch(s.toString()) } - - } } override fun afterTextChanged(s: Editable?) { if (s!!.isEmpty()) { - recyclerView.visibility = GONE + searchRecView.visibility = GONE historyRecycler.visibility = VISIBLE var historylist = getHistory() if (historylist.size != 0) { @@ -167,10 +174,10 @@ class SearchFragment : Fragment() { autoTextView.setAdapter(adapter) } } - private fun fetchSearch(query: String, recyclerView: RecyclerView){ + private fun fetchSearch(query: String){ lifecycleScope.launchWhenCreated { val response = try { - RetrofitInstance.api.getSearchResults(query, "all") + RetrofitInstance.api.getSearchResults(query, "videos") } catch (e: IOException) { println(e) Log.e(TAG, "IOException, you might not have internet connection $e") @@ -179,15 +186,34 @@ class SearchFragment : Fragment() { Log.e(TAG, "HttpException, unexpected response") return@launchWhenCreated } + nextPage = response.nextpage if(response.items!!.isNotEmpty()){ runOnUiThread { - recyclerView.adapter = SearchAdapter(response.items, selectedFilter) + searchAdapter = SearchAdapter(response.items, selectedFilter) + searchRecView.adapter = searchAdapter } } } } + private fun fetchNextSearchItems(query: String){ + lifecycleScope.launchWhenCreated { + val response = try { + RetrofitInstance.api.getSearchResultsNextPage(query!!, "videos", 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 + searchAdapter?.updateItems(response.items!!) + } + } + private fun Fragment?.runOnUiThread(action: () -> Unit) { this ?: return if (!isAdded) return // Fragment not attached to an Activity diff --git a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt index f49ce4931..bf99aecf9 100644 --- a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt @@ -14,6 +14,7 @@ import com.github.libretube.MainActivity import com.github.libretube.PlayerFragment import com.github.libretube.R import com.github.libretube.formatShort +import com.github.libretube.obj.Comment import com.github.libretube.obj.SearchItem import com.squareup.picasso.Picasso import kotlinx.coroutines.NonDisposableHandle.parent @@ -22,7 +23,13 @@ private var showVideos = true private var showChannels = true private var showPlaylists = true -class SearchAdapter(private val searchItems: List, private val selectedFilter : Int): RecyclerView.Adapter() { +class SearchAdapter(private val searchItems: MutableList, private val selectedFilter : Int): RecyclerView.Adapter() { + + fun updateItems(newItems: List){ + var searchItemsSize = searchItems.size + searchItems.addAll(newItems) + notifyItemRangeInserted(searchItemsSize, newItems.size) + } override fun getItemCount(): Int { return searchItems.size diff --git a/app/src/main/java/com/github/libretube/obj/SearchResult.kt b/app/src/main/java/com/github/libretube/obj/SearchResult.kt index 297619799..13172c9a9 100644 --- a/app/src/main/java/com/github/libretube/obj/SearchResult.kt +++ b/app/src/main/java/com/github/libretube/obj/SearchResult.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties @JsonIgnoreProperties(ignoreUnknown = true) data class SearchResult( - val items: List? = listOf(), + val items: MutableList? = arrayListOf(), val nextpage: String? ="", val suggestion: String?="", val corrected: Boolean? = null