mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 00:10:32 +05:30
commit
e5a748f3f3
@ -17,6 +17,7 @@ import android.view.WindowInsetsController
|
||||
import android.view.WindowManager
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.os.bundleOf
|
||||
@ -46,6 +47,7 @@ class MainActivity : AppCompatActivity() {
|
||||
lateinit var navController: NavController
|
||||
private var startFragmentId = R.id.homeFragment
|
||||
var autoRotationEnabled = false
|
||||
lateinit var searchView: SearchView
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// set the app theme (e.g. Material You)
|
||||
@ -133,6 +135,7 @@ class MainActivity : AppCompatActivity() {
|
||||
// clear backstack if it's the start fragment
|
||||
if (startFragmentId == it.itemId) navController.backQueue.clear()
|
||||
// set menu item on click listeners
|
||||
removeSearchFocus()
|
||||
when (it.itemId) {
|
||||
R.id.homeFragment -> {
|
||||
navController.navigate(R.id.homeFragment)
|
||||
@ -151,10 +154,37 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeSearchFocus() {
|
||||
searchView.setQuery("", false)
|
||||
searchView.clearFocus()
|
||||
searchView.onActionViewCollapsed()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
menuInflater.inflate(R.menu.action_bar, menu)
|
||||
return true
|
||||
|
||||
// stuff for the search in the topBar
|
||||
val searchItem = menu.findItem(R.id.action_search)
|
||||
searchView = searchItem.actionView as SearchView
|
||||
searchView.setMaxWidth(Integer.MAX_VALUE)
|
||||
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("query", query)
|
||||
navController.navigate(R.id.searchResultFragment, bundle)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?): Boolean {
|
||||
val bundle = Bundle()
|
||||
bundle.putString("query", newText)
|
||||
navController.navigate(R.id.searchFragment, bundle)
|
||||
return true
|
||||
}
|
||||
})
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
@ -311,6 +341,9 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
// remove focus from search
|
||||
removeSearchFocus()
|
||||
|
||||
if (binding.mainMotionLayout.progress == 0F) {
|
||||
try {
|
||||
minimizePlayer()
|
||||
|
@ -2,16 +2,14 @@ package com.github.libretube.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.SearchhistoryRowBinding
|
||||
import com.github.libretube.fragments.SearchFragment
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
|
||||
class SearchHistoryAdapter(
|
||||
private var historyList: List<String>,
|
||||
private val editText: EditText,
|
||||
private val searchFragment: SearchFragment
|
||||
private val searchView: SearchView
|
||||
) :
|
||||
RecyclerView.Adapter<SearchHistoryViewHolder>() {
|
||||
|
||||
@ -37,8 +35,7 @@ class SearchHistoryAdapter(
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
editText.setText(historyQuery)
|
||||
searchFragment.fetchSearch(historyQuery)
|
||||
searchView.setQuery(historyQuery, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,13 @@ package com.github.libretube.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.SearchsuggestionRowBinding
|
||||
import com.github.libretube.fragments.SearchFragment
|
||||
|
||||
class SearchSuggestionsAdapter(
|
||||
private var suggestionsList: List<String>,
|
||||
private var editText: EditText,
|
||||
private val searchFragment: SearchFragment
|
||||
private val searchView: SearchView
|
||||
) :
|
||||
RecyclerView.Adapter<SearchSuggestionsViewHolder>() {
|
||||
|
||||
@ -31,8 +29,7 @@ class SearchSuggestionsAdapter(
|
||||
holder.binding.apply {
|
||||
suggestionText.text = suggestion
|
||||
root.setOnClickListener {
|
||||
editText.setText(suggestion)
|
||||
searchFragment.fetchSearch(editText.text.toString())
|
||||
searchView.setQuery(suggestion, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,34 @@
|
||||
package com.github.libretube.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView.GONE
|
||||
import android.widget.TextView.OnEditorActionListener
|
||||
import android.widget.TextView.VISIBLE
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.adapters.SearchAdapter
|
||||
import com.github.libretube.activities.MainActivity
|
||||
import com.github.libretube.adapters.SearchHistoryAdapter
|
||||
import com.github.libretube.adapters.SearchSuggestionsAdapter
|
||||
import com.github.libretube.databinding.FragmentSearchBinding
|
||||
import com.github.libretube.preferences.PreferenceHelper
|
||||
import com.github.libretube.preferences.PreferenceKeys
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import com.github.libretube.util.hideKeyboard
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
class SearchFragment : Fragment() {
|
||||
class SearchFragment() : Fragment() {
|
||||
private val TAG = "SearchFragment"
|
||||
private lateinit var binding: FragmentSearchBinding
|
||||
|
||||
private var apiSearchFilter = "all"
|
||||
private var nextPage: String? = null
|
||||
|
||||
private var searchAdapter: SearchAdapter? = null
|
||||
private var isLoading: Boolean = true
|
||||
private var isFetchingSearch: Boolean = false
|
||||
private var query: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
}
|
||||
query = arguments?.getString("query")
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@ -60,103 +43,26 @@ class SearchFragment : Fragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.clearSearchImageView.setOnClickListener {
|
||||
binding.autoCompleteTextView.text.clear()
|
||||
binding.historyRecycler.adapter = null
|
||||
showHistory()
|
||||
// add the query to the history
|
||||
if (query != null) addToHistory(query!!)
|
||||
|
||||
binding.suggestionsRecycler.layoutManager = LinearLayoutManager(requireContext())
|
||||
// fetch the search or history
|
||||
if (query == null || query == "") showHistory()
|
||||
else fetchSuggestions(query!!)
|
||||
}
|
||||
|
||||
private fun addToHistory(query: String) {
|
||||
val searchHistoryEnabled =
|
||||
PreferenceHelper.getBoolean(PreferenceKeys.SEARCH_HISTORY_TOGGLE, true)
|
||||
if (searchHistoryEnabled && query != "") {
|
||||
PreferenceHelper.saveToSearchHistory(query)
|
||||
}
|
||||
|
||||
binding.filterMenuImageView.setOnClickListener {
|
||||
val filterOptions = arrayOf(
|
||||
getString(R.string.all),
|
||||
getString(R.string.videos),
|
||||
getString(R.string.channels),
|
||||
getString(R.string.playlists),
|
||||
getString(R.string.music_songs),
|
||||
getString(R.string.music_videos),
|
||||
getString(R.string.music_albums),
|
||||
getString(R.string.music_playlists)
|
||||
)
|
||||
|
||||
MaterialAlertDialogBuilder(view.context)
|
||||
.setTitle(getString(R.string.choose_filter))
|
||||
.setItems(filterOptions) { _, id ->
|
||||
apiSearchFilter = when (id) {
|
||||
0 -> "all"
|
||||
1 -> "videos"
|
||||
2 -> "channels"
|
||||
3 -> "playlists"
|
||||
4 -> "music_songs"
|
||||
5 -> "music_videos"
|
||||
6 -> "music_albums"
|
||||
7 -> "music_playlists"
|
||||
else -> "all"
|
||||
}
|
||||
fetchSearch(binding.autoCompleteTextView.text.toString())
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel), null)
|
||||
.show()
|
||||
}
|
||||
|
||||
// show search history
|
||||
binding.historyRecycler.layoutManager = LinearLayoutManager(view.context)
|
||||
showHistory()
|
||||
|
||||
binding.searchRecycler.layoutManager = GridLayoutManager(view.context, 1)
|
||||
binding.autoCompleteTextView.requestFocus()
|
||||
val imm =
|
||||
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(binding.autoCompleteTextView, InputMethodManager.SHOW_IMPLICIT)
|
||||
|
||||
binding.autoCompleteTextView.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
count: Int,
|
||||
after: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
if (s.toString() != "") {
|
||||
binding.searchRecycler.adapter = null
|
||||
|
||||
binding.searchRecycler.viewTreeObserver
|
||||
.addOnScrollChangedListener {
|
||||
if (!binding.searchRecycler.canScrollVertically(1)) {
|
||||
fetchNextSearchItems(binding.autoCompleteTextView.text.toString())
|
||||
}
|
||||
}
|
||||
fetchSuggestions(s.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
if (s!!.isEmpty()) {
|
||||
binding.historyRecycler.adapter = null
|
||||
showHistory()
|
||||
}
|
||||
}
|
||||
})
|
||||
binding.autoCompleteTextView.setOnEditorActionListener(
|
||||
OnEditorActionListener { textView, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH && textView.text.toString() != "") {
|
||||
view.let { context?.hideKeyboard(it) }
|
||||
binding.searchRecycler.visibility = VISIBLE
|
||||
binding.historyRecycler.visibility = GONE
|
||||
fetchSearch(binding.autoCompleteTextView.text.toString())
|
||||
return@OnEditorActionListener true
|
||||
}
|
||||
false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun fetchSuggestions(query: String) {
|
||||
fun run() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
binding.searchRecycler.visibility = GONE
|
||||
binding.historyRecycler.visibility = VISIBLE
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSuggestions(query)
|
||||
} catch (e: IOException) {
|
||||
@ -168,74 +74,28 @@ class SearchFragment : Fragment() {
|
||||
return@launchWhenCreated
|
||||
}
|
||||
// only load the suggestions if the input field didn't get cleared yet
|
||||
if (binding.autoCompleteTextView.text.toString() != "") {
|
||||
val suggestionsAdapter =
|
||||
SearchSuggestionsAdapter(
|
||||
response,
|
||||
binding.autoCompleteTextView,
|
||||
this@SearchFragment
|
||||
)
|
||||
binding.historyRecycler.adapter = suggestionsAdapter
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isFetchingSearch) run()
|
||||
}
|
||||
|
||||
fun fetchSearch(query: String) {
|
||||
runOnUiThread {
|
||||
binding.historyRecycler.visibility = GONE
|
||||
}
|
||||
lifecycleScope.launchWhenCreated {
|
||||
isFetchingSearch = true
|
||||
view?.let { context?.hideKeyboard(it) }
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResults(query, apiSearchFilter)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection $e")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
}
|
||||
nextPage = response.nextpage
|
||||
if (response.items!!.isNotEmpty()) {
|
||||
runOnUiThread {
|
||||
binding.searchRecycler.visibility = VISIBLE
|
||||
searchAdapter = SearchAdapter(response.items, childFragmentManager)
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
}
|
||||
}
|
||||
addToHistory(query)
|
||||
isLoading = false
|
||||
isFetchingSearch = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchNextSearchItems(query: String) {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
if (!isLoading) {
|
||||
isLoading = true
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResultsNextPage(
|
||||
query,
|
||||
apiSearchFilter,
|
||||
nextPage!!
|
||||
val suggestionsAdapter =
|
||||
SearchSuggestionsAdapter(
|
||||
response,
|
||||
(activity as MainActivity).searchView
|
||||
)
|
||||
} 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
|
||||
runOnUiThread {
|
||||
binding.suggestionsRecycler.adapter = suggestionsAdapter
|
||||
}
|
||||
nextPage = response.nextpage
|
||||
searchAdapter?.updateItems(response.items!!)
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
run()
|
||||
}
|
||||
|
||||
private fun showHistory() {
|
||||
val historyList = PreferenceHelper.getSearchHistory()
|
||||
if (historyList.isNotEmpty()) {
|
||||
binding.suggestionsRecycler.adapter =
|
||||
SearchHistoryAdapter(
|
||||
historyList,
|
||||
(activity as MainActivity).searchView
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||
@ -244,35 +104,9 @@ class SearchFragment : Fragment() {
|
||||
activity?.runOnUiThread(action)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
requireActivity().window.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
view?.let { context?.hideKeyboard(it) }
|
||||
}
|
||||
|
||||
private fun showHistory() {
|
||||
binding.searchRecycler.visibility = GONE
|
||||
val historyList = PreferenceHelper.getSearchHistory()
|
||||
if (historyList.isNotEmpty()) {
|
||||
binding.historyRecycler.adapter =
|
||||
SearchHistoryAdapter(
|
||||
historyList,
|
||||
binding.autoCompleteTextView,
|
||||
this
|
||||
)
|
||||
binding.historyRecycler.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun addToHistory(query: String) {
|
||||
val searchHistoryEnabled =
|
||||
PreferenceHelper.getBoolean(PreferenceKeys.SEARCH_HISTORY_TOGGLE, true)
|
||||
if (searchHistoryEnabled && query != "") {
|
||||
PreferenceHelper.saveToSearchHistory(query)
|
||||
}
|
||||
override fun onDestroy() {
|
||||
// remove the backstack entries
|
||||
findNavController().popBackStack(R.id.searchFragment, true)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,128 @@
|
||||
package com.github.libretube.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.adapters.SearchAdapter
|
||||
import com.github.libretube.databinding.FragmentSearchResultBinding
|
||||
import com.github.libretube.util.RetrofitInstance
|
||||
import com.github.libretube.util.hideKeyboard
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
class SearchResultFragment : Fragment() {
|
||||
private val TAG = "SearchResultFragment"
|
||||
private lateinit var binding: FragmentSearchResultBinding
|
||||
|
||||
private lateinit var nextPage: String
|
||||
private var query: String = ""
|
||||
|
||||
private lateinit var searchAdapter: SearchAdapter
|
||||
private var apiSearchFilter: String = "all"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
query = arguments?.getString("query").toString()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentSearchResultBinding.inflate(layoutInflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// filter options
|
||||
binding.filterChipGroup.setOnCheckedStateChangeListener { _, _ ->
|
||||
apiSearchFilter = when (
|
||||
binding.filterChipGroup.checkedChipId
|
||||
) {
|
||||
R.id.chip_all -> "all"
|
||||
R.id.chip_videos -> "videos"
|
||||
R.id.chip_channels -> "channels"
|
||||
R.id.chip_playlists -> "playlists"
|
||||
R.id.chip_music_songs -> "music_songs"
|
||||
R.id.chip_music_videos -> "music_videos"
|
||||
R.id.chip_music_albums -> "music_albums"
|
||||
R.id.chip_music_playlists -> "music_playlists"
|
||||
else -> throw IllegalArgumentException("Filter out of range")
|
||||
}
|
||||
fetchSearch()
|
||||
}
|
||||
|
||||
fetchSearch()
|
||||
|
||||
binding.searchRecycler.viewTreeObserver
|
||||
.addOnScrollChangedListener {
|
||||
if (!binding.searchRecycler.canScrollVertically(1)) {
|
||||
fetchNextSearchItems()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchSearch() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
view?.let { context?.hideKeyboard(it) }
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResults(query, apiSearchFilter)
|
||||
} catch (e: IOException) {
|
||||
println(e)
|
||||
Log.e(TAG, "IOException, you might not have internet connection $e")
|
||||
return@launchWhenCreated
|
||||
} catch (e: HttpException) {
|
||||
Log.e(TAG, "HttpException, unexpected response")
|
||||
return@launchWhenCreated
|
||||
}
|
||||
runOnUiThread {
|
||||
if (response.items?.isNotEmpty() == true) {
|
||||
binding.searchRecycler.layoutManager = LinearLayoutManager(requireContext())
|
||||
searchAdapter = SearchAdapter(response.items, childFragmentManager)
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
}
|
||||
}
|
||||
nextPage = response.nextpage!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchNextSearchItems() {
|
||||
lifecycleScope.launchWhenCreated {
|
||||
val response = try {
|
||||
RetrofitInstance.api.getSearchResultsNextPage(
|
||||
query,
|
||||
apiSearchFilter,
|
||||
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!!
|
||||
kotlin.runCatching {
|
||||
if (response.items?.isNotEmpty() == true) {
|
||||
searchAdapter.updateItems(response.items.toMutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Fragment?.runOnUiThread(action: () -> Unit) {
|
||||
this ?: return
|
||||
if (!isAdded) return // Fragment not attached to an Activity
|
||||
activity?.runOnUiThread(action)
|
||||
}
|
||||
}
|
@ -1,101 +1,14 @@
|
||||
<?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"
|
||||
<FrameLayout 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=".fragments.SearchFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/searchbar_holder"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/suggestions_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_marginVertical="10dp" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/outlinedTextField"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:hintEnabled="false">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/autoCompleteTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:hint="@string/search_hint"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="textFilter|textNoSuggestions"
|
||||
android:maxLines="1"
|
||||
android:padding="12dp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/clearSearch_imageView"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_close" />
|
||||
|
||||
</RelativeLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/filterMenu_imageView"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginTop="25dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_weight="0"
|
||||
android:src="@drawable/ic_filter" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/history_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginVertical="10dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/searchbar_holder" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/searchbar_holder" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
78
app/src/main/res/layout/fragment_search_result.xml
Normal file
78
app/src/main/res/layout/fragment_search_result.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".fragments.SearchFragment">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/filter_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none"
|
||||
app:layout_constraintBottom_toTopOf="@id/recycler_view"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/filter_chip_group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
app:selectionRequired="true"
|
||||
app:singleLine="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_all"
|
||||
style="@style/Chip"
|
||||
android:text="@string/all" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_videos"
|
||||
style="@style/Chip"
|
||||
android:text="@string/videos" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_channels"
|
||||
style="@style/Chip"
|
||||
android:text="@string/channels" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_playlists"
|
||||
style="@style/Chip"
|
||||
android:text="@string/playlists" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_music_songs"
|
||||
style="@style/Chip"
|
||||
android:text="@string/music_songs" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_music_videos"
|
||||
style="@style/Chip"
|
||||
android:text="@string/music_videos" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_music_albums"
|
||||
style="@style/Chip"
|
||||
android:text="@string/music_albums" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_music_playlists"
|
||||
style="@style/Chip"
|
||||
android:text="@string/music_playlists" />
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
</HorizontalScrollView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/search_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp" />
|
||||
|
||||
</LinearLayout>
|
@ -6,7 +6,9 @@
|
||||
android:id="@+id/action_search"
|
||||
android:icon="@drawable/ic_search"
|
||||
android:title="@string/search_hint"
|
||||
app:showAsAction="ifRoom" />
|
||||
app:showAsAction="ifRoom"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
android:focusableInTouchMode="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
|
@ -19,12 +19,17 @@
|
||||
android:id="@+id/libraryFragment"
|
||||
android:name="com.github.libretube.fragments.LibraryFragment"
|
||||
android:label="fragment_library"
|
||||
tools:layout="@layout/fragment_library"></fragment>
|
||||
tools:layout="@layout/fragment_library" />
|
||||
<fragment
|
||||
android:id="@+id/searchFragment"
|
||||
android:name="com.github.libretube.fragments.SearchFragment"
|
||||
android:label="fragment_search"
|
||||
tools:layout="@layout/fragment_search" />
|
||||
<fragment
|
||||
android:id="@+id/searchResultFragment"
|
||||
android:name="com.github.libretube.fragments.SearchResultFragment"
|
||||
android:label="fragment_search"
|
||||
tools:layout="@layout/fragment_search_result" />
|
||||
<fragment
|
||||
android:id="@+id/channelFragment"
|
||||
android:name="com.github.libretube.fragments.ChannelFragment"
|
||||
|
@ -147,4 +147,11 @@
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="Chip" parent="Widget.Material3.Chip.Suggestion">
|
||||
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
|
||||
</style>
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user