aboutsummaryrefslogtreecommitdiff
path: root/src/android
diff options
context:
space:
mode:
authorNixyn <contact@innix.space>2025-09-15 06:26:06 +0200
committercrueter <crueter@eden-emu.dev>2025-09-15 06:26:06 +0200
commit4c5d03f5defedd6decf2dfbbaca93a518e6d0adc (patch)
tree22feb5e9d52db8386ce1c3d53801a80fa22ac9af /src/android
parentd207df959a29cc4758c5328a3cdc96d909a96c92 (diff)
[android / GameUI] Add grid compact layout and fix ugly borders on grid layout (#401)
Tis PR adds a new layout for the Game Adapter with shorter cards and fixes the ugly borders in Game Adapter's Grid layout. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/401 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev> Co-authored-by: Nixyn <contact@innix.space> Co-committed-by: Nixyn <contact@innix.space>
Diffstat (limited to 'src/android')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt46
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt13
-rw-r--r--src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml9
-rw-r--r--src/android/app/src/main/res/layout/card_game_grid.xml15
-rw-r--r--src/android/app/src/main/res/layout/card_game_grid_compact.xml82
-rw-r--r--src/android/app/src/main/res/menu/menu_game_views.xml3
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
7 files changed, 161 insertions, 8 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
index 98f342c274..0a2cb41745 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
@@ -36,17 +36,18 @@ import androidx.core.net.toUri
import androidx.core.content.edit
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
+import org.yuzu.yuzu_emu.databinding.CardGameGridCompactBinding
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
-import org.yuzu.yuzu_emu.utils.NativeConfig
class GameAdapter(private val activity: AppCompatActivity) :
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
companion object {
const val VIEW_TYPE_GRID = 0
- const val VIEW_TYPE_LIST = 1
- const val VIEW_TYPE_CAROUSEL = 2
+ const val VIEW_TYPE_GRID_COMPACT = 1
+ const val VIEW_TYPE_LIST = 2
+ const val VIEW_TYPE_CAROUSEL = 3
}
private var viewType = 0
@@ -80,6 +81,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
listBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
listBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
}
+
VIEW_TYPE_GRID -> {
val gridBinding = holder.binding as CardGameGridBinding
gridBinding.cardGameGrid.scaleX = 1f
@@ -89,6 +91,17 @@ class GameAdapter(private val activity: AppCompatActivity) :
gridBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
gridBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
}
+
+ VIEW_TYPE_GRID_COMPACT -> {
+ val gridCompactBinding = holder.binding as CardGameGridCompactBinding
+ gridCompactBinding.cardGameGridCompact.scaleX = 1f
+ gridCompactBinding.cardGameGridCompact.scaleY = 1f
+ gridCompactBinding.cardGameGridCompact.alpha = 1f
+ // Reset layout params to XML defaults (same as normal grid)
+ gridCompactBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
+ gridCompactBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ }
+
VIEW_TYPE_CAROUSEL -> {
val carouselBinding = holder.binding as CardGameCarouselBinding
// soothens transient flickering
@@ -105,16 +118,25 @@ class GameAdapter(private val activity: AppCompatActivity) :
parent,
false
)
+
VIEW_TYPE_GRID -> CardGameGridBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
+
+ VIEW_TYPE_GRID_COMPACT -> CardGameGridCompactBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+
VIEW_TYPE_CAROUSEL -> CardGameCarouselBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
+
else -> throw IllegalArgumentException("Invalid view type")
}
return GameViewHolder(binding, viewType)
@@ -130,6 +152,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
VIEW_TYPE_LIST -> bindListView(model)
VIEW_TYPE_GRID -> bindGridView(model)
VIEW_TYPE_CAROUSEL -> bindCarouselView(model)
+ VIEW_TYPE_GRID_COMPACT -> bindGridCompactView(model)
}
}
@@ -168,6 +191,23 @@ class GameAdapter(private val activity: AppCompatActivity) :
gridBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
}
+ private fun bindGridCompactView(model: Game) {
+ val gridCompactBinding = binding as CardGameGridCompactBinding
+
+ gridCompactBinding.imageGameScreenCompact.scaleType = ImageView.ScaleType.CENTER_CROP
+ GameIconUtils.loadGameIcon(model, gridCompactBinding.imageGameScreenCompact)
+
+ gridCompactBinding.textGameTitleCompact.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
+
+ gridCompactBinding.textGameTitleCompact.marquee()
+ gridCompactBinding.cardGameGridCompact.setOnClickListener { onClick(model) }
+ gridCompactBinding.cardGameGridCompact.setOnLongClickListener { onLongClick(model) }
+
+ // Reset layout params to XML defaults (same as normal grid)
+ gridCompactBinding.root.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
+ gridCompactBinding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ }
+
private fun bindCarouselView(model: Game) {
val carouselBinding = binding as CardGameCarouselBinding
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
index 03fa1a3a2e..80055628e1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
@@ -194,6 +194,10 @@ class GamesFragment : Fragment() {
val columns = resources.getInteger(R.integer.game_columns_grid)
GridLayoutManager(context, columns)
}
+ GameAdapter.VIEW_TYPE_GRID_COMPACT -> {
+ val columns = resources.getInteger(R.integer.game_columns_grid)
+ GridLayoutManager(context, columns)
+ }
GameAdapter.VIEW_TYPE_LIST -> {
val columns = resources.getInteger(R.integer.game_columns_list)
GridLayoutManager(context, columns)
@@ -300,6 +304,7 @@ class GamesFragment : Fragment() {
val currentViewType = getCurrentViewType()
when (currentViewType) {
GameAdapter.VIEW_TYPE_LIST -> popup.menu.findItem(R.id.view_list).isChecked = true
+ GameAdapter.VIEW_TYPE_GRID_COMPACT -> popup.menu.findItem(R.id.view_grid_compact).isChecked = true
GameAdapter.VIEW_TYPE_GRID -> popup.menu.findItem(R.id.view_grid).isChecked = true
GameAdapter.VIEW_TYPE_CAROUSEL -> popup.menu.findItem(R.id.view_carousel).isChecked = true
}
@@ -314,6 +319,14 @@ class GamesFragment : Fragment() {
true
}
+ R.id.view_grid_compact -> {
+ if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause()
+ setCurrentViewType(GameAdapter.VIEW_TYPE_GRID_COMPACT)
+ applyGridGamesBinding()
+ item.isChecked = true
+ true
+ }
+
R.id.view_list -> {
if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause()
setCurrentViewType(GameAdapter.VIEW_TYPE_LIST)
diff --git a/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml b/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml
new file mode 100644
index 0000000000..f74cfa0d05
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/gradient_overlay_bottom.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:angle="270"
+ android:startColor="@android:color/transparent"
+ android:centerColor="#66000000"
+ android:endColor="#AA000000"
+ android:type="linear" />
+</shape>
diff --git a/src/android/app/src/main/res/layout/card_game_grid.xml b/src/android/app/src/main/res/layout/card_game_grid.xml
index 3e0bf6005c..f03a77c4f1 100644
--- a/src/android/app/src/main/res/layout/card_game_grid.xml
+++ b/src/android/app/src/main/res/layout/card_game_grid.xml
@@ -5,27 +5,32 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
- android:focusableInTouchMode="false">
+ android:focusableInTouchMode="false"
+ android:padding="4dp">
<org.yuzu.yuzu_emu.views.GradientBorderCardView
android:id="@+id/card_game_grid"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/eden_card_background"
- app:strokeWidth="1dp"
- app:strokeColor="@color/eden_border"
+ app:strokeWidth="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:layout_margin="4dp"
android:clickable="true"
android:clipToPadding="true"
android:focusable="true"
android:transitionName="card_game"
- app:cardCornerRadius="16dp">
+ app:cardCornerRadius="16dp"
+ android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="6dp">
+ android:paddingTop="14dp"
+ android:paddingLeft="6dp"
+ android:paddingRight="6dp"
+ android:paddingBottom="6dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image_game_screen"
diff --git a/src/android/app/src/main/res/layout/card_game_grid_compact.xml b/src/android/app/src/main/res/layout/card_game_grid_compact.xml
new file mode 100644
index 0000000000..bb86595d5c
--- /dev/null
+++ b/src/android/app/src/main/res/layout/card_game_grid_compact.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout 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="wrap_content"
+ android:focusable="false"
+ android:focusableInTouchMode="false"
+ android:padding="4dp">
+
+ <org.yuzu.yuzu_emu.views.GradientBorderCardView
+ android:id="@+id/card_game_grid_compact"
+ app:cardElevation="0dp"
+ app:cardBackgroundColor="@color/eden_card_background"
+ app:strokeWidth="0dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_margin="4dp"
+ android:clickable="true"
+ android:clipToPadding="true"
+ android:focusable="true"
+ android:transitionName="card_game_compact"
+ app:cardCornerRadius="16dp"
+ android:foreground="@color/eden_border_gradient_start">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="14dp"
+ android:paddingLeft="6dp"
+ android:paddingRight="6dp"
+ android:paddingBottom="6dp">
+
+ <FrameLayout
+ android:id="@+id/image_container"
+ android:layout_width="150dp"
+ android:layout_height="100dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <com.google.android.material.imageview.ShapeableImageView
+ android:id="@+id/image_game_screen_compact"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
+ android:scaleType="centerCrop"
+ tools:src="@drawable/default_icon" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/gradient_overlay_bottom" />
+
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_game_title_compact"
+ style="@style/SynthwaveText.Body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_margin="6dp"
+ android:requiresFadingEdge="horizontal"
+ android:textAlignment="center"
+ android:textSize="12sp"
+ android:textStyle="bold"
+ android:textColor="@android:color/white"
+ android:shadowColor="@android:color/black"
+ android:shadowDx="1"
+ android:shadowDy="1"
+ android:shadowRadius="2"
+ android:maxLines="2"
+ android:ellipsize="end"
+ tools:text="The Legend of Zelda: Skyward Sword" />
+
+ </FrameLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ </org.yuzu.yuzu_emu.views.GradientBorderCardView>
+
+</FrameLayout>
diff --git a/src/android/app/src/main/res/menu/menu_game_views.xml b/src/android/app/src/main/res/menu/menu_game_views.xml
index 241cdcb4b5..11bf3e695e 100644
--- a/src/android/app/src/main/res/menu/menu_game_views.xml
+++ b/src/android/app/src/main/res/menu/menu_game_views.xml
@@ -5,6 +5,9 @@
android:id="@+id/view_grid"
android:title="@string/view_grid"/>
<item
+ android:id="@+id/view_grid_compact"
+ android:title="@string/view_grid_compact"/>
+ <item
android:id="@+id/view_list"
android:title="@string/view_list"
android:checked="true"/>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 2c7923d5a3..20c6e85b6c 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -266,6 +266,7 @@
<string name="alphabetical">Alphabetical</string>
<string name="view_list">List</string>
<string name="view_grid">Grid</string>
+ <string name="view_grid_compact">Compact Grid</string>
<string name="view_carousel">Carousel</string>
<string name="game_image_desc">Screenshot for %1$s</string>
<string name="folder">Folder</string>