mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-24 19:12:50 +08:00
refactor: AboutView, AppCardView, VersionPickerView
1. AboutView: Subdivided some Views 2. AboutView: Added the display of system version number and specific chip model 3. AppCardView: Added the display of the minimum system version and module display 4. AppCardView: Optimized the display of the number of available versions and the number of dependent components 5. VersionPickerView: Added the product icon display in the Header part 6. VersionPickerView: Optimized the download architecture prompt 7. VersionPickerView: Optimized the display of product version, provided the display of productVersion and buildGuid 8. VersionPickerView: Optimized the display of dependent components, added the display of total number of dependencies and buildGuid 9. VersionPickerView: In DEBUG mode, you can check whether the dependent component hits the correct version, the selected version, and the reason for not hitting, and added the selected version icon 10. VersionPickerView: Adjusted the version display of dependent components, and no longer displayed baseVersion by default 11. VersionPickerView: Added optional module display and information
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -26,13 +26,11 @@ DerivedData/
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
*.xcuserstate
|
||||
.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
||||
@@ -16,6 +16,25 @@ private var _globalNetworkManager: NetworkManager?
|
||||
private var _globalNewDownloadUtils: NewDownloadUtils?
|
||||
private var _globalCancelTracker: CancelTracker?
|
||||
|
||||
struct DependencyCacheKey: Hashable {
|
||||
let sapCode: String
|
||||
let targetPlatform: String
|
||||
}
|
||||
|
||||
private var _globalDependencyCache: [DependencyCacheKey: Product.Platform.LanguageSet.Dependency]?
|
||||
|
||||
var globalDependencyCache: [DependencyCacheKey: Product.Platform.LanguageSet.Dependency] {
|
||||
get {
|
||||
if _globalDependencyCache == nil {
|
||||
_globalDependencyCache = [:]
|
||||
}
|
||||
return _globalDependencyCache!
|
||||
}
|
||||
set {
|
||||
_globalDependencyCache = newValue
|
||||
}
|
||||
}
|
||||
|
||||
// 计算属性,确保总是返回有效实例
|
||||
var globalStiResult: NewParseResult {
|
||||
get {
|
||||
|
||||
@@ -59,6 +59,21 @@ struct Product: Codable, Equatable {
|
||||
var baseVersion: String
|
||||
var productVersion: String
|
||||
var buildGuid: String
|
||||
var isMatchPlatform: Bool
|
||||
var targetPlatform: String
|
||||
var selectedPlatform: String
|
||||
var selectedReason: String
|
||||
|
||||
init(sapCode: String, baseVersion: String, productVersion: String, buildGuid: String, isMatchPlatform: Bool = false, targetPlatform: String = "", selectedPlatform: String = "", selectedReason: String = "") {
|
||||
self.sapCode = sapCode
|
||||
self.baseVersion = baseVersion
|
||||
self.productVersion = productVersion
|
||||
self.buildGuid = buildGuid
|
||||
self.isMatchPlatform = isMatchPlatform
|
||||
self.targetPlatform = targetPlatform
|
||||
self.selectedPlatform = selectedPlatform
|
||||
self.selectedReason = selectedReason
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
@StateObject private var networkManager = globalNetworkManager
|
||||
@State private var isRefreshing = false
|
||||
@State private var errorMessage: String?
|
||||
@State private var showDownloadManager = false
|
||||
@State private var searchText = ""
|
||||
@State private var currentApiVersion = StorageData.shared.apiVersion
|
||||
|
||||
private var apiVersion: String {
|
||||
get { StorageData.shared.apiVersion }
|
||||
set {
|
||||
StorageData.shared.apiVersion = newValue
|
||||
refreshData()
|
||||
}
|
||||
}
|
||||
|
||||
private var filteredProducts: [UniqueProduct] {
|
||||
if searchText.isEmpty { return globalUniqueProducts }
|
||||
|
||||
@@ -32,7 +25,7 @@ struct ContentView: View {
|
||||
errorMessage = nil
|
||||
|
||||
Task {
|
||||
await globalNetworkManager.fetchProducts()
|
||||
await networkManager.fetchProducts()
|
||||
await MainActor.run { isRefreshing = false }
|
||||
}
|
||||
}
|
||||
@@ -45,7 +38,7 @@ struct ContentView: View {
|
||||
set: { newValue in
|
||||
StorageData.shared.downloadAppleSilicon = newValue
|
||||
Task {
|
||||
await globalNetworkManager.fetchProducts()
|
||||
await networkManager.fetchProducts()
|
||||
}
|
||||
}
|
||||
)) { Text("Apple Silicon") }
|
||||
@@ -102,8 +95,8 @@ struct ContentView: View {
|
||||
.buttonStyle(.borderless)
|
||||
.overlay(
|
||||
Group {
|
||||
if !globalNetworkManager.downloadTasks.isEmpty {
|
||||
Text("\(globalNetworkManager.downloadTasks.count)")
|
||||
if !networkManager.downloadTasks.isEmpty {
|
||||
Text("\(networkManager.downloadTasks.count)")
|
||||
.font(.caption2)
|
||||
.padding(3)
|
||||
.background(Color.blue)
|
||||
@@ -134,7 +127,7 @@ struct ContentView: View {
|
||||
Color(NSColor.windowBackgroundColor)
|
||||
.ignoresSafeArea()
|
||||
|
||||
switch globalNetworkManager.loadingState {
|
||||
switch networkManager.loadingState {
|
||||
case .idle, .loading:
|
||||
ProgressView("正在加载...")
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
@@ -156,7 +149,7 @@ struct ContentView: View {
|
||||
.padding(.bottom, 10)
|
||||
|
||||
Button(action: {
|
||||
globalNetworkManager.retryFetchData()
|
||||
networkManager.retryFetchData()
|
||||
}) {
|
||||
HStack() {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Adobe Exit Code
|
||||
107: 架构不一致或安装文件被损坏
|
||||
103: 权限问题
|
||||
182: 可能是文件不全或者出错了
|
||||
182: 表示创建的包不包含要安装的包
|
||||
133: 磁盘空间不足
|
||||
*/
|
||||
import Foundation
|
||||
@@ -115,15 +115,15 @@ actor InstallManager {
|
||||
let errorMessage: String
|
||||
switch exitCode {
|
||||
case 107:
|
||||
errorMessage = String(localized: "安装失败: 架构或版本不一致 (退出代码: \(exitCode))")
|
||||
errorMessage = String(localized: "架构或版本不一致 (退出代码: \(exitCode))")
|
||||
case 103:
|
||||
errorMessage = String(localized: "安装失败: 权限问题 (退出代码: \(exitCode))")
|
||||
errorMessage = String(localized: "权限问题 (退出代码: \(exitCode))")
|
||||
case 182:
|
||||
errorMessage = String(localized: "安装失败: 安装文件不完整或损坏 (退出代码: \(exitCode))")
|
||||
errorMessage = String(localized: "安装文件不完整或损坏 (退出代码: \(exitCode))")
|
||||
case -1:
|
||||
errorMessage = String(localized: "安装失败: Setup 组件未被处理 (退出代码: \(exitCode))")
|
||||
errorMessage = String(localized: "Setup 组件未被处理 (退出代码: \(exitCode))")
|
||||
default:
|
||||
errorMessage = String(localized: "安装失败 (退出代码: \(exitCode))")
|
||||
errorMessage = String(localized: "(退出代码: \(exitCode))")
|
||||
}
|
||||
progressHandler(0.0, errorMessage)
|
||||
continuation.resume(throwing: InstallError.installationFailed(errorMessage))
|
||||
|
||||
@@ -283,31 +283,69 @@ class NewJSONParser {
|
||||
return Product.Platform.LanguageSet.Dependency(sapCode: "",baseVersion: "",productVersion: "",buildGuid: "")
|
||||
}
|
||||
|
||||
let targetPlatform = AppStatics.isAppleSilicon ? "macarm64" : "osx10-64"
|
||||
let cacheKey = DependencyCacheKey(sapCode: sapCode, targetPlatform: targetPlatform)
|
||||
|
||||
if let cachedDependency = globalDependencyCache[cacheKey] {
|
||||
return cachedDependency
|
||||
}
|
||||
|
||||
var productVersion = ""
|
||||
var buildGuid = ""
|
||||
var isMatchPlatform = false
|
||||
var selectedPlatform = ""
|
||||
var selectedReason = ""
|
||||
|
||||
if !globalStiResult.products.isEmpty {
|
||||
let matchingProducts = globalStiResult.products.filter { $0.id == sapCode }
|
||||
|
||||
|
||||
if let latestProduct = matchingProducts.sorted(by: {
|
||||
return AppStatics.compareVersions($0.version, $1.version) < 0
|
||||
}).last {
|
||||
let targetPlatformId = AppStatics.isAppleSilicon ? "macarm64" : "osx10-64"
|
||||
let _ = latestProduct.platforms.map { $0.id }
|
||||
if let matchingPlatform = latestProduct.platforms.first(where: { $0.id == targetPlatformId }),
|
||||
return AppStatics.compareVersions($0.version, $1.version) > 0
|
||||
}).first {
|
||||
if let matchingPlatform = latestProduct.platforms.first(where: { platform in
|
||||
platform.id == targetPlatform || platform.id == "macuniversal"
|
||||
}),
|
||||
let firstLanguageSet = matchingPlatform.languageSet.first {
|
||||
productVersion = firstLanguageSet.productVersion
|
||||
buildGuid = firstLanguageSet.buildGuid
|
||||
isMatchPlatform = true
|
||||
selectedPlatform = matchingPlatform.id
|
||||
selectedReason = matchingPlatform.id == "macuniversal" ?
|
||||
"成功匹配通用平台 macuniversal(支持所有 Mac 平台)" :
|
||||
"成功匹配目标平台"
|
||||
} else {
|
||||
if let firstAvailablePlatform = latestProduct.platforms.first,
|
||||
let firstLanguageSet = firstAvailablePlatform.languageSet.first {
|
||||
productVersion = firstLanguageSet.productVersion
|
||||
buildGuid = firstLanguageSet.buildGuid
|
||||
isMatchPlatform = false
|
||||
selectedPlatform = firstAvailablePlatform.id
|
||||
selectedReason = "当前依赖所有版本中无匹配平台,使用可用平台: \(firstAvailablePlatform.id)"
|
||||
} else {
|
||||
selectedReason = "未找到任何可用平台"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedReason = "未找到最新版本产品"
|
||||
}
|
||||
} else {
|
||||
selectedReason = "globalStiResult.products 为空"
|
||||
}
|
||||
|
||||
return Product.Platform.LanguageSet.Dependency(
|
||||
let dependency = Product.Platform.LanguageSet.Dependency(
|
||||
sapCode: sapCode,
|
||||
baseVersion: baseVersion,
|
||||
productVersion: productVersion,
|
||||
buildGuid: buildGuid
|
||||
buildGuid: buildGuid,
|
||||
isMatchPlatform: isMatchPlatform,
|
||||
targetPlatform: targetPlatform,
|
||||
selectedPlatform: selectedPlatform,
|
||||
selectedReason: selectedReason
|
||||
)
|
||||
|
||||
globalDependencyCache[cacheKey] = dependency
|
||||
|
||||
return dependency
|
||||
}
|
||||
newLanguageSet.dependencies.append(contentsOf: dependencies)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -369,13 +369,54 @@ private struct ProductInfoView: View {
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
HStack(spacing: 4) {
|
||||
let product = findProduct(id: viewModel.uniqueProduct.id)
|
||||
let versions = Set(product?.platforms.first?.languageSet.map { $0.productVersion } ?? [])
|
||||
let dependenciesCount = product?.platforms.first?.languageSet.first?.dependencies.count ?? 0
|
||||
Text("可用版本: \(versions.count)")
|
||||
Text("|")
|
||||
Text("依赖包: \(dependenciesCount)")
|
||||
let products = findProducts(id: viewModel.uniqueProduct.id)
|
||||
let versions = products.compactMap { product -> String? in
|
||||
let platforms = product.platforms.filter { platform in
|
||||
StorageData.shared.allowedPlatform.contains(platform.id)
|
||||
}
|
||||
return platforms.isEmpty ? nil : product.version
|
||||
}
|
||||
let uniqueVersions = Set(versions)
|
||||
|
||||
let dependenciesCount = products.first?.platforms.first?.languageSet.first?.dependencies.count ?? 0
|
||||
let minOSVersion = products.first?.platforms.first?.range.first?.min ?? ""
|
||||
let modulesCount = products.first?.platforms.first?.modules.count ?? 0
|
||||
|
||||
HStack(spacing: 12) {
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "tag")
|
||||
Text("\(uniqueVersions.count)")
|
||||
}
|
||||
|
||||
if dependenciesCount > 0 {
|
||||
Text("•")
|
||||
.foregroundColor(.gray)
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "shippingbox")
|
||||
Text("\(dependenciesCount)")
|
||||
}
|
||||
}
|
||||
|
||||
if !minOSVersion.isEmpty {
|
||||
Text("•")
|
||||
.foregroundColor(.gray)
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "macwindow")
|
||||
Text(minOSVersion.replacingOccurrences(of: "-", with: ""))
|
||||
}
|
||||
}
|
||||
|
||||
if modulesCount > 0 {
|
||||
Text("•")
|
||||
.foregroundColor(.gray)
|
||||
|
||||
HStack(spacing: 2) {
|
||||
Image(systemName: "square.stack.3d.up")
|
||||
Text("\(modulesCount)")
|
||||
}
|
||||
}
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
@@ -431,7 +472,7 @@ private struct SheetModifier: ViewModifier {
|
||||
content
|
||||
.sheet(isPresented: $viewModel.showVersionPicker) {
|
||||
if let product = findProduct(id: viewModel.uniqueProduct.id) {
|
||||
VersionPickerView(product: product) { version in
|
||||
VersionPickerView(productId: viewModel.uniqueProduct.id) { version in
|
||||
Task {
|
||||
await viewModel.handleDownloadRequest(
|
||||
version,
|
||||
|
||||
@@ -8,8 +8,8 @@ import SwiftUI
|
||||
|
||||
private enum VersionPickerConstants {
|
||||
static let headerPadding: CGFloat = 5
|
||||
static let viewWidth: CGFloat = 400
|
||||
static let viewHeight: CGFloat = 500
|
||||
static let viewWidth: CGFloat = 500
|
||||
static let viewHeight: CGFloat = 600
|
||||
static let iconSize: CGFloat = 32
|
||||
static let verticalSpacing: CGFloat = 8
|
||||
static let horizontalSpacing: CGFloat = 12
|
||||
@@ -26,19 +26,19 @@ struct VersionPickerView: View {
|
||||
@StorageValue(\.downloadAppleSilicon) private var downloadAppleSilicon
|
||||
@State private var expandedVersions: Set<String> = []
|
||||
|
||||
private let product: Product
|
||||
private let productId: String
|
||||
private let onSelect: (String) -> Void
|
||||
|
||||
init(product: Product, onSelect: @escaping (String) -> Void) {
|
||||
self.product = product
|
||||
init(productId: String, onSelect: @escaping (String) -> Void) {
|
||||
self.productId = productId
|
||||
self.onSelect = onSelect
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
VersionPickerHeaderView(product: product, downloadAppleSilicon: downloadAppleSilicon)
|
||||
VersionPickerHeaderView(productId: productId, downloadAppleSilicon: downloadAppleSilicon)
|
||||
VersionListView(
|
||||
product: product,
|
||||
productId: productId,
|
||||
expandedVersions: $expandedVersions,
|
||||
onSelect: onSelect,
|
||||
dismiss: dismiss
|
||||
@@ -49,16 +49,32 @@ struct VersionPickerView: View {
|
||||
}
|
||||
|
||||
private struct VersionPickerHeaderView: View {
|
||||
let product: Product
|
||||
let productId: String
|
||||
let downloadAppleSilicon: Bool
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@EnvironmentObject private var networkManager: NetworkManager
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Text("\(product.displayName)")
|
||||
.font(.headline)
|
||||
if let product = findProduct(id: productId) {
|
||||
if let icon = product.getBestIcon() {
|
||||
AsyncImage(url: URL(string: icon.value)) { image in
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 24, height: 24)
|
||||
} placeholder: {
|
||||
Image(systemName: "app.fill")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
}
|
||||
|
||||
Text("\(product.displayName)")
|
||||
.font(.headline)
|
||||
}
|
||||
Text("选择版本")
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
@@ -68,10 +84,20 @@ private struct VersionPickerHeaderView: View {
|
||||
}
|
||||
.padding(.bottom, VersionPickerConstants.headerPadding)
|
||||
|
||||
Text("🔔 即将下载 \(downloadAppleSilicon ? "Apple Silicon" : "Intel") (\(platformText)) 版本 🔔")
|
||||
.font(.caption)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.bottom, 10)
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: downloadAppleSilicon ? "m.square" : "x.square")
|
||||
.foregroundColor(.blue)
|
||||
Text(downloadAppleSilicon ? "Apple Silicon" : "Intel")
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
Text("•")
|
||||
.foregroundColor(.secondary)
|
||||
Text(platformText)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.bottom, 10)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
@@ -84,51 +110,64 @@ private struct VersionPickerHeaderView: View {
|
||||
}
|
||||
|
||||
private struct VersionListView: View {
|
||||
@EnvironmentObject private var networkManager: NetworkManager
|
||||
let product: Product
|
||||
let productId: String
|
||||
@Binding var expandedVersions: Set<String>
|
||||
let onSelect: (String) -> Void
|
||||
let dismiss: DismissAction
|
||||
|
||||
var body: some View {
|
||||
ScrollView(showsIndicators: false) {
|
||||
LazyVStack(spacing: VersionPickerConstants.verticalSpacing) {
|
||||
ForEach(filteredVersions, id: \.key) { version, info in
|
||||
VersionRow(
|
||||
product: product,
|
||||
version: version,
|
||||
info: info,
|
||||
isExpanded: expandedVersions.contains(version),
|
||||
onSelect: handleVersionSelect,
|
||||
onToggle: handleVersionToggle
|
||||
)
|
||||
VStack(spacing: 0) {
|
||||
LazyVStack(spacing: VersionPickerConstants.verticalSpacing) {
|
||||
ForEach(filteredVersions, id: \.key) { version, info in
|
||||
VersionRow(
|
||||
productId: productId,
|
||||
version: version,
|
||||
info: info,
|
||||
isExpanded: expandedVersions.contains(version),
|
||||
onSelect: handleVersionSelect,
|
||||
onToggle: handleVersionToggle
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
HStack(spacing: 8) {
|
||||
Capsule()
|
||||
.fill(Color.secondary.opacity(0.2))
|
||||
.frame(width: 6, height: 6)
|
||||
Text("获取到 \(filteredVersions.count) 个版本")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.padding(.bottom, 16)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.background(Color(NSColor.windowBackgroundColor))
|
||||
}
|
||||
|
||||
private var filteredVersions: [(key: String, value: Product.Platform)] {
|
||||
// 获取支持的平台
|
||||
let platforms = product.platforms.filter { platform in
|
||||
StorageData.shared.allowedPlatform.contains(platform.id) &&
|
||||
platform.languageSet.first != nil
|
||||
}
|
||||
|
||||
// 如果没有支持的平台,返回空数组
|
||||
if platforms.isEmpty {
|
||||
let products = findProducts(id: productId)
|
||||
if products.isEmpty {
|
||||
return []
|
||||
}
|
||||
|
||||
var versionPlatformMap: [String: Product.Platform] = [:]
|
||||
|
||||
// 将平台按版本号降序排序
|
||||
return platforms.map { platform in
|
||||
// 使用第一个语言集的 productVersion 作为版本号
|
||||
(key: platform.languageSet.first?.productVersion ?? "", value: platform)
|
||||
}.sorted { pair1, pair2 in
|
||||
// 按版本号降序排序
|
||||
AppStatics.compareVersions(pair1.key, pair2.key) > 0
|
||||
for product in products {
|
||||
let platforms = product.platforms.filter { platform in
|
||||
StorageData.shared.allowedPlatform.contains(platform.id)
|
||||
}
|
||||
|
||||
if let firstPlatform = platforms.first {
|
||||
versionPlatformMap[product.version] = firstPlatform
|
||||
}
|
||||
}
|
||||
|
||||
return versionPlatformMap.map { (key: $0.key, value: $0.value) }
|
||||
.sorted { pair1, pair2 in
|
||||
AppStatics.compareVersions(pair1.key, pair2.key) > 0
|
||||
}
|
||||
}
|
||||
|
||||
private func handleVersionSelect(_ version: String) {
|
||||
@@ -150,7 +189,7 @@ private struct VersionListView: View {
|
||||
private struct VersionRow: View {
|
||||
@StorageValue(\.defaultLanguage) private var defaultLanguage
|
||||
|
||||
let product: Product
|
||||
let productId: String
|
||||
let version: String
|
||||
let info: Product.Platform
|
||||
let isExpanded: Bool
|
||||
@@ -159,7 +198,7 @@ private struct VersionRow: View {
|
||||
|
||||
private var existingPath: URL? {
|
||||
globalNetworkManager.isVersionDownloaded(
|
||||
productId: product.id,
|
||||
productId: productId,
|
||||
version: version,
|
||||
language: defaultLanguage
|
||||
)
|
||||
@@ -172,7 +211,7 @@ private struct VersionRow: View {
|
||||
info: info,
|
||||
isExpanded: isExpanded,
|
||||
hasExistingPath: existingPath != nil,
|
||||
onSelect: handleSelect,
|
||||
onSelect: { onToggle(version) },
|
||||
onToggle: { onToggle(version) }
|
||||
)
|
||||
|
||||
@@ -188,15 +227,6 @@ private struct VersionRow: View {
|
||||
.background(Color(NSColor.controlBackgroundColor))
|
||||
.cornerRadius(VersionPickerConstants.cornerRadius)
|
||||
}
|
||||
|
||||
private func handleSelect() {
|
||||
let dependencies = info.languageSet.first?.dependencies ?? []
|
||||
if dependencies.isEmpty {
|
||||
onSelect(version)
|
||||
} else {
|
||||
onToggle(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct VersionHeader: View {
|
||||
@@ -207,16 +237,20 @@ private struct VersionHeader: View {
|
||||
let onSelect: () -> Void
|
||||
let onToggle: () -> Void
|
||||
|
||||
private var hasDependencies: Bool {
|
||||
!(info.languageSet.first?.dependencies.isEmpty ?? true)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button(action: onSelect) {
|
||||
HStack {
|
||||
VersionInfo(version: version, platform: info.id)
|
||||
VersionInfo(version: version, platform: info.id, info: info)
|
||||
Spacer()
|
||||
ExistingPathButton(isVisible: hasExistingPath)
|
||||
ExpandButton(
|
||||
isExpanded: isExpanded,
|
||||
onToggle: onToggle,
|
||||
hasDependencies: !(info.languageSet.first?.dependencies.isEmpty ?? true)
|
||||
hasDependencies: hasDependencies
|
||||
)
|
||||
}
|
||||
.padding(.vertical, VersionPickerConstants.buttonPadding)
|
||||
@@ -229,14 +263,46 @@ private struct VersionHeader: View {
|
||||
private struct VersionInfo: View {
|
||||
let version: String
|
||||
let platform: String
|
||||
let info: Product.Platform
|
||||
|
||||
private var productVersion: String? {
|
||||
info.languageSet.first?.productVersion
|
||||
}
|
||||
|
||||
private var buildGuid: String? {
|
||||
info.languageSet.first?.buildGuid
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(version)
|
||||
.font(.headline)
|
||||
Text(platform)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
HStack(spacing: 6) {
|
||||
Text(version)
|
||||
.font(.headline)
|
||||
|
||||
if let pv = productVersion, pv != version {
|
||||
Text("•")
|
||||
.foregroundColor(.secondary)
|
||||
Text("v\(pv)")
|
||||
.font(.caption)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
}
|
||||
|
||||
HStack(spacing: 4) {
|
||||
Text(platform)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
if let guid = buildGuid {
|
||||
Text("•")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Text(guid)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,17 +329,10 @@ private struct ExpandButton: View {
|
||||
let hasDependencies: Bool
|
||||
|
||||
var body: some View {
|
||||
Button(action: onToggle) {
|
||||
Image(systemName: iconName)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
private var iconName: String {
|
||||
if !hasDependencies {
|
||||
return "chevron.right"
|
||||
}
|
||||
return isExpanded ? "chevron.down" : "chevron.right"
|
||||
Image(systemName: isExpanded ? "chevron.down" : "chevron.right")
|
||||
.foregroundColor(.secondary)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture(perform: onToggle)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,15 +341,56 @@ private struct VersionDetails: View {
|
||||
let version: String
|
||||
let onSelect: (String) -> Void
|
||||
|
||||
private var hasDependencies: Bool {
|
||||
!(info.languageSet.first?.dependencies.isEmpty ?? true)
|
||||
}
|
||||
|
||||
private var hasModules: Bool {
|
||||
!(info.modules.isEmpty)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: VersionPickerConstants.verticalSpacing) {
|
||||
Text("依赖包:")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.top, 8)
|
||||
.padding(.leading, 16)
|
||||
|
||||
DependenciesList(dependencies: info.languageSet.first?.dependencies ?? [])
|
||||
if hasDependencies || hasModules {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
if hasDependencies {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "shippingbox")
|
||||
.foregroundColor(.blue)
|
||||
Text("依赖组件")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Text("(\(info.languageSet.first?.dependencies.count ?? 0))")
|
||||
.font(.caption)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
DependenciesList(dependencies: info.languageSet.first?.dependencies ?? [])
|
||||
.padding(.leading, 8)
|
||||
}
|
||||
|
||||
if hasModules {
|
||||
if hasDependencies {
|
||||
Divider()
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "square.stack.3d.up")
|
||||
.foregroundColor(.blue)
|
||||
Text("可选模块")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
Text("(\(info.modules.count))")
|
||||
.font(.caption)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
ModulesList(modules: info.modules)
|
||||
.padding(.leading, 8)
|
||||
}
|
||||
}
|
||||
.background(Color(NSColor.controlBackgroundColor).opacity(0.5))
|
||||
.cornerRadius(6)
|
||||
}
|
||||
|
||||
DownloadButton(version: version, onSelect: onSelect)
|
||||
}
|
||||
@@ -304,15 +404,118 @@ private struct DependenciesList: View {
|
||||
|
||||
var body: some View {
|
||||
ForEach(dependencies, id: \.sapCode) { dependency in
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "cube.box")
|
||||
.foregroundColor(.blue)
|
||||
.frame(width: 16)
|
||||
Text("\(dependency.sapCode) (\(dependency.baseVersion))")
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack(spacing: 6) {
|
||||
getPlatformIcon(for: dependency.selectedPlatform)
|
||||
.foregroundColor(.blue)
|
||||
.frame(width: 16)
|
||||
|
||||
Text(dependency.sapCode)
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
|
||||
Text("v\(dependency.productVersion)")
|
||||
.font(.caption)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
|
||||
HStack(spacing: 8) {
|
||||
if dependency.baseVersion != dependency.productVersion {
|
||||
Text("base: \(dependency.baseVersion)")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
if !dependency.buildGuid.isEmpty {
|
||||
HStack(spacing: 4) {
|
||||
Text("buildGuid:")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
Text(dependency.buildGuid)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.leading, 22)
|
||||
|
||||
// 第三行:调试信息(仅在 DEBUG 模式下显示)
|
||||
#if DEBUG
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack(spacing: 4) {
|
||||
Text("Match:")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
Text(dependency.isMatchPlatform ? "✅" : "❌")
|
||||
.font(.caption2)
|
||||
|
||||
Text("•")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Text("Target:")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
Text(dependency.targetPlatform)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
|
||||
if !dependency.selectedReason.isEmpty {
|
||||
HStack(spacing: 4) {
|
||||
Text("Reason:")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
Text(dependency.selectedReason)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.orange)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.leading, 22)
|
||||
#endif
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
}
|
||||
|
||||
private func getPlatformIcon(for platform: String) -> Image {
|
||||
switch platform {
|
||||
case "macarm64":
|
||||
return Image(systemName: "m.square")
|
||||
case "macuniversal":
|
||||
return Image(systemName: "m.circle")
|
||||
case "osx10", "osx10-64":
|
||||
return Image(systemName: "x.square")
|
||||
default:
|
||||
return Image(systemName: "questionmark.square")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ModulesList: View {
|
||||
let modules: [Product.Platform.Module]
|
||||
|
||||
var body: some View {
|
||||
ForEach(modules, id: \.id) { module in
|
||||
HStack(spacing: 6) {
|
||||
Circle()
|
||||
.fill(Color.blue.opacity(0.2))
|
||||
.frame(width: 6, height: 6)
|
||||
|
||||
Text(module.displayName)
|
||||
.font(.caption)
|
||||
|
||||
if !module.deploymentType.isEmpty {
|
||||
Text("(\(module.deploymentType))")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.leading, 24)
|
||||
.padding(.vertical, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,11 +525,10 @@ private struct DownloadButton: View {
|
||||
let onSelect: (String) -> Void
|
||||
|
||||
var body: some View {
|
||||
Button("下载此版本") {
|
||||
Button("下载") {
|
||||
onSelect(version)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.padding(.top, 8)
|
||||
.padding(.leading, 16)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
"strings" : {
|
||||
"" : {
|
||||
|
||||
},
|
||||
" [%@]" : {
|
||||
|
||||
},
|
||||
"(%@)" : {
|
||||
|
||||
},
|
||||
"(%lld)" : {
|
||||
|
||||
},
|
||||
"(可能导致处理 Setup 组件失败)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -21,6 +22,7 @@
|
||||
}
|
||||
},
|
||||
"(将导致无法使用安装功能)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -29,6 +31,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"(退出代码: %lld)" : {
|
||||
|
||||
},
|
||||
"[%@]" : {
|
||||
|
||||
},
|
||||
"/" : {
|
||||
|
||||
@@ -126,6 +134,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"•" : {
|
||||
|
||||
},
|
||||
"• 错误 2700:不太可能会出现,除非 Setup 组件处理失败了\n• 错误 107:所下载的文件架构与系统架构不一致或者安装文件被损坏\n• 错误 103:出现权限问题,请确保 Helper 状态正常\n• 错误 182:文件不齐全或文件被损坏,或者你的Setup组件不一致,请重新下载 X1a0He CC\n• 错误 133:系统磁盘空间不足\n• 错误 -1:Setup 组件未处理或处理失败,请联系开发者\n• 错误 195:所下载的产品不支持你当前的系统\n• 错误 146:请在 Mac 系统设置中给予 Adobe Downloader 全磁盘权限\n• 错误 255:Setup 组件需要更新,请联系开发者解决" : {
|
||||
"localizations" : {
|
||||
@@ -137,10 +148,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"|" : {
|
||||
"✅" : {
|
||||
|
||||
},
|
||||
"❌" : {
|
||||
|
||||
},
|
||||
"🔔 即将下载 %@ (%@) 版本 🔔" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -285,12 +300,17 @@
|
||||
},
|
||||
"Apple Silicon" : {
|
||||
|
||||
},
|
||||
"base: %@" : {
|
||||
|
||||
},
|
||||
"buildGuid:" : {
|
||||
|
||||
},
|
||||
"By X1a0He. ❤️ Love from China. 🇨🇳" : {
|
||||
|
||||
},
|
||||
"Debug 模式" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -420,9 +440,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Intel" : {
|
||||
|
||||
},
|
||||
"macOS %@" : {
|
||||
|
||||
},
|
||||
"Match:" : {
|
||||
|
||||
},
|
||||
"OK" : {
|
||||
|
||||
},
|
||||
"Reason:" : {
|
||||
|
||||
},
|
||||
"Setup 组件安装成功" : {
|
||||
"extractionState" : "stale",
|
||||
@@ -454,6 +486,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Setup 组件未被处理 (退出代码: %lld)" : {
|
||||
|
||||
},
|
||||
"Setup未备份提示" : {
|
||||
"localizations" : {
|
||||
@@ -464,6 +499,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Target:" : {
|
||||
|
||||
},
|
||||
"v%@" : {
|
||||
|
||||
},
|
||||
"v4" : {
|
||||
|
||||
@@ -478,6 +519,7 @@
|
||||
|
||||
},
|
||||
"X1a0He CC 下载并处理成功" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -488,6 +530,7 @@
|
||||
}
|
||||
},
|
||||
"X1a0He CC 下载成功" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -640,6 +683,7 @@
|
||||
},
|
||||
"下载此版本" : {
|
||||
"comment" : "版本选择页面",
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -837,6 +881,7 @@
|
||||
}
|
||||
},
|
||||
"依赖包:" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -847,6 +892,7 @@
|
||||
}
|
||||
},
|
||||
"依赖包: %lld" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -855,6 +901,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"依赖组件" : {
|
||||
|
||||
},
|
||||
"修改 Setup 组件失败" : {
|
||||
"localizations" : {
|
||||
@@ -1088,6 +1137,7 @@
|
||||
}
|
||||
},
|
||||
"可用版本: %lld" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1116,6 +1166,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"可选模块" : {
|
||||
|
||||
},
|
||||
"命令行安装" : {
|
||||
"localizations" : {
|
||||
@@ -1270,6 +1323,7 @@
|
||||
}
|
||||
},
|
||||
"安装失败 (退出代码: %lld)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1290,6 +1344,7 @@
|
||||
}
|
||||
},
|
||||
"安装失败: Setup 组件未被处理 (退出代码: %lld)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1300,6 +1355,7 @@
|
||||
}
|
||||
},
|
||||
"安装失败: 安装文件不完整或损坏 (退出代码: %lld)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1310,6 +1366,7 @@
|
||||
}
|
||||
},
|
||||
"安装失败: 权限问题 (退出代码: %lld)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1320,6 +1377,7 @@
|
||||
}
|
||||
},
|
||||
"安装失败: 架构或版本不一致 (退出代码: %lld)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1348,6 +1406,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"安装文件不完整或损坏 (退出代码: %lld)" : {
|
||||
|
||||
},
|
||||
"安装程序已存在" : {
|
||||
"localizations" : {
|
||||
@@ -1392,7 +1453,6 @@
|
||||
}
|
||||
},
|
||||
"将执行的命令:" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1433,7 +1493,6 @@
|
||||
}
|
||||
},
|
||||
"展开全部" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1454,6 +1513,7 @@
|
||||
}
|
||||
},
|
||||
"已处理" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1464,6 +1524,7 @@
|
||||
}
|
||||
},
|
||||
"已备份" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1669,7 +1730,6 @@
|
||||
}
|
||||
},
|
||||
"折叠全部" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2107,6 +2167,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"权限问题 (退出代码: %lld)" : {
|
||||
|
||||
},
|
||||
"架构或版本不一致 (退出代码: %lld)" : {
|
||||
|
||||
},
|
||||
"查看持久化文件" : {
|
||||
|
||||
},
|
||||
"检查中" : {
|
||||
"localizations" : {
|
||||
@@ -2672,6 +2741,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"系统信息" : {
|
||||
|
||||
},
|
||||
"继续" : {
|
||||
"localizations" : {
|
||||
@@ -2745,6 +2817,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"获取到 %lld 个版本" : {
|
||||
|
||||
},
|
||||
"获取到 %lld 款产品" : {
|
||||
"localizations" : {
|
||||
|
||||
Reference in New Issue
Block a user