committed by
bunnei
20 changed files with 551 additions and 189 deletions
-
10src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
-
5src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt
-
222src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
-
2src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
-
3src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
-
7src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
-
14src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
-
116src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
-
43src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
-
4src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
-
15src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
-
9src/android/app/src/main/res/drawable/ic_clear.xml
-
9src/android/app/src/main/res/drawable/ic_search.xml
-
1src/android/app/src/main/res/layout/activity_main.xml
-
74src/android/app/src/main/res/layout/fragment_games.xml
-
180src/android/app/src/main/res/layout/fragment_search.xml
-
5src/android/app/src/main/res/menu/menu_navigation.xml
-
5src/android/app/src/main/res/navigation/home_navigation.xml
-
7src/android/app/src/main/res/values/dimens.xml
-
9src/android/app/src/main/res/values/strings.xml
@ -0,0 +1,222 @@ |
|||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
package org.yuzu.yuzu_emu.fragments |
||||
|
|
||||
|
import android.content.Context |
||||
|
import android.content.SharedPreferences |
||||
|
import android.os.Bundle |
||||
|
import android.view.LayoutInflater |
||||
|
import android.view.View |
||||
|
import android.view.ViewGroup |
||||
|
import android.view.inputmethod.InputMethodManager |
||||
|
import androidx.appcompat.app.AppCompatActivity |
||||
|
import androidx.core.view.ViewCompat |
||||
|
import androidx.core.view.WindowInsetsCompat |
||||
|
import androidx.core.view.updatePadding |
||||
|
import androidx.core.widget.doOnTextChanged |
||||
|
import androidx.fragment.app.Fragment |
||||
|
import androidx.fragment.app.activityViewModels |
||||
|
import androidx.preference.PreferenceManager |
||||
|
import info.debatty.java.stringsimilarity.Jaccard |
||||
|
import org.yuzu.yuzu_emu.R |
||||
|
import org.yuzu.yuzu_emu.YuzuApplication |
||||
|
import org.yuzu.yuzu_emu.adapters.GameAdapter |
||||
|
import org.yuzu.yuzu_emu.databinding.FragmentSearchBinding |
||||
|
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager |
||||
|
import org.yuzu.yuzu_emu.model.Game |
||||
|
import org.yuzu.yuzu_emu.model.GamesViewModel |
||||
|
import org.yuzu.yuzu_emu.model.HomeViewModel |
||||
|
import org.yuzu.yuzu_emu.utils.FileUtil |
||||
|
import org.yuzu.yuzu_emu.utils.Log |
||||
|
import java.util.Locale |
||||
|
|
||||
|
class SearchFragment : Fragment() { |
||||
|
private var _binding: FragmentSearchBinding? = null |
||||
|
private val binding get() = _binding!! |
||||
|
|
||||
|
private val gamesViewModel: GamesViewModel by activityViewModels() |
||||
|
private val homeViewModel: HomeViewModel by activityViewModels() |
||||
|
|
||||
|
private lateinit var preferences: SharedPreferences |
||||
|
|
||||
|
companion object { |
||||
|
private const val SEARCH_TEXT = "SearchText" |
||||
|
} |
||||
|
|
||||
|
override fun onCreateView( |
||||
|
inflater: LayoutInflater, |
||||
|
container: ViewGroup?, |
||||
|
savedInstanceState: Bundle? |
||||
|
): View { |
||||
|
_binding = FragmentSearchBinding.inflate(layoutInflater) |
||||
|
return binding.root |
||||
|
} |
||||
|
|
||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
|
homeViewModel.setNavigationVisibility(visible = true, animated = false) |
||||
|
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) |
||||
|
|
||||
|
if (savedInstanceState != null) { |
||||
|
binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT)) |
||||
|
} |
||||
|
|
||||
|
gamesViewModel.searchFocused.observe(viewLifecycleOwner) { searchFocused -> |
||||
|
if (searchFocused) { |
||||
|
focusSearch() |
||||
|
gamesViewModel.setSearchFocused(false) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
binding.gridGamesSearch.apply { |
||||
|
layoutManager = AutofitGridLayoutManager( |
||||
|
requireContext(), |
||||
|
requireContext().resources.getDimensionPixelSize(R.dimen.card_width) |
||||
|
) |
||||
|
adapter = GameAdapter(requireActivity() as AppCompatActivity) |
||||
|
} |
||||
|
|
||||
|
binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() } |
||||
|
|
||||
|
binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int -> |
||||
|
if (text.toString().isNotEmpty()) { |
||||
|
binding.clearButton.visibility = View.VISIBLE |
||||
|
} else { |
||||
|
binding.clearButton.visibility = View.INVISIBLE |
||||
|
} |
||||
|
filterAndSearch() |
||||
|
} |
||||
|
|
||||
|
gamesViewModel.games.observe(viewLifecycleOwner) { filterAndSearch() } |
||||
|
gamesViewModel.searchedGames.observe(viewLifecycleOwner) { |
||||
|
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it) |
||||
|
if (it.isEmpty()) { |
||||
|
binding.noResultsView.visibility = View.VISIBLE |
||||
|
} else { |
||||
|
binding.noResultsView.visibility = View.GONE |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
binding.clearButton.setOnClickListener { binding.searchText.setText("") } |
||||
|
|
||||
|
binding.searchBackground.setOnClickListener { focusSearch() } |
||||
|
|
||||
|
setInsets() |
||||
|
filterAndSearch() |
||||
|
} |
||||
|
|
||||
|
private inner class ScoredGame(val score: Double, val item: Game) |
||||
|
|
||||
|
private fun filterAndSearch() { |
||||
|
val baseList = gamesViewModel.games.value!! |
||||
|
val filteredList: List<Game> = when (binding.chipGroup.checkedChipId) { |
||||
|
R.id.chip_recently_played -> { |
||||
|
baseList.filter { |
||||
|
val lastPlayedTime = preferences.getLong(it.keyLastPlayedTime, 0L) |
||||
|
lastPlayedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
R.id.chip_recently_added -> { |
||||
|
baseList.filter { |
||||
|
val addedTime = preferences.getLong(it.keyAddedToLibraryTime, 0L) |
||||
|
addedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
R.id.chip_homebrew -> { |
||||
|
baseList.filter { |
||||
|
Log.error("Guh - ${it.path}") |
||||
|
FileUtil.hasExtension(it.path, "nro") |
||||
|
|| FileUtil.hasExtension(it.path, "nso") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
R.id.chip_retail -> baseList.filter { |
||||
|
FileUtil.hasExtension(it.path, "xci") |
||||
|
|| FileUtil.hasExtension(it.path, "nsp") |
||||
|
} |
||||
|
|
||||
|
else -> baseList |
||||
|
} |
||||
|
|
||||
|
if (binding.searchText.text.toString().isEmpty() |
||||
|
&& binding.chipGroup.checkedChipId != View.NO_ID) { |
||||
|
gamesViewModel.setSearchedGames(filteredList) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
val searchTerm = binding.searchText.text.toString().lowercase(Locale.getDefault()) |
||||
|
val searchAlgorithm = Jaccard(2) |
||||
|
val sortedList: List<Game> = filteredList.mapNotNull { game -> |
||||
|
val title = game.title.lowercase(Locale.getDefault()) |
||||
|
val score = searchAlgorithm.similarity(searchTerm, title) |
||||
|
if (score > 0.03) { |
||||
|
ScoredGame(score, game) |
||||
|
} else { |
||||
|
null |
||||
|
} |
||||
|
}.sortedByDescending { it.score }.map { it.item } |
||||
|
gamesViewModel.setSearchedGames(sortedList) |
||||
|
} |
||||
|
|
||||
|
override fun onDestroyView() { |
||||
|
super.onDestroyView() |
||||
|
_binding = null |
||||
|
} |
||||
|
|
||||
|
override fun onSaveInstanceState(outState: Bundle) { |
||||
|
super.onSaveInstanceState(outState) |
||||
|
if (_binding != null) { |
||||
|
outState.putString(SEARCH_TEXT, binding.searchText.text.toString()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private fun focusSearch() { |
||||
|
if (_binding != null) { |
||||
|
binding.searchText.requestFocus() |
||||
|
val imm = |
||||
|
requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? |
||||
|
imm?.showSoftInput(binding.searchText, InputMethodManager.SHOW_IMPLICIT) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private fun setInsets() = |
||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> |
||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) |
||||
|
val extraListSpacing = resources.getDimensionPixelSize(R.dimen.spacing_med) |
||||
|
val navigationSpacing = resources.getDimensionPixelSize(R.dimen.spacing_navigation) |
||||
|
val chipSpacing = resources.getDimensionPixelSize(R.dimen.spacing_chip) |
||||
|
|
||||
|
binding.frameSearch.updatePadding( |
||||
|
left = insets.left, |
||||
|
top = insets.top, |
||||
|
right = insets.right |
||||
|
) |
||||
|
|
||||
|
binding.gridGamesSearch.setPadding( |
||||
|
insets.left, |
||||
|
extraListSpacing, |
||||
|
insets.right, |
||||
|
insets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_navigation) + extraListSpacing |
||||
|
) |
||||
|
|
||||
|
binding.noResultsView.updatePadding( |
||||
|
left = insets.left, |
||||
|
right = insets.right, |
||||
|
bottom = insets.bottom + navigationSpacing |
||||
|
) |
||||
|
|
||||
|
val mlpDivider = binding.divider.layoutParams as ViewGroup.MarginLayoutParams |
||||
|
mlpDivider.leftMargin = insets.left + chipSpacing |
||||
|
mlpDivider.rightMargin = insets.right + chipSpacing |
||||
|
binding.divider.layoutParams = mlpDivider |
||||
|
|
||||
|
binding.chipGroup.updatePadding( |
||||
|
left = insets.left + chipSpacing, |
||||
|
right = insets.right + chipSpacing |
||||
|
) |
||||
|
|
||||
|
windowInsets |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24"> |
||||
|
<path |
||||
|
android:fillColor="?attr/colorControlNormal" |
||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" /> |
||||
|
</vector> |
||||
@ -0,0 +1,9 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24"> |
||||
|
<path |
||||
|
android:fillColor="?attr/colorControlNormal" |
||||
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" /> |
||||
|
</vector> |
||||
@ -1,74 +1,34 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout |
|
||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
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" |
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/coordinator_main" |
|
||||
|
android:id="@+id/swipe_refresh" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
android:layout_height="match_parent" |
||||
android:background="?attr/colorSurface"> |
|
||||
|
android:background="?attr/colorSurface" |
||||
|
android:clipToPadding="false"> |
||||
|
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout |
|
||||
android:id="@+id/swipe_refresh" |
|
||||
|
<RelativeLayout |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
|
||||
android:clipToPadding="false" |
|
||||
app:layout_behavior="@string/searchbar_scrolling_view_behavior"> |
|
||||
|
android:layout_height="match_parent"> |
||||
|
|
||||
<RelativeLayout |
|
||||
|
<com.google.android.material.textview.MaterialTextView |
||||
|
android:id="@+id/notice_text" |
||||
|
style="@style/TextAppearance.Material3.BodyLarge" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
|
||||
|
|
||||
<com.google.android.material.textview.MaterialTextView |
|
||||
android:id="@+id/notice_text" |
|
||||
style="@style/TextAppearance.Material3.BodyLarge" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:gravity="center" |
|
||||
android:padding="@dimen/spacing_large" |
|
||||
android:text="@string/empty_gamelist" |
|
||||
tools:visibility="gone" /> |
|
||||
|
|
||||
<androidx.recyclerview.widget.RecyclerView |
|
||||
android:id="@+id/grid_games" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:clipToPadding="false" |
|
||||
tools:listitem="@layout/card_game" /> |
|
||||
|
|
||||
</RelativeLayout> |
|
||||
|
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
|
||||
|
|
||||
<com.google.android.material.appbar.AppBarLayout |
|
||||
android:id="@+id/app_bar_search" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:fitsSystemWindows="true" |
|
||||
app:liftOnScrollTargetViewId="@id/grid_games"> |
|
||||
|
|
||||
<com.google.android.material.search.SearchBar |
|
||||
android:id="@+id/search_bar" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="wrap_content" |
|
||||
android:hint="@string/home_search_games" /> |
|
||||
|
|
||||
</com.google.android.material.appbar.AppBarLayout> |
|
||||
|
|
||||
<com.google.android.material.search.SearchView |
|
||||
android:id="@+id/search_view" |
|
||||
android:layout_width="match_parent" |
|
||||
android:layout_height="match_parent" |
|
||||
android:hint="@string/home_search_games" |
|
||||
app:layout_anchor="@id/search_bar"> |
|
||||
|
android:layout_height="match_parent" |
||||
|
android:gravity="center" |
||||
|
android:padding="@dimen/spacing_large" |
||||
|
android:text="@string/empty_gamelist" |
||||
|
tools:visibility="gone" /> |
||||
|
|
||||
<androidx.recyclerview.widget.RecyclerView |
<androidx.recyclerview.widget.RecyclerView |
||||
android:id="@+id/grid_search" |
|
||||
|
android:id="@+id/grid_games" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
android:layout_height="match_parent" |
||||
android:clipToPadding="false" |
android:clipToPadding="false" |
||||
tools:listitem="@layout/card_game" /> |
tools:listitem="@layout/card_game" /> |
||||
|
|
||||
</com.google.android.material.search.SearchView> |
|
||||
|
</RelativeLayout> |
||||
|
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
|
||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> |
||||
@ -0,0 +1,180 @@ |
|||||
|
<?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="match_parent" |
||||
|
android:background="?attr/colorSurface"> |
||||
|
|
||||
|
<RelativeLayout |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@+id/divider"> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:id="@+id/no_results_view" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical" |
||||
|
android:gravity="center"> |
||||
|
|
||||
|
<ImageView |
||||
|
android:id="@+id/icon_no_results" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="80dp" |
||||
|
android:src="@drawable/ic_search" /> |
||||
|
|
||||
|
<com.google.android.material.textview.MaterialTextView |
||||
|
android:id="@+id/notice_text" |
||||
|
style="@style/TextAppearance.Material3.TitleLarge" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:gravity="center" |
||||
|
android:paddingTop="8dp" |
||||
|
android:text="@string/search_and_filter_games" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
<androidx.recyclerview.widget.RecyclerView |
||||
|
android:id="@+id/grid_games_search" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:clipToPadding="false" /> |
||||
|
|
||||
|
</RelativeLayout> |
||||
|
|
||||
|
<FrameLayout |
||||
|
android:id="@+id/frame_search" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_margin="20dp" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toTopOf="parent"> |
||||
|
|
||||
|
<com.google.android.material.card.MaterialCardView |
||||
|
android:id="@+id/search_background" |
||||
|
style="?attr/materialCardViewFilledStyle" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="56dp" |
||||
|
app:cardCornerRadius="28dp"> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:id="@+id/search_container" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:layout_marginStart="24dp" |
||||
|
android:layout_marginEnd="56dp" |
||||
|
android:orientation="horizontal"> |
||||
|
|
||||
|
<ImageView |
||||
|
android:layout_width="28dp" |
||||
|
android:layout_height="28dp" |
||||
|
android:layout_gravity="center_vertical" |
||||
|
android:layout_marginEnd="24dp" |
||||
|
android:src="@drawable/ic_search" |
||||
|
app:tint="?attr/colorOnSurfaceVariant" /> |
||||
|
|
||||
|
<EditText |
||||
|
android:id="@+id/search_text" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:background="@android:color/transparent" |
||||
|
android:hint="@string/home_search_games" |
||||
|
android:inputType="text" |
||||
|
android:maxLines="1" |
||||
|
android:imeOptions="flagNoFullscreen" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
<ImageView |
||||
|
android:id="@+id/clear_button" |
||||
|
android:layout_width="24dp" |
||||
|
android:layout_height="24dp" |
||||
|
android:layout_gravity="center_vertical|end" |
||||
|
android:layout_marginEnd="24dp" |
||||
|
android:background="?attr/selectableItemBackground" |
||||
|
android:src="@drawable/ic_clear" |
||||
|
android:visibility="invisible" |
||||
|
app:tint="?attr/colorOnSurfaceVariant" |
||||
|
tools:visibility="visible" /> |
||||
|
|
||||
|
</com.google.android.material.card.MaterialCardView> |
||||
|
|
||||
|
</FrameLayout> |
||||
|
|
||||
|
<HorizontalScrollView |
||||
|
android:id="@+id/horizontalScrollView" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:fadingEdge="horizontal" |
||||
|
android:scrollbars="none" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@+id/frame_search"> |
||||
|
|
||||
|
<com.google.android.material.chip.ChipGroup |
||||
|
android:id="@+id/chip_group" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:clipToPadding="false" |
||||
|
android:paddingVertical="4dp" |
||||
|
app:chipSpacingHorizontal="12dp" |
||||
|
app:singleLine="true" |
||||
|
app:singleSelection="true"> |
||||
|
|
||||
|
<com.google.android.material.chip.Chip |
||||
|
android:id="@+id/chip_recently_played" |
||||
|
style="@style/Widget.Material3.Chip.Suggestion.Elevated" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:checked="false" |
||||
|
android:text="@string/search_recently_played" |
||||
|
app:chipCornerRadius="28dp" /> |
||||
|
|
||||
|
<com.google.android.material.chip.Chip |
||||
|
android:id="@+id/chip_recently_added" |
||||
|
style="@style/Widget.Material3.Chip.Suggestion.Elevated" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:checked="false" |
||||
|
android:text="@string/search_recently_added" |
||||
|
app:chipCornerRadius="28dp" /> |
||||
|
|
||||
|
<com.google.android.material.chip.Chip |
||||
|
android:id="@+id/chip_retail" |
||||
|
style="@style/Widget.Material3.Chip.Suggestion.Elevated" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:checked="false" |
||||
|
android:text="@string/search_retail" |
||||
|
app:chipCornerRadius="28dp" /> |
||||
|
|
||||
|
<com.google.android.material.chip.Chip |
||||
|
android:id="@+id/chip_homebrew" |
||||
|
style="@style/Widget.Material3.Chip.Suggestion.Elevated" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:checked="false" |
||||
|
android:text="@string/search_homebrew" |
||||
|
app:chipCornerRadius="28dp" /> |
||||
|
|
||||
|
</com.google.android.material.chip.ChipGroup> |
||||
|
|
||||
|
</HorizontalScrollView> |
||||
|
|
||||
|
<com.google.android.material.divider.MaterialDivider |
||||
|
android:id="@+id/divider" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginHorizontal="20dp" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toBottomOf="@+id/horizontalScrollView" /> |
||||
|
|
||||
|
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue