added more gameids to download covers and additional game info

This commit is contained in:
izzy2lost
2025-10-25 06:53:17 -04:00
parent ac1949de1d
commit eed0cb4344
5 changed files with 87770 additions and 169 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -4,15 +4,24 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.izzy2lost.weeu.common.ui.components.ScreenContent
import com.izzy2lost.weeu.common.ui.localization.regionToString
import com.izzy2lost.weeu.common.ui.localization.tr
import com.izzy2lost.weeu.gamelist.cover.GameTitleMapper
import com.izzy2lost.weeu.nativeinterface.NativeGameTitles.Game
import java.time.LocalDate
import java.time.format.DateTimeFormatter
@@ -23,23 +32,81 @@ fun GameDetailsScreen(game: Game?, navigateBack: () -> Unit) {
if (game == null)
return
val context = LocalContext.current
var gameInfo by remember { mutableStateOf<GameInfo?>(null) }
LaunchedEffect(game.titleId) {
GameTitleMapper.initialize(context)
val titleIdHex = game.titleId.toString(16).uppercase().padStart(16, '0')
val gameId = GameTitleMapper.getGameCodeFromTitleId(titleIdHex)
if (gameId != null) {
gameInfo = GameInfoLoader.loadGameInfo(context, gameId)
}
}
ScreenContent(
appBarText = tr("About title"),
contentModifier = Modifier.padding(16.dp),
contentModifier = Modifier
.padding(16.dp)
.verticalScroll(rememberScrollState()),
contentVerticalArrangement = Arrangement.spacedBy(16.dp),
navigateBack = navigateBack,
) {
GameDetails(game)
GameDetails(game, gameInfo)
}
}
@Composable
fun GameDetails(game: Game) {
fun GameDetails(game: Game, gameInfo: GameInfo?) {
GameIcon(
game = game,
modifier = Modifier.size(128.dp),
)
TitleDetailsEntry(entryName = tr("Title name"), entryData = game.name)
// Game database information
if (gameInfo != null) {
gameInfo.title?.let {
TitleDetailsEntry(entryName = tr("Title"), entryData = it)
}
gameInfo.developer?.let {
TitleDetailsEntry(entryName = tr("Developer"), entryData = it)
}
gameInfo.publisher?.let {
TitleDetailsEntry(entryName = tr("Publisher"), entryData = it)
}
gameInfo.releaseDate?.let {
TitleDetailsEntry(entryName = tr("Release Date"), entryData = it)
}
gameInfo.genre?.let {
TitleDetailsEntry(entryName = tr("Genre"), entryData = it)
}
gameInfo.rating?.let {
TitleDetailsEntry(entryName = tr("Rating"), entryData = it)
}
if (gameInfo.ratingDescriptors.isNotEmpty()) {
TitleDetailsEntry(
entryName = tr("Content Descriptors"),
entryData = gameInfo.ratingDescriptors.joinToString(", ")
)
}
gameInfo.players?.let {
TitleDetailsEntry(entryName = tr("Players"), entryData = it)
}
gameInfo.wifiPlayers?.let {
TitleDetailsEntry(entryName = tr("Wi-Fi Players"), entryData = it)
}
if (gameInfo.wifiFeatures.isNotEmpty()) {
TitleDetailsEntry(
entryName = tr("Wi-Fi Features"),
entryData = gameInfo.wifiFeatures.joinToString(", ")
)
}
gameInfo.synopsis?.let {
TitleDetailsEntry(entryName = tr("Synopsis"), entryData = it)
}
}
// Local game information
TitleDetailsEntry(entryName = tr("Title ID"), entryData = game.titleId)
TitleDetailsEntry(entryName = tr("Version"), entryData = game.version)
TitleDetailsEntry(entryName = tr("DLC"), entryData = game.dlc)
@@ -0,0 +1,208 @@
package com.izzy2lost.weeu.gamelist
import android.content.Context
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
import java.io.InputStreamReader
data class GameInfo(
val id: String,
val title: String?,
val synopsis: String?,
val developer: String?,
val publisher: String?,
val releaseDate: String?,
val genre: String?,
val rating: String?,
val ratingDescriptors: List<String>,
val players: String?,
val wifiPlayers: String?,
val wifiFeatures: List<String>
)
object GameInfoLoader {
private var gameInfoCache: MutableMap<String, GameInfo> = mutableMapOf()
fun loadGameInfo(context: Context, gameId: String): GameInfo? {
// Check cache first
if (gameInfoCache.containsKey(gameId)) {
return gameInfoCache[gameId]
}
try {
val inputStream = context.assets.open("wiiutdb.xml")
val reader = InputStreamReader(inputStream)
val factory = XmlPullParserFactory.newInstance()
val parser = factory.newPullParser()
parser.setInput(reader)
var eventType = parser.eventType
var currentGameId: String? = null
var title: String? = null
var synopsis: String? = null
var developer: String? = null
var publisher: String? = null
var releaseDate: String? = null
var genre: String? = null
var rating: String? = null
val ratingDescriptors = mutableListOf<String>()
var players: String? = null
var wifiPlayers: String? = null
val wifiFeatures = mutableListOf<String>()
var inGame = false
var inLocale = false
var inRating = false
var inWifi = false
var inInput = false
while (eventType != XmlPullParser.END_DOCUMENT) {
when (eventType) {
XmlPullParser.START_TAG -> {
when (parser.name) {
"game" -> {
inGame = true
// Reset values for new game
currentGameId = null
title = null
synopsis = null
developer = null
publisher = null
releaseDate = null
genre = null
rating = null
ratingDescriptors.clear()
players = null
wifiPlayers = null
wifiFeatures.clear()
}
"id" -> {
if (inGame) {
parser.next()
currentGameId = parser.text
}
}
"locale" -> {
if (inGame && parser.getAttributeValue(null, "lang") == "EN") {
inLocale = true
}
}
"title" -> {
if (inLocale) {
parser.next()
title = parser.text
}
}
"synopsis" -> {
if (inLocale) {
parser.next()
synopsis = parser.text
}
}
"developer" -> {
if (inGame) {
parser.next()
developer = parser.text
}
}
"publisher" -> {
if (inGame) {
parser.next()
publisher = parser.text
}
}
"date" -> {
if (inGame) {
val year = parser.getAttributeValue(null, "year")
val month = parser.getAttributeValue(null, "month")
val day = parser.getAttributeValue(null, "day")
releaseDate = "$year-$month-$day"
}
}
"genre" -> {
if (inGame) {
parser.next()
genre = parser.text
}
}
"rating" -> {
if (inGame) {
inRating = true
val type = parser.getAttributeValue(null, "type")
val value = parser.getAttributeValue(null, "value")
rating = "$type: $value"
}
}
"descriptor" -> {
if (inRating) {
parser.next()
parser.text?.let { ratingDescriptors.add(it) }
}
}
"wi-fi" -> {
if (inGame) {
inWifi = true
wifiPlayers = parser.getAttributeValue(null, "players")
}
}
"feature" -> {
if (inWifi) {
parser.next()
parser.text?.let { wifiFeatures.add(it) }
}
}
"input" -> {
if (inGame) {
inInput = true
players = parser.getAttributeValue(null, "players")
}
}
}
}
XmlPullParser.END_TAG -> {
when (parser.name) {
"game" -> {
// Check if this is the game we're looking for
if (currentGameId == gameId) {
val gameInfo = GameInfo(
id = currentGameId,
title = title,
synopsis = synopsis,
developer = developer,
publisher = publisher,
releaseDate = releaseDate,
genre = genre,
rating = rating,
ratingDescriptors = ratingDescriptors.toList(),
players = players,
wifiPlayers = wifiPlayers,
wifiFeatures = wifiFeatures.toList()
)
gameInfoCache[gameId] = gameInfo
reader.close()
return gameInfo
}
inGame = false
}
"locale" -> inLocale = false
"rating" -> inRating = false
"wi-fi" -> inWifi = false
"input" -> inInput = false
}
}
}
eventType = parser.next()
}
reader.close()
} catch (e: Exception) {
println("Error loading game info for $gameId: ${e.message}")
e.printStackTrace()
}
return null
}
fun clearCache() {
gameInfoCache.clear()
}
}