refactor to SideStoreAppKit

This commit is contained in:
Joe Mattiello
2023-03-01 19:09:33 -05:00
parent df5b0c3af1
commit c28a45f100
92 changed files with 145 additions and 120 deletions

View File

@@ -72,6 +72,7 @@ let package = Package(
.executableTarget( .executableTarget(
name: "SideStore", name: "SideStore",
dependencies: [ dependencies: [
"SideStoreAppKit",
"SidePatcher", "SidePatcher",
"EmotionalDamage", "EmotionalDamage",
"MiniMuxerSwift", "MiniMuxerSwift",
@@ -83,7 +84,6 @@ let package = Package(
"SideKit", "SideKit",
"KeychainAccess", "KeychainAccess",
"SemanticVersion", "SemanticVersion",
// .product(name: "CrashReporter", package: "PLCrashReporter"),
.product(name: "libimobiledevice", package: "iMobileDevice.swift"), .product(name: "libimobiledevice", package: "iMobileDevice.swift"),
.product(name: "Roxas", package: "Roxas"), .product(name: "Roxas", package: "Roxas"),
.product(name: "RoxasUI", package: "Roxas"), .product(name: "RoxasUI", package: "Roxas"),
@@ -166,6 +166,10 @@ let package = Package(
.linkedFramework("UserNotifications", .when(platforms: [.iOS, .macCatalyst])), .linkedFramework("UserNotifications", .when(platforms: [.iOS, .macCatalyst])),
.linkedFramework("MobileCoreServices", .when(platforms: [.iOS, .macCatalyst])), .linkedFramework("MobileCoreServices", .when(platforms: [.iOS, .macCatalyst])),
.linkedLibrary("AppleArchive") .linkedLibrary("AppleArchive")
],
plugins: [
.plugin(name: "IntentBuilderPlugin", package: "SwiftPMPlugins"),
.plugin(name: "LoggerPlugin", package: "SwiftPMPlugins")
] ]
), ),

View File

@@ -13,23 +13,12 @@ import UserNotifications
import AltSign import AltSign
import SideStoreCore import SideStoreCore
import SideStoreAppKit
import EmotionalDamage import EmotionalDamage
import RoxasUIKit import RoxasUIKit
extension AppDelegate {
static let openPatreonSettingsDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".OpenPatreonSettingsDeepLinkNotification")
static let importAppDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".ImportAppDeepLinkNotification")
static let addSourceDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".AddSourceDeepLinkNotification")
static let appBackupDidFinish = Notification.Name(Bundle.Info.appbundleIdentifier + ".AppBackupDidFinish")
static let importAppDeepLinkURLKey = "fileURL"
static let appBackupResultKey = "result"
static let addSourceDeepLinkURLKey = "sourceURL"
}
@UIApplicationMain @UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate { final class AppDelegate: SideStoreAppDelegate {
var window: UIWindow? var window: UIWindow?
@available(iOS 14, *) @available(iOS 14, *)

View File

@@ -1,17 +0,0 @@
//
// Proxy.swift
// SideStore
//
// Created by Joseph Mattiello on 11/7/22.
// Copyright © 2022 Riley Testut. All rights reserved.
//
import Foundation
public extension Consts {
enum Proxy {
static let address = "127.0.0.1"
static let port = "51820"
static let serverURL = "\(address):\(port)"
}
}

View File

@@ -9,6 +9,7 @@
import EmotionalDamage import EmotionalDamage
import minimuxer import minimuxer
import MiniMuxerSwift import MiniMuxerSwift
import SideStoreAppKit
import RoxasUIKit import RoxasUIKit
import UIKit import UIKit

View File

@@ -8,6 +8,7 @@
import SideStoreCore import SideStoreCore
import EmotionalDamage import EmotionalDamage
import SideStoreAppKit
import UIKit import UIKit
@available(iOS 13, *) @available(iOS 13, *)

View File

@@ -16,7 +16,7 @@ import AppCenterCrashes
private let appCenterAppSecret = "73532d3e-e573-4693-99a4-9f85840bbb44" private let appCenterAppSecret = "73532d3e-e573-4693-99a4-9f85840bbb44"
extension AnalyticsManager { public extension AnalyticsManager {
enum EventProperty: String { enum EventProperty: String {
case name case name
case bundleIdentifier case bundleIdentifier
@@ -33,7 +33,7 @@ extension AnalyticsManager {
case updatedApp(InstalledApp) case updatedApp(InstalledApp)
case refreshedApp(InstalledApp) case refreshedApp(InstalledApp)
var name: String { public var name: String {
switch self { switch self {
case .installedApp: return "installed_app" case .installedApp: return "installed_app"
case .updatedApp: return "updated_app" case .updatedApp: return "updated_app"
@@ -41,7 +41,7 @@ extension AnalyticsManager {
} }
} }
var properties: [EventProperty: String] { public var properties: [EventProperty: String] {
let properties: [EventProperty: String?] let properties: [EventProperty: String?]
switch self { switch self {
@@ -66,13 +66,13 @@ extension AnalyticsManager {
} }
} }
final class AnalyticsManager { public final class AnalyticsManager {
static let shared = AnalyticsManager() public static let shared = AnalyticsManager()
private init() {} private init() {}
} }
extension AnalyticsManager { public extension AnalyticsManager {
func start() { func start() {
AppCenter.start(withAppSecret: appCenterAppSecret, services: [ AppCenter.start(withAppSecret: appCenterAppSecret, services: [
Analytics.self, Analytics.self,

View File

@@ -11,7 +11,7 @@ import SideStoreCore
import Intents import Intents
@available(iOS 14, *) @available(iOS 14, *)
final class IntentHandler: NSObject, RefreshAllIntentHandling { public final class IntentHandler: NSObject, RefreshAllIntentHandling {
private let queue = DispatchQueue(label: "io.altstore.IntentHandler") private let queue = DispatchQueue(label: "io.altstore.IntentHandler")
private var completionHandlers = [RefreshAllIntent: (RefreshAllIntentResponse) -> Void]() private var completionHandlers = [RefreshAllIntent: (RefreshAllIntentResponse) -> Void]()
@@ -19,7 +19,7 @@ final class IntentHandler: NSObject, RefreshAllIntentHandling {
private var operations = [RefreshAllIntent: BackgroundRefreshAppsOperation]() private var operations = [RefreshAllIntent: BackgroundRefreshAppsOperation]()
func confirm(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) { public func confirm(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) {
// Refreshing apps usually, but not always, completes within alotted time. // Refreshing apps usually, but not always, completes within alotted time.
// As a workaround, we'll start refreshing apps in confirm() so we can // As a workaround, we'll start refreshing apps in confirm() so we can
// take advantage of some extra time before starting handle() timeout timer. // take advantage of some extra time before starting handle() timeout timer.
@@ -53,7 +53,7 @@ final class IntentHandler: NSObject, RefreshAllIntentHandling {
} }
} }
func handle(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) { public func handle(intent: RefreshAllIntent, completion: @escaping (RefreshAllIntentResponse) -> Void) {
completionHandlers[intent] = { response in completionHandlers[intent] = { response in
// Ignore .ready response from confirm() timeout. // Ignore .ready response from confirm() timeout.
guard response.code != .ready else { return } guard response.code != .ready else { return }

View File

@@ -8,8 +8,8 @@
import AVFoundation import AVFoundation
final class BackgroundTaskManager { public final class BackgroundTaskManager {
static let shared = BackgroundTaskManager() public static let shared = BackgroundTaskManager()
private var isPlaying = false private var isPlaying = false
@@ -39,7 +39,7 @@ final class BackgroundTaskManager {
} }
} }
extension BackgroundTaskManager { public extension BackgroundTaskManager {
func performExtendedBackgroundTask(taskHandler: @escaping ((Result<Void, Error>, @escaping () -> Void) -> Void)) { func performExtendedBackgroundTask(taskHandler: @escaping ((Result<Void, Error>, @escaping () -> Void) -> Void)) {
func finish() { func finish() {
player.stop() player.stop()

View File

@@ -0,0 +1,17 @@
//
// Proxy.swift
// SideStore
//
// Created by Joseph Mattiello on 11/7/22.
// Copyright © 2022 Joseph Mattiello. All rights reserved.
//
import Foundation
public extension Consts {
enum Proxy {
public static let address = "127.0.0.1"
public static let port = "51820"
public static let serverURL = "\(address):\(port)"
}
}

View File

@@ -20,7 +20,7 @@ import SideKit
import SideStoreCore import SideStoreCore
import RoxasUIKit import RoxasUIKit
extension AppManager { public extension AppManager {
static let didFetchSourceNotification = Notification.Name("io.altstore.AppManager.didFetchSource") static let didFetchSourceNotification = Notification.Name("io.altstore.AppManager.didFetchSource")
static let didUpdatePatronsNotification = Notification.Name("io.altstore.AppManager.didUpdatePatrons") static let didUpdatePatronsNotification = Notification.Name("io.altstore.AppManager.didUpdatePatrons")
@@ -29,7 +29,7 @@ extension AppManager {
} }
@available(iOS 13, *) @available(iOS 13, *)
final class AppManagerPublisher: ObservableObject { public final class AppManagerPublisher: ObservableObject {
@Published @Published
fileprivate(set) var installationProgress = [String: Progress]() fileprivate(set) var installationProgress = [String: Progress]()
@@ -41,8 +41,8 @@ private func == (lhs: OperatingSystemVersion, rhs: OperatingSystemVersion) -> Bo
lhs.majorVersion == rhs.majorVersion && lhs.minorVersion == rhs.minorVersion && lhs.patchVersion == rhs.patchVersion lhs.majorVersion == rhs.majorVersion && lhs.minorVersion == rhs.minorVersion && lhs.patchVersion == rhs.patchVersion
} }
final class AppManager { public final class AppManager {
static let shared = AppManager() public static let shared = AppManager()
private(set) var updatePatronsResult: Result<Void, Error>? private(set) var updatePatronsResult: Result<Void, Error>?
@@ -116,7 +116,7 @@ final class AppManager {
} }
} }
extension AppManager { public extension AppManager {
func update() { func update() {
DatabaseManager.shared.persistentContainer.performBackgroundTask { context in DatabaseManager.shared.persistentContainer.performBackgroundTask { context in
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
@@ -275,7 +275,7 @@ extension AppManager {
} }
} }
extension AppManager { public extension AppManager {
func fetchSource(sourceURL: URL, func fetchSource(sourceURL: URL,
managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext(), managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.persistentContainer.newBackgroundContext(),
dependencies: [Foundation.Operation] = [], dependencies: [Foundation.Operation] = [],
@@ -662,9 +662,9 @@ extension AppManager {
} }
} }
extension AppManager { public extension AppManager {
@discardableResult @discardableResult
func backgroundRefresh(_ installedApps: [InstalledApp], presentsNotifications: Bool = false, completionHandler: @escaping (Result<[String: Result<InstalledApp, Error>], Error>) -> Void) -> BackgroundRefreshAppsOperation { public func backgroundRefresh(_ installedApps: [InstalledApp], presentsNotifications: Bool = false, completionHandler: @escaping (Result<[String: Result<InstalledApp, Error>], Error>) -> Void) -> BackgroundRefreshAppsOperation {
let backgroundRefreshAppsOperation = BackgroundRefreshAppsOperation(installedApps: installedApps) let backgroundRefreshAppsOperation = BackgroundRefreshAppsOperation(installedApps: installedApps)
backgroundRefreshAppsOperation.resultHandler = completionHandler backgroundRefreshAppsOperation.resultHandler = completionHandler
backgroundRefreshAppsOperation.presentsFinishedNotification = presentsNotifications backgroundRefreshAppsOperation.presentsFinishedNotification = presentsNotifications

View File

@@ -11,16 +11,16 @@ import Foundation
import SideStoreCore import SideStoreCore
extension AppManager { public extension AppManager {
struct FetchSourcesError: LocalizedError, CustomNSError { struct FetchSourcesError: LocalizedError, CustomNSError {
var primaryError: Error? public private(set) var primaryError: Error?
var sources: Set<Source>? public private(set) var sources: Set<Source>?
var errors = [Source: Error]() public private(set) var errors = [Source: Error]()
var managedObjectContext: NSManagedObjectContext? public private(set) var managedObjectContext: NSManagedObjectContext?
var errorDescription: String? { public var errorDescription: String? {
if let error = primaryError { if let error = primaryError {
return error.localizedDescription return error.localizedDescription
} else { } else {
@@ -41,7 +41,7 @@ extension AppManager {
} }
} }
var recoverySuggestion: String? { public var recoverySuggestion: String? {
if let error = primaryError as NSError? { if let error = primaryError as NSError? {
return error.localizedRecoverySuggestion return error.localizedRecoverySuggestion
} else if errors.count == 1 { } else if errors.count == 1 {
@@ -51,16 +51,16 @@ extension AppManager {
} }
} }
var errorUserInfo: [String: Any] { public var errorUserInfo: [String: Any] {
guard let error = errors.values.first, errors.count == 1 else { return [:] } guard let error = errors.values.first, errors.count == 1 else { return [:] }
return [NSUnderlyingErrorKey: error] return [NSUnderlyingErrorKey: error]
} }
init(_ error: Error) { public init(_ error: Error) {
primaryError = error primaryError = error
} }
init(sources: Set<Source>, errors: [Source: Error], context: NSManagedObjectContext) { public init(sources: Set<Source>, errors: [Source: Error], context: NSManagedObjectContext) {
self.sources = sources self.sources = sources
self.errors = errors self.errors = errors
managedObjectContext = context managedObjectContext = context

View File

@@ -65,7 +65,7 @@ final class MyAppsViewController: UICollectionViewController {
super.init(coder: aDecoder) super.init(coder: aDecoder)
NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.didFetchSource(_:)), name: AppManager.didFetchSourceNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.didFetchSource(_:)), name: AppManager.didFetchSourceNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(MyAppsViewController.importApp(_:)), name: SideStoreAppDelegate.importAppDeepLinkNotification, object: nil)
} }
override func viewDidLoad() { override func viewDidLoad() {
@@ -1171,7 +1171,7 @@ private extension MyAppsViewController {
// Make sure left UIBarButtonItem has been set. // Make sure left UIBarButtonItem has been set.
loadViewIfNeeded() loadViewIfNeeded()
guard let url = notification.userInfo?[AppDelegate.importAppDeepLinkURLKey] as? URL else { return } guard let url = notification.userInfo?[SideStoreAppDelegate.importAppDeepLinkURLKey] as? URL else { return }
sideloadApp(at: url) { _ in sideloadApp(at: url) { _ in
guard url.isFileURL else { return } guard url.isFileURL else { return }

View File

@@ -58,7 +58,7 @@ final class NewsViewController: UICollectionViewController {
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
NotificationCenter.default.addObserver(self, selector: #selector(NewsViewController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(NewsViewController.importApp(_:)), name: SideStoreAppDelegate.importAppDeepLinkNotification, object: nil)
} }
override func viewDidLoad() { override func viewDidLoad() {

View File

@@ -33,8 +33,8 @@ enum AuthenticationError: LocalizedError {
} }
@objc(AuthenticationOperation) @objc(AuthenticationOperation)
final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, ALTAppleAPISession)> { public final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, ALTAppleAPISession)> {
let context: AuthenticatedOperationContext public let context: AuthenticatedOperationContext
private weak var presentingViewController: UIViewController? private weak var presentingViewController: UIViewController?
@@ -56,7 +56,7 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A
private var submitCodeAction: UIAlertAction? private var submitCodeAction: UIAlertAction?
init(context: AuthenticatedOperationContext, presentingViewController: UIViewController?) { public init(context: AuthenticatedOperationContext, presentingViewController: UIViewController?) {
self.context = context self.context = context
self.presentingViewController = presentingViewController self.presentingViewController = presentingViewController
@@ -67,7 +67,7 @@ final class AuthenticationOperation: ResultOperation<(ALTTeam, ALTCertificate, A
progress.totalUnitCount = 4 progress.totalUnitCount = 4
} }
override func main() { public override func main() {
super.main() super.main()
if let error = context.error { if let error = context.error {

View File

@@ -45,23 +45,23 @@ private let ReceivedApplicationState: @convention(c) (CFNotificationCenter?, Uns
} }
@objc(BackgroundRefreshAppsOperation) @objc(BackgroundRefreshAppsOperation)
final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<InstalledApp, Error>]> { public final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<InstalledApp, Error>]> {
let installedApps: [InstalledApp] public let installedApps: [InstalledApp]
private let managedObjectContext: NSManagedObjectContext private let managedObjectContext: NSManagedObjectContext
var presentsFinishedNotification: Bool = false public var presentsFinishedNotification: Bool = false
private let refreshIdentifier: String = UUID().uuidString private let refreshIdentifier: String = UUID().uuidString
private var runningApplications: Set<String> = [] private var runningApplications: Set<String> = []
init(installedApps: [InstalledApp]) { public init(installedApps: [InstalledApp]) {
self.installedApps = installedApps self.installedApps = installedApps
managedObjectContext = installedApps.compactMap { $0.managedObjectContext }.first ?? DatabaseManager.shared.persistentContainer.newBackgroundContext() managedObjectContext = installedApps.compactMap { $0.managedObjectContext }.first ?? DatabaseManager.shared.persistentContainer.newBackgroundContext()
super.init() super.init()
} }
override func finish(_ result: Result<[String: Result<InstalledApp, Error>], Error>) { public override func finish(_ result: Result<[String: Result<InstalledApp, Error>], Error>) {
super.finish(result) super.finish(result)
scheduleFinishedRefreshingNotification(for: result, delay: 0) scheduleFinishedRefreshingNotification(for: result, delay: 0)
@@ -75,7 +75,7 @@ final class BackgroundRefreshAppsOperation: ResultOperation<[String: Result<Inst
} }
} }
override func main() { public override func main() {
super.main() super.main()
guard !installedApps.isEmpty else { guard !installedApps.isEmpty else {

View File

@@ -146,10 +146,10 @@ private extension BackupAppOperation {
} }
var backupResponseObserver: NSObjectProtocol! var backupResponseObserver: NSObjectProtocol!
backupResponseObserver = NotificationCenter.default.addObserver(forName: AppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] notification in backupResponseObserver = NotificationCenter.default.addObserver(forName: SideStoreAppDelegate.appBackupDidFinish, object: nil, queue: nil) { [weak self] notification in
self?.timeoutTimer?.invalidate() self?.timeoutTimer?.invalidate()
let result = notification.userInfo?[AppDelegate.appBackupResultKey] as? Result<Void, Error> ?? .failure(OperationError.unknownResult) let result = notification.userInfo?[SideStoreAppDelegate.appBackupResultKey] as? Result<Void, Error> ?? .failure(OperationError.unknownResult)
self?.finish(result) self?.finish(result)
NotificationCenter.default.removeObserver(backupResponseObserver!) NotificationCenter.default.removeObserver(backupResponseObserver!)

View File

@@ -16,10 +16,10 @@ private extension URL {
#endif #endif
} }
extension FetchTrustedSourcesOperation { public extension FetchTrustedSourcesOperation {
struct TrustedSource: Decodable { public struct TrustedSource: Decodable {
var identifier: String public var identifier: String
var sourceURL: URL? public var sourceURL: URL?
} }
private struct Response: Decodable { private struct Response: Decodable {
@@ -28,8 +28,8 @@ extension FetchTrustedSourcesOperation {
} }
} }
final class FetchTrustedSourcesOperation: ResultOperation<[FetchTrustedSourcesOperation.TrustedSource]> { public final class FetchTrustedSourcesOperation: ResultOperation<[FetchTrustedSourcesOperation.TrustedSource]> {
override func main() { public override func main() {
super.main() super.main()
let dataTask = URLSession.shared.dataTask(with: .trustedSources) { data, response, error in let dataTask = URLSession.shared.dataTask(with: .trustedSources) { data, response, error in

View File

@@ -9,11 +9,11 @@
import Foundation import Foundation
import RoxasUIKit import RoxasUIKit
class ResultOperation<ResultType>: Operation { public class ResultOperation<ResultType>: Operation {
var resultHandler: ((Result<ResultType, Error>) -> Void)? var resultHandler: ((Result<ResultType, Error>) -> Void)?
@available(*, unavailable) @available(*, unavailable)
override func finish() { public override func finish() {
super.finish() super.finish()
} }
@@ -30,12 +30,12 @@ class ResultOperation<ResultType>: Operation {
} }
} }
class Operation: RSTOperation, ProgressReporting { public class Operation: RSTOperation, ProgressReporting {
let progress = Progress.discreteProgress(totalUnitCount: 1) public let progress = Progress.discreteProgress(totalUnitCount: 1)
private var backgroundTaskID: UIBackgroundTaskIdentifier? private var backgroundTaskID: UIBackgroundTaskIdentifier?
override var isAsynchronous: Bool { public override var isAsynchronous: Bool {
true true
} }
@@ -45,7 +45,7 @@ class Operation: RSTOperation, ProgressReporting {
progress.cancellationHandler = { [weak self] in self?.cancel() } progress.cancellationHandler = { [weak self] in self?.cancel() }
} }
override func cancel() { public override func cancel() {
super.cancel() super.cancel()
if !progress.isCancelled { if !progress.isCancelled {
@@ -53,7 +53,7 @@ class Operation: RSTOperation, ProgressReporting {
} }
} }
override func main() { public override func main() {
super.main() super.main()
let name = "com.altstore." + NSStringFromClass(type(of: self)) let name = "com.altstore." + NSStringFromClass(type(of: self))
@@ -67,7 +67,7 @@ class Operation: RSTOperation, ProgressReporting {
} }
} }
override func finish() { public override func finish() {
guard !isFinished else { return } guard !isFinished else { return }
super.finish() super.finish()

View File

@@ -13,14 +13,14 @@ import Network
import AltSign import AltSign
import SideStoreCore import SideStoreCore
class OperationContext { public class OperationContext {
var error: Error? var error: Error?
var presentingViewController: UIViewController? var presentingViewController: UIViewController?
let operations: NSHashTable<Foundation.Operation> let operations: NSHashTable<Foundation.Operation>
init(error: Error? = nil, operations: [Foundation.Operation] = []) { public init(error: Error? = nil, operations: [Foundation.Operation] = []) {
self.error = error self.error = error
self.operations = NSHashTable<Foundation.Operation>.weakObjects() self.operations = NSHashTable<Foundation.Operation>.weakObjects()
@@ -29,12 +29,12 @@ class OperationContext {
} }
} }
convenience init(context: OperationContext) { public convenience init(context: OperationContext) {
self.init(error: context.error, operations: context.operations.allObjects) self.init(error: context.error, operations: context.operations.allObjects)
} }
} }
final class AuthenticatedOperationContext: OperationContext { public final class AuthenticatedOperationContext: OperationContext {
var session: ALTAppleAPISession? var session: ALTAppleAPISession?
var team: ALTTeam? var team: ALTTeam?
@@ -42,7 +42,7 @@ final class AuthenticatedOperationContext: OperationContext {
weak var authenticationOperation: AuthenticationOperation? weak var authenticationOperation: AuthenticationOperation?
convenience init(context: AuthenticatedOperationContext) { public convenience init(context: AuthenticatedOperationContext) {
self.init(error: context.error, operations: context.operations.allObjects) self.init(error: context.error, operations: context.operations.allObjects)
session = context.session session = context.session

View File

@@ -48,7 +48,7 @@ private struct OTAUpdate {
} }
@available(iOS 14, *) @available(iOS 14, *)
final class PatchAppOperation: ResultOperation<Void> { public final class PatchAppOperation: ResultOperation<Void> {
let context: PatchAppContext let context: PatchAppContext
var progressHandler: ((Progress, String) -> Void)? var progressHandler: ((Progress, String) -> Void)?
@@ -66,7 +66,7 @@ final class PatchAppOperation: ResultOperation<Void> {
progress.totalUnitCount = 100 progress.totalUnitCount = 100
} }
override func main() { public override func main() {
super.main() super.main()
if let error = context.error { if let error = context.error {
@@ -98,7 +98,7 @@ final class PatchAppOperation: ResultOperation<Void> {
} receiveValue: { _ in } } receiveValue: { _ in }
} }
override func cancel() { public override func cancel() {
super.cancel() super.cancel()
cancellable?.cancel() cancellable?.cancel()

View File

@@ -27,7 +27,7 @@ extension PatchViewController {
} }
@available(iOS 14.0, *) @available(iOS 14.0, *)
final class PatchViewController: UIViewController { public final class PatchViewController: UIViewController {
var patchApp: AnyApp? var patchApp: AnyApp?
var installedApp: InstalledApp? var installedApp: InstalledApp?
@@ -57,7 +57,7 @@ final class PatchViewController: UIViewController {
@IBOutlet private var cancelBarButtonItem: UIBarButtonItem! @IBOutlet private var cancelBarButtonItem: UIBarButtonItem!
@IBOutlet private var cancelButton: UIButton! @IBOutlet private var cancelButton: UIButton!
override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
isModalInPresentation = true isModalInPresentation = true
@@ -81,7 +81,7 @@ final class PatchViewController: UIViewController {
update() update()
} }
override func viewWillAppear(_ animated: Bool) { public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
if installedApp != nil { if installedApp != nil {

View File

@@ -12,7 +12,7 @@ import Foundation
import AltSign import AltSign
import SideStoreCore import SideStoreCore
final class RefreshGroup: NSObject { public final class RefreshGroup: NSObject {
let context: AuthenticatedOperationContext let context: AuthenticatedOperationContext
let progress = Progress.discreteProgress(totalUnitCount: 0) let progress = Progress.discreteProgress(totalUnitCount: 0)
@@ -30,7 +30,7 @@ final class RefreshGroup: NSObject {
private let dispatchGroup = DispatchGroup() private let dispatchGroup = DispatchGroup()
private var operations: [Foundation.Operation] = [] private var operations: [Foundation.Operation] = []
init(context: AuthenticatedOperationContext = AuthenticatedOperationContext()) { public init(context: AuthenticatedOperationContext = AuthenticatedOperationContext()) {
self.context = context self.context = context
super.init() super.init()
@@ -38,7 +38,7 @@ final class RefreshGroup: NSObject {
/// Used to keep track of which operations belong to this group. /// Used to keep track of which operations belong to this group.
/// This does _not_ add them to any operation queue. /// This does _not_ add them to any operation queue.
func add(_ operations: [Foundation.Operation]) { public func add(_ operations: [Foundation.Operation]) {
for operation in operations { for operation in operations {
dispatchGroup.enter() dispatchGroup.enter()
@@ -56,7 +56,7 @@ final class RefreshGroup: NSObject {
self.operations.append(contentsOf: operations) self.operations.append(contentsOf: operations)
} }
func set(_ result: Result<InstalledApp, Error>, forAppWithBundleIdentifier bundleIdentifier: String) { public func set(_ result: Result<InstalledApp, Error>, forAppWithBundleIdentifier bundleIdentifier: String) {
results[bundleIdentifier] = result results[bundleIdentifier] = result
switch result { switch result {
@@ -67,7 +67,7 @@ final class RefreshGroup: NSObject {
} }
} }
func cancel() { public func cancel() {
operations.forEach { $0.cancel() } operations.forEach { $0.cancel() }
} }
} }

View File

@@ -12,6 +12,7 @@ import RoxasUIKit
import AltSign import AltSign
import SideStoreCore import SideStoreCore
@objc(ResignAppOperation) @objc(ResignAppOperation)
final class ResignAppOperation: ResultOperation<ALTApplication> { final class ResignAppOperation: ResultOperation<ALTApplication> {
let context: InstallAppOperationContext let context: InstallAppOperationContext

View File

@@ -76,7 +76,7 @@ final class SettingsViewController: UITableViewController {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) super.init(coder: aDecoder)
NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.openPatreonSettings(_:)), name: SideStoreAppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
} }
override func viewDidLoad() { override func viewDidLoad() {

View File

@@ -0,0 +1,33 @@
//
// SideStoreAppDelegate.swift
// AltStore
//
// Created by Riley Testut on 5/9/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import AVFoundation
import Intents
import UIKit
import UserNotifications
import AltSign
import SideStoreCore
import EmotionalDamage
import RoxasUIKit
open class SideStoreAppDelegate: UIResponder, UIApplicationDelegate {
}
public extension SideStoreAppDelegate {
static let openPatreonSettingsDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".OpenPatreonSettingsDeepLinkNotification")
static let importAppDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".ImportAppDeepLinkNotification")
static let addSourceDeepLinkNotification = Notification.Name(Bundle.Info.appbundleIdentifier + ".AddSourceDeepLinkNotification")
static let appBackupDidFinish = Notification.Name(Bundle.Info.appbundleIdentifier + ".AppBackupDidFinish")
static let importAppDeepLinkURLKey = "fileURL"
static let appBackupResultKey = "result"
static let addSourceDeepLinkURLKey = "sourceURL"
}

View File

@@ -1,4 +0,0 @@
import Foundation
import UIKit
public final class SideStoreAppKit { }

View File

@@ -18,7 +18,7 @@ extension TabBarController {
} }
} }
final class TabBarController: UITabBarController { public final class TabBarController: UITabBarController {
private var initialSegue: (identifier: String, sender: Any?)? private var initialSegue: (identifier: String, sender: Any?)?
private var _viewDidAppear = false private var _viewDidAppear = false
@@ -26,12 +26,12 @@ final class TabBarController: UITabBarController {
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) super.init(coder: aDecoder)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.openPatreonSettings(_:)), name: SideStoreAppDelegate.openPatreonSettingsDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: AppDelegate.importAppDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.importApp(_:)), name: SideStoreAppDelegate.importAppDeepLinkNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: AppDelegate.addSourceDeepLinkNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(TabBarController.presentSources(_:)), name: SideStoreAppDelegate.addSourceDeepLinkNotification, object: nil)
} }
override func viewDidAppear(_ animated: Bool) { public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
_viewDidAppear = true _viewDidAppear = true
@@ -48,13 +48,13 @@ final class TabBarController: UITabBarController {
} }
} }
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let identifier = segue.identifier else { return } guard let identifier = segue.identifier else { return }
switch identifier { switch identifier {
case "presentSources": case "presentSources":
guard let notification = sender as? Notification, guard let notification = sender as? Notification,
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL let sourceURL = notification.userInfo?[SideStoreAppDelegate.addSourceDeepLinkURLKey] as? URL
else { return } else { return }
let navigationController = segue.destination as! UINavigationController let navigationController = segue.destination as! UINavigationController
@@ -76,7 +76,7 @@ final class TabBarController: UITabBarController {
} }
} }
override func performSegue(withIdentifier identifier: String, sender: Any?) { public override func performSegue(withIdentifier identifier: String, sender: Any?) {
guard _viewDidAppear else { guard _viewDidAppear else {
initialSegue = (identifier, sender) initialSegue = (identifier, sender)
return return
@@ -92,7 +92,7 @@ extension TabBarController {
if let navigationController = presentedViewController as? UINavigationController, if let navigationController = presentedViewController as? UINavigationController,
let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController { let sourcesViewController = navigationController.viewControllers.first as? SourcesViewController {
if let notification = (sender as? Notification), if let notification = (sender as? Notification),
let sourceURL = notification.userInfo?[AppDelegate.addSourceDeepLinkURLKey] as? URL { let sourceURL = notification.userInfo?[SideStoreAppDelegate.addSourceDeepLinkURLKey] as? URL {
sourcesViewController.deepLinkSourceURL = sourceURL sourcesViewController.deepLinkSourceURL = sourceURL
} else { } else {
// Don't dismiss SourcesViewController if it's already presented. // Don't dismiss SourcesViewController if it's already presented.