diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index 1ac3556d..9c38c0be 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -320,6 +320,7 @@ BFF0B69A2322D7D0007A79E1 /* UIScreen+CompactHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B6992322D7D0007A79E1 /* UIScreen+CompactHeight.swift */; }; BFF435D8255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */; }; BFF615A82510042B00484D3B /* AltStoreCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF66EE7E2501AE50007EE018 /* AltStoreCore.framework */; }; + D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */; }; D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8B62727841800A9B5DD /* libAppleArchive.tbd */; settings = {ATTRIBUTES = (Weak, ); }; }; D533E8BE2727BBF800A9B5DD /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8BD2727BBF800A9B5DD /* libcurl.a */; }; D54DED1428CBC44B008B27A0 /* ErrorLogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */; }; @@ -818,6 +819,7 @@ BFF7EC4C25081E9300BDE521 /* AltStore 8.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "AltStore 8.xcdatamodel"; sourceTree = ""; }; BFFCFA45248835530077BFCE /* AltDaemon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AltDaemon.entitlements; sourceTree = ""; }; D504F42528AD72C50014BB5D /* ProgressRing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressRing.swift; sourceTree = ""; }; + D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = ""; }; D533E8B62727841800A9B5DD /* libAppleArchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libAppleArchive.tbd; path = usr/lib/libAppleArchive.tbd; sourceTree = SDKROOT; }; D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = ""; }; D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dependencies/fragmentzip/libfragmentzip.a; sourceTree = SOURCE_ROOT; }; @@ -1299,6 +1301,7 @@ BF66EEC92501AECA007EE018 /* Account.swift */, BF66EEC72501AECA007EE018 /* AppID.swift */, BF66EEC62501AECA007EE018 /* AppPermission.swift */, + D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */, BF66EECA2501AECA007EE018 /* DatabaseManager.swift */, BF66EEC02501AECA007EE018 /* InstalledApp.swift */, BF66EECB2501AECA007EE018 /* InstalledExtension.swift */, @@ -2370,6 +2373,7 @@ BFAECC592501B0A400528F27 /* Result+Conveniences.swift in Sources */, BFAECC542501B0A400528F27 /* NSError+ALTServerError.m in Sources */, BF66EEE12501AECA007EE018 /* DatabaseManager.swift in Sources */, + D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */, BF66EEEA2501AED0007EE018 /* UIColor+Hex.swift in Sources */, BF66EECC2501AECA007EE018 /* Source.swift in Sources */, BF66EED72501AECA007EE018 /* InstalledApp.swift in Sources */, diff --git a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents b/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents index 82d3a30c..72733b89 100644 --- a/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents +++ b/AltStoreCore/Model/AltStore.xcdatamodeld/AltStore 10.xcdatamodel/contents @@ -31,6 +31,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -158,10 +178,12 @@ + + diff --git a/AltStoreCore/Model/AppVersion.swift b/AltStoreCore/Model/AppVersion.swift new file mode 100644 index 00000000..fda513ca --- /dev/null +++ b/AltStoreCore/Model/AppVersion.swift @@ -0,0 +1,92 @@ +// +// AppVersion.swift +// AltStoreCore +// +// Created by Riley Testut on 8/18/22. +// Copyright © 2022 Riley Testut. All rights reserved. +// + +import CoreData + +@objc(AppVersion) +public class AppVersion: NSManagedObject, Decodable, Fetchable +{ + /* Properties */ + @NSManaged public var version: String + @NSManaged public var date: Date + @NSManaged public var localizedDescription: String? + + @NSManaged public var downloadURL: URL + @NSManaged public var size: Int64 + + @nonobjc public var minOSVersion: OperatingSystemVersion? { + guard let osVersionString = self._minOSVersion else { return nil } + + let osVersion = OperatingSystemVersion(string: osVersionString) + return osVersion + } + @NSManaged @objc(minOSVersion) private var _minOSVersion: String? + + @nonobjc public var maxOSVersion: OperatingSystemVersion? { + guard let osVersionString = self._maxOSVersion else { return nil } + + let osVersion = OperatingSystemVersion(string: osVersionString) + return osVersion + } + @NSManaged @objc(maxOSVersion) private var _maxOSVersion: String? + + @NSManaged public var appBundleID: String + @NSManaged public var sourceID: String? + + /* Relationships */ + @NSManaged public private(set) var app: StoreApp? + @NSManaged public private(set) var latestVersionApp: StoreApp? + + private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) + { + super.init(entity: entity, insertInto: context) + } + + + private enum CodingKeys: String, CodingKey + { + case version + case date + case localizedDescription + case downloadURL + case size + case _minOSVersion + case _maxOSVersion + case appBundleID + case sourceID + } + + public required init(from decoder: Decoder) throws + { + guard let context = decoder.managedObjectContext else { preconditionFailure("Decoder must have non-nil NSManagedObjectContext.") } + + super.init(entity: NewsItem.entity(), insertInto: context) + + let container = try decoder.container(keyedBy: CodingKeys.self) + self.version = try container.decode(String.self, forKey: .version) + self.date = try container.decode(Date.self, forKey: .date) + + self.localizedDescription = try container.decodeIfPresent(String.self, forKey: .localizedDescription) + self.downloadURL = try container.decode(URL.self, forKey: .downloadURL) + self.size = try container.decode(Int64.self, forKey: .size) + + self._minOSVersion = try container.decodeIfPresent(String.self, forKey: ._minOSVersion) + self._maxOSVersion = try container.decodeIfPresent(String.self, forKey: ._maxOSVersion) + + self.appBundleID = try container.decode(String.self, forKey: .appBundleID) + self.sourceID = try container.decodeIfPresent(String.self, forKey: .sourceID) + } +} + +public extension AppVersion +{ + @nonobjc class func fetchRequest() -> NSFetchRequest + { + return NSFetchRequest(entityName: "AppVersion") + } +} diff --git a/AltStoreCore/Model/StoreApp.swift b/AltStoreCore/Model/StoreApp.swift index 6c145140..97a07ed3 100644 --- a/AltStoreCore/Model/StoreApp.swift +++ b/AltStoreCore/Model/StoreApp.swift @@ -129,6 +129,9 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable @NSManaged @objc(source) public var _source: Source? @NSManaged @objc(permissions) public var _permissions: NSOrderedSet + @NSManaged public private(set) var latestVersion: AppVersion? + @NSManaged @objc(versions) public private(set) var _versions: NSOrderedSet + @NSManaged public private(set) var loggedErrors: NSSet /* Set */ // Use NSSet to avoid eagerly fetching values. @nonobjc public var source: Source? { @@ -145,6 +148,10 @@ public class StoreApp: NSManagedObject, Decodable, Fetchable return self._permissions.array as! [AppPermission] } + @nonobjc public var versions: [AppVersion] { + return self._versions.array as! [AppVersion] + } + private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { super.init(entity: entity, insertInto: context)