mirror of
https://github.com/ninxsoft/Mist.git
synced 2025-05-16 16:14:49 -04:00
Add support for toggling custom SUCatalogs
This commit is contained in:
parent
e8a4835f4e
commit
1688095e18
8 changed files with 290 additions and 88 deletions
|
@ -26,7 +26,7 @@
|
|||
390451DC28573F1000E0B563 /* Dictionary+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451DB28573F1000E0B563 /* Dictionary+Extension.swift */; };
|
||||
390451DF28573FAA00E0B563 /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 390451DE28573FAA00E0B563 /* Yams */; };
|
||||
390451E1285740E800E0B563 /* Sequence+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E0285740E800E0B563 /* Sequence+Extension.swift */; };
|
||||
390451E528574F0000E0B563 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E428574F0000E0B563 /* Catalog.swift */; };
|
||||
390451E528574F0000E0B563 /* CatalogType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E428574F0000E0B563 /* CatalogType.swift */; };
|
||||
390451E72857510C00E0B563 /* TextTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E62857510B00E0B563 /* TextTag.swift */; };
|
||||
39148CFC28DD55B300011FF5 /* PathControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39148CFB28DD55B300011FF5 /* PathControl.swift */; };
|
||||
39252A77285A849F00956C74 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39252A76285A849F00956C74 /* AppDelegate.swift */; };
|
||||
|
@ -94,7 +94,8 @@
|
|||
398734D028603D9E00B4C357 /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734CF28603D9E00B4C357 /* UInt8+Extension.swift */; };
|
||||
398734D228603DE700B4C357 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D128603DE700B4C357 /* Array+Extension.swift */; };
|
||||
398734D4286046B000B4C357 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D3286046B000B4C357 /* UInt32+Extension.swift */; };
|
||||
39CF4E732859C03D009E708C /* CatalogRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CF4E722859C03D009E708C /* CatalogRow.swift */; };
|
||||
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */; };
|
||||
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */; };
|
||||
39CF55A028614DD8006FB5D2 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CF559F28614DD8006FB5D2 /* main.swift */; };
|
||||
39CF55AA286154A5006FB5D2 /* Blessed in Frameworks */ = {isa = PBXBuildFile; productRef = 39CF55A9286154A5006FB5D2 /* Blessed */; };
|
||||
39CF55AB286154D1006FB5D2 /* com.ninxsoft.mist.helper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 39CF559D28614DD8006FB5D2 /* com.ninxsoft.mist.helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
|
@ -173,7 +174,7 @@
|
|||
390451D928573ADC00E0B563 /* ExportListType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportListType.swift; sourceTree = "<group>"; };
|
||||
390451DB28573F1000E0B563 /* Dictionary+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Extension.swift"; sourceTree = "<group>"; };
|
||||
390451E0285740E800E0B563 /* Sequence+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Extension.swift"; sourceTree = "<group>"; };
|
||||
390451E428574F0000E0B563 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
||||
390451E428574F0000E0B563 /* CatalogType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogType.swift; sourceTree = "<group>"; };
|
||||
390451E62857510B00E0B563 /* TextTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextTag.swift; sourceTree = "<group>"; };
|
||||
39148CFB28DD55B300011FF5 /* PathControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathControl.swift; sourceTree = "<group>"; };
|
||||
39252A76285A849F00956C74 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -237,7 +238,8 @@
|
|||
398734CF28603D9E00B4C357 /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = "<group>"; };
|
||||
398734D128603DE700B4C357 /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
|
||||
398734D3286046B000B4C357 /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = "<group>"; };
|
||||
39CF4E722859C03D009E708C /* CatalogRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogRow.swift; sourceTree = "<group>"; };
|
||||
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
||||
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSeedType.swift; sourceTree = "<group>"; };
|
||||
39CF559D28614DD8006FB5D2 /* com.ninxsoft.mist.helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.ninxsoft.mist.helper; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
39CF559F28614DD8006FB5D2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
39CF55A528614E66006FB5D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
|
@ -379,8 +381,9 @@
|
|||
390451C32856E4A500E0B563 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
390451E428574F0000E0B563 /* Catalog.swift */,
|
||||
39CF4E722859C03D009E708C /* CatalogRow.swift */,
|
||||
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */,
|
||||
390451E428574F0000E0B563 /* CatalogType.swift */,
|
||||
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */,
|
||||
398734CB28603D5F00B4C357 /* Chunklist.swift */,
|
||||
398734CD28603D7F00B4C357 /* Chunk.swift */,
|
||||
395DCD15287FE36E00C411CE /* DownloadAlertType.swift */,
|
||||
|
@ -740,6 +743,7 @@
|
|||
398734C428600E6E00B4C357 /* TaskManager.swift in Sources */,
|
||||
390451D62856F7FE00E0B563 /* UInt64+Extension.swift in Sources */,
|
||||
3935F47E2864813B00760AB0 /* DownloadManager.swift in Sources */,
|
||||
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */,
|
||||
39252AA1285C2A1600956C74 /* PaddedDivider.swift in Sources */,
|
||||
39CF560C2861AE93006FB5D2 /* HelperToolCommandResponse.swift in Sources */,
|
||||
39252A99285BFE2C00956C74 /* MistTaskState.swift in Sources */,
|
||||
|
@ -767,14 +771,14 @@
|
|||
390451C22856E3F500E0B563 /* Hardware.swift in Sources */,
|
||||
39CF56092861AE7F006FB5D2 /* HelperToolCommandRequest.swift in Sources */,
|
||||
390451C82856E94900E0B563 /* FirmwareListRow.swift in Sources */,
|
||||
39CF4E732859C03D009E708C /* CatalogRow.swift in Sources */,
|
||||
390451E528574F0000E0B563 /* Catalog.swift in Sources */,
|
||||
390451E528574F0000E0B563 /* CatalogType.swift in Sources */,
|
||||
3935F4852866B64900760AB0 /* MistTaskSection.swift in Sources */,
|
||||
390451AC2856E1D900E0B563 /* ContentView.swift in Sources */,
|
||||
3935F4A4286AD21000760AB0 /* DownloadProgressView.swift in Sources */,
|
||||
39252A89285AD0AB00956C74 /* SettingsHeaderView.swift in Sources */,
|
||||
39252A85285ACDC800956C74 /* ResetToDefaultButton.swift in Sources */,
|
||||
39CF560F2861B857006FB5D2 /* XPCRoute+Extension.swift in Sources */,
|
||||
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */,
|
||||
39252A7F285AC6F600956C74 /* SettingsPackagesView.swift in Sources */,
|
||||
39CF562F2862A797006FB5D2 /* ISOConverter.swift in Sources */,
|
||||
39CF56392862D75D006FB5D2 /* FileCreator.swift in Sources */,
|
||||
|
|
|
@ -2,32 +2,61 @@
|
|||
// Catalog.swift
|
||||
// Mist
|
||||
//
|
||||
// Created by Nindi Gill on 13/6/2022.
|
||||
// Created by Nindi Gill on 6/12/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum Catalog: String, CaseIterable {
|
||||
// swiftlint:disable redundant_string_enum_value
|
||||
struct Catalog: Identifiable, Decodable, Equatable {
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
// swiftlint:disable:next redundant_string_enum_value
|
||||
case type = "type"
|
||||
// swiftlint:disable:next redundant_string_enum_value
|
||||
case standard = "standard"
|
||||
case customer = "customer"
|
||||
case developer = "developer"
|
||||
case `public` = "public"
|
||||
|
||||
static var urls: [String] {
|
||||
self.allCases.map { $0.url }
|
||||
// swiftlint:disable:next redundant_string_enum_value
|
||||
case customerSeed = "customerSeed"
|
||||
// swiftlint:disable:next redundant_string_enum_value
|
||||
case developerSeed = "developerSeed"
|
||||
// swiftlint:disable:next redundant_string_enum_value
|
||||
case publicSeed = "publicSeed"
|
||||
}
|
||||
|
||||
var url: String {
|
||||
switch self {
|
||||
case .standard:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .customer:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12customerseed-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .developer:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12seed-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .`public`:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12beta-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
static var example: Catalog {
|
||||
Catalog(type: .ventura, standard: true, customerSeed: false, developerSeed: false, publicSeed: false)
|
||||
}
|
||||
|
||||
var id: UUID = UUID()
|
||||
var type: CatalogType
|
||||
var standard: Bool
|
||||
var customerSeed: Bool
|
||||
var developerSeed: Bool
|
||||
var publicSeed: Bool
|
||||
|
||||
init(type: CatalogType, standard: Bool, customerSeed: Bool, developerSeed: Bool, publicSeed: Bool) {
|
||||
self.type = type
|
||||
self.standard = standard
|
||||
self.customerSeed = customerSeed
|
||||
self.developerSeed = developerSeed
|
||||
self.publicSeed = publicSeed
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container: KeyedDecodingContainer<Catalog.CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||
type = try container.decode(CatalogType.self, forKey: .type)
|
||||
standard = try container.decode(Bool.self, forKey: .standard)
|
||||
customerSeed = try container.decode(Bool.self, forKey: .customerSeed)
|
||||
developerSeed = try container.decode(Bool.self, forKey: .developerSeed)
|
||||
publicSeed = try container.decode(Bool.self, forKey: .publicSeed)
|
||||
}
|
||||
|
||||
func dictionary() -> [String: Any] {
|
||||
[
|
||||
"type": type.description,
|
||||
"standard": standard,
|
||||
"customerSeed": customerSeed,
|
||||
"developerSeed": developerSeed,
|
||||
"publicSeed": publicSeed
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
//
|
||||
// CatalogRow.swift
|
||||
// Mist
|
||||
//
|
||||
// Created by Nindi Gill on 15/6/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CatalogRow: Identifiable, Hashable {
|
||||
|
||||
static var example: CatalogRow {
|
||||
CatalogRow(url: Catalog.standard.url)
|
||||
}
|
||||
|
||||
var id: UUID = UUID()
|
||||
var url: String
|
||||
}
|
19
Mist/Model/CatalogSeedType.swift
Normal file
19
Mist/Model/CatalogSeedType.swift
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// CatalogSeedType.swift
|
||||
// Mist
|
||||
//
|
||||
// Created by Nindi Gill on 8/12/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum CatalogSeedType: String {
|
||||
case standard = "Standard"
|
||||
case customer = "Customer"
|
||||
case developer = "Developer"
|
||||
case `public` = "Public"
|
||||
|
||||
var description: String {
|
||||
rawValue
|
||||
}
|
||||
}
|
80
Mist/Model/CatalogType.swift
Normal file
80
Mist/Model/CatalogType.swift
Normal file
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// CatalogType.swift
|
||||
// Mist
|
||||
//
|
||||
// Created by Nindi Gill on 13/6/2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum CatalogType: String, CaseIterable, Comparable, Decodable {
|
||||
case ventura = "macOS Ventura"
|
||||
case monterey = "macOS Monterey"
|
||||
case bigSur = "macOS Big Sur"
|
||||
|
||||
var description: String {
|
||||
rawValue
|
||||
}
|
||||
|
||||
var imageName: String {
|
||||
rawValue
|
||||
}
|
||||
|
||||
private var sortOrder: Int {
|
||||
switch self {
|
||||
case .ventura:
|
||||
return 0
|
||||
case .monterey:
|
||||
return 1
|
||||
case .bigSur:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
static func < (lhs: CatalogType, rhs: CatalogType) -> Bool {
|
||||
lhs.sortOrder < rhs.sortOrder
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func url(for seedType: CatalogSeedType) -> String {
|
||||
|
||||
switch self {
|
||||
case .ventura:
|
||||
switch seedType {
|
||||
case .standard:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .customer:
|
||||
// swiftlint:disable:next line_length
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-13customerseed-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .developer:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-13seed-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .public:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-13beta-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
}
|
||||
case .monterey:
|
||||
switch seedType {
|
||||
case .standard:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .customer:
|
||||
// swiftlint:disable:next line_length
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12customerseed-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .developer:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12seed-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .public:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-12beta-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
}
|
||||
case .bigSur:
|
||||
switch seedType {
|
||||
case .standard:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .customer:
|
||||
// swiftlint:disable:next line_length
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-10.16customerseed-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .developer:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-10.16seed-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
case .public:
|
||||
return "https://swscan.apple.com/content/catalogs/others/index-10.16beta-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import SwiftUI
|
||||
|
||||
// swiftlint:disable:next type_body_length
|
||||
struct RefreshView: View {
|
||||
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
||||
@Binding var firmwares: [Firmware]
|
||||
|
@ -124,11 +125,11 @@ struct RefreshView: View {
|
|||
|
||||
private func retrieveInstallers() throws -> [Installer] {
|
||||
var installers: [Installer] = []
|
||||
let catalogs: [String] = UserDefaults.standard.array(forKey: "catalogURLs") as? [String] ?? Catalog.urls
|
||||
let catalogURLs: [String] = getCatalogURLs()
|
||||
|
||||
for catalog in catalogs {
|
||||
for catalogURL in catalogURLs {
|
||||
|
||||
guard let url: URL = URL(string: catalog) else {
|
||||
guard let url: URL = URL(string: catalogURL) else {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -161,6 +162,49 @@ struct RefreshView: View {
|
|||
return installers
|
||||
}
|
||||
|
||||
private func getCatalogURLs() -> [String] {
|
||||
|
||||
var catalogURLs: [String] = []
|
||||
var catalogs: [Catalog] = []
|
||||
let defaultCatalogs: [Catalog] = CatalogType.allCases.map { Catalog(type: $0, standard: true, customerSeed: false, developerSeed: false, publicSeed: false) }
|
||||
|
||||
if let array: [[String: Any]] = UserDefaults.standard.array(forKey: "catalogs") as? [[String: Any]] {
|
||||
do {
|
||||
catalogs = try JSONDecoder().decode([Catalog].self, from: JSONSerialization.data(withJSONObject: array))
|
||||
let catalogTypes: [CatalogType] = catalogs.map { $0.type }
|
||||
|
||||
for catalogType in CatalogType.allCases where !catalogTypes.contains(catalogType) {
|
||||
let catalog: Catalog = Catalog(type: catalogType, standard: true, customerSeed: false, developerSeed: false, publicSeed: false)
|
||||
catalogs.append(catalog)
|
||||
}
|
||||
} catch {
|
||||
catalogs = defaultCatalogs
|
||||
}
|
||||
} else {
|
||||
catalogs = defaultCatalogs
|
||||
}
|
||||
|
||||
for catalog in catalogs {
|
||||
if catalog.standard {
|
||||
catalogURLs.append(catalog.type.url(for: .standard))
|
||||
}
|
||||
|
||||
if catalog.customerSeed {
|
||||
catalogURLs.append(catalog.type.url(for: .customer))
|
||||
}
|
||||
|
||||
if catalog.developerSeed {
|
||||
catalogURLs.append(catalog.type.url(for: .developer))
|
||||
}
|
||||
|
||||
if catalog.publicSeed {
|
||||
catalogURLs.append(catalog.type.url(for: .public))
|
||||
}
|
||||
}
|
||||
|
||||
return catalogURLs
|
||||
}
|
||||
|
||||
private func getInstallers(from dictionary: [String: Any]) -> [Installer] {
|
||||
|
||||
var installers: [Installer] = []
|
||||
|
|
|
@ -8,47 +8,81 @@
|
|||
import SwiftUI
|
||||
|
||||
struct SettingsInstallersCatalogsView: View {
|
||||
@Binding var catalogRows: [CatalogRow]
|
||||
@Binding var selectedCatalogRow: CatalogRow?
|
||||
@Binding var catalogs: [Catalog]
|
||||
// swiftlint:disable:next line_length
|
||||
private let description: String = "Apple Software Update Catalogs are used to determine available macOS Installers.\n\n- **Standard:** The default catalog that ships with macOS\n- **Customer Seed:** The catalog available as part of the [AppleSeed Program](https://appleseed.apple.com/)\n- **Developer Seed:** The catalog available as part of the [Apple Developer Program](https://developer.apple.com/programs/)\n- **Public Seed:** The catalog available as part of the [Apple Beta Software Program](https://beta.apple.com/)\n\n**Note:** Catalogs from the Seed Programs may contain beta / unreleased versions of macOS. Ensure you are a member of these programs before proceeding."
|
||||
private let height: CGFloat = 120
|
||||
private let width: CGFloat = 150
|
||||
private let length: CGFloat = 16
|
||||
private let height: CGFloat = 200
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Catalog URLs:")
|
||||
FooterText("Apple Software Update Catalogs are used to determine all available macOS Installers.")
|
||||
List(selection: $selectedCatalogRow) {
|
||||
ForEach($catalogRows) { catalogRow in
|
||||
HStack {
|
||||
ScaledSystemImage(systemName: "line.3.horizontal", length: length)
|
||||
.foregroundColor(.secondary)
|
||||
TextEditor(text: catalogRow.url)
|
||||
}
|
||||
}
|
||||
.onMove { indexSet, offset in
|
||||
catalogRows.move(fromOffsets: indexSet, toOffset: offset)
|
||||
}
|
||||
.onDelete { indexSet in
|
||||
catalogRows.remove(atOffsets: indexSet)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: height)
|
||||
HStack {
|
||||
Spacer()
|
||||
Button("Add") {
|
||||
addCatalog()
|
||||
Text("Software Update Catalogs:")
|
||||
FooterText(description)
|
||||
Table(catalogs) {
|
||||
TableColumn("") { catalog in
|
||||
ScaledImage(name: catalog.type.imageName, length: length)
|
||||
}
|
||||
.width(length)
|
||||
TableColumn("Catalog Type") { catalog in
|
||||
Text(catalog.type.description)
|
||||
}
|
||||
.width(width)
|
||||
TableColumn(CatalogSeedType.standard.description) { catalog in
|
||||
toggle(.standard, using: catalog)
|
||||
}
|
||||
TableColumn(CatalogSeedType.customer.description) { catalog in
|
||||
toggle(.customer, using: catalog)
|
||||
}
|
||||
TableColumn(CatalogSeedType.developer.description) { catalog in
|
||||
toggle(.developer, using: catalog)
|
||||
}
|
||||
TableColumn(CatalogSeedType.public.description) { catalog in
|
||||
toggle(.public, using: catalog)
|
||||
}
|
||||
}
|
||||
.tableStyle(.bordered)
|
||||
.frame(minHeight: height, maxHeight: height)
|
||||
}
|
||||
}
|
||||
|
||||
private func addCatalog() {
|
||||
catalogRows.append(CatalogRow(url: "https://"))
|
||||
private func toggle(_ catalogSeedType: CatalogSeedType, using catalog: Catalog) -> some View {
|
||||
Toggle(catalogSeedType.description, isOn: Binding<Bool>(
|
||||
get: {
|
||||
switch catalogSeedType {
|
||||
case .standard:
|
||||
return catalog.standard
|
||||
case .customer:
|
||||
return catalog.customerSeed
|
||||
case .developer:
|
||||
return catalog.developerSeed
|
||||
case .public:
|
||||
return catalog.publicSeed
|
||||
}
|
||||
},
|
||||
set: {
|
||||
guard let index: Int = catalogs.firstIndex(where: { $0.id == catalog.id }) else {
|
||||
return
|
||||
}
|
||||
|
||||
switch catalogSeedType {
|
||||
case .standard:
|
||||
catalogs[index].standard = $0
|
||||
case .customer:
|
||||
catalogs[index].customerSeed = $0
|
||||
case .developer:
|
||||
catalogs[index].developerSeed = $0
|
||||
case .public:
|
||||
catalogs[index].publicSeed = $0
|
||||
}
|
||||
}
|
||||
))
|
||||
.labelsHidden()
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsInstallersCatalogsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsInstallersCatalogsView(catalogRows: .constant([.example]), selectedCatalogRow: .constant(.example))
|
||||
SettingsInstallersCatalogsView(catalogs: .constant([.example]))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,10 @@ import SwiftUI
|
|||
struct SettingsInstallersView: View {
|
||||
@AppStorage("cacheDownloads") private var cacheDownloads: Bool = false
|
||||
@AppStorage("cacheDirectory") private var cacheDirectory: String = .cacheDirectory
|
||||
@State private var catalogRows: [CatalogRow] = []
|
||||
@State private var selectedCatalogRow: CatalogRow?
|
||||
@State private var catalogs: [Catalog] = []
|
||||
private let cacheDownloadsDefault: Bool = false
|
||||
private let cacheDirectoryDefault: String = .cacheDirectory
|
||||
private var defaultCatalogRows: [CatalogRow] = Catalog.urls.map { CatalogRow(url: $0) }
|
||||
private let defaultCatalogs: [Catalog] = CatalogType.allCases.map { Catalog(type: $0, standard: true, customerSeed: false, developerSeed: false, publicSeed: false) }
|
||||
private let imageName: String = "Installer"
|
||||
private let title: String = "Installers"
|
||||
private let description: String = "macOS Installers are a collection of files that can be used to build macOS Installer **Applications**, **Disk Images**, **ISOs** and **Packages**."
|
||||
|
@ -25,7 +24,7 @@ struct SettingsInstallersView: View {
|
|||
PaddedDivider()
|
||||
SettingsInstallersCacheView(cacheDownloads: $cacheDownloads, cacheDirectory: $cacheDirectory)
|
||||
PaddedDivider()
|
||||
SettingsInstallersCatalogsView(catalogRows: $catalogRows, selectedCatalogRow: $selectedCatalogRow)
|
||||
SettingsInstallersCatalogsView(catalogs: $catalogs)
|
||||
PaddedDivider()
|
||||
ResetToDefaultButton {
|
||||
reset()
|
||||
|
@ -33,27 +32,38 @@ struct SettingsInstallersView: View {
|
|||
}
|
||||
.padding()
|
||||
.onAppear {
|
||||
populateCatalogURLs()
|
||||
catalogs = getCatalogs()
|
||||
}
|
||||
.onChange(of: catalogRows) { catalogRows in
|
||||
UserDefaults.standard.setValue(catalogRows.map { $0.url }, forKey: "catalogURLs")
|
||||
.onChange(of: catalogs) { catalogs in
|
||||
UserDefaults.standard.setValue(catalogs.map { $0.dictionary() }, forKey: "catalogs")
|
||||
}
|
||||
}
|
||||
|
||||
private func populateCatalogURLs() {
|
||||
private func getCatalogs() -> [Catalog] {
|
||||
|
||||
guard let urls: [String] = UserDefaults.standard.array(forKey: "catalogURLs") as? [String] else {
|
||||
catalogRows = defaultCatalogRows
|
||||
return
|
||||
guard let array: [[String: Any]] = UserDefaults.standard.array(forKey: "catalogs") as? [[String: Any]] else {
|
||||
return defaultCatalogs
|
||||
}
|
||||
|
||||
catalogRows = urls.map { CatalogRow(url: $0) }
|
||||
do {
|
||||
var catalogs: [Catalog] = try JSONDecoder().decode([Catalog].self, from: JSONSerialization.data(withJSONObject: array))
|
||||
let catalogTypes: [CatalogType] = catalogs.map { $0.type }
|
||||
|
||||
for catalogType in CatalogType.allCases where !catalogTypes.contains(catalogType) {
|
||||
let catalog: Catalog = Catalog(type: catalogType, standard: true, customerSeed: false, developerSeed: false, publicSeed: false)
|
||||
catalogs.append(catalog)
|
||||
}
|
||||
|
||||
return catalogs.sorted { $0.type < $1.type }
|
||||
} catch {
|
||||
return defaultCatalogs
|
||||
}
|
||||
}
|
||||
|
||||
private func reset() {
|
||||
cacheDownloads = cacheDownloadsDefault
|
||||
cacheDirectory = cacheDirectoryDefault
|
||||
catalogRows = defaultCatalogRows
|
||||
catalogs = defaultCatalogs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue