Merge pull request #938 from Bnyro/master

search refactor
This commit is contained in:
Bnyro 2022-07-31 23:18:23 +02:00 committed by GitHub
commit e5a748f3f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 308 additions and 314 deletions

View File

@ -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()

View File

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

View File

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

View File

@ -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()
}
}

View File

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

View File

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

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

View File

@ -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"

View File

@ -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"

View File

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