Version 2.2
@ -17,7 +17,6 @@
|
||||
3841946C2C4E4D2B00396613 /* ControllerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384194612C4E4D2B00396613 /* ControllerView.swift */; };
|
||||
3841946D2C4E4D2B00396613 /* SudachiEmulationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384194672C4E4D2B00396613 /* SudachiEmulationView.swift */; };
|
||||
384194702C4E540500396613 /* SudachiEmulationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3841946F2C4E53FD00396613 /* SudachiEmulationHandler.swift */; };
|
||||
3841947F2C4E5D2E00396613 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = 3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */; };
|
||||
384F18922C1DCB520073375C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 384F18912C1DCB520073375C /* Assets.xcassets */; };
|
||||
386F6EE52C42E0B900C62EBE /* GameButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386F6EDE2C42E0B900C62EBE /* GameButtonView.swift */; };
|
||||
386F6EE62C42E0B900C62EBE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386F6ED92C42E0B900C62EBE /* ContentView.swift */; };
|
||||
@ -41,8 +40,6 @@
|
||||
38C50D0A2C1DCF3E0007A953 /* libswresample.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B12C1DCE8900331706 /* libswresample.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
38C50D0B2C1DCF420007A953 /* libswscale.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B22C1DCE8900331706 /* libswscale.xcframework */; };
|
||||
38C50D0C2C1DCF420007A953 /* libswscale.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B22C1DCE8900331706 /* libswscale.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
38C50D102C1DCF5F0007A953 /* SwiftSyntax in Frameworks */ = {isa = PBXBuildFile; productRef = 38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */; };
|
||||
38C50D122C1DCF690007A953 /* SwiftSyntaxMacros in Frameworks */ = {isa = PBXBuildFile; productRef = 38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */; };
|
||||
38C50D152C1DD4570007A953 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C50D142C1DD4570007A953 /* GameController.framework */; };
|
||||
38C50D172C1DD45F0007A953 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C50D162C1DD45F0007A953 /* CoreBluetooth.framework */; };
|
||||
38C50D182C1DD5370007A953 /* boost_context.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B62C1DCE8900331706 /* boost_context.xcframework */; };
|
||||
@ -70,6 +67,8 @@
|
||||
499A5E0F2C74A22D00EC0925 /* GameButtonListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A5E0E2C74A22D00EC0925 /* GameButtonListView.swift */; };
|
||||
4E0E35EA2C7AB5CB001D24EE /* libSPIRV.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846C72C1DCE8900331706 /* libSPIRV.xcframework */; };
|
||||
4E0E35EB2C7AB5CB001D24EE /* libSPIRV.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846C72C1DCE8900331706 /* libSPIRV.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
4E1687CE2CC7A27000485EDB /* SudachiMetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */; };
|
||||
4E1687D02CC83C9100485EDB /* AppIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1687CF2CC83C8E00485EDB /* AppIconView.swift */; };
|
||||
4E4AF11B2C919C0F00BBF2DE /* Haptics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4AF11A2C919C0F00BBF2DE /* Haptics.swift */; };
|
||||
4E4AF1272C9243B500BBF2DE /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846AC2C1DCE8900331706 /* MoltenVK.xcframework */; };
|
||||
4E4AF1282C9243B500BBF2DE /* MoltenVK.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846AC2C1DCE8900331706 /* MoltenVK.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -91,6 +90,7 @@
|
||||
4EE462C62CB5770700BF268E /* TopBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE462C52CB5770700BF268E /* TopBarView.swift */; };
|
||||
4EE462C92CB5774900BF268E /* GameGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE462C82CB5774900BF268E /* GameGridView.swift */; };
|
||||
4EE593FF2C5FA1D1000939C4 /* AppIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */; };
|
||||
4EE9B1EC2CC47025008FA07B /* LaunchGameIntentDef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */; };
|
||||
4EEA0CFA2CA376AB0029A55D /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = 4EEA0CF92CA376AB0029A55D /* Zip */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -186,6 +186,8 @@
|
||||
38F284CB2C2683A000994A77 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||
499A5E0B2C74A1B200EC0925 /* GameListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListView.swift; sourceTree = "<group>"; };
|
||||
499A5E0E2C74A22D00EC0925 /* GameButtonListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameButtonListView.swift; sourceTree = "<group>"; };
|
||||
4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SudachiMetalView.swift; sourceTree = "<group>"; };
|
||||
4E1687CF2CC83C8E00485EDB /* AppIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconView.swift; sourceTree = "<group>"; };
|
||||
4E4AF11A2C919C0F00BBF2DE /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = "<group>"; };
|
||||
4E4AF12C2C926BBD00BBF2DE /* FolderMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderMonitor.swift; sourceTree = "<group>"; };
|
||||
4E5855E22CB6770F00047C2A /* AskForJIT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AskForJIT.swift; sourceTree = "<group>"; };
|
||||
@ -203,6 +205,7 @@
|
||||
4EE462C52CB5770700BF268E /* TopBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBarView.swift; sourceTree = "<group>"; };
|
||||
4EE462C82CB5774900BF268E /* GameGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameGridView.swift; sourceTree = "<group>"; };
|
||||
4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconProvider.swift; sourceTree = "<group>"; };
|
||||
4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchGameIntentDef.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -224,7 +227,6 @@
|
||||
38C50D2A2C1DD5530007A953 /* libGenericCodeGen.xcframework in Frameworks */,
|
||||
4E0E35EA2C7AB5CB001D24EE /* libSPIRV.xcframework in Frameworks */,
|
||||
4EEA0CFA2CA376AB0029A55D /* Zip in Frameworks */,
|
||||
38C50D122C1DCF690007A953 /* SwiftSyntaxMacros in Frameworks */,
|
||||
38C50D092C1DCF3E0007A953 /* libswresample.xcframework in Frameworks */,
|
||||
38C50D0B2C1DCF420007A953 /* libswscale.xcframework in Frameworks */,
|
||||
4E4AF12E2C927E8E00BBF2DE /* libdynarmic.xcframework in Frameworks */,
|
||||
@ -239,12 +241,10 @@
|
||||
38C50D072C1DCF1E0007A953 /* libavfilter.xcframework in Frameworks */,
|
||||
38C50D2E2C1DD5650007A953 /* libmbedcrypto.xcframework in Frameworks */,
|
||||
38C50D1C2C1DD53C0007A953 /* boost_program_options.xcframework in Frameworks */,
|
||||
3841947F2C4E5D2E00396613 /* SwiftUIIntrospect in Frameworks */,
|
||||
38C50D152C1DD4570007A953 /* GameController.framework in Frameworks */,
|
||||
38C50D1A2C1DD5390007A953 /* boost_iostreams.xcframework in Frameworks */,
|
||||
38C50D052C1DCF1B0007A953 /* libavutil.xcframework in Frameworks */,
|
||||
38C50D012C1DCF150007A953 /* libavcodec.xcframework in Frameworks */,
|
||||
38C50D102C1DCF5F0007A953 /* SwiftSyntax in Frameworks */,
|
||||
38C846592C1DCC8400331706 /* OpenSSL in Frameworks */,
|
||||
38C50D282C1DD5510007A953 /* libfmt.xcframework in Frameworks */,
|
||||
38C50D322C1DD56B0007A953 /* libmbedx509.xcframework in Frameworks */,
|
||||
@ -336,6 +336,7 @@
|
||||
384194692C4E4D2B00396613 /* Emulation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E1687CB2CC7A24000485EDB /* MetalViewHandler */,
|
||||
38B7FDFB2C760CF600D274FB /* AirPlay */,
|
||||
3841946E2C4E53F100396613 /* EmulationHandlers */,
|
||||
384194622C4E4D2B00396613 /* ControllerView */,
|
||||
@ -377,6 +378,7 @@
|
||||
384F188C2C1DCB4F0073375C /* Pomelo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EE9B1EA2CC4700F008FA07B /* Intents */,
|
||||
4EE462B62CB54F0400BF268E /* ScreenshotManager */,
|
||||
4EE462B32CB548D800BF268E /* Extentions */,
|
||||
384194692C4E4D2B00396613 /* Emulation */,
|
||||
@ -535,6 +537,14 @@
|
||||
path = Dependencies;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E1687CB2CC7A24000485EDB /* MetalViewHandler */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */,
|
||||
);
|
||||
path = MetalViewHandler;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4E2E693A2C97F7F900BCFFCC /* Dynamic Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -619,11 +629,20 @@
|
||||
4EE593FD2C5FA1C4000939C4 /* AppIcon */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4E1687CF2CC83C8E00485EDB /* AppIconView.swift */,
|
||||
4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */,
|
||||
);
|
||||
path = AppIcon;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4EE9B1EA2CC4700F008FA07B /* Intents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */,
|
||||
);
|
||||
path = Intents;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -644,9 +663,6 @@
|
||||
packageProductDependencies = (
|
||||
38C846542C1DCC7200331706 /* SDL */,
|
||||
38C846582C1DCC8400331706 /* OpenSSL */,
|
||||
38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */,
|
||||
38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */,
|
||||
3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */,
|
||||
4EEA0CF92CA376AB0029A55D /* Zip */,
|
||||
4EC662AF2CAA1229000DBC5F /* SwiftUIJoystick */,
|
||||
);
|
||||
@ -682,8 +698,6 @@
|
||||
packageReferences = (
|
||||
38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */,
|
||||
38C846572C1DCC8400331706 /* XCRemoteSwiftPackageReference "OpenSSL" */,
|
||||
38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */,
|
||||
3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
||||
4EEA0CF82CA376AB0029A55D /* XCRemoteSwiftPackageReference "Zip" */,
|
||||
4EC662AE2CAA1229000DBC5F /* XCRemoteSwiftPackageReference "SwiftUIJoystick" */,
|
||||
);
|
||||
@ -730,12 +744,14 @@
|
||||
files = (
|
||||
4EE593FF2C5FA1D1000939C4 /* AppIconProvider.swift in Sources */,
|
||||
386F6EEC2C42E0C800C62EBE /* PomeloApp.swift in Sources */,
|
||||
4E1687CE2CC7A27000485EDB /* SudachiMetalView.swift in Sources */,
|
||||
4E5855E32CB6770F00047C2A /* AskForJIT.swift in Sources */,
|
||||
384194702C4E540500396613 /* SudachiEmulationHandler.swift in Sources */,
|
||||
38020F562C43A02100029E9A /* BootOSView.swift in Sources */,
|
||||
38020F302C43568500029E9A /* AdvancedSettingsView.swift in Sources */,
|
||||
386F6EE52C42E0B900C62EBE /* GameButtonView.swift in Sources */,
|
||||
386F6F302C42E64000C62EBE /* SettingsView.swift in Sources */,
|
||||
4EE9B1EC2CC47025008FA07B /* LaunchGameIntentDef.swift in Sources */,
|
||||
4EC662B42CAA1257000DBC5F /* JoystickView.swift in Sources */,
|
||||
386F6EE62C42E0B900C62EBE /* ContentView.swift in Sources */,
|
||||
4EE462B52CB548E800BF268E /* MTLViewExtentions.swift in Sources */,
|
||||
@ -743,6 +759,7 @@
|
||||
4E4AF11B2C919C0F00BBF2DE /* Haptics.swift in Sources */,
|
||||
386F6EE82C42E0B900C62EBE /* LibraryView.swift in Sources */,
|
||||
386F6EE92C42E0B900C62EBE /* FileManager.swift in Sources */,
|
||||
4E1687D02CC83C9100485EDB /* AppIconView.swift in Sources */,
|
||||
4E5855E62CB6776C00047C2A /* utils.m in Sources */,
|
||||
386F6F342C42E98700C62EBE /* InfoView.swift in Sources */,
|
||||
3841946A2C4E4D2B00396613 /* MetalView.swift in Sources */,
|
||||
@ -921,7 +938,7 @@
|
||||
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
||||
INFOPLIST_KEY_UIStatusBarStyle = "";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@ -934,7 +951,7 @@
|
||||
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
MARKETING_VERSION = 2.0;
|
||||
MARKETING_VERSION = 2.2;
|
||||
OTHER_LDFLAGS = "-lSudachi";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.Pomelo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -987,7 +1004,7 @@
|
||||
INFOPLIST_KEY_UIStatusBarHidden = NO;
|
||||
INFOPLIST_KEY_UIStatusBarStyle = "";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@ -1000,7 +1017,7 @@
|
||||
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
MARKETING_VERSION = 2.0;
|
||||
MARKETING_VERSION = 2.2;
|
||||
OTHER_LDFLAGS = "-lSudachi";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.Pomelo;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -1044,14 +1061,6 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.3.0;
|
||||
};
|
||||
};
|
||||
38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ctreffs/SwiftSDL2";
|
||||
@ -1068,14 +1077,6 @@
|
||||
minimumVersion = 3.1.5004;
|
||||
};
|
||||
};
|
||||
38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/apple/swift-syntax.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 510.0.2;
|
||||
};
|
||||
};
|
||||
4EC662AE2CAA1229000DBC5F /* XCRemoteSwiftPackageReference "SwiftUIJoystick" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/michael94ellis/SwiftUIJoystick";
|
||||
@ -1095,21 +1096,6 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
|
||||
productName = SwiftUIIntrospect;
|
||||
};
|
||||
38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */;
|
||||
productName = SwiftSyntax;
|
||||
};
|
||||
38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */;
|
||||
productName = SwiftSyntaxMacros;
|
||||
};
|
||||
38C846542C1DCC7200331706 /* SDL */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */;
|
||||
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 1.1 MiB |
36
Pomelo/Assets.xcassets/Old.appiconset/Contents.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "fun 1.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "tinted"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/Old.appiconset/fun 1.png
Normal file
After Width: | Height: | Size: 202 KiB |
BIN
Pomelo/Assets.xcassets/fun 1.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
21
Pomelo/Assets.xcassets/old.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "fun 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/old.imageset/fun 1.png
vendored
Normal file
After Width: | Height: | Size: 202 KiB |
36
Pomelo/Assets.xcassets/original.appiconset/Contents.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "favicon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "tinted"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/original.appiconset/favicon.png
Normal file
After Width: | Height: | Size: 568 KiB |
21
Pomelo/Assets.xcassets/original.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "favicon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/original.imageset/favicon.png
vendored
Normal file
After Width: | Height: | Size: 568 KiB |
36
Pomelo/Assets.xcassets/secondary.appiconset/Contents.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "fun 1.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "tinted"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/secondary.appiconset/fun 1.png
Normal file
After Width: | Height: | Size: 154 KiB |
21
Pomelo/Assets.xcassets/secondary.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "fun 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Pomelo/Assets.xcassets/secondary.imageset/fun 1.png
vendored
Normal file
After Width: | Height: | Size: 154 KiB |
@ -12,12 +12,24 @@ import UIKit
|
||||
|
||||
|
||||
struct ContentView: View {
|
||||
@State var urlgame: PomeloGame? = nil
|
||||
@AppStorage("icloudsaves") var icloudsaves: Bool = false
|
||||
@AppStorage("useTrollStore") var useTrollStore: Bool = false
|
||||
@State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0])
|
||||
var body: some View {
|
||||
//NavView(core: $core) // pain and suffering
|
||||
LibraryView(core: core)
|
||||
LibraryView(urlgame: $urlgame, core: core)
|
||||
.onOpenURL(perform: { url in
|
||||
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
||||
components.host == "game",
|
||||
let text = components.queryItems?.first(where: { $0.name == "id" })?.value {
|
||||
print(text)
|
||||
let isJIT = UserDefaults.standard.bool(forKey: "JIT-ENABLED")
|
||||
|
||||
urlgame = core.games.map(\.self).first(where: { String(describing: $0.programid) == text })
|
||||
print(urlgame)
|
||||
}
|
||||
})
|
||||
.onAppear() {
|
||||
Air.play(AnyView(
|
||||
Text("Select Game")
|
||||
|
@ -16,6 +16,7 @@ class SudachiEmulationViewModel: ObservableObject {
|
||||
var device: MTLDevice?
|
||||
@State var mtkView: MTKView = MTKView()
|
||||
var CaLayer: CAMetalLayer?
|
||||
@State var isPaused: Bool = false
|
||||
private var sudachiGame: PomeloGame?
|
||||
private let sudachi = Sudachi.shared
|
||||
private var thread: Thread!
|
||||
@ -39,11 +40,13 @@ class SudachiEmulationViewModel: ObservableObject {
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async { [self] in
|
||||
if let sudachiGame = self.sudachiGame {
|
||||
|
||||
if sudachiGame.fileURL == URL(string: "BootMii") {
|
||||
self.sudachi.bootMii()
|
||||
} else {
|
||||
self.sudachi.insert(game: sudachiGame.fileURL)
|
||||
}
|
||||
|
||||
} else {
|
||||
self.sudachi.bootOS()
|
||||
}
|
||||
@ -58,7 +61,12 @@ class SudachiEmulationViewModel: ObservableObject {
|
||||
|
||||
private func step() {
|
||||
while true {
|
||||
sudachi.step()
|
||||
if !isPaused {
|
||||
sudachi.step()
|
||||
} else {
|
||||
print("pased")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import Sudachi
|
||||
import Foundation
|
||||
import GameController
|
||||
import UIKit
|
||||
import SwiftUIIntrospect
|
||||
|
||||
|
||||
struct SudachiEmulationView: View {
|
||||
@ -18,8 +17,7 @@ struct SudachiEmulationView: View {
|
||||
@State var controllerconnected = false
|
||||
@State var game: PomeloGame?
|
||||
@State var sudachi = Sudachi.shared
|
||||
var device: MTLDevice? = MTLCreateSystemDefaultDevice()
|
||||
@State var CaLayer: CAMetalLayer?
|
||||
@State var device: MTLDevice? = MTLCreateSystemDefaultDevice()
|
||||
@State var ShowPopup: Bool = false
|
||||
@State var mtkview: MTKView?
|
||||
@State private var thread: Thread!
|
||||
@ -40,23 +38,7 @@ struct SudachiEmulationView: View {
|
||||
ZStack {
|
||||
|
||||
if !isairplay {
|
||||
MetalView(device: device) { view in
|
||||
DispatchQueue.main.async {
|
||||
if let metalView = view as? MTKView {
|
||||
mtkview = metalView
|
||||
viewModel.configureSudachi(with: metalView)
|
||||
} else {
|
||||
print("Error: view is not of type MTKView")
|
||||
}
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.persistentSystemOverlays(.hidden)
|
||||
.onRotate { size in
|
||||
if !isairplay {
|
||||
viewModel.handleOrientationChange()
|
||||
}
|
||||
}
|
||||
SudachiMetalView(viewModel: viewModel, mtkview: $mtkview, device: $device)
|
||||
}
|
||||
|
||||
|
||||
@ -148,21 +130,7 @@ struct SudachiEmulationView: View {
|
||||
})
|
||||
|
||||
if isairplay {
|
||||
Air.play(AnyView(
|
||||
MetalView(device: device) { view in
|
||||
DispatchQueue.main.async {
|
||||
if let metalView = view as? MTKView {
|
||||
mtkview = metalView
|
||||
viewModel.configureSudachi(with: metalView)
|
||||
} else {
|
||||
print("Error: view is not of type MTKView")
|
||||
}
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
)
|
||||
)
|
||||
|
||||
Air.play(AnyView(SudachiMetalView(viewModel: viewModel, mtkview: $mtkview, device: $device)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,10 +145,6 @@ struct SudachiEmulationView: View {
|
||||
uiTabBarController?.tabBar.isHidden = false
|
||||
}
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { (tabBarController) in
|
||||
tabBarController.tabBar.isHidden = true
|
||||
uiTabBarController = tabBarController
|
||||
}
|
||||
}
|
||||
|
||||
private func startPollingFirstFrameShowed() {
|
||||
|
58
Pomelo/Emulation/MetalViewHandler/SudachiMetalView.swift
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// SudachiMetalView.swift
|
||||
// Pomelo
|
||||
//
|
||||
// Created by Stossy11 on 22/10/2024.
|
||||
// Copyright © 2024 Stossy11. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Sudachi
|
||||
import Foundation
|
||||
import GameController
|
||||
import UIKit
|
||||
|
||||
struct SudachiMetalView: View {
|
||||
@StateObject var viewModel: SudachiEmulationViewModel
|
||||
@Binding var mtkview: MTKView?
|
||||
@Binding var device: MTLDevice?
|
||||
@AppStorage("isairplay") private var isairplay: Bool = true
|
||||
var body: some View {
|
||||
if #available(iOS 16.0, *) {
|
||||
MetalView(device: device) { view in
|
||||
DispatchQueue.main.async {
|
||||
if let metalView = view as? MTKView {
|
||||
mtkview = metalView
|
||||
viewModel.configureSudachi(with: metalView)
|
||||
} else {
|
||||
print("Error: view is not of type MTKView")
|
||||
}
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.persistentSystemOverlays(.hidden)
|
||||
.onRotate { size in
|
||||
if !isairplay {
|
||||
viewModel.handleOrientationChange()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MetalView(device: device) { view in
|
||||
DispatchQueue.main.async {
|
||||
if let metalView = view as? MTKView {
|
||||
mtkview = metalView
|
||||
viewModel.configureSudachi(with: metalView)
|
||||
} else {
|
||||
print("Error: view is not of type MTKView")
|
||||
}
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.onRotate { size in
|
||||
if !isairplay {
|
||||
viewModel.handleOrientationChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,9 +20,12 @@ class SudachiScreenView: UIView {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
if userDefaults.bool(forKey: "isfullscreen") {
|
||||
// setupSudachiScreenforcools()
|
||||
setupSudachiScreen2()
|
||||
} else if userDefaults.bool(forKey: "isairplay") {
|
||||
setupSudachiScreen2()
|
||||
} else if userDefaults.bool(forKey: "169fullscreen") { // this is for the 16/9 aspect ratio full screen
|
||||
setupSudachiScreenforcools()
|
||||
} else if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
setupSudachiScreenforiPad()
|
||||
} else {
|
||||
@ -87,6 +90,55 @@ class SudachiScreenView: UIView {
|
||||
addConstraints(fullscreenconstraints)
|
||||
}
|
||||
|
||||
func setupSudachiScreenforcools() { // oh god this took a long time, im going insane
|
||||
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||
primaryScreen.clipsToBounds = true
|
||||
|
||||
addSubview(primaryScreen)
|
||||
|
||||
primaryScreen.layer.cornerRadius = 5
|
||||
primaryScreen.layer.masksToBounds = true
|
||||
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
primaryScreen.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
primaryScreen.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
primaryScreen.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor),
|
||||
primaryScreen.heightAnchor.constraint(lessThanOrEqualTo: heightAnchor)
|
||||
])
|
||||
|
||||
let aspectRatio: CGFloat = 16.0/9.0
|
||||
let aspectRatioConstraint = NSLayoutConstraint(
|
||||
item: primaryScreen ?? UIView(),
|
||||
attribute: .width,
|
||||
relatedBy: .equal,
|
||||
toItem: primaryScreen,
|
||||
attribute: .height,
|
||||
multiplier: aspectRatio,
|
||||
constant: 0
|
||||
)
|
||||
aspectRatioConstraint.priority = .required - 1
|
||||
primaryScreen.addConstraint(aspectRatioConstraint)
|
||||
|
||||
let heightConstraint = primaryScreen.heightAnchor.constraint(equalTo: heightAnchor)
|
||||
heightConstraint.priority = .defaultHigh
|
||||
let widthConstraint = primaryScreen.widthAnchor.constraint(equalTo: widthAnchor)
|
||||
widthConstraint.priority = .defaultHigh
|
||||
|
||||
NSLayoutConstraint.activate([heightConstraint, widthConstraint])
|
||||
|
||||
// Make primaryScreen fill container
|
||||
fullscreenconstraints = [
|
||||
primaryScreen.topAnchor.constraint(equalTo: primaryScreen.topAnchor),
|
||||
primaryScreen.bottomAnchor.constraint(equalTo: primaryScreen.bottomAnchor),
|
||||
primaryScreen.leadingAnchor.constraint(equalTo: primaryScreen.leadingAnchor),
|
||||
primaryScreen.trailingAnchor.constraint(equalTo: primaryScreen.trailingAnchor)
|
||||
]
|
||||
|
||||
NSLayoutConstraint.activate(fullscreenconstraints)
|
||||
}
|
||||
|
||||
func setupSudachiScreenforiPad() {
|
||||
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
|
||||
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
@ -14,6 +14,7 @@ import Zip
|
||||
|
||||
struct Core : Comparable, Hashable {
|
||||
|
||||
let supportedFileTypes = ["nca", "nro", "nsp", "nso", "xci"]
|
||||
let name = "Pomelo"
|
||||
var games: [PomeloGame]
|
||||
let root: URL
|
||||
@ -22,6 +23,16 @@ struct Core : Comparable, Hashable {
|
||||
lhs.name < rhs.name
|
||||
}
|
||||
|
||||
func refreshcore(core: inout Core) {
|
||||
print("Getting Roms...")
|
||||
do {
|
||||
core = try LibraryManager.shared.library()
|
||||
} catch {
|
||||
print("Failed to fetch library: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func AddFirmware(at fileURL: URL) {
|
||||
do {
|
||||
let fileManager = FileManager.default
|
||||
@ -137,105 +148,6 @@ class LibraryManager {
|
||||
}
|
||||
}
|
||||
|
||||
func homebrewroms() -> [PomeloGame] {
|
||||
|
||||
var urls: [URL] = []
|
||||
|
||||
let sdmc = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("sdmc", conformingTo: .folder)
|
||||
let sdfolder = sdmc.appendingPathComponent("switch", conformingTo: .folder)
|
||||
if FileManager.default.fileExists(atPath: sdfolder.path) {
|
||||
if let dirContents = FileManager.default.enumerator(at: sdmc, includingPropertiesForKeys: nil, options: []) {
|
||||
do {
|
||||
try dirContents.forEach() { files in
|
||||
if let file = files as? URL {
|
||||
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
|
||||
if let isfile = getaboutfile.isRegularFile, isfile {
|
||||
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
|
||||
urls.append(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
|
||||
do {
|
||||
try dirContents.forEach() { files in
|
||||
if let file = files as? URL {
|
||||
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
|
||||
if let isfile = getaboutfile.isRegularFile, isfile {
|
||||
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
|
||||
urls.append(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("damn")
|
||||
|
||||
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
|
||||
do {
|
||||
try dirContents.forEach() { files in
|
||||
if let file = files as? URL {
|
||||
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
|
||||
if let isfile = getaboutfile.isRegularFile, isfile {
|
||||
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
|
||||
urls.append(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
|
||||
do {
|
||||
try dirContents.forEach() { files in
|
||||
if let file = files as? URL {
|
||||
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
|
||||
if let isfile = getaboutfile.isRegularFile, isfile {
|
||||
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
|
||||
urls.append(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
|
||||
func games(from urls: [URL]) -> [PomeloGame] {
|
||||
var pomelogames: [PomeloGame] = []
|
||||
pomelogames = urls.reduce(into: [PomeloGame]()) { partialResult, element in
|
||||
let iscustom = element.startAccessingSecurityScopedResource()
|
||||
let information = Sudachi.shared.information(for: element)
|
||||
let game = PomeloGame(developer: information.developer, fileURL: element,
|
||||
imageData: information.iconData,
|
||||
title: information.title)
|
||||
if iscustom {
|
||||
element.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
partialResult.append(game)
|
||||
}
|
||||
|
||||
return pomelogames
|
||||
}
|
||||
|
||||
return games(from: urls)
|
||||
}
|
||||
|
||||
func library() throws -> Core {
|
||||
func getromsfromdir() throws -> [URL] {
|
||||
guard let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) else {
|
||||
@ -283,7 +195,8 @@ class LibraryManager {
|
||||
let iscustom = element.startAccessingSecurityScopedResource()
|
||||
let information = Sudachi.shared.information(for: element)
|
||||
|
||||
let game = PomeloGame(developer: information.developer, fileURL: element,
|
||||
|
||||
let game = PomeloGame(programid: Int(information.programID), ishomebrew: information.isHomebrew, developer: information.developer, fileURL: element,
|
||||
imageData: information.iconData,
|
||||
title: information.title)
|
||||
if iscustom {
|
||||
|
@ -11,6 +11,8 @@ import Foundation
|
||||
struct PomeloGame : Comparable, Hashable, Identifiable {
|
||||
var id = UUID()
|
||||
|
||||
let programid: Int
|
||||
let ishomebrew: Bool
|
||||
let developer: String
|
||||
let fileURL: URL
|
||||
let imageData: Data
|
||||
|
@ -2,8 +2,51 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.stossy11.Pomelo</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>pomelo</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>LaunchGameIntent</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>CFBundleIcons</key>
|
||||
<dict>
|
||||
<key>CFBundlePrimaryIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>AppIcon</string>
|
||||
<string>secondary</string>
|
||||
<string>old</string>
|
||||
<string>original</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>UINewsstandIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string></string>
|
||||
</array>
|
||||
<key>UINewsstandBindingType</key>
|
||||
<string>UINewsstandBindingTypeMagazine</string>
|
||||
<key>UINewsstandBindingEdge</key>
|
||||
<string>UINewsstandBindingEdgeLeft</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIRequiresPersistentWiFi</key>
|
||||
<true/>
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
|
58
Pomelo/Intents/LaunchGameIntentDef.swift
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// LaunchGameIntent.swift
|
||||
// Pomelo
|
||||
//
|
||||
// Created by Stossy11 on 20/10/2024.
|
||||
// Copyright © 2024 Stossy11. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Intents
|
||||
import AppIntents
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
struct LaunchGameIntentDef: AppIntent {
|
||||
|
||||
static let title: LocalizedStringResource = "Launch Game"
|
||||
|
||||
static var description = IntentDescription("Launches the Selected Game.")
|
||||
|
||||
@Parameter(title: "Game Name / Id")
|
||||
var gameName: String
|
||||
|
||||
static var parameterSummary: some ParameterSummary {
|
||||
Summary("Launch \(\.$gameName)")
|
||||
}
|
||||
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
@MainActor
|
||||
func perform() async throws -> some IntentResult {
|
||||
let core = try LibraryManager.shared.library()
|
||||
|
||||
var currentid: Int?
|
||||
if let pomeloGame = core.games.first(where: { $0.title == self.gameName }) {
|
||||
currentid = pomeloGame.programid
|
||||
}
|
||||
|
||||
if let pomeloGame = core.games.first(where: { $0.title.localizedCaseInsensitiveContains(self.gameName) }) {
|
||||
currentid = pomeloGame.programid
|
||||
}
|
||||
|
||||
if let pomeloGame = core.games.first(where: { String(describing: $0.programid) == self.gameName }) {
|
||||
currentid = pomeloGame.programid
|
||||
}
|
||||
|
||||
|
||||
if let currentid {
|
||||
let urlString = "pomelo://game?id=\(currentid)"
|
||||
if let url = URL(string: urlString) {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return .result()
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ struct GameIconView: View {
|
||||
|
||||
|
||||
NavigationLink(
|
||||
destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar),
|
||||
destination: SudachiEmulationView(game: game),
|
||||
isActive: $startgame,
|
||||
label: {
|
||||
EmptyView() // Keeps the link hidden
|
||||
|
@ -29,7 +29,7 @@ struct GameGridView: View {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200))], spacing: 2) {
|
||||
ForEach(0..<filteredGames.count, id: \.self) { index in
|
||||
let game = filteredGames[index] // Use filteredGames here
|
||||
NavigationLink(destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar)) {
|
||||
NavigationLink(destination: SudachiEmulationView(game: game)) {
|
||||
GameIconView(game: game, selectedGame: $selectedGame)
|
||||
.frame(maxWidth: 200, minHeight: 250)
|
||||
}
|
||||
@ -48,7 +48,7 @@ struct GameGridView: View {
|
||||
Text("Remove")
|
||||
}
|
||||
Button(action: {
|
||||
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appending(path: "roms") {
|
||||
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("roms") {
|
||||
UIApplication.shared.open(documentsURL, options: [:], completionHandler: nil)
|
||||
}
|
||||
}) {
|
||||
@ -58,7 +58,7 @@ struct GameGridView: View {
|
||||
Text("Open in Files")
|
||||
}
|
||||
}
|
||||
NavigationLink(destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar)) {
|
||||
NavigationLink(destination: SudachiEmulationView(game: game)) {
|
||||
Text("Launch")
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import Sudachi
|
||||
|
||||
struct GameListView: View {
|
||||
// let games: [PomeloGame]
|
||||
@State var core: Core
|
||||
@Binding var core: Core
|
||||
@Binding var selectedGame: PomeloGame?
|
||||
|
||||
var body: some View {
|
||||
@ -22,6 +22,19 @@ struct GameListView: View {
|
||||
HStack(spacing: 0) {
|
||||
ForEach(core.games.prefix(12)) { game in
|
||||
GameIconView(game: game, selectedGame: $selectedGame)
|
||||
.contextMenu {
|
||||
Button {
|
||||
UIPasteboard.general.string = String(describing: game.programid)
|
||||
} label: {
|
||||
Text("Game ID: \(String(describing: game.programid))")
|
||||
}
|
||||
|
||||
Button {
|
||||
saveImageToIconsFolder(gameImageData: game.imageData, imageName: game.title)
|
||||
} label: {
|
||||
Text("Save Icon")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if core.games.count > 12 {
|
||||
@ -47,7 +60,46 @@ struct GameListView: View {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func saveImageToIconsFolder(gameImageData: Data, imageName: String) {
|
||||
// Convert Data to UIImage
|
||||
if let image = UIImage(data: gameImageData) {
|
||||
// Convert UIImage to PNG data
|
||||
if let pngData = image.pngData() {
|
||||
// Access the app's Documents directory
|
||||
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
// Create the "Icons" folder path
|
||||
let iconsFolder = documentsDirectory.appendingPathComponent("icons")
|
||||
|
||||
// Create the "Icons" folder if it doesn't exist
|
||||
if !FileManager.default.fileExists(atPath: iconsFolder.path) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: iconsFolder, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
print("Error creating Icons folder: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Create the file path for the PNG image
|
||||
let imagePath = iconsFolder.appendingPathComponent("\(imageName).png")
|
||||
|
||||
// Save the PNG data to the file
|
||||
do {
|
||||
try pngData.write(to: imagePath)
|
||||
print("Image saved successfully at: \(imagePath)")
|
||||
} catch {
|
||||
print("Error saving image: \(error)")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("Failed to convert UIImage to PNG data.")
|
||||
}
|
||||
} else {
|
||||
print("Failed to create UIImage from Data.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func doeskeysexist() -> (Bool, Bool) {
|
||||
var doesprodexist = false
|
||||
|
@ -13,22 +13,26 @@ import Sudachi
|
||||
struct LibraryView: View {
|
||||
@State private var selectedGame: PomeloGame? = nil
|
||||
|
||||
|
||||
@Binding var urlgame: PomeloGame?
|
||||
|
||||
@State var core: Core
|
||||
|
||||
init(selectedGame: PomeloGame? = nil, core: Core) {
|
||||
|
||||
_core = State(wrappedValue: core)
|
||||
self.selectedGame = selectedGame
|
||||
print("Getting Roms...")
|
||||
do {
|
||||
_core = State(wrappedValue: try LibraryManager.shared.library())
|
||||
} catch {
|
||||
print("Failed to fetch library: \(error)")
|
||||
}
|
||||
|
||||
var binding: Binding<Bool> {
|
||||
Binding(
|
||||
get: { urlgame != nil },
|
||||
set: { newValue in
|
||||
if !newValue {
|
||||
urlgame = nil
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
NavigationView {
|
||||
|
||||
GeometryReader { geometry in
|
||||
VStack {
|
||||
TopBarView()
|
||||
@ -37,43 +41,43 @@ struct LibraryView: View {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
GameListView(core: core, selectedGame: $selectedGame)
|
||||
GameListView(core: $core, selectedGame: $selectedGame)
|
||||
|
||||
Spacer()
|
||||
|
||||
BottomMenuView(core: core)
|
||||
BottomMenuView(core: $core)
|
||||
}
|
||||
|
||||
NavigationLink(
|
||||
destination: SudachiEmulationView(game: urlgame),
|
||||
isActive: binding,
|
||||
label: {
|
||||
EmptyView() // Keeps the link hidden
|
||||
}
|
||||
)
|
||||
.hidden()
|
||||
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationViewStyle(.stack)
|
||||
.background(Color.gray.opacity(0.1))
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.onAppear {
|
||||
refreshcore()
|
||||
core.refreshcore(core: &core)
|
||||
|
||||
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||
let romsFolderURL = documentsDirectory.appendingPathComponent("roms")
|
||||
|
||||
_ = FolderMonitor(folderURL: romsFolderURL) {
|
||||
do {
|
||||
core = Core(games: [], root: documentsDirectory)
|
||||
core = try LibraryManager.shared.library()
|
||||
} catch {
|
||||
print("Error refreshing core: \(error)")
|
||||
}
|
||||
do {
|
||||
core = Core(games: [], root: documentsDirectory)
|
||||
core = try LibraryManager.shared.library()
|
||||
} catch {
|
||||
print("Error refreshing core: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func refreshcore() {
|
||||
print("Getting Roms...")
|
||||
do {
|
||||
core = try LibraryManager.shared.library()
|
||||
} catch {
|
||||
print("Failed to fetch library: \(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,9 +7,11 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Sudachi
|
||||
|
||||
struct BottomMenuView: View {
|
||||
@State var core: Core
|
||||
@Binding var core: Core
|
||||
@State var isImporting: Bool = false
|
||||
var body: some View {
|
||||
HStack(spacing: 40) {
|
||||
|
||||
@ -48,7 +50,21 @@ struct BottomMenuView: View {
|
||||
.frame(width: 50, height: 50)
|
||||
.foregroundColor(Color.init(uiColor: .darkGray))
|
||||
}
|
||||
// ScreenshotGridView
|
||||
|
||||
Button {
|
||||
isImporting = true
|
||||
} label: {
|
||||
Circle()
|
||||
.overlay {
|
||||
Image(systemName: "plus")
|
||||
.font(.system(size: 30))
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
.frame(width: 50, height: 50)
|
||||
.foregroundColor(Color.init(uiColor: .darkGray))
|
||||
}
|
||||
|
||||
|
||||
NavigationLink(destination: SettingsView(core: core)) {
|
||||
Circle()
|
||||
.overlay {
|
||||
@ -73,5 +89,52 @@ struct BottomMenuView: View {
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 20)
|
||||
.fileImporter(isPresented: $isImporting, allowedContentTypes: [.zip, .item]) { result in
|
||||
switch result {
|
||||
case .success(let url):
|
||||
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
if url.lastPathComponent.hasSuffix(".zip") {
|
||||
core.AddFirmware(at: url)
|
||||
}
|
||||
|
||||
if core.supportedFileTypes.contains(url.pathExtension.lowercased()) {
|
||||
let fileManager = FileManager.default
|
||||
let has = url.startAccessingSecurityScopedResource()
|
||||
do {
|
||||
// Move the file
|
||||
try fileManager.copyItem(at: url, to: directory.appendingPathComponent("roms").appendingPathComponent(url.lastPathComponent))
|
||||
} catch {
|
||||
print("Error moving file: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
if has {
|
||||
url.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
}
|
||||
|
||||
if url.lastPathComponent.hasSuffix(".keys") {
|
||||
let fileManager = FileManager.default
|
||||
let has = url.startAccessingSecurityScopedResource()
|
||||
do {
|
||||
// Move the file
|
||||
try fileManager.copyItem(at: url, to: directory.appendingPathComponent("keys").appendingPathComponent(url.lastPathComponent))
|
||||
} catch {
|
||||
print("Error moving file: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
if has {
|
||||
url.stopAccessingSecurityScopedResource()
|
||||
}
|
||||
|
||||
let sudachi = Sudachi.shared
|
||||
|
||||
sudachi.refreshKeys()
|
||||
}
|
||||
|
||||
core.refreshcore(core: &core)
|
||||
case .failure(let err):
|
||||
print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ struct TopBarView: View {
|
||||
|
||||
HStack {
|
||||
NavigationLink {
|
||||
SudachiEmulationView(game: PomeloGame(developer: "", fileURL: URL(string: "BootMii")!, imageData: Data(), title: "BootOS"))
|
||||
SudachiEmulationView(game: PomeloGame(programid: 0, ishomebrew: false, developer: "", fileURL: URL(string: "BootMii")!, imageData: Data(), title: "BootOS"))
|
||||
} label: {
|
||||
Image(systemName: "person.crop.circle.fill")
|
||||
.resizable()
|
||||
|
@ -2,20 +2,12 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.stossy11.Pomelo</string>
|
||||
</array>
|
||||
<key>com.apple.developer.icloud-services</key>
|
||||
<array>
|
||||
<string>CloudDocuments</string>
|
||||
</array>
|
||||
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.stossy11.Pomelo</string>
|
||||
</array>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import AppIntents
|
||||
infix operator --: LogicalDisjunctionPrecedence
|
||||
|
||||
func --(lhs: Bool, rhs: Bool) -> Bool {
|
||||
@ -14,10 +15,16 @@ func --(lhs: Bool, rhs: Bool) -> Bool {
|
||||
|
||||
@main
|
||||
struct PomeloApp: App {
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView() // i dont know if i should change anything
|
||||
.persistentSystemOverlays(.hidden)
|
||||
if #available(iOS 16, *) {
|
||||
ContentView() // i dont know if i should change anything
|
||||
.persistentSystemOverlays(.hidden)
|
||||
} else {
|
||||
ContentView() // i dont know if i should change anything
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .appShortcuts([])
|
||||
|
@ -2,20 +2,12 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.icloud-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.stossy11.Pomelo</string>
|
||||
</array>
|
||||
<key>com.apple.developer.icloud-services</key>
|
||||
<array>
|
||||
<string>CloudDocuments</string>
|
||||
</array>
|
||||
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
||||
<array>
|
||||
<string>iCloud.com.stossy11.Pomelo</string>
|
||||
</array>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
|
@ -26,7 +26,9 @@ struct ZoomableModifier: ViewModifier {
|
||||
if #available(iOS 17.0, *) {
|
||||
view.gesture(magnificationGesture)
|
||||
} else {
|
||||
view.gesture(oldMagnificationGesture)
|
||||
if #available(iOS 16.0, *) {
|
||||
view.gesture(oldMagnificationGesture)
|
||||
}
|
||||
}
|
||||
}
|
||||
.gesture(doubleTapGesture)
|
||||
@ -64,20 +66,29 @@ struct ZoomableModifier: ViewModifier {
|
||||
}
|
||||
|
||||
private var doubleTapGesture: some Gesture {
|
||||
SpatialTapGesture(count: 2)
|
||||
.onEnded { value in
|
||||
let newTransform: CGAffineTransform =
|
||||
if #available(iOS 16.0, *) {
|
||||
SpatialTapGesture(count: 2)
|
||||
.onEnded { value in
|
||||
let newTransform: CGAffineTransform =
|
||||
if transform.isIdentity {
|
||||
.anchoredScale(scale: doubleTapZoomScale, anchor: value.location)
|
||||
} else {
|
||||
.identity
|
||||
}
|
||||
|
||||
withAnimation(.linear(duration: 0.15)) {
|
||||
transform = newTransform
|
||||
lastTransform = newTransform
|
||||
|
||||
withAnimation(.linear(duration: 0.15)) {
|
||||
transform = newTransform
|
||||
lastTransform = newTransform
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AnyGesture(
|
||||
TapGesture()
|
||||
.onEnded { value in
|
||||
// Add your fallback behavior here if needed.
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private var dragGesture: some Gesture {
|
||||
|
@ -12,6 +12,7 @@ import Foundation
|
||||
struct AdvancedSettingsView: View {
|
||||
@AppStorage("icloudsaves2") var icloudsaves: Bool = false
|
||||
@AppStorage("isfullscreen") var isFullScreen: Bool = false
|
||||
@AppStorage("169fullscreen") var sixteenbynineaspect: Bool = false
|
||||
@AppStorage("exitgame") var exitgame: Bool = false
|
||||
@AppStorage("ClearBackingRegion") var kpagetable: Bool = false
|
||||
@AppStorage("WaitingforJIT") var waitingJIT: Bool = false
|
||||
@ -28,7 +29,7 @@ struct AdvancedSettingsView: View {
|
||||
.frame(width: .infinity, height: 50)
|
||||
.overlay() {
|
||||
HStack {
|
||||
Toggle("FullScreen", isOn: $isFullScreen)
|
||||
Toggle("Fullscreen", isOn: $isFullScreen)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
@ -36,6 +37,22 @@ struct AdvancedSettingsView: View {
|
||||
.padding(.bottom)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
|
||||
Rectangle()
|
||||
.fill(Color(uiColor: UIColor.secondarySystemBackground))
|
||||
.cornerRadius(10)
|
||||
.frame(width: .infinity, height: 50)
|
||||
.overlay() {
|
||||
HStack {
|
||||
Toggle("Fullscreen (16/9)", isOn: $sixteenbynineaspect)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
Text("This is unstable and can lead to crashes. Use at your own risk.")
|
||||
.padding(.bottom)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
|
||||
/*
|
||||
Rectangle()
|
||||
.fill(Color(uiColor: UIColor.secondarySystemBackground))
|
||||
@ -119,6 +136,8 @@ struct AdvancedSettingsView: View {
|
||||
.font(.footnote)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationViewStyle(.stack)
|
||||
.onAppear() {
|
||||
// isshowing = true
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ enum AppIconProvider {
|
||||
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
|
||||
|
||||
let iconFileName = iconFiles.last else {
|
||||
|
||||
print("Could not find icons in bundle")
|
||||
return ""
|
||||
}
|
||||
|
114
Pomelo/SettingsViews/AppIcon/AppIconView.swift
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// AppIconView.swift
|
||||
// Pomelo
|
||||
//
|
||||
// Created by Stossy11 on 23/10/2024.
|
||||
// Copyright © 2024 Stossy11. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AppIcon: Identifiable {
|
||||
let id = UUID()
|
||||
let name: String
|
||||
let iconName: String?
|
||||
}
|
||||
|
||||
struct AppIconSwitcherView: View {
|
||||
@State private var selectedIcon: String?
|
||||
|
||||
let appIcons: [AppIcon] = [
|
||||
AppIcon(name: "Default", iconName: nil),
|
||||
AppIcon(name: "Secondary", iconName: "secondary"),
|
||||
AppIcon(name: "Old", iconName: "old"),
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(appIcons) { icon in
|
||||
IconRow(icon: icon, isSelected: icon.iconName == selectedIcon)
|
||||
.onTapGesture {
|
||||
changeAppIcon(to: icon.iconName)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("App Icons")
|
||||
.onAppear {
|
||||
// Get current app icon
|
||||
|
||||
if let iconName = UIApplication.shared.alternateIconName {
|
||||
selectedIcon = iconName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func changeAppIcon(to iconName: String?) {
|
||||
guard UIApplication.shared.supportsAlternateIcons else {
|
||||
print("App icon changing not supported")
|
||||
return
|
||||
}
|
||||
|
||||
UIApplication.shared.setAlternateIconName(iconName) { error in
|
||||
if let error = error {
|
||||
print("Error changing app icon: \(error.localizedDescription)")
|
||||
} else {
|
||||
selectedIcon = iconName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct IconRow: View {
|
||||
let icon: AppIcon
|
||||
let isSelected: Bool
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
if let iconImage = getIconImage(for: icon.iconName) {
|
||||
Image(uiImage: iconImage)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(12)
|
||||
} else {
|
||||
// Fallback to app's primary icon
|
||||
if let primaryIcon = Bundle.main.icon {
|
||||
Image(uiImage: primaryIcon)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 60, height: 60)
|
||||
.cornerRadius(12)
|
||||
}
|
||||
}
|
||||
|
||||
Text(icon.name)
|
||||
.padding(.leading, 8)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
private func getIconImage(for iconName: String?) -> UIImage? {
|
||||
if let iconName = iconName {
|
||||
// Try to get alternate icon
|
||||
return UIImage(named: iconName)
|
||||
} else {
|
||||
// Return primary app icon
|
||||
return Bundle.main.icon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extension to get the app's primary icon
|
||||
extension Bundle {
|
||||
var icon: UIImage? {
|
||||
if let icons = infoDictionary?["CFBundleIcons"] as? [String: Any],
|
||||
let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
|
||||
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
|
||||
let lastIcon = iconFiles.last {
|
||||
return UIImage(named: lastIcon)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ struct InfoView: View {
|
||||
@AppStorage("entitlementNotExists") private var entitlementNotExists: Bool = false
|
||||
@AppStorage("increaseddebugmem") private var increaseddebugmem: Bool = false
|
||||
@AppStorage("extended-virtual-addressing") private var extended: Bool = false
|
||||
@State var gd = false
|
||||
let infoDictionary = Bundle.main.infoDictionary
|
||||
|
||||
var body: some View {
|
||||
@ -52,8 +53,19 @@ struct InfoView: View {
|
||||
}
|
||||
.padding()
|
||||
|
||||
Text("Version: \(getAppVersion())")
|
||||
.foregroundColor(.gray)
|
||||
HStack {
|
||||
Text("Version: \(getAppVersion())")
|
||||
.foregroundColor(.white)
|
||||
.font(.system(size: 12))
|
||||
.onTapGesture {
|
||||
gd.toggle()
|
||||
}
|
||||
if getAppVersion() == "2.2", gd {
|
||||
Text("Geometry Dash????? ;)")
|
||||
.foregroundStyle(.secondary)
|
||||
.font(.system(size: 5))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func getAppVersion() -> String {
|
||||
|
@ -15,7 +15,7 @@ struct SettingsView: View {
|
||||
|
||||
@AppStorage("useTrollStore") var useTrollStore: Bool = false
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
NavigationView {
|
||||
ScrollView {
|
||||
VStack(alignment: .center) {
|
||||
if iconused == 1 {
|
||||
@ -123,6 +123,23 @@ struct SettingsView: View {
|
||||
|
||||
}
|
||||
.padding()
|
||||
|
||||
NavigationLink(destination: AppIconSwitcherView()) {
|
||||
Rectangle()
|
||||
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
|
||||
.cornerRadius(10) // Apply rounded corners
|
||||
.frame(width: .infinity, height: 50) // Set the desired dimensions
|
||||
.overlay() {
|
||||
HStack {
|
||||
Text("App Icon")
|
||||
.foregroundColor(.primary)
|
||||
.padding()
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.padding()
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
@ -131,7 +148,11 @@ struct SettingsView: View {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationViewStyle(.stack)
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationViewStyle(.stack)
|
||||
.onAppear() {
|
||||
do {
|
||||
core = try LibraryManager.shared.library()
|
||||
|
@ -255,6 +255,7 @@ public:
|
||||
static KeyManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
KeyManager(const KeyManager&) = delete;
|
||||
KeyManager& operator=(const KeyManager&) = delete;
|
||||
|
@ -1138,7 +1138,6 @@ public:
|
||||
const void* data) const noexcept {
|
||||
dld->vkCmdPushDescriptorSetWithTemplateKHR(handle, update_template, layout, set, data);
|
||||
}
|
||||
|
||||
void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
|
||||
dld->vkCmdBindPipeline(handle, bind_point, pipeline);
|
||||
}
|
||||
|
@ -28,17 +28,17 @@ bool isiOS16OrBelow() {
|
||||
|
||||
std::string versionString = systemInfo.release;
|
||||
|
||||
// Extract major and minor version numbers from the release string
|
||||
int majorVersion = std::stoi(versionString.substr(0, versionString.find('.')));
|
||||
|
||||
// For iOS 16, the major version is 16.x.x
|
||||
if (majorVersion <= 16) {
|
||||
return true; // iOS 16 or below
|
||||
} else {
|
||||
return false; // iOS 17 or above
|
||||
// Extract major version number from the release string
|
||||
size_t dotPos = versionString.find('.');
|
||||
if (dotPos == std::string::npos) {
|
||||
return false; // In case the format is unexpected
|
||||
}
|
||||
}
|
||||
|
||||
int majorVersion = std::stoi(versionString.substr(0, dotPos));
|
||||
|
||||
// For iOS 16, the major version is 16.x.x
|
||||
return majorVersion <= 16;
|
||||
}
|
||||
|
||||
#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
|
||||
#include <adrenotools/bcenabler.h>
|
||||
@ -1174,8 +1174,6 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
// extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
|
||||
extensions.extended_dynamic_state = false;
|
||||
|
||||
extensions.extended_dynamic_state = false;
|
||||
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
|
||||
features.extended_dynamic_state,
|
||||
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
|
@ -30,6 +30,10 @@ public struct Sudachi {
|
||||
sudachiObjC.insert(games: urls)
|
||||
}
|
||||
|
||||
public func refreshKeys() {
|
||||
sudachiObjC.refreshKeys()
|
||||
}
|
||||
|
||||
public func bootOS() {
|
||||
sudachiObjC.bootOS()
|
||||
}
|
||||
@ -44,7 +48,7 @@ public struct Sudachi {
|
||||
public func play() {
|
||||
sudachiObjC.play()
|
||||
}
|
||||
|
||||
|
||||
public func ispaused() -> Bool {
|
||||
return sudachiObjC.ispaused()
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
|
||||
nullptr, // Parental Controls
|
||||
nullptr, // Photo Viewer
|
||||
nullptr, // Profile Selector
|
||||
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // Web Browser
|
||||
});
|
||||
|
||||
@ -283,22 +283,22 @@ Core::SystemResultStatus EmulationSession::MiiEditor() {
|
||||
nullptr, // Parental Controls
|
||||
nullptr, // Photo Viewer
|
||||
nullptr, // Profile Selector
|
||||
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // Web Browser
|
||||
});
|
||||
|
||||
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::OfflineWeb);
|
||||
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
|
||||
auto bis_system = m_system.GetFileSystemController().GetSystemNANDContents();
|
||||
|
||||
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
|
||||
|
||||
m_system.GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::OfflineWeb);
|
||||
m_system.GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit);
|
||||
|
||||
const auto filename = qlaunch_applet_nca->GetFullPath();
|
||||
|
||||
auto params = Service::AM::FrontendAppletParameters {
|
||||
.program_id = QLaunchId,
|
||||
.applet_id = Service::AM::AppletId::OfflineWeb,
|
||||
.applet_id = Service::AM::AppletId::MiiEdit,
|
||||
.applet_type = Service::AM::AppletType::SystemApplet
|
||||
};
|
||||
|
||||
@ -352,7 +352,7 @@ Core::SystemResultStatus EmulationSession::BootOS() {
|
||||
nullptr, // Parental Controls
|
||||
nullptr, // Photo Viewer
|
||||
nullptr, // Profile Selector
|
||||
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // Web Browser
|
||||
});
|
||||
|
||||
|
@ -23,7 +23,7 @@ void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) {
|
||||
m_window_height = size.height;
|
||||
|
||||
// Ensures that we emulate with the correct aspect ratio.
|
||||
UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
|
||||
// UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
|
||||
|
||||
window_info.render_surface = reinterpret_cast<void*>(surface);
|
||||
window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale];
|
||||
|
@ -58,6 +58,7 @@ typedef NS_ENUM(NSUInteger, VirtualControllerButtonType) {
|
||||
-(void) quit;
|
||||
-(void) insertGame:(NSURL *)url NS_SWIFT_NAME(insert(game:));
|
||||
-(void) insertGames:(NSArray<NSURL *> *)games NS_SWIFT_NAME(insert(games:));
|
||||
-(void) refreshKeys;
|
||||
-(void) step;
|
||||
-(BOOL) hasfirstfame;
|
||||
|
||||
|
@ -90,7 +90,6 @@
|
||||
|
||||
YuzuSettings::values.dump_shaders.SetValue(true);
|
||||
YuzuSettings::values.use_asynchronous_shaders.SetValue(true);
|
||||
// YuzuSettings::values.astc_recompression.SetValue(YuzuSettings::AstcRecompression::Bc3);
|
||||
YuzuSettings::values.shader_backend.SetValue(YuzuSettings::ShaderBackend::SpirV);
|
||||
// YuzuSettings::values.resolution_setup.SetValue(YuzuSettings::ResolutionSetup::Res1X);
|
||||
// YuzuSettings::values.scaling_filter.SetValue(YuzuSettings::ScalingFilter::Bilinear);
|
||||
@ -189,6 +188,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void) refreshKeys {
|
||||
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
||||
}
|
||||
|
||||
-(void) step {
|
||||
void(EmulationSession::GetInstance().System().Run());
|
||||
}
|
||||
|