fix: Fixed the issue where a successful backup prompt failed

This commit is contained in:
X1a0He
2025-03-27 14:49:57 +08:00
parent f823984b7f
commit ee2ac727ce
11 changed files with 295 additions and 98 deletions

View File

@@ -31,7 +31,7 @@
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"

View File

@@ -9,8 +9,8 @@ struct Adobe_DownloaderApp: App {
@State private var showLanguagePicker = false
@State private var showCreativeCloudAlert = false
@State private var showBackupResultAlert = false
@State private var backupResultMessage = ""
@State private var backupSuccess = false
@StateObject private var backupResult = BackupResult()
private var storage: StorageData { StorageData.shared }
private let updaterController: SPUStandardUpdaterController
@@ -72,18 +72,25 @@ struct Adobe_DownloaderApp: App {
ShouldExistsSetUpView()
.environmentObject(globalNetworkManager)
}
.alert("Setup未备份提示", isPresented: $showBackupAlert) {
Button("确定") {
.sheet(isPresented: $showBackupAlert) {
SetupBackupAlertView(
onConfirm: {
showBackupAlert = false
handleBackup()
},
onCancel: {
showBackupAlert = false
}
Button("取消", role: .cancel) {}
} message: {
Text("检测到Setup文件尚未备份如果你需要安装程序则Setup必须被处理点击确定后你需要输入密码Adobe Downloader将自动处理并备份为Setup.original")
)
}
.alert(backupSuccess ? "备份成功" : "备份失败", isPresented: $showBackupResultAlert) {
Button("确定") { }
} message: {
Text(backupResultMessage)
.sheet(isPresented: $showBackupResultAlert) {
SetupBackupResultView(
isSuccess: backupResult.success,
message: backupResult.message,
onDismiss: {
showBackupResultAlert = false
}
)
}
.sheet(isPresented: $showTipsSheet) {
TipsSheetView(
@@ -141,9 +148,11 @@ struct Adobe_DownloaderApp: App {
private func handleBackup() {
ModifySetup.backupAndModifySetupFile { success, message in
backupSuccess = success
backupResultMessage = message
showBackupResultAlert = true
DispatchQueue.main.async {
self.backupResult.success = success
self.backupResult.message = message
self.showBackupResultAlert = true
}
}
}
}
@@ -157,3 +166,8 @@ extension Scene {
}
}
}
class BackupResult: ObservableObject {
@Published var success: Bool = false
@Published var message: String = ""
}

View File

@@ -91,15 +91,15 @@ class ModifySetup {
completion(!result.starts(with: "Error:"))
}
} else {
print("未检测到备份文件,尝试创建备份...")
PrivilegedHelperManager.shared.executeCommand("/bin/cp -f '\(setupPath)' '\(backupPath)'") { result in
if result.starts(with: "Error:") {
print("创建备份失败: \(result)")
completion(false)
return
}
if !result.starts(with: "Error:") {
if FileManager.default.fileExists(atPath: backupPath) {
print("备份文件创建成功")
PrivilegedHelperManager.shared.executeCommand("/bin/chmod 644 '\(backupPath)'") { chmodResult in
if chmodResult.starts(with: "Error:") {
print("设置备份文件权限失败: \(chmodResult)")
@@ -138,7 +138,6 @@ class ModifySetup {
return
}
print("执行命令 [\(index + 1)/\(commands.count)]: \(commands[index])")
PrivilegedHelperManager.shared.executeCommand(commands[index]) { result in
if result.starts(with: "Error:") {
print("命令执行失败: \(commands[index])")
@@ -146,7 +145,6 @@ class ModifySetup {
completion(false)
return
}
print("命令执行成功")
executeNextCommand(index + 1)
}
}

View File

@@ -159,6 +159,7 @@ final class GeneralSettingsViewModel: ObservableObject {
@Published var showLanguagePicker = false
@Published var showDownloadConfirmAlert = false
@Published var showReprocessConfirmAlert = false
@Published var showDownloadOnlyConfirmAlert = false
@Published var isProcessing = false
@Published var helperConnectionStatus: HelperConnectionStatus = .disconnected
@Published var downloadAppleSilicon: Bool {
@@ -358,7 +359,29 @@ private struct GeneralSettingsAlerts: ViewModifier {
} message: {
Text("确定要下载并处理 X1a0He CC 吗?这将完成下载并自动对 Setup 组件进行处理")
}
.alert("确认下载", isPresented: $viewModel.showReprocessConfirmAlert) {
.alert("确认处理", isPresented: $viewModel.showReprocessConfirmAlert) {
Button("取消", role: .cancel) { }
Button("确定") {
Task {
viewModel.isProcessing = true
ModifySetup.backupAndModifySetupFile { success, message in
viewModel.setupVersion = ModifySetup.checkComponentVersion()
viewModel.isSuccess = success
viewModel.alertMessage = success ? "Setup 组件处理成功" : "处理失败: \(message)"
viewModel.showAlert = true
viewModel.isProcessing = false
}
}
}
} message: {
Text("确定要重新处理 Setup 组件吗?这将对 Setup 组件进行修改以启用安装功能。")
}
.alert(viewModel.isSuccess ? "操作成功" : "操作失败", isPresented: $viewModel.showAlert) {
Button("确定") { }
} message: {
Text(viewModel.alertMessage)
}
.alert("确认下载", isPresented: $viewModel.showDownloadOnlyConfirmAlert) {
Button("取消", role: .cancel) { }
Button("确定") {
Task {
@@ -368,11 +391,6 @@ private struct GeneralSettingsAlerts: ViewModifier {
} message: {
Text("确定要下载 X1a0He CC 吗?下载完成后需要手动处理。")
}
.alert(viewModel.isSuccess ? "操作成功" : "操作失败", isPresented: $viewModel.showAlert) {
Button("确定") { }
} message: {
Text(viewModel.alertMessage)
}
}
private func startDownloadSetup(shouldProcess: Bool) {
@@ -1284,7 +1302,7 @@ struct SetupComponentRow: View {
}
Button(action: {
viewModel.showReprocessConfirmAlert = true
viewModel.showDownloadOnlyConfirmAlert = true
}) {
Label("仅下载", systemImage: "arrow.down")
.frame(maxWidth: .infinity, alignment: .leading)
@@ -1423,11 +1441,6 @@ struct QAView: View {
question: String(localized: "如何修复安装失败的问题?"),
answer: String(localized: "如果安装失败,您可以尝试以下步骤:\n1. 确保已正确安装并连接 Helper\n2. 确保已下载并处理 Setup 组件\n3. 检查磁盘剩余空间是否充足\n4. 尝试重新下载并安装\n如果问题仍然存在,可以尝试重新安装 Helper 和重新处理 Setup 组件。")
)
QAItem(
question: String(localized: "为什么我安装的时候会遇到错误代码,错误代码表示什么意思?"),
answer: String(localized: "• 错误 2700不太可能会出现除非 Setup 组件处理失败了\n• 错误 107所下载的文件架构与系统架构不一致或者安装文件被损坏\n• 错误 103出现权限问题请确保 Helper 状态正常\n• 错误 182文件不齐全或文件被损坏或者你的Setup组件不一致请重新下载 X1a0He CC\n• 错误 133系统磁盘空间不足\n• 错误 -1Setup 组件未处理或处理失败,请联系开发者\n• 错误 195所下载的产品不支持你当前的系统\n• 错误 146请在 Mac 系统设置中给予 Adobe Downloader 全磁盘权限\n• 错误 255Setup 组件需要更新,请联系开发者解决")
)
}
}
.padding()

View File

@@ -12,7 +12,7 @@ private enum AppCardConstants {
static let cardHeight: CGFloat = 200
static let iconSize: CGFloat = 64
static let cornerRadius: CGFloat = 12
static let buttonHeight: CGFloat = 36
static let buttonHeight: CGFloat = 24
static let titleFontSize: CGFloat = 16
static let buttonFontSize: CGFloat = 14
@@ -472,11 +472,10 @@ private struct DownloadButtonView: View {
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: AppCardConstants.buttonHeight)
.contentShape(Rectangle())
.foregroundColor(.white)
}
.buttonStyle(.borderedProminent)
.tint(viewModel.isDownloading ? .gray : .blue)
.buttonStyle(BeautifulButtonStyle(baseColor: viewModel.isDownloading ? Color.gray : Color.blue))
.disabled(!viewModel.canDownload)
.scaleEffect(isHovered && viewModel.canDownload ? 1.02 : 1.0)
.animation(.easeInOut(duration: 0.2), value: isHovered)
.onHover { hovering in
isHovered = hovering
@@ -517,7 +516,7 @@ private struct SheetModifier: ViewModifier {
func body(content: Content) -> 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(

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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
}
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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• 错误 -1Setup 组件未处理或处理失败,请联系开发者\n• 错误 195所下载的产品不支持你当前的系统\n• 错误 146请在 Mac 系统设置中给予 Adobe Downloader 全磁盘权限\n• 错误 255Setup 组件需要更新,请联系开发者解决" : {
"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" : {