Merge pull request 'Update manager fix' (#8) from XITRIX/MeloNX:Update-manager-fix into XC-ios-ht

Reviewed-on: MeloNX/MeloNX#8
This commit is contained in:
stossy11 2025-02-16 20:14:58 +00:00
commit b3bb9cefcf
4 changed files with 198 additions and 183 deletions

View File

@ -14,7 +14,10 @@ struct GameInfoSheet: View {
var body: some View {
iOSNav {
VStack {
List {
Section {}
header: {
VStack(alignment: .center) {
if let icon = game.icon {
Image(uiImage: icon)
.resizable()
@ -36,23 +39,27 @@ struct GameInfoSheet: View {
.frame(width: 150, height: 150)
.padding()
}
VStack(alignment: .leading) {
VStack(alignment: .leading) {
VStack(alignment: .center) {
Text("**\(game.titleName)** | \(game.titleId.capitalized)")
.multilineTextAlignment(.center)
Text(game.developer)
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 3)
}
.frame(maxWidth: .infinity)
}
VStack(alignment: .leading, spacing: 5) {
Text("Information")
.font(.title2)
.bold()
Text("**Version:** \(game.version)")
Text("**Title ID:** \(game.titleId)")
Section {
HStack {
Text("**Version**")
Spacer()
Text(game.version)
.foregroundStyle(Color.secondary)
}
HStack {
Text("**Title ID**")
.contextMenu {
Button {
UIPasteboard.general.string = game.titleId
@ -60,15 +67,32 @@ struct GameInfoSheet: View {
Text("Copy Title ID")
}
}
Text("**Game Size:** \(fetchFileSize(for: game.fileURL) ?? 0) bytes")
Text("**File Type:** .\(getFileType(game.fileURL))")
Text("**Game URL:** \(trimGameURL(game.fileURL))")
}
}
Spacer()
Text(game.titleId)
.foregroundStyle(Color.secondary)
}
HStack {
Text("**Game Size**")
Spacer()
Text("\(fetchFileSize(for: game.fileURL) ?? 0) bytes")
.foregroundStyle(Color.secondary)
}
HStack {
Text("**File Type**")
Spacer()
Text(getFileType(game.fileURL))
.foregroundStyle(Color.secondary)
}
VStack(alignment: .leading, spacing: 4) {
Text("**Game URL**")
Text(trimGameURL(game.fileURL))
.foregroundStyle(Color.secondary)
}
} header: {
Text("Information")
}
.headerProminence(.increased)
}
.padding(.horizontal, 5)
.navigationTitle(game.titleName)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
@ -103,10 +127,6 @@ struct GameInfoSheet: View {
}
func getFileType(_ url: URL) -> String {
let path = url.path
if let range = path.range(of: ".") {
return String(path[range.upperBound...])
}
return "Unknown"
url.pathExtension
}
}

View File

@ -48,15 +48,7 @@ struct GameLibraryView: View {
var body: some View {
iOSNav {
ScrollView {
LazyVStack(alignment: .leading, spacing: 20) {
if !isSearching {
Text("Games")
.font(.system(size: 34, weight: .bold))
.padding(.horizontal)
.padding(.top, 12)
}
List {
if Ryujinx.shared.games.isEmpty {
VStack(spacing: 16) {
Image(systemName: "gamecontroller.fill")
@ -108,7 +100,6 @@ struct GameLibraryView: View {
}
}
} else {
LazyVStack(spacing: 2) {
ForEach(filteredGames) { game in
GameListRow(game: game, startemu: $startemu, games: games, isViewingGameInfo: $isViewingGameInfo, isSelectingGameUpdate: $isSelectingGameUpdate, gameInfo: $gameInfo)
.onTapGesture {
@ -118,7 +109,8 @@ struct GameLibraryView: View {
}
}
}
}
.navigationTitle("Games")
.navigationBarTitleDisplayMode(.large)
.onAppear {
loadRecentGames()
@ -143,9 +135,8 @@ struct GameLibraryView: View {
print(error)
}
}
}
.toolbar {
ToolbarItem(placement: .topBarLeading) {
ToolbarItem(placement: .topBarTrailing) {
Button {
isSelectingGameFile.toggle()
} label: {
@ -215,7 +206,6 @@ struct GameLibraryView: View {
}
}
}
.background(Color(.systemGroupedBackground))
.searchable(text: $searchText)
.onChange(of: searchText) { _ in
isSearching = !searchText.isEmpty
@ -296,7 +286,6 @@ struct GameLibraryView: View {
}
}
private func addToRecentGames(_ game: Game) {
recentGames.removeAll { $0.id == game.id }
@ -329,7 +318,6 @@ struct GameLibraryView: View {
}
}
// MARK: - Delete Game Function
func deleteGame(game: Game) {
let fileManager = FileManager.default
@ -474,9 +462,6 @@ struct GameListRow: View {
.foregroundColor(.accentColor)
.opacity(0.8)
}
.padding(.horizontal)
.padding(.vertical, 8)
.background(Color(.systemBackground))
.contextMenu {
Section {
Button {
@ -533,4 +518,3 @@ struct GameListRow: View {
}
}
}

View File

@ -18,16 +18,22 @@ struct UpdateManagerSheet: View {
var body: some View {
NavigationView {
VStack {
List(paths, id: \..self) { item in
List(paths, id: \..self, selection: $selectedItem) { item in
Button(action: {
selectItem(item.lastPathComponent)
}) {
HStack {
Text(item.lastPathComponent)
if selectedItem == "\(game!.titleId)/\(item.lastPathComponent)" {
.foregroundStyle(Color(uiColor: .label))
Spacer()
Image(systemName: "checkmark")
if selectedItem == "updates/\(game!.titleId)/\(item.lastPathComponent)" {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(Color.accentColor)
.font(.system(size: 24))
} else {
Image(systemName: "circle")
.foregroundStyle(Color(uiColor: .secondaryLabel))
.font(.system(size: 24))
}
}
}
@ -39,15 +45,15 @@ struct UpdateManagerSheet: View {
}
}
}
}
.onAppear() {
.onAppear {
print(URL.documentsDirectory.appendingPathComponent("games").appendingPathComponent(game!.titleId).appendingPathComponent("updates.json"))
loadJSON(URL.documentsDirectory.appendingPathComponent("games").appendingPathComponent(game!.titleId).appendingPathComponent("updates.json"))
}
.navigationTitle("\(game!.titleName) Updates")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
Button("+") {
Button("Add", systemImage: "plus") {
isSelectingGameUpdate = true
}
}
@ -80,7 +86,8 @@ struct UpdateManagerSheet: View {
let destinationURL = romUpdatedDirectory.appendingPathComponent(url.lastPathComponent)
try? fileManager.copyItem(at: url, to: destinationURL)
Ryujinx.shared.setTitleUpdate(titleId: gameInfo.titleId, updatePath: "\(gameInfo.titleId)/" + url.lastPathComponent)
items.append("updates/" + gameInfo.titleId + "/" + url.lastPathComponent)
selectItem(url.lastPathComponent)
Ryujinx.shared.games = Ryujinx.shared.loadGames()
loadJSON(jsonURL!)
} catch {
@ -93,7 +100,7 @@ struct UpdateManagerSheet: View {
}
func removeUpdate(_ game: URL) {
let gameString = "\(self.game!.titleId)/\(game.lastPathComponent)"
let gameString = "updates/\(self.game!.titleId)/\(game.lastPathComponent)"
paths.removeAll { $0 == game }
items.removeAll { $0 == gameString }
@ -108,6 +115,7 @@ struct UpdateManagerSheet: View {
}
saveJSON(selectedItem: selectedItem ?? "")
Ryujinx.shared.games = Ryujinx.shared.loadGames()
}
func saveJSON(selectedItem: String) {
@ -122,26 +130,28 @@ struct UpdateManagerSheet: View {
}
func loadJSON(_ json: URL) {
self.jsonURL = json
print("Failed to read JSO")
guard let jsonURL = jsonURL else { return }
print("Failed to read JSOK")
guard let jsonURL else { return }
do {
let data = try Data(contentsOf: jsonURL)
if let jsonDict = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let list = jsonDict["paths"] as? [String] {
var urls: [URL] = []
let list = jsonDict["paths"] as? [String]
{
for path in list {
urls.append(URL.documentsDirectory.appendingPathComponent("updates").appendingPathComponent(path))
let filteredList = list.filter { relativePath in
let path = URL.documentsDirectory.appendingPathComponent(relativePath)
return FileManager.default.fileExists(atPath: path.path)
}
self.items = list
self.paths = urls
self.selectedItem = jsonDict["selected"] as? String
let urls: [URL] = filteredList.map { relativePath in
URL.documentsDirectory.appendingPathComponent(relativePath)
}
items = filteredList
paths = urls
selectedItem = jsonDict["selected"] as? String
}
} catch {
print("Failed to read JSON: \(error)")
@ -155,17 +165,17 @@ struct UpdateManagerSheet: View {
do {
let newData = try JSONSerialization.data(withJSONObject: defaultData, options: .prettyPrinted)
try newData.write(to: jsonURL)
self.items = []
self.selectedItem = ""
items = []
selectedItem = ""
} catch {
print("Failed to create default JSON: \(error)")
}
}
func selectItem(_ item: String) {
let newSelection = "\(game!.titleId)/\(item)"
let newSelection = "updates/\(game!.titleId)/\(item)"
guard let jsonURL = jsonURL else { return }
guard let jsonURL else { return }
do {
let data = try Data(contentsOf: jsonURL)
@ -175,7 +185,7 @@ struct UpdateManagerSheet: View {
jsonDict["selected"] = ""
selectedItem = ""
} else {
jsonDict["selected"] = newSelection
jsonDict["selected"] = "\(newSelection)"
selectedItem = newSelection
}
@ -183,9 +193,9 @@ struct UpdateManagerSheet: View {
let newData = try JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
try newData.write(to: jsonURL)
Ryujinx.shared.games = Ryujinx.shared.loadGames()
} catch {
print("Failed to update JSON: \(error)")
}
}
}

View File

@ -751,7 +751,8 @@ namespace Ryujinx.Headless.SDL2
if (File.Exists(titleUpdateMetadataPath))
{
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected;
string updatePathRelative = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected;
updatePath = Path.Combine(AppDataManager.BaseDirPath, updatePathRelative);
if (File.Exists(updatePath))
{