mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-20 04:03:26 +01:00
refactor to SideStoreAppKit
This commit is contained in:
@@ -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")
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -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, *)
|
||||||
|
|||||||
@@ -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)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import SideStoreCore
|
import SideStoreCore
|
||||||
import EmotionalDamage
|
import EmotionalDamage
|
||||||
|
import SideStoreAppKit
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@available(iOS 13, *)
|
@available(iOS 13, *)
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -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 }
|
||||||
@@ -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()
|
||||||
17
Sources/SideStoreAppKit/Consts/Consts+Proxy.swift
Normal file
17
Sources/SideStoreAppKit/Consts/Consts+Proxy.swift
Normal 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)"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 }
|
||||||
@@ -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() {
|
||||||
@@ -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 {
|
||||||
@@ -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 {
|
||||||
@@ -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!)
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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 {
|
||||||
@@ -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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -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() {
|
||||||
33
Sources/SideStoreAppKit/SideStoreAppDelegate.swift
Normal file
33
Sources/SideStoreAppKit/SideStoreAppDelegate.swift
Normal 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"
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public final class SideStoreAppKit { }
|
|
||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user