android: Implemented about game dialog (#304)

This feature is accessible by long-pressing on a game card, replacing the old method of accessing the cheats menu

The cheats menu is now accessed from within the about game dialog

Adapted from 69c323289f

Co-authored-by: Ishan09811 <156402647+ishan09811@users.noreply.github.com>
Co-authored-by: kleidis <167202775+kleidis@users.noreply.github.com>
This commit is contained in:
OpenSauce04 2024-07-27 17:14:08 +01:00
parent 1c5ec87069
commit a9dd78b8be
6 changed files with 201 additions and 13 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Lime3DS Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -10,6 +10,8 @@ import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.content.Context
import android.widget.TextView
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
@ -23,6 +25,9 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import io.github.lime3ds.android.HomeNavigationDirections
import io.github.lime3ds.android.LimeApplication
import io.github.lime3ds.android.R
@ -32,8 +37,10 @@ import io.github.lime3ds.android.features.cheats.ui.CheatsFragmentDirections
import io.github.lime3ds.android.model.Game
import io.github.lime3ds.android.utils.GameIconUtils
import io.github.lime3ds.android.viewmodel.GamesViewModel
import io.github.lime3ds.android.features.settings.ui.SettingsActivity
import io.github.lime3ds.android.features.settings.utils.SettingsFile
class GameAdapter(private val activity: AppCompatActivity) :
class GameAdapter(private val activity: AppCompatActivity, private val inflater: LayoutInflater) :
ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()),
View.OnClickListener, View.OnLongClickListener {
private var lastClickTime = 0L
@ -83,7 +90,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
}
/**
* Opens the cheats settings for the game that was clicked on.
* Opens the about game dialog for the game that was clicked on.
*
* @param view The view representing the game the user wants to play.
*/
@ -99,8 +106,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
.setPositiveButton(android.R.string.ok, null)
.show()
} else {
val action = CheatsFragmentDirections.actionGlobalCheatsFragment(holder.game.titleId)
view.findNavController().navigate(action)
showAboutGameDialog(context, holder.game, holder, view)
}
return true
}
@ -156,7 +162,8 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.textGameTitle.text = game.title
binding.textCompany.text = game.company
binding.textFilename.text = game.filename
binding.textGameRegion.text = game.regions
val backgroundColorId =
if (
@ -181,14 +188,45 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.textCompany.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textCompany.isSelected = true
binding.textFilename.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textFilename.isSelected = true
binding.textGameRegion.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textGameRegion.isSelected = true
},
3000
)
}
}
private fun showAboutGameDialog(context: Context, game: Game, holder: GameViewHolder, view: View) {
val bottomSheetView = inflater.inflate(R.layout.dialog_about_game, null)
val bottomSheetDialog = BottomSheetDialog(context)
bottomSheetDialog.setContentView(bottomSheetView)
bottomSheetView.findViewById<TextView>(R.id.about_game_title).text = game.title
bottomSheetView.findViewById<TextView>(R.id.about_game_company).text = game.company
bottomSheetView.findViewById<TextView>(R.id.about_game_region).text = game.regions
bottomSheetView.findViewById<TextView>(R.id.about_game_id).text = "ID: " + String.format("%016X", game.titleId)
bottomSheetView.findViewById<TextView>(R.id.about_game_filename).text = "File: " + game.filename
GameIconUtils.loadGameIcon(activity, game, bottomSheetView.findViewById(R.id.game_icon))
bottomSheetView.findViewById<MaterialButton>(R.id.about_game_play).setOnClickListener {
val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game)
view.findNavController().navigate(action)
}
bottomSheetView.findViewById<MaterialButton>(R.id.cheats).setOnClickListener {
val action = CheatsFragmentDirections.actionGlobalCheatsFragment(holder.game.titleId)
view.findNavController().navigate(action)
bottomSheetDialog.dismiss()
}
val bottomSheetBehavior = bottomSheetDialog.getBehavior()
bottomSheetBehavior.skipCollapsed = true
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
bottomSheetDialog.show()
}
private fun isValidGame(extension: String): Boolean {
return Game.badExtensions.stream()
.noneMatch { extension == it.lowercase() }

View File

@ -60,13 +60,14 @@ class GamesFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
homeViewModel.setNavigationVisibility(visible = true, animated = true)
homeViewModel.setStatusBarShadeVisibility(visible = true)
val inflater = LayoutInflater.from(requireContext())
binding.gridGames.apply {
layoutManager = GridLayoutManager(
requireContext(),
resources.getInteger(R.integer.game_grid_columns)
)
adapter = GameAdapter(requireActivity() as AppCompatActivity)
adapter = GameAdapter(requireActivity() as AppCompatActivity, inflater)
}
binding.swipeRefresh.apply {

View File

@ -71,12 +71,14 @@ class SearchFragment : Fragment() {
binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT))
}
val inflater = LayoutInflater.from(requireContext())
binding.gridGamesSearch.apply {
layoutManager = GridLayoutManager(
requireContext(),
resources.getInteger(R.integer.game_grid_columns)
)
adapter = GameAdapter(requireActivity() as AppCompatActivity)
adapter = GameAdapter(requireActivity() as AppCompatActivity, inflater)
}
binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() }

View File

@ -64,7 +64,7 @@
tools:text="Nintendo" />
<TextView
android:id="@+id/text_filename"
android:id="@+id/text_game_region"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -73,7 +73,7 @@
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="none"
android:requiresFadingEdge="horizontal"
tools:text="Pilotwings_Resort.cxi" />
tools:text="Region" />
</LinearLayout>

View File

@ -0,0 +1,144 @@
<?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="wrap_content"
android:orientation="vertical">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusRight="@id/about_game_play"
android:paddingHorizontal="16dp"
android:paddingBottom="8dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/game_icon"
android:layout_width="140dp"
android:layout_height="140dp"
android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:shapeAppearance="?attr/shapeAppearanceCornerLarge" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="140dp"
app:layout_constraintStart_toEndOf="@id/game_icon"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/about_game_title"
style="?attr/textAppearanceTitleMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Game Title" />
<TextView
android:id="@+id/about_game_company"
style="?attr/textAppearanceBodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/about_game_filename"
app:layout_constraintTop_toBottomOf="@+id/about_game_title"
tools:text="Game Company" />
<TextView
android:id="@+id/about_game_region"
style="?attr/textAppearanceBodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/about_game_title"
app:layout_constraintTop_toBottomOf="@+id/about_game_company"
tools:text="Game Region" />
<TextView
android:id="@+id/about_game_id"
style="?attr/textAppearanceBodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/about_game_filename"
app:layout_constraintTop_toBottomOf="@+id/about_game_region"
tools:text="Game ID" />
<TextView
android:id="@+id/about_game_filename"
style="?attr/textAppearanceBodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/about_game_title"
app:layout_constraintTop_toBottomOf="@+id/about_game_id"
tools:text="Game Filename" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/horizontal_layout"
style="@style/ThemeOverlay.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="start|center"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/game_icon">
<com.google.android.material.button.MaterialButton
android:id="@+id/about_game_play"
style="@style/Widget.Material3.Button.Icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:contentDescription="@string/play"
android:focusedByDefault="true"
android:text="@string/play"
app:icon="@drawable/ic_play" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:id="@+id/game_button_tray"
style="@style/ThemeOverlay.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="start|center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/horizontal_layout">
<com.google.android.material.button.MaterialButton
android:id="@+id/cheats"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/cheats"
android:text="@string/cheats" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@ -432,10 +432,13 @@
<string name="fatal_error">Fatal Error</string>
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
<!-- Disk shader cache -->
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Preparing Shaders</string>
<string name="building_shaders">Building Shaders</string>
<!-- About Game Dialog -->
<string name="play">Play</string>
<!-- Cheats -->
<string name="cheats">Cheats</string>
<string name="cheats_add">Add Cheat</string>