From a98398791adc2c1a5839dbd89e9b7b333f327519 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 30 Apr 2026 15:55:43 +0000 Subject: [PATCH] swift reworks --- src/ios/AppUI.swift | 10 ++ src/ios/EmulationHandler.swift | 4 +- src/ios/EmulationView.swift | 6 +- src/ios/GameButtonView.swift | 172 +++++++++--------------- src/ios/LibraryView.swift | 239 ++++++++++----------------------- src/ios/PomeloApp.swift | 24 +--- src/yuzu/Info.plist | 2 +- 7 files changed, 154 insertions(+), 303 deletions(-) diff --git a/src/ios/AppUI.swift b/src/ios/AppUI.swift index 4aff2db905..6a134bef72 100644 --- a/src/ios/AppUI.swift +++ b/src/ios/AppUI.swift @@ -6,6 +6,7 @@ import UIKit import Foundation import QuartzCore.CAMetalLayer +import SwiftUI public struct AppUI { public static let shared = AppUI() @@ -101,3 +102,12 @@ public struct AppUI { appUIObjC.settingsChanged() } } + +struct EdenApp: App { + @StateObject private var core = EmulationViewModel() + var body: some Scene { + WindowGroup { + ContentView(core: core) + } + } +} \ No newline at end of file diff --git a/src/ios/EmulationHandler.swift b/src/ios/EmulationHandler.swift index 4db9de1fdb..7ad8457881 100644 --- a/src/ios/EmulationHandler.swift +++ b/src/ios/EmulationHandler.swift @@ -8,7 +8,7 @@ import SwiftUI import Metal import Foundation -class EmulationViewModel: ObservableObject { +class EmulationSessionViewModel: ObservableObject { @Published var isShowingCustomButton = true @State var should = false var device: MTLDevice? @@ -93,4 +93,4 @@ class EmulationViewModel: ObservableObject { return .unknown } } -} +} \ No newline at end of file diff --git a/src/ios/EmulationView.swift b/src/ios/EmulationView.swift index 55131d1d02..e1e4745fcd 100644 --- a/src/ios/EmulationView.swift +++ b/src/ios/EmulationView.swift @@ -349,7 +349,7 @@ class Haptics { struct ButtonView: View { var button: VirtualControllerButtonType - @StateObject private var viewModel: EmulationViewModel = EmulationViewModel(game: nil) + @StateObject private var viewModel: EmulationViewModel = EmulationViewModel() let appui = AppUI.shared @State var mtkView: MTKView? @State var width: CGFloat = 45 @@ -446,7 +446,7 @@ struct EmulationView: View { @Environment(\.scenePhase) var scenePhase init(game: EmulationGame?) { - _viewModel = StateObject(wrappedValue: EmulationViewModel(game: game)) + _viewModel = StateObject(wrappedValue: EmulationViewModel()) } var body: some View { @@ -555,4 +555,4 @@ struct SizePreferenceKey: PreferenceKey { static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() } -} +} \ No newline at end of file diff --git a/src/ios/GameButtonView.swift b/src/ios/GameButtonView.swift index 5b2a09f17c..05f774b1c9 100644 --- a/src/ios/GameButtonView.swift +++ b/src/ios/GameButtonView.swift @@ -10,7 +10,7 @@ import UniformTypeIdentifiers import Combine struct SettingsView: View { - @State var core: Core + @ObservedObject var core: EmulationViewModel @State var showprompt = false @AppStorage("icon") var iconused = 1 @@ -78,116 +78,70 @@ struct GameIconView: View { } } -struct BottomMenuView: View { - @State var core: Core - var body: some View { - HStack(spacing: 40) { - Button { +// Remove or refactor HomeView and GameCarouselView to not use Core or BottomMenuView(core: core) with Core. +// If these are not used in the iOS UI, comment them out to avoid build errors. +// struct HomeView: View { +// @State private var selectedGame: EmulationGame? = nil - } label: { - Circle() - .overlay { - Image(systemName: "message").font(.system(size: 30)).foregroundColor(.red) - } - .frame(width: 50, height: 50) - .foregroundColor(Color.init(uiColor: .lightGray)) - } - Button { +// @State var core: Core - } label: { - Circle() - .overlay { - Image(systemName: "photo").font(.system(size: 30)).foregroundColor(.blue) - } - .frame(width: 50, height: 50) - .foregroundColor(Color.init(uiColor: .lightGray)) - } - NavigationLink(destination: SettingsView(core: core)) { - Circle() - .overlay { - Image(systemName: "gearshape").foregroundColor(Color.init(uiColor: .darkGray)).font(.system(size: 30)) - } - .frame(width: 50, height: 50) - .foregroundColor(Color.init(uiColor: .lightGray)) - } +// init(selectedGame: EmulationGame? = nil, core: Core) { +// _core = State(wrappedValue: core) +// self.selectedGame = selectedGame +// refreshcore() +// } - Button { +// var body: some View { +// NavigationStack { +// GeometryReader { geometry in +// VStack { +// GameCarouselView(core: core, selectedGame: $selectedGame) +// Spacer() +// BottomMenuView(core: core) +// } +// } +// } +// .background(Color.gray.opacity(0.1)) +// .edgesIgnoringSafeArea(.all) +// .onAppear { +// refreshcore() +// if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { +// let romsFolderURL = documentsDirectory.appendingPathComponent("roms") +// let folderMonitor = FolderMonitor(folderURL: romsFolderURL) { +// do { +// core = Core(games: [], root: documentsDirectory) +// core = try LibraryManager.shared.library() +// } catch { +// print("Error refreshing core: \(error)") +// } +// } +// } +// } +// } - } label: { - Circle() - .overlay { - Image(systemName: "power").foregroundColor(Color.init(uiColor: .darkGray)).font(.system(size: 30)) - } - .frame(width: 50, height: 50) - .foregroundColor(Color.init(uiColor: .lightGray)) - } - } - .padding(.bottom, 20) - } -} +// func refreshcore() { +// print("Loading library...") +// do { +// core = try LibraryManager.shared.library() +// print(core.games) +// } catch { +// print("Failed to fetch library: \(error)") +// return +// } +// } +// } -struct HomeView: View { - @State private var selectedGame: EmulationGame? = nil - - @State var core: Core - - init(selectedGame: EmulationGame? = nil, core: Core) { - _core = State(wrappedValue: core) - self.selectedGame = selectedGame - refreshcore() - } - - var body: some View { - NavigationStack { - GeometryReader { geometry in - VStack { - GameCarouselView(core: core, selectedGame: $selectedGame) - Spacer() - BottomMenuView(core: core) - } - } - } - .background(Color.gray.opacity(0.1)) - .edgesIgnoringSafeArea(.all) - .onAppear { - refreshcore() - if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { - let romsFolderURL = documentsDirectory.appendingPathComponent("roms") - let folderMonitor = FolderMonitor(folderURL: romsFolderURL) { - do { - core = Core(games: [], root: documentsDirectory) - core = try LibraryManager.shared.library() - } catch { - print("Error refreshing core: \(error)") - } - } - } - } - } - - func refreshcore() { - print("Loading library...") - do { - core = try LibraryManager.shared.library() - print(core.games) - } catch { - print("Failed to fetch library: \(error)") - return - } - } -} - -struct GameCarouselView: View { - // let games: [EmulationGame] - @State var core: Core - @Binding var selectedGame: EmulationGame? - var body: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 20) { - ForEach(core.games) { game in - GameIconView(game: game, selectedGame: $selectedGame) - } - } - } - } -} +// struct GameCarouselView: View { +// // let games: [EmulationGame] +// @State var core: Core +// @Binding var selectedGame: EmulationGame? +// var body: some View { +// ScrollView(.horizontal, showsIndicators: false) { +// HStack(spacing: 20) { +// ForEach(core.games) { game in +// GameIconView(game: game, selectedGame: $selectedGame) +// } +// } +// } +// } +// } \ No newline at end of file diff --git a/src/ios/LibraryView.swift b/src/ios/LibraryView.swift index a12e88dd1f..96973a6055 100644 --- a/src/ios/LibraryView.swift +++ b/src/ios/LibraryView.swift @@ -1,184 +1,89 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 -// SPDX-License-Identifier: GPL-3.0-or-later import SwiftUI -import CryptoKit +import Foundation struct LibraryView: View { - @Binding var core: Core - @State var isGridView: Bool = true - @State var doesitexist = (false, false) - @State var importedgame: EmulationGame? = nil - @State var importgame: Bool = false - @State var isimportingfirm: Bool = false - @State var launchGame: Bool = false + @State private var selectedGame: EmulationGame? = nil + @Binding var urlgame: EmulationGame? + @ObservedObject var core: EmulationViewModel + + var binding: Binding { + Binding( + get: { urlgame != nil }, + set: { newValue in + if !newValue { + urlgame = nil + } + } + ) + } + var body: some View { - NavigationStack { - if let importedgame = importedgame { + NavigationView { + GeometryReader { geometry in + VStack { + TopBarView() + + if UIDevice.current.userInterfaceIdiom == .pad { + Spacer() + } + + ScrollView { + LazyVGrid(columns: [ + GridItem(.adaptive(minimum: 140), spacing: 10) + ], spacing: 10) { + ForEach(core.games, id: \EmulationGame.id) { game in + GameCardView(game: game) + .frame(width: 140, height: 160) + .onTapGesture { + selectedGame = game + urlgame = game + } + } + } + .padding() + } + + Spacer() + + BottomMenuView(core: core) + } + NavigationLink( - isActive: $launchGame, - destination: { - EmulationView(game: importedgame).toolbar(.hidden, for: .tabBar) - }, + destination: EmulationView(game: urlgame), + isActive: binding, label: { - EmptyView() // This keeps the link hidden + EmptyView() } ) - } - - VStack { - if doesitexist.0, doesitexist.1 { - HomeView(core: core) - } else { - let (doesKeyExist, doesProdExist) = doesKeysExist() - ScrollView { - Text("You Are Missing These Files:") - .font(.headline) - .foregroundColor(.red) - HStack { - if !doesProdExist { - Text("Prod.keys") - .font(.subheadline) - .foregroundColor(.red) - } - if !doesKeyExist { - Text("Title.keys") - .font(.subheadline) - .foregroundColor(.red) - } - } - Text("These goes into the Keys folder") - .font(.caption) - .foregroundColor(.red) - .padding(.bottom) - - if !LibraryManager.shared.homebrewroms().isEmpty { - Text("Homebrew Roms:") - .font(.headline) - LazyVGrid(columns: [GridItem(.adaptive(minimum: 160))], spacing: 10) { - ForEach(LibraryManager.shared.homebrewroms()) { game in - NavigationLink(destination: EmulationView(game: game).toolbar(.hidden, for: .tabBar)) { - // GameButtonView(game: game) - // .frame(maxWidth: .infinity, minHeight: 200) - } - .contextMenu { - NavigationLink(destination: EmulationView(game: game)) { - Text("Launch") - } - } - } - } - } - } - .refreshable { - doesitexist = doesKeysExist() - } - - - } - - } - .fileImporter(isPresented: $isimportingfirm, allowedContentTypes: [.zip], onCompletion: { result in - switch result { - case .success(let elements): - core.AddFirmware(at: elements) - case .failure(let error): - - print(error.localizedDescription) - } - }) - .fileImporter(isPresented: $importgame, allowedContentTypes: [.item], onCompletion: { result in - switch result { - case .success(let elements): - let iscustom = elements.startAccessingSecurityScopedResource() - let information = AppUI.shared.information(for: elements) - - let game = EmulationGame(developer: information.developer, fileURL: elements, - imageData: information.iconData, - title: information.title) - - importedgame = game - - - DispatchQueue.main.async { - - if iscustom { - elements.stopAccessingSecurityScopedResource() - } - - launchGame = true - } - case .failure(let error): - - print(error.localizedDescription) - } - }) - .onAppear() { - doesitexist = doesKeysExist() - } - .navigationBarTitle("Library", displayMode: .inline) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { // why did this take me so long to figure out lmfao - Button(action: { - isGridView.toggle() - }) { - Image(systemName: isGridView ? "rectangle.grid.1x2" : "square.grid.2x2") - .imageScale(.large) - .padding() - } - } - - ToolbarItem(placement: .navigationBarTrailing) { // funsies - Menu { - Button(action: { - importgame = true // this part took a while - - }) { - Text("Launch Game") - } - - Button(action: { - isimportingfirm = true - }) { - Text("Import Firmware") - } - } label: { - Image(systemName: "plus.circle.fill") - .imageScale(.large) - .padding() - } - - } + .hidden() } } - } - - func doesKeysExist() -> (Bool, Bool) { - var doesprodexist = false - var doestitleexist = false - let title = core.root.appendingPathComponent("keys").appendingPathComponent("title.keys") - let prod = core.root.appendingPathComponent("keys").appendingPathComponent("prod.keys") - let fileManager = FileManager.default - if fileManager.fileExists(atPath: prod.path) { - doesprodexist = true - } else { - print("File does not exist") + .background(Color.gray.opacity(0.1)) + .edgesIgnoringSafeArea(.all) + .onAppear { } - if fileManager.fileExists(atPath: title.path) { - doestitleexist = true - } else { - print("File does not exist") - } - return (doestitleexist, doesprodexist) } } -func getDeveloperNames() -> String { - // guard let s = infoDictionary?["CFBundleIdentifier"] as? String else { - // return "Unknown" - // } - // return s - return "what" -} +struct GameCardView: View { + let game: EmulationGame + + var body: some View { + VStack { + Rectangle() + .fill(Color.gray) + .frame(height: 120) + + Text(game.title) + .font(.caption) + .lineLimit(1) + .truncationMode(.tail) + } + .background(Color.white) + .cornerRadius(8) + .shadow(radius: 4) + } +} \ No newline at end of file diff --git a/src/ios/PomeloApp.swift b/src/ios/PomeloApp.swift index 6a2449ff93..ff4ff98a07 100644 --- a/src/ios/PomeloApp.swift +++ b/src/ios/PomeloApp.swift @@ -50,28 +50,10 @@ class YuzuFileManager { } } -struct ContentView: View { -@State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) - var body: some View { - HomeView(core: core).onAppear() { - do { - try YuzuFileManager.shared.createdirectories() // this took a while to create the proper directories - do { - core = try LibraryManager.shared.library() // this shit is like you tried to throw a egg into a blender with no lid on - } catch { - print("Failed to fetch library: \(error)") // aaaaaaaaa - } - } catch { - print("Failed to create directories: \(error)") // i wonder why hmmmmmmm - return - } - } - } -} - @main struct PomeloApp: App { + @StateObject private var core = EmulationViewModel(game: nil) var body: some Scene { - WindowGroup { ContentView() } + WindowGroup { ContentView(core: core) } } -} +} \ No newline at end of file diff --git a/src/yuzu/Info.plist b/src/yuzu/Info.plist index fa44859580..59f9544aa7 100644 --- a/src/yuzu/Info.plist +++ b/src/yuzu/Info.plist @@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later CFBundleDevelopmentRegion English CFBundleExecutable - ${EXECUTABLE_NAME} + $(EXECUTABLE_NAME) CFBundleGetInfoString CFBundleIconFile