diff --git a/AnimeGen.xcodeproj/project.pbxproj b/AnimeGen.xcodeproj/project.pbxproj index 540d3c5a..08c28c0d 100644 --- a/AnimeGen.xcodeproj/project.pbxproj +++ b/AnimeGen.xcodeproj/project.pbxproj @@ -34,9 +34,11 @@ 13910EC92B80D5C2009BF17E /* nekos-best.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13910EC82B80D5C2009BF17E /* nekos-best.swift */; }; 13910ECB2B80D5C8009BF17E /* waifu-pics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13910ECA2B80D5C8009BF17E /* waifu-pics.swift */; }; 139A2E0A2BA4D642003F2598 /* kyoko.swift in Sources */ = {isa = PBXBuildFile; fileRef = 139A2E092BA4D642003F2598 /* kyoko.swift */; }; - 13A2B7902BD1615600B79DF7 /* Developer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A2B78F2BD1615600B79DF7 /* Developer.swift */; }; + 13A2B7902BD1615600B79DF7 /* Hmtai-pref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A2B78F2BD1615600B79DF7 /* Hmtai-pref.swift */; }; 13A325922B94D8A100F1C357 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13A325912B94D8A100F1C357 /* Secrets.swift */; }; 13BE98C02B828B8000379AB7 /* nekosmoe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */; }; + 13C6CA732BD990E30046923C /* waifu-it.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C6CA722BD990E30046923C /* waifu-it.swift */; }; + 13C6CA752BDA2FDF0046923C /* waifu-it-pref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C6CA742BDA2FDF0046923C /* waifu-it-pref.swift */; }; 13C8011D2B94C5E900BFD198 /* HmtaiSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C8011C2B94C5E900BFD198 /* HmtaiSender.swift */; }; 13C8011F2B94CAD900BFD198 /* HmtaiReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C8011E2B94CAD900BFD198 /* HmtaiReader.swift */; }; 13CC95082B8BA40100B5705E /* ApiPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CC95072B8BA40100B5705E /* ApiPage.swift */; }; @@ -74,9 +76,11 @@ 13910EC82B80D5C2009BF17E /* nekos-best.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "nekos-best.swift"; sourceTree = ""; }; 13910ECA2B80D5C8009BF17E /* waifu-pics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "waifu-pics.swift"; sourceTree = ""; }; 139A2E092BA4D642003F2598 /* kyoko.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = kyoko.swift; sourceTree = ""; }; - 13A2B78F2BD1615600B79DF7 /* Developer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Developer.swift; sourceTree = ""; }; + 13A2B78F2BD1615600B79DF7 /* Hmtai-pref.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Hmtai-pref.swift"; sourceTree = ""; }; 13A325912B94D8A100F1C357 /* Secrets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = ""; }; 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = nekosmoe.swift; sourceTree = ""; }; + 13C6CA722BD990E30046923C /* waifu-it.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "waifu-it.swift"; sourceTree = ""; }; + 13C6CA742BDA2FDF0046923C /* waifu-it-pref.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "waifu-it-pref.swift"; sourceTree = ""; }; 13C8011C2B94C5E900BFD198 /* HmtaiSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HmtaiSender.swift; sourceTree = ""; }; 13C8011E2B94CAD900BFD198 /* HmtaiReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HmtaiReader.swift; sourceTree = ""; }; 13CC95072B8BA40100B5705E /* ApiPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiPage.swift; sourceTree = ""; }; @@ -176,10 +180,10 @@ 13877B1A2B82017A00251A60 /* Settings */ = { isa = PBXGroup; children = ( + 13C6CA762BDA3ABC0046923C /* Developer-Pref */, 13877B182B82001800251A60 /* SettingsPage.swift */, 13877B1D2B82024A00251A60 /* AboutPage.swift */, 13CC95072B8BA40100B5705E /* ApiPage.swift */, - 13A2B78F2BD1615600B79DF7 /* Developer.swift */, 13CC95092B8BA43600B5705E /* API.xcassets */, ); path = Settings; @@ -197,6 +201,7 @@ 13BE98BF2B828B8000379AB7 /* nekosmoe.swift */, 139A2E092BA4D642003F2598 /* kyoko.swift */, 13E2DC832BA5D2CF00320E2F /* purr.swift */, + 13C6CA722BD990E30046923C /* waifu-it.swift */, ); path = APIs; sourceTree = ""; @@ -212,6 +217,15 @@ path = Extensions; sourceTree = ""; }; + 13C6CA762BDA3ABC0046923C /* Developer-Pref */ = { + isa = PBXGroup; + children = ( + 13A2B78F2BD1615600B79DF7 /* Hmtai-pref.swift */, + 13C6CA742BDA2FDF0046923C /* waifu-it-pref.swift */, + ); + path = "Developer-Pref"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -295,6 +309,7 @@ 1375B3EA2BB813DA00E3D128 /* Activity.swift in Sources */, 139A2E0A2BA4D642003F2598 /* kyoko.swift in Sources */, 13E2DC842BA5D2CF00320E2F /* purr.swift in Sources */, + 13C6CA752BDA2FDF0046923C /* waifu-it-pref.swift in Sources */, 13910EC72B80D5B9009BF17E /* waifu-im.swift in Sources */, 13877B192B82001800251A60 /* SettingsPage.swift in Sources */, 13BE98C02B828B8000379AB7 /* nekosmoe.swift in Sources */, @@ -305,9 +320,10 @@ 130A80552B78C02E0028985F /* SceneDelegate.swift in Sources */, 13910ECB2B80D5C8009BF17E /* waifu-pics.swift in Sources */, 13877B1E2B82024A00251A60 /* AboutPage.swift in Sources */, + 13C6CA732BD990E30046923C /* waifu-it.swift in Sources */, 13910EC52B80D5A6009BF17E /* pic-re.swift in Sources */, 1365E8202BB0112D005E0548 /* HistoryView.swift in Sources */, - 13A2B7902BD1615600B79DF7 /* Developer.swift in Sources */, + 13A2B7902BD1615600B79DF7 /* Hmtai-pref.swift in Sources */, 1365E8222BB011F6005E0548 /* ImageHistory.swift in Sources */, 13C8011D2B94C5E900BFD198 /* HmtaiSender.swift in Sources */, 131515712BAB284A00A1C770 /* Refresh-API-Button.swift in Sources */, @@ -469,7 +485,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = AnimeGen/AnimeGen.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 27; + CURRENT_PROJECT_VERSION = 28; DEVELOPMENT_TEAM = 399LMK6Q2Y; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AnimeGen/Info.plist; @@ -504,7 +520,7 @@ CODE_SIGN_ENTITLEMENTS = AnimeGen/AnimeGen.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 27; + CURRENT_PROJECT_VERSION = 28; DEVELOPMENT_TEAM = 399LMK6Q2Y; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AnimeGen/Info.plist; diff --git a/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate b/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate index 547d44ed..1f13917d 100644 Binary files a/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate and b/AnimeGen.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/AnimeGen/APIs/kyoko.swift b/AnimeGen/APIs/kyoko.swift index 7972fbdd..1f4f2c13 100644 --- a/AnimeGen/APIs/kyoko.swift +++ b/AnimeGen/APIs/kyoko.swift @@ -28,20 +28,24 @@ extension ViewController { let apiEndpoint = "\(endpointPrefix)\(randomCategory)" guard let url = URL(string: apiEndpoint) else { + showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) print("Invalid URL") stopLoadingIndicator() return } - let task = URLSession.shared.dataTask(with: url) { (data, response, error) in + let task = URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in + guard let self = self else { return } DispatchQueue.main.async { if let error = error { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) print("Invalid HTTP response") self.stopLoadingIndicator() return @@ -49,49 +53,25 @@ extension ViewController { if let data = data { do { - if let jsonResponse = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], + if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let requestResult = jsonResponse["RequestResult"] as? [String: Any], let imageUrlString = requestResult["url"] as? String, let imageUrl = URL(string: imageUrlString) { - - if let imageData = try? Data(contentsOf: imageUrl) { - if imageUrlString.lowercased().hasSuffix(".gif") { - if let animatedImage = UIImage.animatedImage(with: UIImage.gifData(data: imageData) ?? [], duration: 1.0) { - self.imageView.image = animatedImage - self.imageView.image = animatedImage - self.animateImageChange(with: animatedImage) - } else { - print("Failed to create animated image from GIF data.") - } - } else { - if let newImage = UIImage(data: imageData) { - self.imageView.image = newImage - self.animateImageChange(with: newImage) - self.addToHistory(image: newImage) - } else { - print("Failed to load image data.") - } - } - - self.currentImageURL = imageUrlString - - self.tagsLabel.isHidden = false - - self.updateUIWithTags([randomCategory]) - - self.stopLoadingIndicator() - - self.incrementCounter() - } else { - print("Failed to load image data.") - self.stopLoadingIndicator() - } + + self.loadImage(from: imageUrl, withCategory: randomCategory) + } else { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing necessary data.", viewController: self) print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() } + } catch { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response.", viewController: self) + print("Failed to parse JSON response:", error) + self.stopLoadingIndicator() } } else { + self.showAlert(withTitle: "Error!", message: "No data received from server.", viewController: self) print("No data received from server.") self.stopLoadingIndicator() } @@ -101,4 +81,57 @@ extension ViewController { task.resume() } + func loadImage(from url: URL, withCategory category: String) { + URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in + guard let self = self else { return } + if let error = error { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + print("Error loading image:", error) + self.stopLoadingIndicator() + return + } + + guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + self.showAlert(withTitle: "Invalid HTTP response", message: "Failed to load image.", viewController: self) + print("Invalid HTTP response") + self.stopLoadingIndicator() + return + } + + if let data = data { + DispatchQueue.main.async { + if let image = UIImage(data: data) { + if url.absoluteString.lowercased().hasSuffix(".gif") { + if let animatedImage = UIImage.animatedImage(with: UIImage.gifData(data: data) ?? [], duration: 1.0) { + self.imageView.image = animatedImage + self.addToHistory(image: animatedImage) + self.animateImageChange(with: animatedImage) + } else { + self.showAlert(withTitle: "Error!", message: "Failed to create animated image from GIF data.", viewController: self) + print("Failed to create animated image from GIF data.") + } + } else { + self.imageView.image = image + self.addToHistory(image: image) + self.animateImageChange(with: image) + } + + self.tagsLabel.isHidden = false + self.updateUIWithTags([category]) + self.currentImageURL = url.absoluteString + self.stopLoadingIndicator() + self.incrementCounter() + } else { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + print("Failed to load image data.") + self.stopLoadingIndicator() + } + } + } else { + self.showAlert(withTitle: "Error!", message: "No image data received from server.", viewController: self) + print("No image data received from server.") + self.stopLoadingIndicator() + } + }.resume() + } } diff --git a/AnimeGen/APIs/nekos-best.swift b/AnimeGen/APIs/nekos-best.swift index 01df6513..970e618a 100644 --- a/AnimeGen/APIs/nekos-best.swift +++ b/AnimeGen/APIs/nekos-best.swift @@ -18,6 +18,11 @@ extension ViewController { let apiEndpoint = "https://nekos.best/api/v2/\(randomCategory)" guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -29,18 +34,33 @@ extension ViewController { let task = URLSession.shared.dataTask(with: request) { (data, response, error) in DispatchQueue.main.async { if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return } guard httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid status code", message: "\(httpResponse.statusCode)", viewController: self) + } + print("Invalid status code: \(httpResponse.statusCode)") self.stopLoadingIndicator() return @@ -68,12 +88,21 @@ extension ViewController { self.stopLoadingIndicator() self.incrementCounter() } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + print("Failed to load image data.") self.stopLoadingIndicator() } } else { print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } } } } diff --git a/AnimeGen/APIs/nekosapi.swift b/AnimeGen/APIs/nekosapi.swift index 0115eaae..f9d504d9 100644 --- a/AnimeGen/APIs/nekosapi.swift +++ b/AnimeGen/APIs/nekosapi.swift @@ -23,6 +23,11 @@ extension ViewController { let apiEndpoint = "https://api.nekosapi.com/v3/images/random?limit=1&rating=\(randomRating)" guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -34,18 +39,33 @@ extension ViewController { let task = URLSession.shared.dataTask(with: request) { (data, response, error) in DispatchQueue.main.async { if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return } guard httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid status code", message: "\(httpResponse.statusCode)", viewController: self) + } + print("Invalid status code: \(httpResponse.statusCode)") self.stopLoadingIndicator() return @@ -79,10 +99,19 @@ extension ViewController { } else { print("Failed to load image data.") self.stopLoadingIndicator() + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + } } else { print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } } } } diff --git a/AnimeGen/APIs/nekosmoe.swift b/AnimeGen/APIs/nekosmoe.swift index 556580f5..16cdf00c 100644 --- a/AnimeGen/APIs/nekosmoe.swift +++ b/AnimeGen/APIs/nekosmoe.swift @@ -18,6 +18,11 @@ extension ViewController { let apiEndpoint = "https://nekos.moe/api/v1/random/image" guard var components = URLComponents(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -26,6 +31,11 @@ extension ViewController { components.queryItems = [URLQueryItem(name: "nsfw", value: isNSFW.description.lowercased())] guard let url = components.url else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -44,6 +54,11 @@ extension ViewController { let images = jsonResponse["images"] as? [[String: Any]], let firstImage = images.first, let imageId = firstImage["id"] as? String else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to get valid response.", viewController: self) + } + print("Failed to get valid response.") self.stopLoadingIndicator() return @@ -78,6 +93,11 @@ extension ViewController { let imageTask = URLSession.shared.dataTask(with: imageRequest) { (imageData, _, imageError) in DispatchQueue.main.async { if let imageError = imageError { + + if self.alert { + self.showAlert(withTitle: "Image loading error", message: "\(imageError)", viewController: self) + } + print("Image loading error: \(imageError)") } else if let imageData = imageData, let newImage = UIImage(data: imageData) { self.imageView.image = newImage @@ -86,6 +106,11 @@ extension ViewController { self.tagsLabel.isHidden = !self.moetags self.incrementCounter() } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + print("Failed to load image data.") } self.stopLoadingIndicator() diff --git a/AnimeGen/APIs/pic-re.swift b/AnimeGen/APIs/pic-re.swift index 35799280..64e8d087 100644 --- a/AnimeGen/APIs/pic-re.swift +++ b/AnimeGen/APIs/pic-re.swift @@ -15,6 +15,11 @@ extension ViewController { let apiEndpoint = "https://pic.re/image" guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -25,18 +30,33 @@ extension ViewController { let task = URLSession.shared.dataTask(with: request) { (data, response, error) in if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return } guard httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid status code", message: "\(httpResponse.statusCode)", viewController: self) + } + print("Invalid status code: \(httpResponse.statusCode)") self.stopLoadingIndicator() return @@ -53,12 +73,22 @@ extension ViewController { } } else { print("No image tags found in response headers.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "No image tags found in response headers.", viewController: self) + } + self.stopLoadingIndicator() return } guard let data = data, let newImage = UIImage(data: data) else { print("Invalid image data") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Invalid image data.", viewController: self) + } + self.stopLoadingIndicator() return } diff --git a/AnimeGen/APIs/purr.swift b/AnimeGen/APIs/purr.swift index e91210b5..742aee17 100644 --- a/AnimeGen/APIs/purr.swift +++ b/AnimeGen/APIs/purr.swift @@ -31,6 +31,11 @@ extension ViewController { let apiEndpoint = "\(endpointPrefix)\(randomCategory)" guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -39,12 +44,22 @@ extension ViewController { let task = URLSession.shared.dataTask(with: url) { (data, response, error) in DispatchQueue.main.async { if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return @@ -64,6 +79,11 @@ extension ViewController { self.animateImageChange(with: animatedImage) } else { print("Failed to create animated image from GIF data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to create animated image from GIF data.", viewController: self) + } + } } else { if let newImage = UIImage(data: imageData) { @@ -72,6 +92,10 @@ extension ViewController { self.addToHistory(image: newImage) } else { print("Failed to load image data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } } } @@ -86,15 +110,28 @@ extension ViewController { self.incrementCounter() } else { + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } print("Failed to load image data.") self.stopLoadingIndicator() } } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } + print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() } } } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "No data received from the server.", viewController: self) + } + print("No data received from server.") self.stopLoadingIndicator() } diff --git a/AnimeGen/APIs/waifu-im.swift b/AnimeGen/APIs/waifu-im.swift index 2219554f..295786f8 100644 --- a/AnimeGen/APIs/waifu-im.swift +++ b/AnimeGen/APIs/waifu-im.swift @@ -22,6 +22,11 @@ extension ViewController { ] guard let url = components?.url else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -33,18 +38,33 @@ extension ViewController { let task = URLSession.shared.dataTask(with: request) { (data, response, error) in DispatchQueue.main.async { if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return } guard httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid status code", message: "\(httpResponse.statusCode)", viewController: self) + } + print("Invalid status code: \(httpResponse.statusCode)") self.stopLoadingIndicator() return @@ -77,10 +97,20 @@ extension ViewController { self.incrementCounter() } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + print("Failed to load image data.") self.stopLoadingIndicator() } } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } + print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() } diff --git a/AnimeGen/APIs/waifu-it.swift b/AnimeGen/APIs/waifu-it.swift new file mode 100644 index 00000000..73d3e832 --- /dev/null +++ b/AnimeGen/APIs/waifu-it.swift @@ -0,0 +1,131 @@ +// +// waifu-it.swift +// AnimeGen +// +// Created by cranci on 24/04/24. +// + +import UIKit + +extension ViewController { + + func loadImageFromWaifuIt() { + startLoadingIndicator() + + let categories: [String] + let endpointPrefix: String = "https://waifu.it/api/v4/" + + if UserDefaults.standard.bool(forKey: "enableExplictiCont") { + categories = ["angry", "baka", "bite", "blush", "bonk", "bored", "bully", "bye", "chase", "cheer", "cringe", "cry", "dab", "dance", "die", "disgust", "facepalm", "feed", "glomp", "happy", "hi", "highfive", "hold", "hug", "kick", "kill", "kiss", "laugh", "lick", "love", "lurk", "midfing", "nervous", "nom", "nope", "nuzzle", "panic", "pat", "peck", "poke", "pout", "punch", "run", "sad", "shoot", "shrug", "sip", "slap", "sleepy", "smile", "smug", "stab", "stare", "suicide", "tease", "think", "thumbsup", "tickle", "triggered", "wag", "wave", "wink", "yes"] + } else { + categories = ["angry", "baka", "bite", "blush", "bonk", "bored", "bye", "chase", "cheer", "cringe", "cry", "cuddle", "dab", "dance", "disgust", "facepalm", "feed", "glomp", "happy", "hi", "highfive", "hold", "hug", "kick", "kiss", "laugh", "lurk", "nervous", "nom", "nope", "nuzzle", "panic", "pat", "peck", "poke", "pout", "run", "sad", "shrug", "sip", "slap", "sleepy", "smile", "smug", "stare", "tease", "think", "thumbsup", "tickle", "wag", "wave", "wink", "yes"] + } + + let randomCategory = categories.randomElement() ?? "pat" + + let apiEndpoint = "\(endpointPrefix)\(randomCategory)" + + guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + + print("Invalid URL") + stopLoadingIndicator() + return + } + + var request = URLRequest(url: url) + request.setValue(Secrets.waifuItToken, forHTTPHeaderField: "Authorization") + + let task = URLSession.shared.dataTask(with: request) { (data, response, error) in + DispatchQueue.main.async { + if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + + print("Error: \(error)") + self.stopLoadingIndicator() + return + } + + guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please check your API Token.", viewController: self) + } + + print("Invalid HTTP response") + self.stopLoadingIndicator() + return + } + + if let data = data, let jsonResponse = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let imageUrlString = jsonResponse["url"] as? String, let imageUrl = URL(string: imageUrlString) { + + if let imageData = try? Data(contentsOf: imageUrl) { + if imageUrlString.lowercased().hasSuffix(".gif") { + if let animatedImage = UIImage.animatedImage(with: UIImage.gifData(data: imageData) ?? [], duration: 1.0) { + self.imageView.image = animatedImage + self.imageView.image = animatedImage + self.animateImageChange(with: animatedImage) + self.addToHistory(image: animatedImage) + } else { + print("Failed to create animated image from GIF data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to create animated image from GIF data.", viewController: self) + } + + } + } else { + if let newImage = UIImage(data: imageData) { + self.imageView.image = newImage + self.addToHistory(image: newImage) + self.animateImageChange(with: newImage) + } else { + print("Failed to load image data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + + } + } + + self.currentImageURL = imageUrlString + + self.tagsLabel.isHidden = false + + self.updateUIWithTags([randomCategory]) + + self.stopLoadingIndicator() + + self.incrementCounter() + } else { + print("Failed to load image data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + + self.stopLoadingIndicator() + } + } else { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } + + print("Failed to parse JSON response or missing necessary data.") + self.stopLoadingIndicator() + } + } + } + + task.resume() + } + +} diff --git a/AnimeGen/APIs/waifu-pics.swift b/AnimeGen/APIs/waifu-pics.swift index 1caa9df0..e0c86281 100644 --- a/AnimeGen/APIs/waifu-pics.swift +++ b/AnimeGen/APIs/waifu-pics.swift @@ -28,6 +28,11 @@ extension ViewController { let apiEndpoint = "\(endpointPrefix)\(randomCategory)" guard let url = URL(string: apiEndpoint) else { + + if self.alert { + self.showAlert(withTitle: "Invalid URL", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid URL") stopLoadingIndicator() return @@ -36,12 +41,22 @@ extension ViewController { let task = URLSession.shared.dataTask(with: url) { (data, response, error) in DispatchQueue.main.async { if let error = error { + + if self.alert { + self.showAlert(withTitle: "Error!", message: "\(error)", viewController: self) + } + print("Error: \(error)") self.stopLoadingIndicator() return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + + if self.alert { + self.showAlert(withTitle: "Invalid HTTP response", message: "Please wait, the api may be down.", viewController: self) + } + print("Invalid HTTP response") self.stopLoadingIndicator() return @@ -54,9 +69,15 @@ extension ViewController { if let animatedImage = UIImage.animatedImage(with: UIImage.gifData(data: imageData) ?? [], duration: 1.0) { self.imageView.image = animatedImage self.imageView.image = animatedImage + self.addToHistory(image: animatedImage) self.animateImageChange(with: animatedImage) } else { print("Failed to create animated image from GIF data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to create animated image from GIF data.", viewController: self) + } + } } else { if let newImage = UIImage(data: imageData) { @@ -65,6 +86,11 @@ extension ViewController { self.animateImageChange(with: newImage) } else { print("Failed to load image data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + } } @@ -79,11 +105,20 @@ extension ViewController { self.incrementCounter() } else { print("Failed to load image data.") + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to load image data.", viewController: self) + } + self.stopLoadingIndicator() } } else { print("Failed to parse JSON response or missing necessary data.") self.stopLoadingIndicator() + + if self.alert { + self.showAlert(withTitle: "Error!", message: "Failed to parse JSON response or missing data.", viewController: self) + } } } } diff --git a/AnimeGen/AppDelegate.swift b/AnimeGen/AppDelegate.swift index e710c130..9516c0d7 100644 --- a/AnimeGen/AppDelegate.swift +++ b/AnimeGen/AppDelegate.swift @@ -18,6 +18,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { UserDefaults.standard.register(defaults: ["enableAnimations": true]) UserDefaults.standard.register(defaults: ["enableTags": true]) + UserDefaults.standard.register(defaults: ["enableGestures": true]) + UserDefaults.standard.register(defaults: ["enableKyokobanner": true]) // Tutorial View Prompt diff --git a/AnimeGen/Boarding/Main-onboard.swift b/AnimeGen/Boarding/Main-onboard.swift index 679bb08f..4246fa92 100644 --- a/AnimeGen/Boarding/Main-onboard.swift +++ b/AnimeGen/Boarding/Main-onboard.swift @@ -23,7 +23,7 @@ struct TutorialView: View { if #available(iOS 15.0, *) { return [ TutorialStep(text: "Welcom to AnimeGen", icon: "star.fill", tintColor: .accentColor, position: "A simple way to enjoy anime Art"), - TutorialStep(text: "Tap the Top button to switch image providers. There are 9 API options with unique images.", icon: "bookmark.fill", tintColor: .yellow, position: "Placed on the Top Center"), + TutorialStep(text: "Tap the Top button to switch image providers. There are 10 API options with unique images.", icon: "bookmark.fill", tintColor: .yellow, position: "Placed on the Top Center"), TutorialStep(text: "Hit refresh for a new image.", icon: "arrow.clockwise.circle.fill", tintColor: .secondary, position: "Placed on the Bottom Center"), TutorialStep(text: "Show some love! Tap the heart to save an image.", icon: "heart.fill", tintColor: .red, position: "Placed on the Bottom Center Right"), TutorialStep(text: "Rewind to the last image with the rewind icon.", icon: "arrowshape.turn.up.backward.circle.fill", tintColor: .green, position: "Placed on the Bottom Center Left"), @@ -37,7 +37,7 @@ struct TutorialView: View { } else { return [ TutorialStep(text: "Welcom to AnimeGen", icon: "star.fill", tintColor: .accentColor, position: "A simple way to enjoy anime Art"), - TutorialStep(text: "Tap the Top button to switch image providers. There are 9 API options with unique images.", icon: "bookmark.fill", tintColor: .yellow, position: "Placed on the Top Center"), + TutorialStep(text: "Tap the Top button to switch image providers. There are 10 API options with unique images.", icon: "bookmark.fill", tintColor: .yellow, position: "Placed on the Top Center"), TutorialStep(text: "Hit refresh for a new image.", icon: "arrow.clockwise.circle.fill", tintColor: .secondary, position: "Placed on the Bottom Center"), TutorialStep(text: "Show some love! Tap the heart to save an image.", icon: "heart.fill", tintColor: .red, position: "Placed on the Bottom Center Right"), TutorialStep(text: "Rewind to the last image with the rewind icon.", icon: "arrowshape.turn.up.backward.circle.fill", tintColor: .green, position: "Placed on the Bottom Center Left"), diff --git a/AnimeGen/Buttons/Refresh-API-Button.swift b/AnimeGen/Buttons/Refresh-API-Button.swift index 5157a1b6..7c15515a 100644 --- a/AnimeGen/Buttons/Refresh-API-Button.swift +++ b/AnimeGen/Buttons/Refresh-API-Button.swift @@ -29,6 +29,9 @@ extension ViewController { case "waifu.im": lastImage = imageView.image loadImageFromWaifuIm() + case "waifu.it": + lastImage = imageView.image + loadImageFromWaifuIt() case "nekos.best": lastImage = imageView.image loadImageFromNekosBest() @@ -66,7 +69,7 @@ extension ViewController { @objc func apiButtonTapped() { let alertController = UIAlertController(title: "Select API", message: nil, preferredStyle: .actionSheet) - let apiOptions = ["Purr", "kyoko", "nekos.moe", "Nekos api", "Hmtai api", "waifu.pics", "nekos.best", "waifu.im", "pic.re"] + let apiOptions = ["Purr", "kyoko", "Hmtai" , "nekos.moe", "Nekos api", "nekos.best", "waifu.it", "waifu.pics", "waifu.im", "pic.re"] for option in apiOptions { let action = UIAlertAction(title: option, style: .default) { _ in self.apiButton.setTitle(option, for: .normal) diff --git a/AnimeGen/Extensions/popup-Banner.swift b/AnimeGen/Extensions/popup-Banner.swift index 28942fe9..a2469c3d 100644 --- a/AnimeGen/Extensions/popup-Banner.swift +++ b/AnimeGen/Extensions/popup-Banner.swift @@ -26,4 +26,10 @@ extension ViewController { } } + func showAlert(withTitle title: String, message: String, viewController: UIViewController) { + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + let okAction = UIAlertAction(title: "OK", style: .default, handler: nil) + alertController.addAction(okAction) + viewController.present(alertController, animated: true, completion: nil) + } } diff --git a/AnimeGen/Secrets.swift b/AnimeGen/Secrets.swift index b909b1c0..3c673232 100644 --- a/AnimeGen/Secrets.swift +++ b/AnimeGen/Secrets.swift @@ -13,4 +13,6 @@ struct Secrets { static var discordWebhookURL = URL(string: "YourWebhookUrl")! static var discordChannelId = "YourChannelIdHere" + + static var waifuItToken = "MTAwMTA1Njg1MDI2NDk5Nzg5OA--.MTcxMzk4NTIzMw--.27303c03394" // dont steal lol, } diff --git a/AnimeGen/Settings/API.xcassets/waifu.it.imageset/79479798.png b/AnimeGen/Settings/API.xcassets/waifu.it.imageset/79479798.png new file mode 100644 index 00000000..269566c6 Binary files /dev/null and b/AnimeGen/Settings/API.xcassets/waifu.it.imageset/79479798.png differ diff --git a/AnimeGen/Settings/API.xcassets/waifu.it.imageset/Contents.json b/AnimeGen/Settings/API.xcassets/waifu.it.imageset/Contents.json new file mode 100644 index 00000000..e8c7886f --- /dev/null +++ b/AnimeGen/Settings/API.xcassets/waifu.it.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "79479798.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AnimeGen/Settings/ApiPage.swift b/AnimeGen/Settings/ApiPage.swift index 7c64275c..42b06bb6 100644 --- a/AnimeGen/Settings/ApiPage.swift +++ b/AnimeGen/Settings/ApiPage.swift @@ -18,10 +18,11 @@ struct ApiPage: View { APIInfo(imageName: "pic-re", apiName: "pic.re", url: URL(string: "https://pic.re")!), APIInfo(imageName: "waifu.im", apiName: "waifu.im", url: URL(string: "https://waifu.im")!), APIInfo(imageName: "waifu.pics", apiName: "waifu.pics", url: URL(string: "https://waifu.pics")!), + APIInfo(imageName: "waifu.it", apiName: "waifu.it", url: URL(string: "https://waifu.it/")!), APIInfo(imageName: "nekos.best", apiName: "nekos.best", url: URL(string: "https://nekos.best")!), - APIInfo(imageName: "Hmtai", apiName: "Hmtai", url: URL(string: "https://hmtai.hatsunia.cfd/endpoints")!), APIInfo(imageName: "nekosapi", apiName: "nekosapi.com", url: URL(string: "https://nekosapi.com")!), APIInfo(imageName: "nekos.moe", apiName: "nekos.moe", url: URL(string: "https://nekos.moe")!), + APIInfo(imageName: "Hmtai", apiName: "Hmtai", url: URL(string: "https://hmtai.hatsunia.cfd/endpoints")!), APIInfo(imageName: "kyoko", apiName: "Kyoko", url: URL(string: "https://api.rei.my.id/docs/ANIME/WAIFU-Generator/")!), APIInfo(imageName: "Purr", apiName: "Purr", url: URL(string: "https://purrbot.site/")!) ] diff --git a/AnimeGen/Settings/Developer.swift b/AnimeGen/Settings/Developer-Pref/Hmtai-pref.swift similarity index 88% rename from AnimeGen/Settings/Developer.swift rename to AnimeGen/Settings/Developer-Pref/Hmtai-pref.swift index 78e8c080..a21fdd72 100644 --- a/AnimeGen/Settings/Developer.swift +++ b/AnimeGen/Settings/Developer-Pref/Hmtai-pref.swift @@ -1,5 +1,5 @@ // -// Developer.swift +// Hmtai-pref.swift // AnimeGen // // Created by cranci on 18/04/24. @@ -29,7 +29,7 @@ struct DeveloperView: View { TextField("Bot DiscordTokenHere", text: $apiToken) .padding() .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1)) - Text("On this value you need to remove 'DiscordTokenHere' and replace it with your discord bot token. Dont remove the 'Bot' prefix and also leave the space.") + Text("Replace 'DiscordTokenHere' with your Discord bot token.") .font(.caption) .padding(.top, -10) .foregroundColor(.gray) @@ -38,7 +38,7 @@ struct DeveloperView: View { TextField("Discord Webhook URL", text: $discordWebhookURL) .padding() .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1)) - Text("On this value make sure to put your discord webhook with the https://") + Text("Provide your Discord webhook URL starting with 'https://'") .font(.caption) .padding(.top, -10) .foregroundColor(.gray) @@ -47,7 +47,7 @@ struct DeveloperView: View { TextField("Discord Channel ID", text: $discordChannelId) .padding() .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1)) - Text("On this value you need to past your discord channel ID.") + Text("Enter your Discord channel ID.") .font(.caption) .padding(.top, -10) .foregroundColor(.gray) @@ -72,7 +72,7 @@ struct DeveloperView: View { Spacer() } .padding() - .navigationBarTitle("Developer Settings", displayMode: .inline) + .navigationBarTitle("Settings", displayMode: .inline) } private func saveValues() { diff --git a/AnimeGen/Settings/Developer-Pref/waifu-it-pref.swift b/AnimeGen/Settings/Developer-Pref/waifu-it-pref.swift new file mode 100644 index 00000000..69a45e80 --- /dev/null +++ b/AnimeGen/Settings/Developer-Pref/waifu-it-pref.swift @@ -0,0 +1,68 @@ +// +// waifu-it-pref.swift +// AnimeGen +// +// Created by cranci on 25/04/24. +// + +import SwiftUI + +struct waifuitView: View { + @State private var waifuittoken: String + + + init() { + _waifuittoken = State(initialValue: UserDefaults.standard.string(forKey: "waifuItToken") ?? Secrets.waifuItToken) + } + + var body: some View { + VStack { + VStack(spacing: 20) { + Text("Waifu.it Preferences") + .font(.largeTitle) + .fontWeight(.semibold) + .frame(maxWidth: .infinity, alignment: .leading) + + TextField("API Token", text: $waifuittoken) + .padding() + .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1)) + Text("Enter your Waifu.it API token.") + .font(.caption) + .padding(.top, -10) + .foregroundColor(.gray) + .frame(maxWidth: .infinity, alignment: .leading) + } + + Button(action: { + saveValues2() + }) { + Text("Save") + .foregroundColor(.white) + .padding() + .frame(maxWidth: .infinity) + .background( + RoundedRectangle(cornerRadius: 10) + .fill(Color.accentColor) + .shadow(radius: 5) + ) + } + .padding(.top, 20) + + Spacer() + } + .padding() + .navigationBarTitle("Settings", displayMode: .inline) + + } + + private func saveValues2() { + UserDefaults.standard.set(waifuittoken, forKey: "waifuItToken") + Secrets.waifuItToken = waifuittoken + } +} + +struct waifuitView_Previews: PreviewProvider { + static var previews: some View { + waifuitView() + } +} diff --git a/AnimeGen/Settings/SettingsPage.swift b/AnimeGen/Settings/SettingsPage.swift index 334a6bb8..aa7d5c0e 100644 --- a/AnimeGen/Settings/SettingsPage.swift +++ b/AnimeGen/Settings/SettingsPage.swift @@ -15,15 +15,17 @@ struct SettingsPage: View { @State private var activitytime = UserDefaults.standard.bool(forKey: "enableTime") @State private var gestures = UserDefaults.standard.bool(forKey: "enableGestures") - // Tags + // API preferences @State private var tags = UserDefaults.standard.bool(forKey: "enableTags") @State private var moetags = UserDefaults.standard.bool(forKey: "enableMoeTags") + @State private var kyokobanner = UserDefaults.standard.bool(forKey: "enableKyokobanner") // Content @State private var explicitCont = UserDefaults.standard.bool(forKey: "enableExplictiCont") // Devloper Mode @State private var developerMode = UserDefaults.standard.bool(forKey: "enableDeveloperMode") + @State private var developerAlert = UserDefaults.standard.bool(forKey: "enableDeveloperAlert") // Tutorial @State private var isShowingTutorial = false @@ -64,7 +66,7 @@ struct SettingsPage: View { )) } - Section(header: Text("Tags"), footer: Text("An app restart is necessary to enable or disable the changes.")) { + Section(header: Text("Api Preferences"), footer: Text("An app restart is necessary to enable or disable the changes.")) { Toggle("Display Tags", isOn: Binding( get: { self.tags }, set: { newValue in @@ -79,6 +81,14 @@ struct SettingsPage: View { UserDefaults.standard.set(newValue, forKey: "enableMoeTags") } )) + Toggle("Kyoko 'Note' banner", isOn: Binding( + get: { self.kyokobanner }, + set: { newValue in + self.kyokobanner = newValue + UserDefaults.standard.set(newValue, forKey: "enableKyokobanner") + } + )) + } Section(header: Text("Content"), footer: Text("This content is on the borderline of explicit material and includes adult content. Viewer discretion is advised.")) { @@ -100,13 +110,29 @@ struct SettingsPage: View { UserDefaults.standard.set(newValue, forKey: "enableDeveloperMode") } )) + + Toggle("Developer Alert", isOn: Binding( + get: { self.developerAlert }, + set: { newValue in + self.developerAlert = newValue + UserDefaults.standard.set(newValue, forKey: "enableDeveloperAlert") + } + )) if UserDefaults.standard.bool(forKey: "enableDeveloperMode") { NavigationLink(destination: DeveloperView()) { - Text("Developer Settings") + Text("Hmtai Preferences") .foregroundColor(.accentColor) } } + + if UserDefaults.standard.bool(forKey: "enableDeveloperMode") { + NavigationLink(destination: waifuitView()) { + Text("Waifu.it Preferences") + .foregroundColor(.accentColor) + } + } + } Section(header: Text("About AnimeGen")) { diff --git a/AnimeGen/ViewController.swift b/AnimeGen/ViewController.swift index 67962d58..9b5a3b13 100644 --- a/AnimeGen/ViewController.swift +++ b/AnimeGen/ViewController.swift @@ -41,6 +41,9 @@ class ViewController: UIViewController { var gestures = UserDefaults.standard.bool(forKey: "enableGestures") var moetags = UserDefaults.standard.bool(forKey: "enableMoeTags") + var kyokobanner = UserDefaults.standard.bool(forKey: "enableKyokobanner") + + var alert = UserDefaults.standard.bool(forKey: "enableDeveloperAlert") var counter: Int = 0 @@ -75,6 +78,7 @@ class ViewController: UIViewController { view.backgroundColor = UIColor(red: 0.125, green: 0.125, blue: 0.125, alpha: 1.0) } + // Image View imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false @@ -305,12 +309,12 @@ class ViewController: UIViewController { } case "waifu.im": loadImageFromWaifuIm() + case "waifu.it": + loadImageFromWaifuIt() case "nekos.best": loadImageFromNekosBest() case "waifu.pics": loadImageFromWaifuPics() - case "Hmtai api": - startHmtaiLoader() case "Nekos api": loadImageFromNekosapi() showPopUpBanner(message: "This API is not supported on your iOS version!", viewController: self) { @@ -323,7 +327,12 @@ class ViewController: UIViewController { } case "nekos.moe": loadImageFromNekosMoe() + case "Hmtai api": + startHmtaiLoader() case "kyoko": + if kyokobanner { + showAlert(withTitle: "Note", message: "The api is very slow.", viewController: self) + } loadImageFromKyoko() case "Purr": loadImageFromPurr() diff --git a/Privacy/Hmtai.md b/Privacy/Hmtai.md index 8a8f467d..ec35a119 100644 --- a/Privacy/Hmtai.md +++ b/Privacy/Hmtai.md @@ -5,3 +5,6 @@ When utilizing the Hmtai API, the generated images are seamlessly sent to a desi It's worth highlighting that my system does not collect any additional data, such as device information, iOS version, model details, or regional data. The sole purpose of the integration is to enhance the user experience within Discord channels without compromising privacy. Im not a discord genius but you can read this reddit article to understand more: [Reddit Article](https://www.reddit.com/r/DataHoarder/comments/16zs1gt/cdndiscordapp_links_will_expire_breaking/). + +> [!Note] +> Since version 1.6-23 on the settings app you can enable the "Developer Mode". With this you can now edit the default "Discord Bot Token", "Discord Webhook" and "Discord Channel ID", giving you full controll of your data.