mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-11 15:53:30 +01:00
Create swift package
This commit is contained in:
30
Sources/SideStoreCore/Extensions/Date+RelativeDate.swift
Normal file
30
Sources/SideStoreCore/Extensions/Date+RelativeDate.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Date+RelativeDate.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 7/28/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Date {
|
||||
func numberOfCalendarDays(since date: Date) -> Int {
|
||||
let today = Calendar.current.startOfDay(for: self)
|
||||
let previousDay = Calendar.current.startOfDay(for: date)
|
||||
|
||||
let components = Calendar.current.dateComponents([.day], from: previousDay, to: today)
|
||||
return components.day!
|
||||
}
|
||||
|
||||
func relativeDateString(since date: Date, dateFormatter: DateFormatter) -> String {
|
||||
let numberOfDays = numberOfCalendarDays(since: date)
|
||||
|
||||
switch numberOfDays {
|
||||
case 0: return NSLocalizedString("Today", comment: "")
|
||||
case 1: return NSLocalizedString("Yesterday", comment: "")
|
||||
case 2 ... 7: return String(format: NSLocalizedString("%@ days ago", comment: ""), NSNumber(value: numberOfDays))
|
||||
default: return dateFormatter.string(from: date)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// FileManager+SharedDirectories.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 5/14/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension FileManager {
|
||||
var altstoreSharedDirectory: URL? {
|
||||
guard let appGroup = Bundle.main.appGroups.first else { return nil }
|
||||
|
||||
let sharedDirectoryURL = containerURL(forSecurityApplicationGroupIdentifier: appGroup)
|
||||
return sharedDirectoryURL
|
||||
}
|
||||
|
||||
var appBackupsDirectory: URL? {
|
||||
let appBackupsDirectory = altstoreSharedDirectory?.appendingPathComponent("Backups", isDirectory: true)
|
||||
return appBackupsDirectory
|
||||
}
|
||||
|
||||
func backupDirectoryURL(for app: InstalledApp) -> URL? {
|
||||
let backupDirectoryURL = appBackupsDirectory?.appendingPathComponent(app.bundleIdentifier, isDirectory: true)
|
||||
return backupDirectoryURL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// JSONDecoder+Properties.swift
|
||||
// Harmony
|
||||
//
|
||||
// Created by Riley Testut on 10/3/18.
|
||||
// Copyright © 2018 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
import Foundation
|
||||
|
||||
public extension CodingUserInfoKey {
|
||||
static let managedObjectContext = CodingUserInfoKey(rawValue: "managedObjectContext")!
|
||||
static let sourceURL = CodingUserInfoKey(rawValue: "sourceURL")!
|
||||
}
|
||||
|
||||
public final class JSONDecoder: Foundation.JSONDecoder {
|
||||
@DecoderItem(key: .managedObjectContext)
|
||||
public var managedObjectContext: NSManagedObjectContext?
|
||||
|
||||
@DecoderItem(key: .sourceURL)
|
||||
public var sourceURL: URL?
|
||||
}
|
||||
|
||||
public extension Decoder {
|
||||
var managedObjectContext: NSManagedObjectContext? { userInfo[.managedObjectContext] as? NSManagedObjectContext }
|
||||
var sourceURL: URL? { userInfo[.sourceURL] as? URL }
|
||||
}
|
||||
|
||||
@propertyWrapper
|
||||
public struct DecoderItem<Value> {
|
||||
public let key: CodingUserInfoKey
|
||||
|
||||
public var wrappedValue: Value? {
|
||||
get { fatalError("only works on instance properties of classes") }
|
||||
set { fatalError("only works on instance properties of classes") }
|
||||
}
|
||||
|
||||
public init(key: CodingUserInfoKey) {
|
||||
self.key = key
|
||||
}
|
||||
|
||||
public static subscript<OuterSelf: JSONDecoder>(
|
||||
_enclosingInstance decoder: OuterSelf,
|
||||
wrapped _: ReferenceWritableKeyPath<OuterSelf, Value?>,
|
||||
storage storageKeyPath: ReferenceWritableKeyPath<OuterSelf, Self>
|
||||
) -> Value? {
|
||||
get {
|
||||
let wrapper = decoder[keyPath: storageKeyPath]
|
||||
|
||||
let value = decoder.userInfo[wrapper.key] as? Value
|
||||
return value
|
||||
}
|
||||
set {
|
||||
let wrapper = decoder[keyPath: storageKeyPath]
|
||||
decoder.userInfo[wrapper.key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// UIApplication+AppExtension.swift
|
||||
// DeltaCore
|
||||
//
|
||||
// Created by Riley Testut on 6/14/18.
|
||||
// Copyright © 2018 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public extension UIApplication {
|
||||
// Cannot normally use UIApplication.shared from extensions, so we get around this by calling value(forKey:).
|
||||
class var alt_shared: UIApplication? {
|
||||
UIApplication.value(forKey: "sharedApplication") as? UIApplication
|
||||
}
|
||||
}
|
||||
23
Sources/SideStoreCore/Extensions/UIColor+AltStore.swift
Normal file
23
Sources/SideStoreCore/Extensions/UIColor+AltStore.swift
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// UIColor+AltStore.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 5/9/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public extension UIColor {
|
||||
private static let colorBundle = Bundle(for: DatabaseManager.self)
|
||||
|
||||
static let altPrimary = UIColor(named: "Primary", in: colorBundle, compatibleWith: nil)!
|
||||
static let deltaPrimary = UIColor(named: "DeltaPrimary", in: colorBundle, compatibleWith: nil)
|
||||
|
||||
static let altPink = UIColor(named: "Pink", in: colorBundle, compatibleWith: nil)!
|
||||
|
||||
static let refreshRed = UIColor(named: "RefreshRed", in: colorBundle, compatibleWith: nil)!
|
||||
static let refreshOrange = UIColor(named: "RefreshOrange", in: colorBundle, compatibleWith: nil)!
|
||||
static let refreshYellow = UIColor(named: "RefreshYellow", in: colorBundle, compatibleWith: nil)!
|
||||
static let refreshGreen = UIColor(named: "RefreshGreen", in: colorBundle, compatibleWith: nil)!
|
||||
}
|
||||
71
Sources/SideStoreCore/Extensions/UIColor+Hex.swift
Normal file
71
Sources/SideStoreCore/Extensions/UIColor+Hex.swift
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// UIColor+Hex.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 7/15/19.
|
||||
// Copyright © 2019 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public extension UIColor {
|
||||
// Borrowed from https://stackoverflow.com/a/26341062
|
||||
var hexString: String {
|
||||
let components = cgColor.components
|
||||
let r: CGFloat = components?[0] ?? 0.0
|
||||
let g: CGFloat = components?[1] ?? 0.0
|
||||
let b: CGFloat = components?[2] ?? 0.0
|
||||
|
||||
let hexString = String(format: "%02lX%02lX%02lX", lroundf(Float(r * 255)), lroundf(Float(g * 255)), lroundf(Float(b * 255)))
|
||||
return hexString
|
||||
}
|
||||
}
|
||||
|
||||
public extension UIColor {
|
||||
convenience init?(hexString: String) {
|
||||
let hexString = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let scanner = Scanner(string: hexString)
|
||||
|
||||
if hexString.hasPrefix("#") {
|
||||
scanner.scanLocation = 1
|
||||
// TODO: Test if this works to replace the above deprecation @JoeMatt
|
||||
// scanner.currentIndex = .init(utf16Offset: 1, in: hexString)
|
||||
}
|
||||
|
||||
var hexNumber: UInt64 = 0
|
||||
|
||||
guard scanner.scanHexInt64(&hexNumber) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var alpha: UInt64 = 255
|
||||
var red: UInt64 = 0
|
||||
var green: UInt64 = 0
|
||||
var blue: UInt64 = 0
|
||||
|
||||
switch hexString.count {
|
||||
case 3: // RGB (12-bit)
|
||||
red = ((hexNumber & 0xF00) >> 8) * 17
|
||||
green = ((hexNumber & 0x0F0) >> 4) * 17
|
||||
blue = (hexNumber & 0x00F) * 17
|
||||
case 6: // RGB (24-bit)
|
||||
red = (hexNumber & 0xFF0000) >> 16
|
||||
green = (hexNumber & 0x00FF00) >> 8
|
||||
blue = hexNumber & 0x0000FF
|
||||
case 8: // ARGB (32-bit)
|
||||
alpha = (hexNumber & 0xFF00_0000) >> 24
|
||||
red = (hexNumber & 0x00FF_0000) >> 16
|
||||
green = (hexNumber & 0x0000_FF00) >> 8
|
||||
blue = hexNumber & 0x0000_00FF
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(
|
||||
red: CGFloat(red) / 255,
|
||||
green: CGFloat(green) / 255,
|
||||
blue: CGFloat(blue) / 255,
|
||||
alpha: CGFloat(alpha) / 255
|
||||
)
|
||||
}
|
||||
}
|
||||
79
Sources/SideStoreCore/Extensions/UserDefaults+AltStore.swift
Normal file
79
Sources/SideStoreCore/Extensions/UserDefaults+AltStore.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// UserDefaults+AltStore.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 6/4/19.
|
||||
// Copyright © 2019 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import Roxas
|
||||
|
||||
public extension UserDefaults {
|
||||
static let shared: UserDefaults = {
|
||||
guard let appGroup = Bundle.main.appGroups.first else { return .standard }
|
||||
|
||||
let sharedUserDefaults = UserDefaults(suiteName: appGroup)!
|
||||
return sharedUserDefaults
|
||||
}()
|
||||
|
||||
@NSManaged var firstLaunch: Date?
|
||||
@NSManaged var requiresAppGroupMigration: Bool
|
||||
@NSManaged var textServer: Bool
|
||||
@NSManaged var textInputAnisetteURL: String?
|
||||
@NSManaged var customAnisetteURL: String?
|
||||
@NSManaged var preferredServerID: String?
|
||||
|
||||
@NSManaged var isBackgroundRefreshEnabled: Bool
|
||||
@NSManaged var isDebugModeEnabled: Bool
|
||||
@NSManaged var presentedLaunchReminderNotification: Bool
|
||||
|
||||
@NSManaged var legacySideloadedApps: [String]?
|
||||
|
||||
@NSManaged var isLegacyDeactivationSupported: Bool
|
||||
@NSManaged var activeAppLimitIncludesExtensions: Bool
|
||||
|
||||
@NSManaged var localServerSupportsRefreshing: Bool
|
||||
|
||||
@NSManaged var patchedApps: [String]?
|
||||
|
||||
@NSManaged var patronsRefreshID: String?
|
||||
|
||||
@NSManaged var trustedSourceIDs: [String]?
|
||||
|
||||
var activeAppsLimit: Int? {
|
||||
get {
|
||||
_activeAppsLimit?.intValue
|
||||
}
|
||||
set {
|
||||
if let value = newValue {
|
||||
_activeAppsLimit = NSNumber(value: value)
|
||||
} else {
|
||||
_activeAppsLimit = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NSManaged @objc(activeAppsLimit) private var _activeAppsLimit: NSNumber?
|
||||
|
||||
class func registerDefaults() {
|
||||
let ios13_5 = OperatingSystemVersion(majorVersion: 13, minorVersion: 5, patchVersion: 0)
|
||||
let isLegacyDeactivationSupported = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5)
|
||||
let activeAppLimitIncludesExtensions = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios13_5)
|
||||
|
||||
let ios14 = OperatingSystemVersion(majorVersion: 14, minorVersion: 0, patchVersion: 0)
|
||||
let localServerSupportsRefreshing = !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14)
|
||||
|
||||
let defaults = [
|
||||
#keyPath(UserDefaults.isBackgroundRefreshEnabled): true,
|
||||
#keyPath(UserDefaults.isLegacyDeactivationSupported): isLegacyDeactivationSupported,
|
||||
#keyPath(UserDefaults.activeAppLimitIncludesExtensions): activeAppLimitIncludesExtensions,
|
||||
#keyPath(UserDefaults.localServerSupportsRefreshing): localServerSupportsRefreshing,
|
||||
#keyPath(UserDefaults.requiresAppGroupMigration): true
|
||||
]
|
||||
|
||||
UserDefaults.standard.register(defaults: defaults)
|
||||
UserDefaults.shared.register(defaults: defaults)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user