diff --git a/Pocket Poster/Controllers/DownloadManager.swift b/Pocket Poster/Controllers/DownloadManager.swift index dae2ac4..a560d5f 100644 --- a/Pocket Poster/Controllers/DownloadManager.swift +++ b/Pocket Poster/Controllers/DownloadManager.swift @@ -19,7 +19,7 @@ class DownloadManager { let (data, response) = try await URLSession.shared.data(for: request) as! (Data, HTTPURLResponse) guard response.statusCode == 200 else { throw URLError(.cannotConnectToHost) } - let newURL = PosterBoardManager.getTendiesStoreURL().appendingPathComponent(getWallpaperNameFromURL(string: url.absoluteString)) + let newURL = PosterBoardManager.shared.getTendiesStoreURL().appendingPathComponent(getWallpaperNameFromURL(string: url.absoluteString)) try data.write(to: newURL) return newURL } @@ -37,7 +37,7 @@ class DownloadManager { url.stopAccessingSecurityScopedResource() } } - let newURL = PosterBoardManager.getTendiesStoreURL().appendingPathComponent(url.lastPathComponent) + let newURL = PosterBoardManager.shared.getTendiesStoreURL().appendingPathComponent(url.lastPathComponent) try FileManager.default.copyItem(at: url, to: newURL) return newURL } diff --git a/Pocket Poster/Controllers/PosterBoardManager.swift b/Pocket Poster/Controllers/PosterBoardManager.swift index 27acf1e..704980a 100644 --- a/Pocket Poster/Controllers/PosterBoardManager.swift +++ b/Pocket Poster/Controllers/PosterBoardManager.swift @@ -9,13 +9,17 @@ import Foundation import ZIPFoundation import UIKit -class PosterBoardManager { +class PosterBoardManager: ObservableObject { static let ShortcutURL = "https://www.icloud.com/shortcuts/a28d2c02ca11453cb5b8f91c12cfa692" static let WallpapersURL = "https://cowabun.ga/wallpapers" static let MaxTendies = 10 - static func getTendiesStoreURL() -> URL { + static let shared = PosterBoardManager() + + @Published var selectedTendies: [URL] = [] + + func getTendiesStoreURL() -> URL { let tendiesStoreURL = SymHandler.getDocumentsDirectory().appendingPathComponent("KFC Bucket", conformingTo: .directory) // create it if it doesn't exist if !FileManager.default.fileExists(atPath: tendiesStoreURL.path()) { @@ -24,7 +28,7 @@ class PosterBoardManager { return tendiesStoreURL } - static func openPosterBoard() -> Bool { + func openPosterBoard() -> Bool { guard let obj = objc_getClass("LSApplicationWorkspace") as? NSObject else { return false } let workspace = obj.perform(Selector(("defaultWorkspace")))?.takeUnretainedValue() as? NSObject @@ -35,7 +39,7 @@ class PosterBoardManager { return false } - private static func unzipFile(at url: URL) throws -> URL { + private func unzipFile(at url: URL) throws -> URL { let fileName = url.deletingPathExtension().lastPathComponent let fileData = try Data(contentsOf: url) let fileManager = FileManager() @@ -68,13 +72,13 @@ class PosterBoardManager { return destinationURL } - static func runShortcut(named name: String) { + func runShortcut(named name: String) { guard let urlEncodedName = name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "shortcuts://run-shortcut?name=\(name)") else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } - static func getDescriptorsFromTendie(_ url: URL) throws -> [String: [URL]]? { + func getDescriptorsFromTendie(_ url: URL) throws -> [String: [URL]]? { for dir in try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) { let fileName = dir.lastPathComponent if fileName.lowercased() == "container" { @@ -99,7 +103,7 @@ class PosterBoardManager { return nil } - static func randomizeWallpaperId(url: URL) throws { + func randomizeWallpaperId(url: URL) throws { let randomizedID = Int.random(in: 9999...99999) var files = [URL]() if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) { @@ -157,10 +161,10 @@ class PosterBoardManager { } } - static func applyTendies(_ urls: [URL], appHash: String) throws { + func applyTendies(appHash: String) throws { // organize the descriptors into their respective extensions var extList: [String: [URL]] = [:] - for url in urls { + for url in selectedTendies { let unzippedDir = try unzipFile(at: url) guard let descriptors = try getDescriptorsFromTendie(unzippedDir) else { continue } // TODO: Add error handling extList.merge(descriptors) { (first, second) in first + second } @@ -188,7 +192,7 @@ class PosterBoardManager { } // clean up all possible files - for url in urls { + for url in selectedTendies { try? FileManager.default.removeItem(at: SymHandler.getDocumentsDirectory().appendingPathComponent("UnzipItems", conformingTo: .directory)) try? FileManager.default.removeItem(at: SymHandler.getDocumentsDirectory().appendingPathComponent(url.lastPathComponent)) try? FileManager.default.removeItem(at: SymHandler.getDocumentsDirectory().appendingPathComponent(url.deletingPathExtension().lastPathComponent)) diff --git a/Pocket Poster/Pocket_PosterApp.swift b/Pocket Poster/Pocket_PosterApp.swift index 1e2c098..6a17223 100644 --- a/Pocket Poster/Pocket_PosterApp.swift +++ b/Pocket Poster/Pocket_PosterApp.swift @@ -13,8 +13,6 @@ struct Pocket_PosterApp: App { @AppStorage("finishedTutorial") var finishedTutorial: Bool = false @AppStorage("pbHash") var pbHash: String = "" - @State var selectedTendies: [URL] = [] - @State var downloadURL: String? = nil @State var showDownloadAlert = false @@ -22,7 +20,7 @@ struct Pocket_PosterApp: App { WindowGroup { Group { if finishedTutorial { - ContentView(selectedTendies: $selectedTendies) + ContentView() } else { OnBoardingView(cards: onBoardingCards, isFinished: $finishedTutorial) } @@ -43,7 +41,7 @@ struct Pocket_PosterApp: App { // prohibit to only tendies files if !url.absoluteString.hasSuffix(".tendies") { UIApplication.shared.alert(body: "Only .tendies files can be downloaded!") - } else if selectedTendies.count >= PosterBoardManager.MaxTendies { + } else if PosterBoardManager.shared.selectedTendies.count >= PosterBoardManager.MaxTendies { UIApplication.shared.alert(title: "Max Tendies Reached", body: "You can only apply \(PosterBoardManager.MaxTendies) descriptors.") } else { downloadURL = url.absoluteString.replacingOccurrences(of: "pocketposter://download?url=", with: "") @@ -55,13 +53,13 @@ struct Pocket_PosterApp: App { pbHash = url.absoluteString.replacingOccurrences(of: "pocketposter://app-hash?uuid=", with: "") } else if url.pathExtension == "tendies" { - if selectedTendies.count >= PosterBoardManager.MaxTendies { + if PosterBoardManager.shared.selectedTendies.count >= PosterBoardManager.MaxTendies { UIApplication.shared.alert(title: "Max Tendies Reached", body: "You can only apply \(PosterBoardManager.MaxTendies) descriptors.") } else { // copy it over to the KFC bucket do { let newURL = try DownloadManager.copyTendies(from: url) - selectedTendies.append(newURL) + PosterBoardManager.shared.selectedTendies.append(newURL) Haptic.shared.notify(.success) UIApplication.shared.alert(title: "Successfully imported \(url.lastPathComponent)", body: "") } catch { @@ -81,7 +79,7 @@ struct Pocket_PosterApp: App { Task { do { let newURL = try await DownloadManager.downloadFromURL(string: downloadURL!) - selectedTendies.append(newURL) + PosterBoardManager.shared.selectedTendies.append(newURL) Haptic.shared.notify(.success) UIApplication.shared.dismissAlert(animated: true) } catch { diff --git a/Pocket Poster/Views/ContentView.swift b/Pocket Poster/Views/ContentView.swift index 7827070..b89fd09 100644 --- a/Pocket Poster/Views/ContentView.swift +++ b/Pocket Poster/Views/ContentView.swift @@ -21,7 +21,6 @@ struct ContentView: View { private let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "" @State var showTendiesImporter: Bool = false - var selectedTendies: Binding<[URL]> @State var showErrorAlert = false @State var lastError: String? @@ -47,9 +46,9 @@ struct ContentView: View { .listRowInsets(EdgeInsets()) .padding(7) - if !selectedTendies.wrappedValue.isEmpty { + if !PosterBoardManager.shared.selectedTendies.isEmpty { Section { - ForEach(selectedTendies.wrappedValue, id: \.self) { tendie in + ForEach(PosterBoardManager.shared.selectedTendies, id: \.self) { tendie in Text(tendie.deletingPathExtension().lastPathComponent) } .onDelete(perform: delete) @@ -63,23 +62,23 @@ struct ContentView: View { Text("Enter your PosterBoard app hash in Settings.") } else { VStack { - if !selectedTendies.wrappedValue.isEmpty { + if !PosterBoardManager.shared.selectedTendies.isEmpty { Button(action: { UIImpactFeedbackGenerator(style: .soft).impactOccurred() UIApplication.shared.alert(title: NSLocalizedString("Applying Tendies...", comment: ""), body: NSLocalizedString("Please wait", comment: ""), animated: false, withButton: false) DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { do { - try PosterBoardManager.applyTendies(selectedTendies.wrappedValue, appHash: pbHash) - selectedTendies.wrappedValue.removeAll() + try PosterBoardManager.shared.applyTendies(appHash: pbHash) + PosterBoardManager.shared.selectedTendies.removeAll() SymHandler.cleanup() // just to be extra sure - try? FileManager.default.removeItem(at: PosterBoardManager.getTendiesStoreURL()) + try? FileManager.default.removeItem(at: PosterBoardManager.shared.getTendiesStoreURL()) Haptic.shared.notify(.success) UIApplication.shared.dismissAlert(animated: false) UIApplication.shared.confirmAlert(title: "Success!", body: "The PosterBoard app will now open. Please close it from the app switcher.", onOK: { - if !PosterBoardManager.openPosterBoard() { + if !PosterBoardManager.shared.openPosterBoard() { UIApplication.shared.confirmAlert(title: "Falling Back to Shortcut", body: "PosterBoard failed to open directly. The fallback shortcut will now be opened.", onOK: { - PosterBoardManager.runShortcut(named: "PosterBoard") + PosterBoardManager.shared.runShortcut(named: "PosterBoard") }, noCancel: true) } }, noCancel: true) @@ -130,10 +129,10 @@ struct ContentView: View { .fileImporter(isPresented: $showTendiesImporter, allowedContentTypes: [UTType(filenameExtension: "tendies", conformingTo: .data)!], allowsMultipleSelection: true, onCompletion: { result in switch result { case .success(let url): - if selectedTendies.wrappedValue.count + url.count > PosterBoardManager.MaxTendies { + if PosterBoardManager.shared.selectedTendies.count + url.count > PosterBoardManager.MaxTendies { UIApplication.shared.alert(title: "Max Tendies Reached", body: "You can only apply \(PosterBoardManager.MaxTendies) descriptors.") } else { - selectedTendies.wrappedValue.append(contentsOf: url) + PosterBoardManager.shared.selectedTendies.append(contentsOf: url) } case .failure(let error): lastError = error.localizedDescription @@ -154,11 +153,10 @@ struct ContentView: View { } func delete(at offsets: IndexSet) { - selectedTendies.wrappedValue.remove(atOffsets: offsets) + PosterBoardManager.shared.selectedTendies.remove(atOffsets: offsets) } - init(selectedTendies: Binding<[URL]>) { - self.selectedTendies = selectedTendies + init() { // Fix file picker let fixMethod = class_getInstanceMethod(UIDocumentPickerViewController.self, #selector(UIDocumentPickerViewController.fix_init(forOpeningContentTypes:asCopy:)))! let origMethod = class_getInstanceMethod(UIDocumentPickerViewController.self, #selector(UIDocumentPickerViewController.init(forOpeningContentTypes:asCopy:)))!