From 78c323c4eb1beb502f1c2b5367ecb8654181c1e0 Mon Sep 17 00:00:00 2001 From: t895 Date: Mon, 8 Jan 2024 00:17:01 -0500 Subject: android: Refactor async diff adapters to use AbstractDiffAdapter --- .../org/yuzu/yuzu_emu/adapters/AddonAdapter.kt | 36 +--- .../org/yuzu/yuzu_emu/adapters/FolderAdapter.kt | 36 +--- .../java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 192 +++++++++------------ 3 files changed, 92 insertions(+), 172 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt index 15c7ca3c9..94c151325 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt @@ -5,48 +5,28 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater import android.view.ViewGroup -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding import org.yuzu.yuzu_emu.model.Addon +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class AddonAdapter : ListAdapter( - AsyncDifferConfig.Builder(DiffCallback()).build() -) { +class AddonAdapter : AbstractDiffAdapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) .also { return AddonViewHolder(it) } } - override fun getItemCount(): Int = currentList.size - - override fun onBindViewHolder(holder: AddonViewHolder, position: Int) = - holder.bind(currentList[position]) - inner class AddonViewHolder(val binding: ListItemAddonBinding) : - RecyclerView.ViewHolder(binding.root) { - fun bind(addon: Addon) { + AbstractViewHolder(binding) { + override fun bind(model: Addon) { binding.root.setOnClickListener { binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked } - binding.title.text = addon.title - binding.version.text = addon.version + binding.title.text = model.title + binding.version.text = model.version binding.addonSwitch.setOnCheckedChangeListener { _, checked -> - addon.enabled = checked + model.enabled = checked } - binding.addonSwitch.isChecked = addon.enabled - } - } - - private class DiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Addon, newItem: Addon): Boolean { - return oldItem == newItem - } - - override fun areContentsTheSame(oldItem: Addon, newItem: Addon): Boolean { - return oldItem == newItem + binding.addonSwitch.isChecked = model.enabled } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt index ab657a7b9..3d8f0bda8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt @@ -8,19 +8,14 @@ import android.text.TextUtils import android.view.LayoutInflater import android.view.ViewGroup import androidx.fragment.app.FragmentActivity -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.databinding.CardFolderBinding import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GamesViewModel +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : - ListAdapter( - AsyncDifferConfig.Builder(DiffCallback()).build() - ) { + AbstractDiffAdapter() { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int @@ -29,18 +24,11 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie .also { return FolderViewHolder(it) } } - override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) = - holder.bind(currentList[position]) - inner class FolderViewHolder(val binding: CardFolderBinding) : - RecyclerView.ViewHolder(binding.root) { - private lateinit var gameDir: GameDir - - fun bind(gameDir: GameDir) { - this.gameDir = gameDir - + AbstractViewHolder(binding) { + override fun bind(model: GameDir) { binding.apply { - path.text = Uri.parse(gameDir.uriString).path + path.text = Uri.parse(model.uriString).path path.postDelayed( { path.isSelected = true @@ -50,7 +38,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie ) buttonEdit.setOnClickListener { - GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir) + GameFolderPropertiesDialogFragment.newInstance(model) .show( activity.supportFragmentManager, GameFolderPropertiesDialogFragment.TAG @@ -58,19 +46,9 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie } buttonDelete.setOnClickListener { - gamesViewModel.removeFolder(this@FolderViewHolder.gameDir) + gamesViewModel.removeFolder(model) } } } } - - private class DiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { - return oldItem == newItem - } - - override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { - return oldItem == newItem - } - } } 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 a578f0de8..e26c2e0ab 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 @@ -9,7 +9,6 @@ import android.graphics.drawable.LayerDrawable import android.net.Uri import android.text.TextUtils import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.Toast @@ -25,10 +24,6 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.preference.PreferenceManager -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -36,122 +31,26 @@ import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.activities.EmulationActivity -import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder import org.yuzu.yuzu_emu.databinding.CardGameBinding import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.utils.GameIconUtils +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class GameAdapter(private val activity: AppCompatActivity) : - ListAdapter(AsyncDifferConfig.Builder(DiffCallback()).build()), - View.OnClickListener, - View.OnLongClickListener { + AbstractDiffAdapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { - // Create a new view. - val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) - binding.cardGame.setOnClickListener(this) - binding.cardGame.setOnLongClickListener(this) - - // Use that view to create a ViewHolder. - return GameViewHolder(binding) - } - - override fun onBindViewHolder(holder: GameViewHolder, position: Int) = - holder.bind(currentList[position]) - - override fun getItemCount(): Int = currentList.size - - /** - * Launches the game that was clicked on. - * - * @param view The card representing the game the user wants to play. - */ - override fun onClick(view: View) { - val holder = view.tag as GameViewHolder - - val gameExists = DocumentFile.fromSingleUri( - YuzuApplication.appContext, - Uri.parse(holder.game.path) - )?.exists() == true - if (!gameExists) { - Toast.makeText( - YuzuApplication.appContext, - R.string.loader_error_file_not_found, - Toast.LENGTH_LONG - ).show() - - ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) - return - } - - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - preferences.edit() - .putLong( - holder.game.keyLastPlayedTime, - System.currentTimeMillis() - ) - .apply() - - val openIntent = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { - action = Intent.ACTION_VIEW - data = Uri.parse(holder.game.path) - } - - activity.lifecycleScope.launch { - withContext(Dispatchers.IO) { - val layerDrawable = ResourcesCompat.getDrawable( - YuzuApplication.appContext.resources, - R.drawable.shortcut, - null - ) as LayerDrawable - layerDrawable.setDrawableByLayerId( - R.id.shortcut_foreground, - GameIconUtils.getGameIcon(activity, holder.game) - .toDrawable(YuzuApplication.appContext.resources) - ) - val inset = YuzuApplication.appContext.resources - .getDimensionPixelSize(R.dimen.icon_inset) - layerDrawable.setLayerInset(1, inset, inset, inset, inset) - val shortcut = - ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) - .setShortLabel(holder.game.title) - .setIcon( - IconCompat.createWithAdaptiveBitmap( - layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) - ) - ) - .setIntent(openIntent) - .build() - ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) - } - } - - val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game, true) - view.findNavController().navigate(action) - } - - override fun onLongClick(view: View): Boolean { - val holder = view.tag as GameViewHolder - val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(holder.game) - view.findNavController().navigate(action) - return true + CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return GameViewHolder(it) } } inner class GameViewHolder(val binding: CardGameBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var game: Game - - init { - binding.cardGame.tag = this - } - - fun bind(game: Game) { - this.game = game - + AbstractViewHolder(binding) { + override fun bind(model: Game) { binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP - GameIconUtils.loadGameIcon(game, binding.imageGameScreen) + GameIconUtils.loadGameIcon(model, binding.imageGameScreen) - binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") + binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") binding.textGameTitle.postDelayed( { @@ -160,16 +59,79 @@ class GameAdapter(private val activity: AppCompatActivity) : }, 3000 ) + + binding.cardGame.setOnClickListener { onClick(model) } + binding.cardGame.setOnLongClickListener { onLongClick(model) } } - } - private class DiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { - return oldItem == newItem + fun onClick(game: Game) { + val gameExists = DocumentFile.fromSingleUri( + YuzuApplication.appContext, + Uri.parse(game.path) + )?.exists() == true + if (!gameExists) { + Toast.makeText( + YuzuApplication.appContext, + R.string.loader_error_file_not_found, + Toast.LENGTH_LONG + ).show() + + ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) + return + } + + val preferences = + PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + preferences.edit() + .putLong( + game.keyLastPlayedTime, + System.currentTimeMillis() + ) + .apply() + + val openIntent = + Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { + action = Intent.ACTION_VIEW + data = Uri.parse(game.path) + } + + activity.lifecycleScope.launch { + withContext(Dispatchers.IO) { + val layerDrawable = ResourcesCompat.getDrawable( + YuzuApplication.appContext.resources, + R.drawable.shortcut, + null + ) as LayerDrawable + layerDrawable.setDrawableByLayerId( + R.id.shortcut_foreground, + GameIconUtils.getGameIcon(activity, game) + .toDrawable(YuzuApplication.appContext.resources) + ) + val inset = YuzuApplication.appContext.resources + .getDimensionPixelSize(R.dimen.icon_inset) + layerDrawable.setLayerInset(1, inset, inset, inset, inset) + val shortcut = + ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) + .setShortLabel(game.title) + .setIcon( + IconCompat.createWithAdaptiveBitmap( + layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) + ) + ) + .setIntent(openIntent) + .build() + ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + } + } + + val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true) + binding.root.findNavController().navigate(action) } - override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { - return oldItem == newItem + fun onLongClick(game: Game): Boolean { + val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game) + binding.root.findNavController().navigate(action) + return true } } } -- cgit v1.2.3