mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-02 04:09:00 +02:00
swift reworks
This commit is contained in:
parent
41ff70345b
commit
a98398791a
7 changed files with 154 additions and 303 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
@ -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<Bool> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue