diff options
| author | 2023-03-23 13:26:05 -0400 | |
|---|---|---|
| committer | 2023-06-03 00:05:47 -0700 | |
| commit | 3878c6ced1e25265e1a84f85f23cebbd62ce98b8 (patch) | |
| tree | d73f9e796880e0252cc47e24e656d34c4269d6f4 /src/android | |
| parent | android: Prevent updating empty game list text on invalid view (diff) | |
| download | yuzu-3878c6ced1e25265e1a84f85f23cebbd62ce98b8.tar.gz yuzu-3878c6ced1e25265e1a84f85f23cebbd62ce98b8.tar.xz yuzu-3878c6ced1e25265e1a84f85f23cebbd62ce98b8.zip | |
android: Use autofit grid for games fragment
Diffstat (limited to 'src/android')
3 files changed, 72 insertions, 28 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt new file mode 100644 index 000000000..be5e4c86c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.layout | ||
| 5 | |||
| 6 | import android.content.Context | ||
| 7 | import androidx.recyclerview.widget.GridLayoutManager | ||
| 8 | import androidx.recyclerview.widget.RecyclerView | ||
| 9 | import androidx.recyclerview.widget.RecyclerView.Recycler | ||
| 10 | import org.yuzu.yuzu_emu.R | ||
| 11 | |||
| 12 | /** | ||
| 13 | * Cut down version of the solution provided here | ||
| 14 | * https://stackoverflow.com/questions/26666143/recyclerview-gridlayoutmanager-how-to-auto-detect-span-count | ||
| 15 | */ | ||
| 16 | class AutofitGridLayoutManager( | ||
| 17 | context: Context, | ||
| 18 | columnWidth: Int | ||
| 19 | ) : GridLayoutManager(context, 1) { | ||
| 20 | private var columnWidth = 0 | ||
| 21 | private var isColumnWidthChanged = true | ||
| 22 | private var lastWidth = 0 | ||
| 23 | private var lastHeight = 0 | ||
| 24 | |||
| 25 | init { | ||
| 26 | setColumnWidth(checkedColumnWidth(context, columnWidth)) | ||
| 27 | } | ||
| 28 | |||
| 29 | private fun checkedColumnWidth(context: Context, columnWidth: Int): Int { | ||
| 30 | var newColumnWidth = columnWidth | ||
| 31 | if (newColumnWidth <= 0) { | ||
| 32 | newColumnWidth = context.resources.getDimensionPixelSize(R.dimen.spacing_xtralarge) | ||
| 33 | } | ||
| 34 | return newColumnWidth | ||
| 35 | } | ||
| 36 | |||
| 37 | private fun setColumnWidth(newColumnWidth: Int) { | ||
| 38 | if (newColumnWidth > 0 && newColumnWidth != columnWidth) { | ||
| 39 | columnWidth = newColumnWidth | ||
| 40 | isColumnWidthChanged = true | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | override fun onLayoutChildren(recycler: Recycler, state: RecyclerView.State) { | ||
| 45 | val width = width | ||
| 46 | val height = height | ||
| 47 | if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) { | ||
| 48 | val totalSpace: Int = if (orientation == VERTICAL) { | ||
| 49 | width - paddingRight - paddingLeft | ||
| 50 | } else { | ||
| 51 | height - paddingTop - paddingBottom | ||
| 52 | } | ||
| 53 | val spanCount = 1.coerceAtLeast(totalSpace / columnWidth) | ||
| 54 | setSpanCount(spanCount) | ||
| 55 | isColumnWidthChanged = false | ||
| 56 | } | ||
| 57 | lastWidth = width | ||
| 58 | lastHeight = height | ||
| 59 | super.onLayoutChildren(recycler, state) | ||
| 60 | } | ||
| 61 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/platform/PlatformGamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/platform/PlatformGamesFragment.kt index 7b8d7c5a3..998a00847 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/platform/PlatformGamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/platform/PlatformGamesFragment.kt | |||
| @@ -8,22 +8,20 @@ import android.os.Bundle | |||
| 8 | import android.view.LayoutInflater | 8 | import android.view.LayoutInflater |
| 9 | import android.view.View | 9 | import android.view.View |
| 10 | import android.view.ViewGroup | 10 | import android.view.ViewGroup |
| 11 | import android.view.ViewTreeObserver.OnGlobalLayoutListener | ||
| 12 | import androidx.appcompat.app.AppCompatActivity | 11 | import androidx.appcompat.app.AppCompatActivity |
| 13 | import androidx.core.view.ViewCompat | 12 | import androidx.core.view.ViewCompat |
| 14 | import androidx.core.view.WindowInsetsCompat | 13 | import androidx.core.view.WindowInsetsCompat |
| 15 | import androidx.core.view.updatePadding | 14 | import androidx.core.view.updatePadding |
| 16 | import androidx.fragment.app.Fragment | 15 | import androidx.fragment.app.Fragment |
| 17 | import androidx.recyclerview.widget.GridLayoutManager | ||
| 18 | import com.google.android.material.color.MaterialColors | 16 | import com.google.android.material.color.MaterialColors |
| 19 | import org.yuzu.yuzu_emu.R | 17 | import org.yuzu.yuzu_emu.R |
| 20 | import org.yuzu.yuzu_emu.YuzuApplication | 18 | import org.yuzu.yuzu_emu.YuzuApplication |
| 21 | import org.yuzu.yuzu_emu.adapters.GameAdapter | 19 | import org.yuzu.yuzu_emu.adapters.GameAdapter |
| 22 | import org.yuzu.yuzu_emu.databinding.FragmentGridBinding | 20 | import org.yuzu.yuzu_emu.databinding.FragmentGridBinding |
| 21 | import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | ||
| 23 | 22 | ||
| 24 | class PlatformGamesFragment : Fragment(), PlatformGamesView { | 23 | class PlatformGamesFragment : Fragment(), PlatformGamesView { |
| 25 | private val presenter = PlatformGamesPresenter(this) | 24 | private val presenter = PlatformGamesPresenter(this) |
| 26 | private var adapter: GameAdapter? = null | ||
| 27 | 25 | ||
| 28 | private var _binding: FragmentGridBinding? = null | 26 | private var _binding: FragmentGridBinding? = null |
| 29 | private val binding get() = _binding!! | 27 | private val binding get() = _binding!! |
| @@ -39,27 +37,12 @@ class PlatformGamesFragment : Fragment(), PlatformGamesView { | |||
| 39 | } | 37 | } |
| 40 | 38 | ||
| 41 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 42 | adapter = GameAdapter(requireActivity() as AppCompatActivity) | 40 | binding.gridGames.apply { |
| 43 | 41 | layoutManager = AutofitGridLayoutManager( | |
| 44 | // Organize our grid layout based on the current view. | 42 | requireContext(), |
| 45 | if (isAdded) { | 43 | requireContext().resources.getDimensionPixelSize(R.dimen.card_width) |
| 46 | view.viewTreeObserver | 44 | ) |
| 47 | .addOnGlobalLayoutListener(object : OnGlobalLayoutListener { | 45 | adapter = GameAdapter(requireActivity() as AppCompatActivity) |
| 48 | override fun onGlobalLayout() { | ||
| 49 | if (view.measuredWidth == 0) { | ||
| 50 | return | ||
| 51 | } | ||
| 52 | var columns = view.measuredWidth / | ||
| 53 | requireContext().resources.getDimensionPixelSize(R.dimen.card_width) | ||
| 54 | if (columns == 0) { | ||
| 55 | columns = 1 | ||
| 56 | } | ||
| 57 | view.viewTreeObserver.removeOnGlobalLayoutListener(this) | ||
| 58 | val layoutManager = GridLayoutManager(activity, columns) | ||
| 59 | binding.gridGames.layoutManager = layoutManager | ||
| 60 | binding.gridGames.adapter = adapter | ||
| 61 | } | ||
| 62 | }) | ||
| 63 | } | 46 | } |
| 64 | 47 | ||
| 65 | // Add swipe down to refresh gesture | 48 | // Add swipe down to refresh gesture |
| @@ -92,8 +75,8 @@ class PlatformGamesFragment : Fragment(), PlatformGamesView { | |||
| 92 | } | 75 | } |
| 93 | 76 | ||
| 94 | override fun showGames(games: Cursor) { | 77 | override fun showGames(games: Cursor) { |
| 95 | if (adapter != null) { | 78 | if (binding.gridGames.adapter != null) { |
| 96 | adapter!!.swapCursor(games) | 79 | (binding.gridGames.adapter as GameAdapter).swapCursor(games) |
| 97 | } | 80 | } |
| 98 | updateTextView() | 81 | updateTextView() |
| 99 | } | 82 | } |
| @@ -103,7 +86,7 @@ class PlatformGamesFragment : Fragment(), PlatformGamesView { | |||
| 103 | return | 86 | return |
| 104 | 87 | ||
| 105 | binding.gamelistEmptyText.visibility = | 88 | binding.gamelistEmptyText.visibility = |
| 106 | if (adapter!!.itemCount == 0) View.VISIBLE else View.GONE | 89 | if ((binding.gridGames.adapter as GameAdapter).itemCount == 0) View.VISIBLE else View.GONE |
| 107 | } | 90 | } |
| 108 | 91 | ||
| 109 | private fun setInsets() { | 92 | private fun setInsets() { |
diff --git a/src/android/app/src/main/res/values/dimens.xml b/src/android/app/src/main/res/values/dimens.xml index 0b028a167..5573d6922 100644 --- a/src/android/app/src/main/res/values/dimens.xml +++ b/src/android/app/src/main/res/values/dimens.xml | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | <dimen name="spacing_list">64dp</dimen> | 6 | <dimen name="spacing_list">64dp</dimen> |
| 7 | <dimen name="spacing_fab">72dp</dimen> | 7 | <dimen name="spacing_fab">72dp</dimen> |
| 8 | <dimen name="menu_width">256dp</dimen> | 8 | <dimen name="menu_width">256dp</dimen> |
| 9 | <dimen name="card_width">150dp</dimen> | 9 | <dimen name="card_width">170dp</dimen> |
| 10 | 10 | ||
| 11 | <dimen name="dialog_margin">20dp</dimen> | 11 | <dimen name="dialog_margin">20dp</dimen> |
| 12 | <dimen name="elevated_app_bar">3dp</dimen> | 12 | <dimen name="elevated_app_bar">3dp</dimen> |