diff --git a/Adobe Downloader.xcodeproj/xcshareddata/xcschemes/Adobe Downloader.xcscheme b/Adobe Downloader.xcodeproj/xcshareddata/xcschemes/Adobe Downloader.xcscheme index a71041f..6ed2fb3 100644 --- a/Adobe Downloader.xcodeproj/xcshareddata/xcschemes/Adobe Downloader.xcscheme +++ b/Adobe Downloader.xcodeproj/xcshareddata/xcschemes/Adobe Downloader.xcscheme @@ -31,7 +31,7 @@ shouldAutocreateTestPlan = "YES"> some View { content .sheet(isPresented: $viewModel.showVersionPicker) { - if let product = findProduct(id: viewModel.uniqueProduct.id) { + if findProduct(id: viewModel.uniqueProduct.id) != nil { VersionPickerView(productId: viewModel.uniqueProduct.id) { version in Task { await viewModel.handleDownloadRequest( diff --git a/Adobe Downloader/Views/DownloadProgressView.swift b/Adobe Downloader/Views/DownloadProgressView.swift index 461131c..3d6bae2 100644 --- a/Adobe Downloader/Views/DownloadProgressView.swift +++ b/Adobe Downloader/Views/DownloadProgressView.swift @@ -5,28 +5,6 @@ // import SwiftUI -public struct BeautifulButtonStyle: ButtonStyle { - var baseColor: Color - @State private var isHovering = false - - public func makeBody(configuration: Configuration) -> some View { - configuration.label - .padding(.vertical, 6) - .padding(.horizontal, 12) - .background( - RoundedRectangle(cornerRadius: 6) - .fill(configuration.isPressed ? baseColor.opacity(0.7) : baseColor) - ) - .overlay( - RoundedRectangle(cornerRadius: 6) - .strokeBorder(baseColor.opacity(0.2), lineWidth: 1) - .opacity(configuration.isPressed ? 0 : 1) - ) - .scaleEffect(configuration.isPressed ? 0.97 : 1.0) - .animation(.easeInOut(duration: 0.15), value: configuration.isPressed) - } -} - struct DownloadProgressView: View { @ObservedObject var task: NewDownloadTask let onCancel: () -> Void @@ -43,6 +21,7 @@ struct DownloadProgressView: View { @State private var showSetupProcessAlert = false @State private var showCommandLineInstall = false @State private var showCopiedAlert = false + @State private var showDeleteConfirmation = false private var statusLabel: some View { Text(task.status.description) @@ -135,7 +114,7 @@ struct DownloadProgressView: View { .buttonStyle(BeautifulButtonStyle(baseColor: .blue)) } - Button(action: onRemove) { + Button(action: { showDeleteConfirmation = true }) { Label("移除", systemImage: "xmark") .font(.system(size: 13, weight: .medium)) .foregroundColor(.white) @@ -192,7 +171,7 @@ struct DownloadProgressView: View { } } - Button(action: onRemove) { + Button(action: { showDeleteConfirmation = true }) { Label("删除", systemImage: "trash") .font(.system(size: 13, weight: .medium)) .foregroundColor(.white) @@ -209,6 +188,14 @@ struct DownloadProgressView: View { .buttonStyle(BeautifulButtonStyle(baseColor: .red)) } } + .alert("确认删除", isPresented: $showDeleteConfirmation) { + Button("取消", role: .cancel) { } + Button("删除", role: .destructive) { + onRemove() + } + } message: { + Text("确定要删除任务\(task.displayName)吗?") + } .sheet(isPresented: $showInstallPrompt) { if task.displayInstallButton { VStack(spacing: 20) { @@ -742,18 +729,7 @@ private struct CommandLineInstallButton: View { showCopiedAlert = false } } - .padding(.vertical, 5) - .padding(.horizontal, 10) - .background( - LinearGradient( - gradient: Gradient(colors: [ - Color.purple.opacity(0.8), - Color.purple - ]), - startPoint: .top, - endPoint: .bottom - ) - ) + .buttonStyle(BeautifulButtonStyle(baseColor: .purple)) .foregroundColor(.white) .clipShape(RoundedRectangle(cornerRadius: 8)) .shadow(color: Color.purple.opacity(0.3), radius: 3, x: 0, y: 2) diff --git a/Adobe Downloader/Views/ExistingFileAlertView.swift b/Adobe Downloader/Views/ExistingFileAlertView.swift index e98529b..506f1a3 100644 --- a/Adobe Downloader/Views/ExistingFileAlertView.swift +++ b/Adobe Downloader/Views/ExistingFileAlertView.swift @@ -11,7 +11,7 @@ private enum AlertConstants { static let warningIconSize: CGFloat = 24 static let warningIconOffset: CGFloat = 10 static let verticalSpacing: CGFloat = 20 - static let buttonHeight: CGFloat = 32 + static let buttonHeight: CGFloat = 24 static let buttonWidth: CGFloat = 260 static let buttonFontSize: CGFloat = 14 static let cornerRadius: CGFloat = 12 @@ -74,6 +74,16 @@ private struct AppIcon: View { } } .frame(width: AlertConstants.iconSize, height: AlertConstants.iconSize) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(Color.secondary.opacity(0.05)) + .padding(-4) + ) + .overlay( + RoundedRectangle(cornerRadius: 8) + .stroke(Color.secondary.opacity(0.1), lineWidth: 1) + .padding(-4) + ) } } @@ -93,7 +103,17 @@ private struct PathSection: View { VStack(alignment: .leading, spacing: 8) { HStack { Text(path.path) + .font(.system(size: 13)) .foregroundColor(.blue) + .padding(8) + .background( + RoundedRectangle(cornerRadius: 6) + .fill(Color.blue.opacity(0.05)) + ) + .overlay( + RoundedRectangle(cornerRadius: 6) + .stroke(Color.blue.opacity(0.1), lineWidth: 0.5) + ) .onTapGesture { openInFinder(path) } @@ -112,7 +132,7 @@ private struct ButtonSection: View { let onCancel: () -> Void var body: some View { - VStack(spacing: 16) { + VStack(spacing: 12) { ActionButton( title: String(localized: "使用现有程序"), icon: "checkmark.circle", @@ -151,9 +171,9 @@ private struct ActionButton: View { .frame(minWidth: 0, maxWidth: AlertConstants.buttonWidth) .frame(height: AlertConstants.buttonHeight) .font(.system(size: AlertConstants.buttonFontSize)) + .foregroundColor(.white) } - .buttonStyle(.borderedProminent) - .tint(color) + .buttonStyle(BeautifulButtonStyle(baseColor: color)) .if(isCancel) { view in view.keyboardShortcut(.cancelAction) } diff --git a/Adobe Downloader/Views/SetupBackupAlertView.swift b/Adobe Downloader/Views/SetupBackupAlertView.swift new file mode 100644 index 0000000..60669c3 --- /dev/null +++ b/Adobe Downloader/Views/SetupBackupAlertView.swift @@ -0,0 +1,86 @@ +// +// SetupBackupAlertView.swift +// Adobe Downloader +// +// Created by X1a0He on 3/27/25. +// +import SwiftUI + +struct SetupBackupAlertView: View { + let onConfirm: () -> Void + let onCancel: () -> Void + @State private var isHovering = false + @State private var countdown = 10 + @State private var isCountdownActive = false + private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() + + var body: some View { + VStack(spacing: 20) { + Image(nsImage: NSImage(named: NSImage.applicationIconName)!) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 80, height: 80) + .padding(.top, 10) + .overlay( + Image(systemName: "exclamationmark.triangle.fill") + .font(.system(size: 24)) + .foregroundColor(.orange) + .offset(x: 30, y: 30) + ) + + Text("Setup未备份提示") + .font(.headline) + .padding(.top, 5) + + Text("检测到Setup文件尚未备份,如果你需要安装程序,则Setup必须被处理,点击确定后你需要输入密码,Adobe Downloader将自动处理并备份为Setup.original") + .font(.system(size: 14)) + .multilineTextAlignment(.center) + .padding(.horizontal, 20) + .foregroundColor(.secondary) + + HStack(spacing: 20) { + Button(action: onCancel) { + Text("取消") + .frame(width: 120, height: 24) + .foregroundColor(.white) + } + .buttonStyle(BeautifulButtonStyle(baseColor: Color.gray.opacity(0.8))) + + #if DEBUG + Button(action: onConfirm) { + Text("确定") + .frame(width: 120, height: 24) + .foregroundColor(.white) + } + .buttonStyle(BeautifulButtonStyle(baseColor: .blue)) + .keyboardShortcut(.defaultAction) + #else + Button(action: isCountdownActive && countdown == 0 ? onConfirm : { + isCountdownActive = true + }) { + Text(isCountdownActive && countdown > 0 ? "\(countdown)" : "确定") + .frame(width: 120, height: 24) + .foregroundColor(.white) + } + .buttonStyle(BeautifulButtonStyle(baseColor: isCountdownActive && countdown > 0 ? Color.blue.opacity(0.6) : .blue)) + .disabled(isCountdownActive && countdown > 0) + .keyboardShortcut(.defaultAction) + .onReceive(timer) { _ in + if isCountdownActive && countdown > 0 { + countdown -= 1 + } + } + #endif + } + .padding(.bottom, 20) + } + .frame(width: 400) + .cornerRadius(12) + .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 2) + .onAppear { + #if !DEBUG + isCountdownActive = true + #endif + } + } +} diff --git a/Adobe Downloader/Views/SetupBackupResultView.swift b/Adobe Downloader/Views/SetupBackupResultView.swift new file mode 100644 index 0000000..1b19071 --- /dev/null +++ b/Adobe Downloader/Views/SetupBackupResultView.swift @@ -0,0 +1,52 @@ +// +// SetupBackupResultView.swift +// Adobe Downloader +// +// Created by X1a0He on 3/27/25. +// +import SwiftUI + +struct SetupBackupResultView: View { + let isSuccess: Bool + let message: String + let onDismiss: () -> Void + + init(isSuccess: Bool, message: String, onDismiss: @escaping () -> Void) { + self.isSuccess = isSuccess + self.message = message + self.onDismiss = onDismiss + } + + var body: some View { + VStack(spacing: 20) { + + Image(systemName: isSuccess ? "checkmark.circle.fill" : "xmark.circle.fill") + .font(.system(size: 50)) + .foregroundColor(isSuccess ? .green : .red) + .padding(.top, 20) + + Text(isSuccess ? "备份成功" : "备份失败") + .font(.title3) + .bold() + .padding(.top, 5) + + Text(message) + .font(.system(size: 14)) + .multilineTextAlignment(.center) + .padding(.horizontal, 20) + .foregroundColor(.secondary) + + Button(action: onDismiss) { + Text("确定") + .frame(width: 120, height: 24) + .foregroundColor(.white) + } + .buttonStyle(BeautifulButtonStyle(baseColor: isSuccess ? Color.green : Color.blue)) + .keyboardShortcut(.defaultAction) + .padding(.bottom, 20) + } + .frame(width: 350) + .cornerRadius(12) + .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 2) + } +} diff --git a/Adobe Downloader/Views/Styles/BeautifulButtonStyle.swift b/Adobe Downloader/Views/Styles/BeautifulButtonStyle.swift new file mode 100644 index 0000000..64a5377 --- /dev/null +++ b/Adobe Downloader/Views/Styles/BeautifulButtonStyle.swift @@ -0,0 +1,29 @@ +// +// Adobe Downloader +// +// Created by X1a0He. +// + +import SwiftUI + +public struct BeautifulButtonStyle: ButtonStyle { + var baseColor: Color + @State private var isHovering = false + + public func makeBody(configuration: Configuration) -> some View { + configuration.label + .padding(.vertical, 6) + .padding(.horizontal, 12) + .background( + RoundedRectangle(cornerRadius: 6) + .fill(configuration.isPressed ? baseColor.opacity(0.7) : baseColor) + ) + .overlay( + RoundedRectangle(cornerRadius: 6) + .strokeBorder(baseColor.opacity(0.2), lineWidth: 1) + .opacity(configuration.isPressed ? 0 : 1) + ) + .scaleEffect(configuration.isPressed ? 0.97 : 1.0) + .animation(.easeInOut(duration: 0.15), value: configuration.isPressed) + } +} \ No newline at end of file diff --git a/Localizables/Localizable.xcstrings b/Localizables/Localizable.xcstrings index 5ec52f7..7b68ca8 100644 --- a/Localizables/Localizable.xcstrings +++ b/Localizables/Localizable.xcstrings @@ -26,6 +26,9 @@ } } } + }, + "(可能导致处理失败)" : { + }, "(将导致无法使用安装功能)" : { "extractionState" : "stale", @@ -37,6 +40,9 @@ } } } + }, + "(无法使用安装功能)" : { + }, "/" : { @@ -139,6 +145,7 @@ }, "• 错误 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 组件需要更新,请联系开发者解决" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -147,12 +154,6 @@ } } } - }, - "✅" : { - - }, - "❌" : { - }, "🔔 即将下载 %@ (%@) 版本 🔔" : { "extractionState" : "stale", @@ -307,6 +308,7 @@ }, "Debug 模式" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -444,15 +446,9 @@ }, "macOS %@" : { - }, - "Match:" : { - }, "OK" : { - }, - "Reason:" : { - }, "Setup 组件安装成功" : { "extractionState" : "stale", @@ -494,9 +490,6 @@ } } } - }, - "Target:" : { - }, "v%@" : { @@ -757,6 +750,7 @@ } }, "为什么我安装的时候会遇到错误代码,错误代码表示什么意思?" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1464,6 +1458,7 @@ } }, "将执行的命令:" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1507,6 +1502,7 @@ }, "展开全部" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1533,7 +1529,6 @@ }, "已处理" : { - "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1544,7 +1539,6 @@ } }, "已备份" : { - "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1761,6 +1755,7 @@ } }, "折叠全部" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2107,6 +2102,12 @@ } } } + }, + "未处理" : { + + }, + "未备份" : { + }, "未安装" : { "localizations" : { @@ -2207,9 +2208,6 @@ }, "查看" : { - }, - "查看持久化文件" : { - }, "检查中" : { "localizations" : { @@ -2622,6 +2620,12 @@ } } } + }, + "确定要删除任务%@吗?" : { + + }, + "确定要重新处理 Setup 组件吗?这将对 Setup 组件进行修改以启用安装功能。" : { + }, "确认" : { "localizations" : { @@ -2652,6 +2656,12 @@ } } } + }, + "确认删除" : { + + }, + "确认处理" : { + }, "确认清理" : { "localizations" : {