From e8f1a7d896f055be5411797356bfff3f5079f162 Mon Sep 17 00:00:00 2001 From: cranci1 <100066266+cranci1@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:26:46 +0100 Subject: [PATCH] Huge things frfrfrf --- Sora-JS.xcodeproj/project.pbxproj | 101 +++++++++- .../xcshareddata/swiftpm/Package.resolved | 16 ++ .../AccentColor.colorset/Contents.json | 4 + .../AppIcon.appiconset/120-1.png | Bin 0 -> 3920 bytes .../AppIcon.appiconset/120.png | Bin 0 -> 3920 bytes .../AppIcon.appiconset/152.png | Bin 0 -> 5475 bytes .../AppIcon.appiconset/167.png | Bin 0 -> 6305 bytes .../AppIcon.appiconset/180.png | Bin 0 -> 7104 bytes .../Assets.xcassets/AppIcon.appiconset/20.png | Bin 0 -> 384 bytes .../Assets.xcassets/AppIcon.appiconset/29.png | Bin 0 -> 565 bytes .../AppIcon.appiconset/40-1.png | Bin 0 -> 832 bytes .../AppIcon.appiconset/40-2.png | Bin 0 -> 832 bytes .../Assets.xcassets/AppIcon.appiconset/40.png | Bin 0 -> 832 bytes .../AppIcon.appiconset/58-1.png | Bin 0 -> 1384 bytes .../Assets.xcassets/AppIcon.appiconset/58.png | Bin 0 -> 1384 bytes .../Assets.xcassets/AppIcon.appiconset/60.png | Bin 0 -> 1473 bytes .../Assets.xcassets/AppIcon.appiconset/76.png | Bin 0 -> 2050 bytes .../AppIcon.appiconset/80-1.png | Bin 0 -> 2197 bytes .../Assets.xcassets/AppIcon.appiconset/80.png | Bin 0 -> 2197 bytes .../Assets.xcassets/AppIcon.appiconset/87.png | Bin 0 -> 2475 bytes .../AppIcon.appiconset/Contents.json | 18 ++ Sora-JS/ContentView.swift | 177 ++---------------- Sora-JS/{ => Loaders}/JSController.swift | 0 Sora-JS/{ => Modules}/Modules.swift | 0 Sora-JS/Settings.swift | 133 ------------- Sora-JS/Sora_JSApp.swift | 6 + Sora-JS/Views/HomeView.swift | 16 ++ Sora-JS/Views/LibraryView.swift | 16 ++ Sora-JS/Views/SearchView.swift | 174 +++++++++++++++++ Sora-JS/Views/SettingsView/SettingsView.swift | 139 ++++++++++++++ .../SubViews/SettingsViewModule.swift | 126 +++++++++++++ 31 files changed, 625 insertions(+), 301 deletions(-) create mode 100644 Sora-JS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/120-1.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/120.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/152.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/167.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/180.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/20.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/29.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/40-1.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/40-2.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/40.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/58-1.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/58.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/60.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/76.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/80-1.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/80.png create mode 100644 Sora-JS/Assets.xcassets/AppIcon.appiconset/87.png rename Sora-JS/{ => Loaders}/JSController.swift (100%) rename Sora-JS/{ => Modules}/Modules.swift (100%) delete mode 100644 Sora-JS/Settings.swift create mode 100644 Sora-JS/Views/HomeView.swift create mode 100644 Sora-JS/Views/LibraryView.swift create mode 100644 Sora-JS/Views/SearchView.swift create mode 100644 Sora-JS/Views/SettingsView/SettingsView.swift create mode 100644 Sora-JS/Views/SettingsView/SubViews/SettingsViewModule.swift diff --git a/Sora-JS.xcodeproj/project.pbxproj b/Sora-JS.xcodeproj/project.pbxproj index 766ee9e..ff8f7b7 100644 --- a/Sora-JS.xcodeproj/project.pbxproj +++ b/Sora-JS.xcodeproj/project.pbxproj @@ -12,8 +12,13 @@ 1329D5CB2D298199008AEDA2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1329D5CA2D298199008AEDA2 /* Assets.xcassets */; }; 1329D5CE2D298199008AEDA2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1329D5CD2D298199008AEDA2 /* Preview Assets.xcassets */; }; 13AEE6192D2A75110096D953 /* Modules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE6182D2A75110096D953 /* Modules.swift */; }; - 13AEE61B2D2A78050096D953 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE61A2D2A78050096D953 /* Settings.swift */; }; + 13AEE61B2D2A78050096D953 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE61A2D2A78050096D953 /* SettingsView.swift */; }; 13AEE61D2D2A78160096D953 /* JSController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE61C2D2A78160096D953 /* JSController.swift */; }; + 13AEE6232D2AAF160096D953 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 13AEE6222D2AAF160096D953 /* Kingfisher */; }; + 13AEE6252D2AB1730096D953 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE6242D2AB1730096D953 /* HomeView.swift */; }; + 13AEE6272D2AB1990096D953 /* LibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE6262D2AB1990096D953 /* LibraryView.swift */; }; + 13AEE6292D2AB2070096D953 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE6282D2AB2070096D953 /* SearchView.swift */; }; + 13AEE62D2D2ABCD30096D953 /* SettingsViewModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13AEE62C2D2ABCD30096D953 /* SettingsViewModule.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,8 +29,12 @@ 1329D5CD2D298199008AEDA2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 1329D5DA2D29821B008AEDA2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 13AEE6182D2A75110096D953 /* Modules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modules.swift; sourceTree = ""; }; - 13AEE61A2D2A78050096D953 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; + 13AEE61A2D2A78050096D953 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 13AEE61C2D2A78160096D953 /* JSController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSController.swift; sourceTree = ""; }; + 13AEE6242D2AB1730096D953 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; + 13AEE6262D2AB1990096D953 /* LibraryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryView.swift; sourceTree = ""; }; + 13AEE6282D2AB2070096D953 /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; + 13AEE62C2D2ABCD30096D953 /* SettingsViewModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModule.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -33,6 +42,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 13AEE6232D2AAF160096D953 /* Kingfisher in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -58,14 +68,14 @@ 1329D5C52D298198008AEDA2 /* Sora-JS */ = { isa = PBXGroup; children = ( + 13AEE6202D2AAD390096D953 /* Modules */, + 13AEE61F2D2AAD2D0096D953 /* Loaders */, + 13AEE61E2D2AAD1E0096D953 /* Views */, 1329D5DA2D29821B008AEDA2 /* Info.plist */, 1329D5C62D298198008AEDA2 /* Sora_JSApp.swift */, 1329D5C82D298198008AEDA2 /* ContentView.swift */, - 13AEE6182D2A75110096D953 /* Modules.swift */, 1329D5CA2D298199008AEDA2 /* Assets.xcassets */, 1329D5CC2D298199008AEDA2 /* Preview Content */, - 13AEE61A2D2A78050096D953 /* Settings.swift */, - 13AEE61C2D2A78160096D953 /* JSController.swift */, ); path = "Sora-JS"; sourceTree = ""; @@ -78,6 +88,50 @@ path = "Preview Content"; sourceTree = ""; }; + 13AEE61E2D2AAD1E0096D953 /* Views */ = { + isa = PBXGroup; + children = ( + 13AEE62A2D2ABCB40096D953 /* SettingsView */, + 13AEE6242D2AB1730096D953 /* HomeView.swift */, + 13AEE6262D2AB1990096D953 /* LibraryView.swift */, + 13AEE6282D2AB2070096D953 /* SearchView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 13AEE61F2D2AAD2D0096D953 /* Loaders */ = { + isa = PBXGroup; + children = ( + 13AEE61C2D2A78160096D953 /* JSController.swift */, + ); + path = Loaders; + sourceTree = ""; + }; + 13AEE6202D2AAD390096D953 /* Modules */ = { + isa = PBXGroup; + children = ( + 13AEE6182D2A75110096D953 /* Modules.swift */, + ); + path = Modules; + sourceTree = ""; + }; + 13AEE62A2D2ABCB40096D953 /* SettingsView */ = { + isa = PBXGroup; + children = ( + 13AEE62B2D2ABCC10096D953 /* SubViews */, + 13AEE61A2D2A78050096D953 /* SettingsView.swift */, + ); + path = SettingsView; + sourceTree = ""; + }; + 13AEE62B2D2ABCC10096D953 /* SubViews */ = { + isa = PBXGroup; + children = ( + 13AEE62C2D2ABCD30096D953 /* SettingsViewModule.swift */, + ); + path = SubViews; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -94,6 +148,9 @@ dependencies = ( ); name = "Sora-JS"; + packageProductDependencies = ( + 13AEE6222D2AAF160096D953 /* Kingfisher */, + ); productName = "Sora-JS"; productReference = 1329D5C32D298198008AEDA2 /* Sora-JS.app */; productType = "com.apple.product-type.application"; @@ -122,6 +179,9 @@ Base, ); mainGroup = 1329D5BA2D298198008AEDA2; + packageReferences = ( + 13AEE6212D2AAF160096D953 /* XCRemoteSwiftPackageReference "Kingfisher" */, + ); productRefGroup = 1329D5C42D298198008AEDA2 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -148,10 +208,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 13AEE6272D2AB1990096D953 /* LibraryView.swift in Sources */, 1329D5C92D298198008AEDA2 /* ContentView.swift in Sources */, + 13AEE62D2D2ABCD30096D953 /* SettingsViewModule.swift in Sources */, 13AEE61D2D2A78160096D953 /* JSController.swift in Sources */, 13AEE6192D2A75110096D953 /* Modules.swift in Sources */, - 13AEE61B2D2A78050096D953 /* Settings.swift in Sources */, + 13AEE6292D2AB2070096D953 /* SearchView.swift in Sources */, + 13AEE6252D2AB1730096D953 /* HomeView.swift in Sources */, + 13AEE61B2D2A78050096D953 /* SettingsView.swift in Sources */, 1329D5C72D298198008AEDA2 /* Sora_JSApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -210,7 +274,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -265,7 +329,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.2; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -292,6 +356,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -322,6 +387,7 @@ INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -357,6 +423,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 13AEE6212D2AAF160096D953 /* XCRemoteSwiftPackageReference "Kingfisher" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/onevcat/Kingfisher.git"; + requirement = { + kind = exactVersion; + version = 7.9.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 13AEE6222D2AAF160096D953 /* Kingfisher */ = { + isa = XCSwiftPackageProductDependency; + package = 13AEE6212D2AAF160096D953 /* XCRemoteSwiftPackageReference "Kingfisher" */; + productName = Kingfisher; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 1329D5BB2D298198008AEDA2 /* Project object */; } diff --git a/Sora-JS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Sora-JS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..bdcfc53 --- /dev/null +++ b/Sora-JS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Kingfisher", + "repositoryURL": "https://github.com/onevcat/Kingfisher.git", + "state": { + "branch": null, + "revision": "b6f62758f21a8c03cd64f4009c037cfa580a256e", + "version": "7.9.1" + } + } + ] + }, + "version": 1 +} diff --git a/Sora-JS/Assets.xcassets/AccentColor.colorset/Contents.json b/Sora-JS/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897..bb57667 100644 --- a/Sora-JS/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/Sora-JS/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,10 @@ { "colors" : [ { + "color" : { + "platform" : "universal", + "reference" : "systemMintColor" + }, "idiom" : "universal" } ], diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/120-1.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/120-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbc052661823797cdef8a8862d1006268546cb5 GIT binary patch literal 3920 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 D4;&WA literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/40-1.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/40-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9c473ca5c40c690f0709c4bd8add833710aa45 GIT binary patch literal 832 zcmV-G1Hb%x&8e(qjo>xxABmEnq1h0U3fUb zE=qxBb3bWx}Y13GH%@9ZDjM?F8WR2P-H2b$+>>B}rjf1sRg!@pxJ*TUKn~>$sT4 z@G%emf9I}OG{DS2Fg*~_5u#lyYDP#VBT?JVRm^{mxA?-_pL^_)M4=`6lT)Kke%-0( zo&D=q53T&~?q$#I{qEuBK{O3|r3^U+5ONr$U1(h59nnyAN<#ows@l(ogLVI&v!3%; zUU;jywf)NLF8%S7yVm`43;+1|Z_X?paY@eNrVJ+`me4+`eh%Yj zkp(*h?+&HvN<_zq^+>EXFg6Lno$=3!heI(DCax3gi|RREdFOO#r!>j&%2EuPn^(Ki zs_EuhJ0*}{86gEBabSy!efC>qg6~|YI|6ZG7j|J6cHxbqIsgFH;Ow{vU?NEX0000< KMNUMnLSTZ_GnTLb literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/40-2.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/40-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9c473ca5c40c690f0709c4bd8add833710aa45 GIT binary patch literal 832 zcmV-G1Hb%x&8e(qjo>xxABmEnq1h0U3fUb zE=qxBb3bWx}Y13GH%@9ZDjM?F8WR2P-H2b$+>>B}rjf1sRg!@pxJ*TUKn~>$sT4 z@G%emf9I}OG{DS2Fg*~_5u#lyYDP#VBT?JVRm^{mxA?-_pL^_)M4=`6lT)Kke%-0( zo&D=q53T&~?q$#I{qEuBK{O3|r3^U+5ONr$U1(h59nnyAN<#ows@l(ogLVI&v!3%; zUU;jywf)NLF8%S7yVm`43;+1|Z_X?paY@eNrVJ+`me4+`eh%Yj zkp(*h?+&HvN<_zq^+>EXFg6Lno$=3!heI(DCax3gi|RREdFOO#r!>j&%2EuPn^(Ki zs_EuhJ0*}{86gEBabSy!efC>qg6~|YI|6ZG7j|J6cHxbqIsgFH;Ow{vU?NEX0000< KMNUMnLSTZ_GnTLb literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/40.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9c473ca5c40c690f0709c4bd8add833710aa45 GIT binary patch literal 832 zcmV-G1Hb%x&8e(qjo>xxABmEnq1h0U3fUb zE=qxBb3bWx}Y13GH%@9ZDjM?F8WR2P-H2b$+>>B}rjf1sRg!@pxJ*TUKn~>$sT4 z@G%emf9I}OG{DS2Fg*~_5u#lyYDP#VBT?JVRm^{mxA?-_pL^_)M4=`6lT)Kke%-0( zo&D=q53T&~?q$#I{qEuBK{O3|r3^U+5ONr$U1(h59nnyAN<#ows@l(ogLVI&v!3%; zUU;jywf)NLF8%S7yVm`43;+1|Z_X?paY@eNrVJ+`me4+`eh%Yj zkp(*h?+&HvN<_zq^+>EXFg6Lno$=3!heI(DCax3gi|RREdFOO#r!>j&%2EuPn^(Ki zs_EuhJ0*}{86gEBabSy!efC>qg6~|YI|6ZG7j|J6cHxbqIsgFH;Ow{vU?NEX0000< KMNUMnLSTZ_GnTLb literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/58-1.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/58-1.png new file mode 100644 index 0000000000000000000000000000000000000000..25a3decb48135e81a452448b490555ff12cb9e06 GIT binary patch literal 1384 zcmV-u1(*7XP)Xd?fXPs}Qv;B)w%j&TwTIISsq{PcV2-`J1}@@~I_a0FOMk)ft0uxH2tfe-2}SSmcaRNBR+q0}pltJY)) zf}|CnkFi=k7K_bprwbLUK63czhYwGOleeW`>lIpC?OHo!WD##k!s~PfTnzWu&;)RG zW78o4^d)}UJvcgv)I4vH#i;axD-8Xq_qqIpy zj(yII&F`s6lB|uk*f|R!GJdLhe)++gV63NdnzC}Nkk~l`f`HRtBV9cHbKcnIdiZYh z*!!vY?J9hI5Z)0?o>=(!ukx-^M5w$qeQe1Uy=&wWIlqSt5EM@Ybf2$QLG|R^CK>Ze z;!>adzoCA_JA`qG-OCzrX_Ezi~)X(CW%Jmp7f#zI?}~g}O8^GPh@y$LoTbbBg0y_607dhvR^%CNOs)05X83W${}; zHj{}OjJJTt!#lh#Cu#N44w@rHQC4JLl?9Sn?X|}%*>GPCFD{$Crh0gFH9Ws0?!-rn zeKOPO^i#B`$S}bZ$lr=NMRl=)i{`zo5D-N{k$>L@Ax(q7o0A|77!N%(`?b@%o3cL1 z{c&n3Yf1_0qoj{F`)rLJUI)X7k_0skB%1qsF#_7}H)w4C@EZ-NisBLl56R?qlNFpq zIj1klO*#X#TQG882AcLCx0*2WTUBI6mVA<6Y>X@#P^hZ^(Q7sMJGZexb7^UEO|Ho` qxhB`-np~4>a!szuHM##6+}{8UiYE-XJo^*?0000`< literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/58.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000000000000000000000000000000000000..25a3decb48135e81a452448b490555ff12cb9e06 GIT binary patch literal 1384 zcmV-u1(*7XP)Xd?fXPs}Qv;B)w%j&TwTIISsq{PcV2-`J1}@@~I_a0FOMk)ft0uxH2tfe-2}SSmcaRNBR+q0}pltJY)) zf}|CnkFi=k7K_bprwbLUK63czhYwGOleeW`>lIpC?OHo!WD##k!s~PfTnzWu&;)RG zW78o4^d)}UJvcgv)I4vH#i;axD-8Xq_qqIpy zj(yII&F`s6lB|uk*f|R!GJdLhe)++gV63NdnzC}Nkk~l`f`HRtBV9cHbKcnIdiZYh z*!!vY?J9hI5Z)0?o>=(!ukx-^M5w$qeQe1Uy=&wWIlqSt5EM@Ybf2$QLG|R^CK>Ze z;!>adzoCA_JA`qG-OCzrX_Ezi~)X(CW%Jmp7f#zI?}~g}O8^GPh@y$LoTbbBg0y_607dhvR^%CNOs)05X83W${}; zHj{}OjJJTt!#lh#Cu#N44w@rHQC4JLl?9Sn?X|}%*>GPCFD{$Crh0gFH9Ws0?!-rn zeKOPO^i#B`$S}bZ$lr=NMRl=)i{`zo5D-N{k$>L@Ax(q7o0A|77!N%(`?b@%o3cL1 z{c&n3Yf1_0qoj{F`)rLJUI)X7k_0skB%1qsF#_7}H)w4C@EZ-NisBLl56R?qlNFpq zIj1klO*#X#TQG882AcLCx0*2WTUBI6mVA<6Y>X@#P^hZ^(Q7sMJGZexb7^UEO|Ho` qxhB`-np~4>a!szuHM##6+}{8UiYE-XJo^*?0000`< literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/60.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000000000000000000000000000000000000..d007118d0a98c07f614ed002bb323e8c59564e78 GIT binary patch literal 1473 zcmV;y1wQ(TP)H2!jX$j0}wJ2r;so_&*knY%zio!h!~a zlKz;aJSwSBGI#??IEZXL{3m+!r+$`1d?(QuLJK2NN1rNz(N6`oe+`e7%RgEsZ}Vr? zfJelS{5Skc4#T@=HA8GP%dd3H2 z^Vek0w`BLXWZh?}@vq)$^2nNZtVSsClBigcDQJM#k)T3dvL2B2Hw^WMJhk$}TD`}$ zZ$p|1Aj&iv*$E?4vF1G|l2LC&w|#qk`=`rBzdF3#)1x~*w|VwgiDT8m+rNx0d4mjn z=5mdK^&eVepH=%jAq{^`T=9#3tl2}?2fY}b^fsCQIqC6m??O6YAdE7M4k5^ys7C=u zhP@uy`PJs>Z+`g-Dw0Ht<^dx-YG_qT|8)NJhWLdkH;%Rm@2`~H{4H7e30eIE+24v> zo|L#gDtYt=viPH2H6Hpg$TI;IK#>Y)3R%u6ig^K#jOq!=Y!kil~r z6|Z9}gjp5z#DVm{=dNu3k)$qe*ti4v?{VFg?Q(fp9=`a>$IV){TeEIj`uYrVu|1jh z;iWbOi64cTvPbkVZc3nJ)i4bNtiNzGfkwr*fQd0@;*e+zdr(UCd+f%p-;y^EkTlu1 z@6ac&zFDeFjX}eP?AkSpT%SPBHYW=|I@2U?%IjSFN2OD}-z492J-yy6T@P6%`WtHo z&?Q{m=4$XENv;2YxaW5*J?r&b$2+FuH`9a^$4jZm8WI^v4%Hx&UprD0jeLpwRb{Y8 zWbb2s`{a?xoDWlPdusU^27*wguW?%p5aM+BgsgOZ);QkqVY1}M)Wxxp#PKAFrV@L| zm9dHa^{>tR=vtSD*M1}Re3W@#;54^*ms@sGT0oE(ew00L&cP7F!tQYu2XcX)@*|vfzvOl(%jS zeDO%5q9xx+y`H5@S^j4!iuJM&-AkVhy5kM>@T?D4^!c#iw~u}QO5RVe6}0^Q>Fpyv z3r~1G`3t>A$by`xm?nZS!)OEx46{y%um6ZpDUbV7r=Ml~z)MjcHp?$$^Ae+~x}j5s z_L7f1q}@lp_NRM17@z#sm8lGK}N_eNiIlaGAl{haXASqF@J+jw#mhG#Vu zS=OCZr2alA*gL3HiB?JXAT4uZ+j{u7}nsE=!VRO|!-Si9Z(v05VOR z?$eZPMYf|~Rb*X*=ASOS%%gAP3j+YQEIXoqusXkS2koF8w1alg4%$IGXb0_}9khdX b&<^?!mHCyHyg}+O00000NkvXXu0mjfzS872 literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/76.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000000000000000000000000000000000000..6648094d7ce1330eea5e056d2badb1a70bbfa5d5 GIT binary patch literal 2050 zcmV+d2>thoP)A~8&8Pq>^epPji zYuB!Y$9o9=ZwZkhGDL>R5E&vvWQYurAu>dU$PgJKLu7~yks&ffhDh!IxjFHV9!dc9 zctSD&L0|&~3S~t`2qvnClBg=$$25`vBtc%Wn9YwA<&Aof(4|zc5YPZOM|9ISS)8OH zl~SPoh87<>1aSH0kG4zokqp2lVy=9l$~|inY(BCf-cgS+6O@#eV~rOc=*wR;Mc0Yg zY}8~rMwQen)<4EcKn}w!S35_paqFUb zoOA<}0^gCMEaH}<56n&8Id@&3bH$S0$s##J7a9^GfRX}`%ZQK-iYJ+9HdMldC`w>TA*I zlHa{J-ka~5at{?@UJxg0is8l-ZfM1hj+#VUL$uz&cvO!e-f-``e-Gbe^^GV+wU7wF z8AeL{cblvYZ#r|Su_n2~y{*gs;m>9U`>k>*AVv+z`cuz4^%XDQ)mAfCTI`lVUIo5k zb2H~s){(Zabjg}y(AElx^#OBTF(#d@=%LY zd;^Og2~^L$QCR$KbZVe?Kk47n67CWVwI2@K#s8k`P?^N(vshGY_h}s z#m$KizVjk2g5$QPq(V>tAORyfTaB4$%j%z9b<4`Or25nSB81ILx3ly$+R)wE+vYC5 zHuJ6C@?FA=*BW&iL(+&5RHfn}08gW2-o5B#-t?w(sVVQIp8ND?d?!7A|BzP~C9zz0 zA_5~)fD);(Fm=JRpa0Dt{6I=z1d11ZryHzW&AGc(&&bd%ncv)2{MlsChk7J#HfTh| zfDWfR?IZ#yhJh_Vl_<8q;Os&yo7nuKD{fqw9=>CNr3@4bkQgB%=YdtU0^f_(B~RM@ z%x6CR*-E7!*9*xvDvUVawI?Su2Iz1i)UxJiBaPCn@Y$Tlx!~757#$LO7&YcwC@TR_*i*Awc zZK!LAn~fT2%eD%yYTY^nAOxQ%&!M^KeXP!T?khJJ&r3vGjx*Q2M<@-HTEFF}Gtb|) z?$m8(oO<-}$F{6!DFg3^`5(Z|hrHf}vCi_neeO+@?(^Pq`pK&tH9h0R&AJ++37Pm8 zcHRG`;#uZ7NRF>o`re*;@xo)Z4g1P{UAo0A@O2Xspzm z9qG1j>G!Uk5jT}cuff&r(O-V@%(|hj`kxNIvoH45RDBDQK&)m5oguhLwkMAW%FpV6 z{inxPot5;DJjP3%Q`@*5%@(Dk@TY}41m$j#?F+_+qO+O&K&hw4xqZ~Xeo=M#l+`rF z^wuP{@bbYkH>@;yZfdbKk9Qb)1W{Fl)j?wAlH;_|vtPbO9=xD6aaOCp=~%aUw-!5^ z5CV4y3cq94pq3e9Q}c!49L@x2)_(G``8($9yJaj3CTbXss|HX_hKvX9y3MIqJ#~G4 zps#+ocy)$#Ht9_YBtmtN2p|x>0A3v}zV4}spk8&hEt3&IiV{ z&n9Zym;oAtY9RpuxOxRyYumslw&ckMQHCZWSIQ0em#p%0 zjuzHQ5x!}4!@89sTH^>Lgcu1?C=`aq;)8RsTlr_E*oPZy5}M9*9TBUC1dvK)eId%8 z6kH$zL&nI^$Yf|BY7f@<2#8R*=Luf)gI6!vZ*2-%HYsnF;V0uNW`a^^Igv$MALnBO z_z}6)%D_t&b4R7#-~LdxaN^s-4U!yXjEAMXbxCFeXX_*&b4h8J8I;cMeE zZYoe8jxa)fu<4Bqi7=QUn(<5q!4Q*)e;Msv`m?M=vNyNH6&ncx#RZOo{~HaU`!F| z0J>7k^D?TU!b%=Llgkfc9wK45Ob{YNWQYurAu>dU$PgJKLu7~yks&ffhR6^ZB12?| g43Qx+L{>k40JS%_3M};7`v3p{07*qoM6N<$f^)Fwod5s; literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/80-1.png b/Sora-JS/Assets.xcassets/AppIcon.appiconset/80-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b0483790844c1d85fe48210db44109d8ff146bdb GIT binary patch literal 2197 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 literal 0 HcmV?d00001 diff --git a/Sora-JS/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sora-JS/Assets.xcassets/AppIcon.appiconset/Contents.json index 9221b9b..1fa06d6 100644 --- a/Sora-JS/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Sora-JS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,91 +1,109 @@ { "images" : [ { + "filename" : "40-2.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { + "filename" : "60.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { + "filename" : "58.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { + "filename" : "87.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { + "filename" : "80.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { + "filename" : "120-1.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { + "filename" : "120.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { + "filename" : "180.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { + "filename" : "20.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { + "filename" : "40-1.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { + "filename" : "29.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { + "filename" : "58-1.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { + "filename" : "40.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { + "filename" : "80-1.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { + "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { + "filename" : "152.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { + "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { + "filename" : "1024.jpg", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" diff --git a/Sora-JS/ContentView.swift b/Sora-JS/ContentView.swift index ea663bd..c92d876 100644 --- a/Sora-JS/ContentView.swift +++ b/Sora-JS/ContentView.swift @@ -6,173 +6,30 @@ // import SwiftUI - -struct AnimeItem: Identifiable { - let id = UUID() - let title: String - let imageUrl: String -} +import Kingfisher struct ContentView: View { - @StateObject private var jsController = JSController() - @EnvironmentObject var moduleManager: ModuleManager - @State private var searchText = "" - @State private var animeItems: [AnimeItem] = [] - @State private var isSearching = false - @AppStorage("selectedModuleId") private var selectedModuleId: String? - - private var selectedModule: ScrapingModule? { - guard let id = selectedModuleId else { return nil } - return moduleManager.modules.first { $0.id.uuidString == id } - } - var body: some View { - NavigationView { - VStack(spacing: 0) { - if let selectedModule = selectedModule { - HStack { - AsyncImage(url: URL(string: selectedModule.metadata.iconUrl)) { image in - image - .resizable() - .aspectRatio(contentMode: .fit) - } placeholder: { - Color.gray - } - .frame(width: 30, height: 30) - .cornerRadius(6) - - VStack(alignment: .leading) { - Text(selectedModule.metadata.mediaType) - .font(.headline) - Text(selectedModule.metadata.language) - .font(.caption) - .foregroundColor(.gray) - } - - Spacer() - - Menu { - ForEach(moduleManager.modules) { module in - Button { - selectedModuleId = module.id.uuidString - } label: { - HStack { - AsyncImage(url: URL(string: module.metadata.iconUrl)) { image in - image - .resizable() - .aspectRatio(contentMode: .fit) - } placeholder: { - Color.gray - } - .frame(width: 20, height: 20) - .cornerRadius(4) - - Text(module.metadata.mediaType) - Spacer() - if module.id.uuidString == selectedModuleId { - Image(systemName: "checkmark") - } - } - } - } - } label: { - Image(systemName: "chevron.up.chevron.down") - .foregroundColor(.gray) - } - } - .padding() - .background(Color(.systemBackground)) - .shadow(color: Color.black.opacity(0.1), radius: 2, y: 1) - } else { - VStack(spacing: 8) { - Text("No Module Selected") - .font(.headline) - Text("Please select a module from settings") - .font(.caption) - .foregroundColor(.gray) - } - .padding() - .frame(maxWidth: .infinity) - .background(Color(.systemBackground)) - .shadow(color: Color.black.opacity(0.1), radius: 2, y: 1) + TabView { + HomeView() + .tabItem { + Label("Home", systemImage: "house") } - - TextField("Search...", text: $searchText) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding() - .onChange(of: searchText) { newValue in - guard !newValue.isEmpty, let module = selectedModule else { - animeItems = [] - return - } - - isSearching = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - Task { - do { - let jsContent = try moduleManager.getModuleContent(module) - jsController.loadScript(jsContent) - jsController.scrapeAnime(keyword: newValue, module: module) { items in - animeItems = items - isSearching = false - } - } catch { - print("Error loading module: \(error)") - isSearching = false - } - } - } - } - - if isSearching { - ProgressView() - .padding() + + LibraryView() + .tabItem { + Label("Library", systemImage: "books.vertical") } - - ScrollView { - LazyVGrid(columns: [ - GridItem(.flexible(), spacing: 16), - GridItem(.flexible(), spacing: 16) - ], spacing: 16) { - ForEach(animeItems) { item in - VStack(alignment: .leading) { - if let url = URL(string: item.imageUrl) { - AsyncImage(url: url) { image in - image - .resizable() - .aspectRatio(contentMode: .fill) - } placeholder: { - Rectangle() - .fill(Color.gray.opacity(0.2)) - .overlay( - ProgressView() - ) - } - .frame(height: 200) - .clipped() - .cornerRadius(8) - } - - Text(item.title) - .font(.headline) - .lineLimit(2) - .padding(.vertical, 4) - } - .frame(maxWidth: .infinity) - .background(Color(.secondarySystemBackground)) - .cornerRadius(12) - } - } - .padding() + + SearchView() + .tabItem { + Label("Search", systemImage: "magnifyingglass") } - } - .navigationTitle("Search") - .navigationBarTitleDisplayMode(.inline) - .toolbar { - NavigationLink(destination: SettingsView()) { - Image(systemName: "gear") + + SettingsView() + .tabItem { + Label("Settings", systemImage: "gear") } - } } } } diff --git a/Sora-JS/JSController.swift b/Sora-JS/Loaders/JSController.swift similarity index 100% rename from Sora-JS/JSController.swift rename to Sora-JS/Loaders/JSController.swift diff --git a/Sora-JS/Modules.swift b/Sora-JS/Modules/Modules.swift similarity index 100% rename from Sora-JS/Modules.swift rename to Sora-JS/Modules/Modules.swift diff --git a/Sora-JS/Settings.swift b/Sora-JS/Settings.swift deleted file mode 100644 index 4e4022c..0000000 --- a/Sora-JS/Settings.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// Settings.swift -// Sora-JS -// -// Created by Francesco on 05/01/25. -// - -import SwiftUI - -struct SettingsView: View { - @EnvironmentObject var moduleManager: ModuleManager - @AppStorage("selectedModuleId") private var selectedModuleId: String? - @State private var showingAddModule = false - @State private var newModuleUrl = "" - @State private var isLoading = false - @State private var errorMessage: String? - - var body: some View { - List { - ForEach(moduleManager.modules) { module in - ModuleRow(module: module, isSelected: module.id.uuidString == selectedModuleId) - .contentShape(Rectangle()) - .onTapGesture { - selectedModuleId = module.id.uuidString - } - .swipeActions { - Button(role: .destructive) { - if selectedModuleId == module.id.uuidString { - selectedModuleId = nil - } - moduleManager.deleteModule(module) - } label: { - Label("Delete", systemImage: "trash") - } - } - } - } - .navigationTitle("Scraping Modules") - .toolbar { - Button { - showingAddModule = true - } label: { - Label("Add Module", systemImage: "plus") - } - } - .sheet(isPresented: $showingAddModule) { - NavigationView { - Form { - Section(header: Text("New Module")) { - TextField("Module JSON URL", text: $newModuleUrl) - .autocapitalization(.none) - .keyboardType(.URL) - } - - if let error = errorMessage { - Section { - Text(error) - .foregroundColor(.red) - } - } - } - .navigationTitle("Add Module") - .navigationBarItems( - leading: Button("Cancel") { - showingAddModule = false - }, - trailing: Button("Add") { - addModule() - } - .disabled(newModuleUrl.isEmpty || isLoading) - ) - } - } - } - - private func addModule() { - isLoading = true - errorMessage = nil - - Task { - do { - _ = try await moduleManager.addModule(metadataUrl: newModuleUrl) - DispatchQueue.main.async { - isLoading = false - showingAddModule = false - newModuleUrl = "" - } - } catch { - DispatchQueue.main.async { - isLoading = false - errorMessage = error.localizedDescription - } - } - } - } -} - -struct ModuleRow: View { - let module: ScrapingModule - let isSelected: Bool - - var body: some View { - HStack { - AsyncImage(url: URL(string: module.metadata.iconUrl)) { image in - image - .resizable() - .aspectRatio(contentMode: .fit) - } placeholder: { - Color.gray - } - .frame(width: 40, height: 40) - .cornerRadius(8) - - VStack(alignment: .leading) { - Text(module.metadata.mediaType) - .font(.headline) - Text("by \(module.metadata.author)") - .font(.caption) - .foregroundColor(.gray) - Text("\(module.metadata.language) • v\(module.metadata.version)") - .font(.caption2) - .foregroundColor(.gray) - } - - Spacer() - - if isSelected { - Image(systemName: "checkmark.circle.fill") - .foregroundColor(.blue) - } - } - } -} diff --git a/Sora-JS/Sora_JSApp.swift b/Sora-JS/Sora_JSApp.swift index 9d33576..70245bd 100644 --- a/Sora-JS/Sora_JSApp.swift +++ b/Sora-JS/Sora_JSApp.swift @@ -9,12 +9,18 @@ import SwiftUI @main struct Sora_JSApp: App { + @StateObject private var settings = Settings() @StateObject private var moduleManager = ModuleManager() var body: some Scene { WindowGroup { ContentView() .environmentObject(moduleManager) + .environmentObject(settings) + .accentColor(settings.accentColor) + .onAppear { + settings.updateAppearance() + } } } } diff --git a/Sora-JS/Views/HomeView.swift b/Sora-JS/Views/HomeView.swift new file mode 100644 index 0000000..db6742f --- /dev/null +++ b/Sora-JS/Views/HomeView.swift @@ -0,0 +1,16 @@ +// +// HomeView.swift +// Sora-JS +// +// Created by Francesco on 05/01/25. +// + +import SwiftUI + +struct HomeView: View { + var body: some View { + Text("Home View") + .font(.largeTitle) + .padding() + } +} diff --git a/Sora-JS/Views/LibraryView.swift b/Sora-JS/Views/LibraryView.swift new file mode 100644 index 0000000..1e6408d --- /dev/null +++ b/Sora-JS/Views/LibraryView.swift @@ -0,0 +1,16 @@ +// +// LibraryView.swift +// Sora-JS +// +// Created by Francesco on 05/01/25. +// + +import SwiftUI + +struct LibraryView: View { + var body: some View { + Text("Library View") + .font(.largeTitle) + .padding() + } +} diff --git a/Sora-JS/Views/SearchView.swift b/Sora-JS/Views/SearchView.swift new file mode 100644 index 0000000..cd144e7 --- /dev/null +++ b/Sora-JS/Views/SearchView.swift @@ -0,0 +1,174 @@ +// +// SearchView.swift +// Sora-JS +// +// Created by Francesco on 05/01/25. +// + +import SwiftUI +import Kingfisher + +struct AnimeItem: Identifiable { + let id = UUID() + let title: String + let imageUrl: String +} + +struct SearchView: View { + @StateObject private var jsController = JSController() + @EnvironmentObject var moduleManager: ModuleManager + @State private var searchText = "" + @State private var animeItems: [AnimeItem] = [] + @State private var isSearching = false + @AppStorage("selectedModuleId") private var selectedModuleId: String? + + private var selectedModule: ScrapingModule? { + guard let id = selectedModuleId else { return nil } + return moduleManager.modules.first { $0.id.uuidString == id } + } + + var body: some View { + NavigationView { + ScrollView { + VStack(spacing: 0) { + if selectedModule == nil { + VStack(spacing: 8) { + Text("No Module Selected") + .font(.headline) + Text("Please select a module from settings") + .font(.caption) + .foregroundColor(.gray) + } + .padding() + .frame(maxWidth: .infinity) + .background(Color(.systemBackground)) + .shadow(color: Color.black.opacity(0.1), radius: 2, y: 1) + } + + SearchBar(text: $searchText, onSearchButtonClicked: performSearch) + .padding() + .disabled(selectedModule == nil) + + if isSearching { + ProgressView() + .padding() + } + + LazyVGrid(columns: [GridItem(.adaptive(minimum: 150))], spacing: 16) { + ForEach(animeItems) { item in + VStack { + KFImage(URL(string: item.imageUrl)) + .resizable() + .aspectRatio(2/3, contentMode: .fill) + .cornerRadius(10) + .frame(width: 150, height: 225) + + Text(item.title) + .font(.subheadline) + .foregroundColor(Color.primary) + .padding([.leading, .bottom], 8) + .lineLimit(1) + } + } + } + .padding() + } + } + .navigationTitle("Search") + .navigationBarTitleDisplayMode(.large) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + HStack { + if let selectedModule = selectedModule { + Text(selectedModule.metadata.mediaType) + .font(.headline) + .foregroundColor(.gray) + } + Menu { + ForEach(moduleManager.modules) { module in + Button { + selectedModuleId = module.id.uuidString + } label: { + HStack { + KFImage(URL(string: module.metadata.iconUrl)) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 20, height: 20) + .cornerRadius(4) + + Text(module.metadata.mediaType) + Spacer() + if module.id.uuidString == selectedModuleId { + Image(systemName: "checkmark") + } + } + } + } + } label: { + Image(systemName: "chevron.up.chevron.down") + .foregroundColor(.gray) + } + } + } + } + } + .navigationViewStyle(StackNavigationViewStyle()) + } + + private func performSearch() { + guard !searchText.isEmpty, let module = selectedModule else { + animeItems = [] + return + } + + isSearching = true + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + Task { + do { + let jsContent = try moduleManager.getModuleContent(module) + jsController.loadScript(jsContent) + jsController.scrapeAnime(keyword: searchText, module: module) { items in + animeItems = items + isSearching = false + } + } catch { + print("Error loading module: \(error)") + isSearching = false + } + } + } + } +} + +struct SearchBar: View { + @Binding var text: String + var onSearchButtonClicked: () -> Void + + var body: some View { + HStack { + TextField("Search...", text: $text, onCommit: onSearchButtonClicked) + .padding(7) + .padding(.horizontal, 25) + .background(Color(.systemGray6)) + .cornerRadius(8) + .overlay( + HStack { + Image(systemName: "magnifyingglass") + .foregroundColor(.gray) + .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) + .padding(.leading, 8) + + if !text.isEmpty { + Button(action: { + self.text = "" + }) { + Image(systemName: "multiply.circle.fill") + .foregroundColor(.gray) + .padding(.trailing, 8) + } + } + } + ) + } + } +} diff --git a/Sora-JS/Views/SettingsView/SettingsView.swift b/Sora-JS/Views/SettingsView/SettingsView.swift new file mode 100644 index 0000000..f882c4f --- /dev/null +++ b/Sora-JS/Views/SettingsView/SettingsView.swift @@ -0,0 +1,139 @@ +// +// SettingsView.swift +// Sora-JS +// +// Created by Francesco on 05/01/25. +// + +import SwiftUI + +struct SettingsView: View { + @EnvironmentObject var settings: Settings + + var body: some View { + NavigationView { + Form { + Section(header: Text("Interface")) { + ColorPicker("Accent Color", selection: $settings.accentColor) + HStack() { + Text("Appearance") + Picker("Appearance", selection: $settings.selectedAppearance) { + Text("System").tag(Appearance.system) + Text("Light").tag(Appearance.light) + Text("Dark").tag(Appearance.dark) + } + .pickerStyle(SegmentedPickerStyle()) + } + } + + Section(header: Text("External Features")) { + NavigationLink(destination: SettingsViewModule()) { + Text("Modules") + } + } + + Section(header: Text("Info")) { + Button(action: { + if let url = URL(string: "https://github.com/cranci1/Sora") { + UIApplication.shared.open(url) + } + }) { + HStack { + Text("Sora github repo") + .foregroundColor(.primary) + Spacer() + Image(systemName: "safari") + .foregroundColor(.secondary) + } + } + Button(action: { + if let url = URL(string: "https://github.com/cranci1/Sora/issues") { + UIApplication.shared.open(url) + } + }) { + HStack { + Text("Report an issue") + .foregroundColor(.primary) + Spacer() + Image(systemName: "safari") + .foregroundColor(.secondary) + } + } + Button(action: { + if let url = URL(string: "https://discord.gg/x7hppDWFDZ") { + UIApplication.shared.open(url) + } + }) { + HStack { + Text("Join the Discord") + .foregroundColor(.primary) + Spacer() + Image(systemName: "safari") + .foregroundColor(.secondary) + } + } + } + } + .navigationTitle("Settings") + } + .navigationViewStyle(StackNavigationViewStyle()) + } +} + +enum Appearance: String, CaseIterable, Identifiable { + case system, light, dark + + var id: String { self.rawValue } +} + +class Settings: ObservableObject { + @Published var accentColor: Color { + didSet { + saveAccentColor(accentColor) + } + } + @Published var selectedAppearance: Appearance { + didSet { + UserDefaults.standard.set(selectedAppearance.rawValue, forKey: "selectedAppearance") + updateAppearance() + } + } + + init() { + if let colorData = UserDefaults.standard.data(forKey: "accentColor"), + let uiColor = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(colorData) as? UIColor { + self.accentColor = Color(uiColor) + } else { + self.accentColor = .accentColor + } + if let appearanceRawValue = UserDefaults.standard.string(forKey: "selectedAppearance"), + let appearance = Appearance(rawValue: appearanceRawValue) { + self.selectedAppearance = appearance + } else { + self.selectedAppearance = .system + } + updateAppearance() + } + + private func saveAccentColor(_ color: Color) { + let uiColor = UIColor(color) + do { + let colorData = try NSKeyedArchiver.archivedData(withRootObject: uiColor, requiringSecureCoding: false) + UserDefaults.standard.set(colorData, forKey: "accentColor") + } catch { + print("Failed to save accent color: \(error.localizedDescription)") + } + } + + func updateAppearance() { + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } + switch selectedAppearance { + case .system: + windowScene.windows.first?.overrideUserInterfaceStyle = .unspecified + case .light: + windowScene.windows.first?.overrideUserInterfaceStyle = .light + case .dark: + windowScene.windows.first?.overrideUserInterfaceStyle = .dark + } + } +} diff --git a/Sora-JS/Views/SettingsView/SubViews/SettingsViewModule.swift b/Sora-JS/Views/SettingsView/SubViews/SettingsViewModule.swift new file mode 100644 index 0000000..6a21f60 --- /dev/null +++ b/Sora-JS/Views/SettingsView/SubViews/SettingsViewModule.swift @@ -0,0 +1,126 @@ +// +// SettingsViewModule.swift +// Sora-JS +// +// Created by Francesco on 05/01/25. +// + +import SwiftUI +import Kingfisher + +struct SettingsViewModule: View { + @EnvironmentObject var moduleManager: ModuleManager + @AppStorage("selectedModuleId") private var selectedModuleId: String? + @State private var isLoading = false + @State private var errorMessage: String? + + var body: some View { + VStack { + Form { + ForEach(moduleManager.modules) { module in + HStack { + KFImage(URL(string: module.metadata.iconUrl)) + .resizable() + .frame(width: 50, height: 50) + .clipShape(Circle()) + .padding(.trailing, 10) + + VStack(alignment: .leading) { + Text(module.metadata.mediaType) + .font(.system(size: 16)) + .foregroundColor(.primary) + Text("Author: \(module.metadata.author)") + .font(.system(size: 14)) + .foregroundColor(.secondary) + Text("\(module.metadata.language) • v\(module.metadata.version)") + .font(.system(size: 14)) + .foregroundColor(.secondary) + } + + Spacer() + + if module.id.uuidString == selectedModuleId { + Image(systemName: "checkmark.circle.fill") + .foregroundColor(.accentColor) + .frame(width: 25, height: 25) + } + } + .contentShape(Rectangle()) + .onTapGesture { + selectedModuleId = module.id.uuidString + } + .contextMenu { + Button(action: { + UIPasteboard.general.string = module.metadata.iconUrl + }) { + Label("Copy URL", systemImage: "doc.on.doc") + } + Button(role: .destructive) { + if selectedModuleId == module.id.uuidString { + selectedModuleId = nil + } + moduleManager.deleteModule(module) + } label: { + Label("Delete", systemImage: "trash") + } + } + .swipeActions { + Button(role: .destructive) { + if selectedModuleId == module.id.uuidString { + selectedModuleId = nil + } + moduleManager.deleteModule(module) + } label: { + Label("Delete", systemImage: "trash") + } + } + } + } + .navigationTitle("Modules") + .navigationBarItems(trailing: Button(action: { + showAddModuleAlert() + }) { + Image(systemName: "plus") + .resizable() + .padding(5) + }) + } + } + + func showAddModuleAlert() { + let alert = UIAlertController(title: "Add Module", message: "Enter the URL of the module file", preferredStyle: .alert) + alert.addTextField { textField in + textField.placeholder = "https://real.url/module.json" + } + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: "Add", style: .default, handler: { _ in + if let url = alert.textFields?.first?.text { + addModule(from: url) + } + })) + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootViewController = windowScene.windows.first?.rootViewController { + rootViewController.present(alert, animated: true, completion: nil) + } + } + + private func addModule(from url: String) { + isLoading = true + errorMessage = nil + + Task { + do { + _ = try await moduleManager.addModule(metadataUrl: url) + DispatchQueue.main.async { + isLoading = false + } + } catch { + DispatchQueue.main.async { + isLoading = false + errorMessage = error.localizedDescription + } + } + } + } +}