android: Create custom game icon loader

master
Charles Lombardo 2023-08-12 19:09:30 +07:00
parent 44bce11853
commit 270f430f70
2 changed files with 79 additions and 22 deletions

@ -3,8 +3,6 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
@ -15,23 +13,20 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder
import org.yuzu.yuzu_emu.databinding.CardGameBinding import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.GameIconUtils
class GameAdapter(private val activity: AppCompatActivity) : class GameAdapter(private val activity: AppCompatActivity) :
ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()),
@ -98,12 +93,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
this.game = game this.game = game
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
activity.lifecycleScope.launch { GameIconUtils.loadGameIcon(game, binding.imageGameScreen)
val bitmap = decodeGameIcon(game.path)
binding.imageGameScreen.load(bitmap) {
error(R.drawable.default_icon)
}
}
binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ")
@ -126,14 +116,4 @@ class GameAdapter(private val activity: AppCompatActivity) :
return oldItem == newItem return oldItem == newItem
} }
} }
private fun decodeGameIcon(uri: String): Bitmap? {
val data = NativeLibrary.getIcon(uri)
return BitmapFactory.decodeByteArray(
data,
0,
data.size,
BitmapFactory.Options()
)
}
} }

@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.ImageView
import androidx.core.graphics.drawable.toDrawable
import coil.ImageLoader
import coil.decode.DataSource
import coil.fetch.DrawableResult
import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.key.Keyer
import coil.memory.MemoryCache
import coil.request.ImageRequest
import coil.request.Options
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game
class GameIconFetcher(
private val game: Game,
private val options: Options
) : Fetcher {
override suspend fun fetch(): FetchResult {
return DrawableResult(
drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources),
isSampled = false,
dataSource = DataSource.DISK
)
}
private fun decodeGameIcon(uri: String): Bitmap? {
val data = NativeLibrary.getIcon(uri)
return BitmapFactory.decodeByteArray(
data,
0,
data.size,
BitmapFactory.Options()
)
}
class Factory : Fetcher.Factory<Game> {
override fun create(data: Game, options: Options, imageLoader: ImageLoader): Fetcher =
GameIconFetcher(data, options)
}
}
class GameIconKeyer : Keyer<Game> {
override fun key(data: Game, options: Options): String = data.path
}
object GameIconUtils {
private val imageLoader = ImageLoader.Builder(YuzuApplication.appContext)
.components {
add(GameIconKeyer())
add(GameIconFetcher.Factory())
}
.memoryCache {
MemoryCache.Builder(YuzuApplication.appContext)
.maxSizePercent(0.25)
.build()
}
.build()
fun loadGameIcon(game: Game, imageView: ImageView) {
val request = ImageRequest.Builder(YuzuApplication.appContext)
.data(game)
.target(imageView)
.error(R.drawable.default_icon)
.build()
imageLoader.enqueue(request)
}
}