mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-25 11:18:53 +08:00
Add: Added Sparkle for checking update and fix some bugs.
This commit is contained in:
@@ -6,13 +6,30 @@
|
||||
objectVersion = 77;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3CB9FF092CDBAEF200D7A58B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 3CB9FF082CDBAEF200D7A58B /* Sparkle */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3CCC3AE02CC67B8F006E22B4 /* Adobe Downloader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Adobe Downloader.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
3CB9FF102CDC44DE00D7A58B /* Exceptions for "Adobe Downloader" folder in "Adobe Downloader" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
);
|
||||
target = 3CCC3ADF2CC67B8F006E22B4 /* Adobe Downloader */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
3CCC3AE22CC67B8F006E22B4 /* Adobe Downloader */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
3CB9FF102CDC44DE00D7A58B /* Exceptions for "Adobe Downloader" folder in "Adobe Downloader" target */,
|
||||
);
|
||||
path = "Adobe Downloader";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -28,6 +45,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3CB9FF092CDBAEF200D7A58B /* Sparkle in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -72,6 +90,7 @@
|
||||
);
|
||||
name = "Adobe Downloader";
|
||||
packageProductDependencies = (
|
||||
3CB9FF082CDBAEF200D7A58B /* Sparkle */,
|
||||
);
|
||||
productName = "Adobe-Downloader";
|
||||
productReference = 3CCC3AE02CC67B8F006E22B4 /* Adobe Downloader.app */;
|
||||
@@ -101,6 +120,9 @@
|
||||
);
|
||||
mainGroup = 3CCC3AD72CC67B8F006E22B4;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
packageReferences = (
|
||||
3CB9FF072CDBAEF200D7A58B /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||
);
|
||||
preferredProjectObjectVersion = 77;
|
||||
productRefGroup = 3CCC3AE12CC67B8F006E22B4 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -185,6 +207,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "./Adobe Downloader/Info.plist";
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
@@ -243,6 +266,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "./Adobe Downloader/Info.plist";
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
@@ -262,7 +286,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Adobe Downloader/Adobe Downloader.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CURRENT_PROJECT_VERSION = 101;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Adobe Downloader/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@@ -275,8 +299,8 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.x1a0he.macOS.Adobe-Downloader";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -291,9 +315,10 @@
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = "Adobe Downloader/Adobe Downloader.entitlements";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
CURRENT_PROJECT_VERSION = 101;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Adobe Downloader/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
@@ -306,8 +331,8 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.x1a0he.macOS.Adobe-Downloader";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -337,6 +362,25 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
3CB9FF072CDBAEF200D7A58B /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sparkle-project/Sparkle";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.6.4;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
3CB9FF082CDBAEF200D7A58B /* Sparkle */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 3CB9FF072CDBAEF200D7A58B /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||
productName = Sparkle;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 3CCC3AD82CC67B8F006E22B4 /* Project object */;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
@main
|
||||
struct Adobe_DownloaderApp: App {
|
||||
@@ -14,8 +15,11 @@ struct Adobe_DownloaderApp: App {
|
||||
@AppStorage("confirmRedownload") private var confirmRedownload: Bool = true
|
||||
@AppStorage("useDefaultDirectory") private var useDefaultDirectory: Bool = true
|
||||
@AppStorage("defaultDirectory") private var defaultDirectory: String = "Downloads"
|
||||
private let updaterController: SPUStandardUpdaterController
|
||||
|
||||
init() {
|
||||
updaterController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
|
||||
|
||||
let isFirstRun = UserDefaults.standard.object(forKey: "downloadAppleSilicon") == nil ||
|
||||
UserDefaults.standard.object(forKey: "useDefaultLanguage") == nil
|
||||
|
||||
@@ -165,9 +169,13 @@ struct Adobe_DownloaderApp: App {
|
||||
}
|
||||
.windowStyle(.hiddenTitleBar)
|
||||
.windowResizability(.contentSize)
|
||||
|
||||
.commands {
|
||||
CommandGroup(after: .appInfo) {
|
||||
CheckForUpdatesView(updater: updaterController.updater)
|
||||
}
|
||||
}
|
||||
Settings {
|
||||
AboutView()
|
||||
AboutView(updater: updaterController.updater)
|
||||
.environmentObject(networkManager)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ enum PackageStatus: Equatable {
|
||||
|
||||
enum NetworkError: Error, LocalizedError {
|
||||
case noConnection
|
||||
case timeout(TimeInterval)
|
||||
case timeout
|
||||
case serverUnreachable(String)
|
||||
|
||||
case invalidURL(String)
|
||||
@@ -104,8 +104,8 @@ enum NetworkError: Error, LocalizedError {
|
||||
switch self {
|
||||
case .noConnection:
|
||||
return NSLocalizedString("没有网络连接", comment: "Network error")
|
||||
case .timeout(let duration):
|
||||
return NSLocalizedString("请求超时: \(duration)", comment: "Network timeout")
|
||||
case .timeout:
|
||||
return NSLocalizedString("请求超时,请检查网络连接后重试", comment: "Network timeout")
|
||||
case .serverUnreachable(let server):
|
||||
return NSLocalizedString("无法连接到服务器: \(server)", comment: "Server unreachable")
|
||||
case .invalidURL(let url):
|
||||
@@ -274,7 +274,7 @@ enum DownloadStatus: Equatable {
|
||||
|
||||
var isActive: Bool {
|
||||
switch self {
|
||||
case .downloading, .preparing, .retrying:
|
||||
case .downloading, .preparing, .waiting, .retrying:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
||||
@@ -111,6 +111,11 @@ class ProductsToDownload: ObservableObject {
|
||||
var buildGuid: String
|
||||
var applicationJson: String?
|
||||
@Published var packages: [Package] = []
|
||||
@Published var completedPackages: Int = 0
|
||||
|
||||
var totalPackages: Int {
|
||||
packages.count
|
||||
}
|
||||
|
||||
init(sapCode: String, version: String, buildGuid: String, applicationJson: String = "") {
|
||||
self.sapCode = sapCode
|
||||
@@ -118,6 +123,16 @@ class ProductsToDownload: ObservableObject {
|
||||
self.buildGuid = buildGuid
|
||||
self.applicationJson = applicationJson
|
||||
}
|
||||
|
||||
func updateCompletedPackages() {
|
||||
completedPackages = packages.filter {
|
||||
if case .completed = $0.status {
|
||||
return true
|
||||
}
|
||||
return $0.downloaded
|
||||
}.count
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
struct SapCodes: Identifiable {
|
||||
|
||||
@@ -2,38 +2,30 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- 允许访问网络 -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<!-- 允许访问本地网络 -->
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
|
||||
<!-- 添加以下键值对 -->
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
<!-- 添加以下权限声明 -->
|
||||
<key>NSDownloadsFolderUsageDescription</key>
|
||||
<string>需要访问下载文件夹来保存Adobe安装文件</string>
|
||||
|
||||
<!-- 添加以下权限 -->
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.files.downloads.read-write</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key>
|
||||
<array>
|
||||
<string>/Downloads/</string>
|
||||
</array>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSDownloadsFolderUsageDescription</key>
|
||||
<string>需要访问下载文件夹来保存Adobe安装文件</string>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.downloads.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key>
|
||||
<array>
|
||||
<string>/Downloads/</string>
|
||||
</array>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>gYylad3ybfiyK5ZTS3xRrw+3c/8063mpXdQnPpMB86Q=</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://raw.githubusercontent.com/X1a0He/Adobe-Downloader/refs/heads/main/appcast.xml</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
34
Adobe Downloader/Models/CheckForUpdatesViewModel.swift
Normal file
34
Adobe Downloader/Models/CheckForUpdatesViewModel.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// CheckForUpdatesViewModel.swift
|
||||
// Adobe Downloader
|
||||
//
|
||||
// Created by X1a0He on 11/6/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
final class CheckForUpdatesViewModel: ObservableObject {
|
||||
@Published var canCheckForUpdates = false
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
updater.publisher(for: \.canCheckForUpdates)
|
||||
.assign(to: &$canCheckForUpdates)
|
||||
}
|
||||
}
|
||||
|
||||
struct CheckForUpdatesView: View {
|
||||
@ObservedObject private var checkForUpdatesViewModel: CheckForUpdatesViewModel
|
||||
private let updater: SPUUpdater
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
self.updater = updater
|
||||
|
||||
self.checkForUpdatesViewModel = CheckForUpdatesViewModel(updater: updater)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button("检查更新...", action: updater.checkForUpdates)
|
||||
.disabled(!checkForUpdatesViewModel.canCheckForUpdates)
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ class NetworkManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Published var installCommand: String = ""
|
||||
private let cancelTracker = CancelTracker()
|
||||
internal var downloadUtils: DownloadUtils!
|
||||
internal var progressObservers: [UUID: NSKeyValueObservation] = [:]
|
||||
@@ -72,6 +73,8 @@ class NetworkManager: ObservableObject {
|
||||
downloadTasks.append(task)
|
||||
updateDockBadge()
|
||||
|
||||
NotificationCenter.default.post(name: NSNotification.Name("UpdateDownloadStatus"), object: nil)
|
||||
|
||||
do {
|
||||
try await downloadUtils.handleDownload(task: task, productInfo: productInfo, allowedPlatform: allowedPlatform, saps: saps)
|
||||
} catch {
|
||||
@@ -190,7 +193,13 @@ class NetworkManager: ObservableObject {
|
||||
installationState = .completed
|
||||
}
|
||||
} catch {
|
||||
let command = await installManager.getInstallCommand(
|
||||
for: path.appendingPathComponent("driver.xml").path
|
||||
)
|
||||
|
||||
await MainActor.run {
|
||||
self.installCommand = command
|
||||
|
||||
if let installError = error as? InstallManager.InstallError {
|
||||
switch installError {
|
||||
case .installationFailed(let message):
|
||||
|
||||
@@ -395,7 +395,6 @@ class DownloadUtils {
|
||||
)))
|
||||
}
|
||||
|
||||
task.objectWillChange.send()
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
|
||||
@@ -437,7 +436,6 @@ class DownloadUtils {
|
||||
lastUpdateTime = now
|
||||
lastBytes = totalBytesWritten
|
||||
|
||||
task.objectWillChange.send()
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
@@ -677,7 +675,7 @@ class DownloadUtils {
|
||||
for product in productsToDownload {
|
||||
await MainActor.run {
|
||||
task.setStatus(.preparing(DownloadStatus.PrepareInfo(
|
||||
message: "正在处理 \(product.sapCode) 的包信息...",
|
||||
message: String(localized: "正在处理 \(product.sapCode) 的包信息..."),
|
||||
timestamp: Date(),
|
||||
stage: .fetchingInfo
|
||||
)))
|
||||
|
||||
@@ -20,10 +20,10 @@ actor InstallManager {
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .setupNotFound: return "找不到安装程序"
|
||||
case .installationFailed(let message): return message
|
||||
case .cancelled: return "安装已取消"
|
||||
case .permissionDenied: return "权限被拒绝"
|
||||
case .setupNotFound: return String(localized: "找不到安装程序")
|
||||
case .installationFailed(let message): return message
|
||||
case .cancelled: return String(localized: "安装已取消")
|
||||
case .permissionDenied: return String(localized: "权限被拒绝")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ actor InstallManager {
|
||||
installationProcess = installProcess
|
||||
|
||||
await MainActor.run {
|
||||
progressHandler(0.0, withSudo ? "正在准备安装..." : "正在重试安装...")
|
||||
progressHandler(0.0, withSudo ? String(localized: "正在准备安装...") : String(localized: "正在重试安装..."))
|
||||
}
|
||||
|
||||
try installProcess.run()
|
||||
@@ -94,8 +94,8 @@ actor InstallManager {
|
||||
let code = Int32(codeStr) {
|
||||
if code != 0 {
|
||||
let errorMessage = code == -1
|
||||
? "安装程序调用失败,请联系X1a0He"
|
||||
: "(退出代码: \(code))"
|
||||
? String(localized: "安装程序调用失败,请联系X1a0He")
|
||||
: String(localized: "(退出代码: \(code))")
|
||||
|
||||
installProcess.terminate()
|
||||
continuation.resume(throwing: InstallError.installationFailed(errorMessage))
|
||||
@@ -116,8 +116,8 @@ actor InstallManager {
|
||||
continuation.resume()
|
||||
} else {
|
||||
let errorMessage = withSudo
|
||||
? "安装失败 (退出代码: \(installProcess.terminationStatus))"
|
||||
: "重试失败,需要重新输入密码"
|
||||
? String(localized: "(退出代码: \(installProcess.terminationStatus))")
|
||||
: String(localized: "重试失败,需要重新输入密码")
|
||||
continuation.resume(throwing: InstallError.installationFailed(errorMessage))
|
||||
}
|
||||
} catch {
|
||||
@@ -127,7 +127,7 @@ actor InstallManager {
|
||||
}
|
||||
|
||||
await MainActor.run {
|
||||
progressHandler(1.0, "安装完成")
|
||||
progressHandler(1.0, String(localized: "安装完成"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ actor InstallManager {
|
||||
authProcess.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
|
||||
let authScript = """
|
||||
tell application "System Events"
|
||||
display dialog "请输入管理员密码以继续安装" default answer "" with hidden answer ¬
|
||||
display dialog "请输入管理员密码以继续安装(Please enter the password to continue the installation)" default answer "" with hidden answer ¬
|
||||
buttons {"取消", "确定"} default button "确定" ¬
|
||||
with icon caution ¬
|
||||
with title "需要管理员权限"
|
||||
@@ -208,22 +208,26 @@ actor InstallManager {
|
||||
if let range = line.range(of: "Exit Code: (-?[0-9]+)", options: .regularExpression),
|
||||
let codeStr = line[range].split(separator: ":").last?.trimmingCharacters(in: .whitespaces),
|
||||
let exitCode = Int(codeStr) {
|
||||
return exitCode == 0 ? (1.0, "安装完成") : nil
|
||||
return exitCode == 0 ? (1.0, String(localized: "安装完成")) : nil
|
||||
}
|
||||
|
||||
if let range = line.range(of: "Progress: ([0-9]{1,3})%", options: .regularExpression),
|
||||
let progressStr = line[range].split(separator: ":").last?.trimmingCharacters(in: .whitespaces),
|
||||
let progressValue = Double(progressStr.replacingOccurrences(of: "%", with: "")) {
|
||||
return (progressValue / 100.0, "正在安装...")
|
||||
return (progressValue / 100.0, String("正在安装..."))
|
||||
}
|
||||
|
||||
if line.contains("Installing packages") {
|
||||
return (0.0, "正在安装包...")
|
||||
return (0.0, String(localized: "正在安装包..."))
|
||||
} else if line.contains("Preparing") {
|
||||
return (0.0, "正在准备...")
|
||||
return (0.0, String(localized: "正在准备..."))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getInstallCommand(for driverPath: String) -> String {
|
||||
return "sudo \"\(setupPath)\" --install=1 --driverXML=\"\(driverPath)\""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,18 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
struct AboutView: View {
|
||||
private let updater: SPUUpdater
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
self.updater = updater
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
GeneralSettingsView()
|
||||
GeneralSettingsView(updater: updater)
|
||||
.tabItem {
|
||||
Label("通用", systemImage: "gear")
|
||||
}
|
||||
@@ -19,7 +26,8 @@ struct AboutView: View {
|
||||
Label("关于", systemImage: "info.circle")
|
||||
}
|
||||
}
|
||||
.frame(width: 500, height: 400)
|
||||
.background(Color(NSColor.windowBackgroundColor))
|
||||
.frame(width: 500, height: 350)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +41,16 @@ struct GeneralSettingsView: View {
|
||||
@State private var showLanguagePicker = false
|
||||
@EnvironmentObject private var networkManager: NetworkManager
|
||||
|
||||
private let updater: SPUUpdater
|
||||
@State private var automaticallyChecksForUpdates: Bool
|
||||
@State private var automaticallyDownloadsUpdates: Bool
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
self.updater = updater
|
||||
_automaticallyChecksForUpdates = State(initialValue: updater.automaticallyChecksForUpdates)
|
||||
_automaticallyDownloadsUpdates = State(initialValue: updater.automaticallyDownloadsUpdates)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
GroupBox(label: Text("下载设置").padding(.bottom, 8)) {
|
||||
@@ -86,8 +104,29 @@ struct GeneralSettingsView: View {
|
||||
networkManager.updateAllowedPlatform(useAppleSilicon: newValue)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
.padding(8)
|
||||
}
|
||||
|
||||
GroupBox(label: Text("更新设置").padding(.bottom, 8)) {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
Toggle("自动检查更新版本", isOn: $automaticallyChecksForUpdates)
|
||||
.onChange(of: automaticallyChecksForUpdates) { newValue in
|
||||
updater.automaticallyChecksForUpdates = newValue
|
||||
}
|
||||
Spacer()
|
||||
|
||||
CheckForUpdatesView(updater: updater)
|
||||
}
|
||||
Divider()
|
||||
Toggle("自动下载最新版本", isOn: $automaticallyDownloadsUpdates)
|
||||
.disabled(!automaticallyChecksForUpdates)
|
||||
.onChange(of: automaticallyDownloadsUpdates) { newValue in
|
||||
updater.automaticallyDownloadsUpdates = newValue
|
||||
}
|
||||
}.padding(8)
|
||||
}
|
||||
.padding(.vertical, 5)
|
||||
}
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
@@ -126,13 +165,20 @@ struct GeneralSettingsView: View {
|
||||
}
|
||||
|
||||
struct AboutAppView: View {
|
||||
private var appVersion: String {
|
||||
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
// let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
|
||||
// return "Version \(version) (\(build))"
|
||||
return "\(version)"
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 12) {
|
||||
Image(nsImage: NSApp.applicationIconImage)
|
||||
.resizable()
|
||||
.frame(width: 96, height: 96)
|
||||
|
||||
Text("Adobe Downloader")
|
||||
Text("Adobe Downloader \(appVersion)")
|
||||
.font(.title2)
|
||||
.bold()
|
||||
|
||||
@@ -168,8 +214,39 @@ struct AboutAppView: View {
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let networkManager = NetworkManager()
|
||||
return AboutView()
|
||||
.environmentObject(networkManager)
|
||||
#Preview("About Tab") {
|
||||
AboutAppView()
|
||||
}
|
||||
|
||||
#Preview("General Settings") {
|
||||
let networkManager = NetworkManager()
|
||||
VStack {
|
||||
GeneralSettingsView(updater: PreviewUpdater())
|
||||
.environmentObject(networkManager)
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewUpdater: SPUUpdater {
|
||||
init() {
|
||||
let hostBundle = Bundle.main
|
||||
let applicationBundle = Bundle.main
|
||||
let userDriver = SPUStandardUserDriver(hostBundle: hostBundle, delegate: nil)
|
||||
|
||||
super.init(
|
||||
hostBundle: hostBundle,
|
||||
applicationBundle: applicationBundle,
|
||||
userDriver: userDriver,
|
||||
delegate: nil
|
||||
)
|
||||
}
|
||||
|
||||
override var automaticallyChecksForUpdates: Bool {
|
||||
get { true }
|
||||
set { }
|
||||
}
|
||||
|
||||
override var automaticallyDownloadsUpdates: Bool {
|
||||
get { true }
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,22 +51,24 @@ class AppCardViewModel: ObservableObject {
|
||||
self.sap = sap
|
||||
self.networkManager = networkManager
|
||||
loadIcon()
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(updateDownloadingStatus),
|
||||
name: NSNotification.Name("UpdateDownloadStatus"),
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
func updateDownloadingStatus() {
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@objc func updateDownloadingStatus() {
|
||||
Task { @MainActor in
|
||||
isDownloading = networkManager?.downloadTasks.contains(where: isTaskDownloading) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
private func isTaskDownloading(_ task: NewDownloadTask) -> Bool {
|
||||
guard task.sapCode == sap.sapCode else { return false }
|
||||
|
||||
switch task.totalStatus {
|
||||
case .downloading, .preparing, .waiting, .retrying:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
isDownloading = networkManager?.downloadTasks.contains { task in
|
||||
return task.sapCode == sap.sapCode && task.status.isActive
|
||||
} ?? false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +205,17 @@ class AppCardViewModel: ObservableObject {
|
||||
guard let networkManager = networkManager,
|
||||
let productInfo = sap.versions[pendingVersion] else { return }
|
||||
|
||||
let existingTask = await networkManager.downloadTasks.first { task in
|
||||
return task.sapCode == sap.sapCode &&
|
||||
task.version == pendingVersion &&
|
||||
task.language == pendingLanguage &&
|
||||
task.directory == path
|
||||
}
|
||||
|
||||
if existingTask != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var productsToDownload: [ProductsToDownload] = []
|
||||
let mainProduct = ProductsToDownload(
|
||||
sapCode: sap.sapCode,
|
||||
@@ -449,35 +462,35 @@ struct AlertModifier: ViewModifier {
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.alert("安装程序已存在", isPresented: $viewModel.showExistingFileAlert) {
|
||||
Button("使用现有程序") {
|
||||
if let path = viewModel.existingFilePath,
|
||||
!viewModel.pendingVersion.isEmpty && !viewModel.pendingLanguage.isEmpty {
|
||||
Task {
|
||||
await viewModel.createCompletedTask(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
Button("重新下载") {
|
||||
if !viewModel.pendingVersion.isEmpty && !viewModel.pendingLanguage.isEmpty {
|
||||
if confirmRedownload {
|
||||
viewModel.showRedownloadConfirm = true
|
||||
} else {
|
||||
viewModel.startDownload(viewModel.pendingVersion, viewModel.pendingLanguage)
|
||||
}
|
||||
}
|
||||
}
|
||||
Button("取消", role: .cancel) {}
|
||||
} message: {
|
||||
VStack(alignment: .leading) {
|
||||
Text("在以下位置找到现有的安装程序:")
|
||||
if let path = viewModel.existingFilePath {
|
||||
Text(path.path)
|
||||
.foregroundColor(.blue)
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.selectFile(path.path, inFileViewerRootedAtPath: path.deletingLastPathComponent().path)
|
||||
.sheet(isPresented: $viewModel.showExistingFileAlert) {
|
||||
if let path = viewModel.existingFilePath {
|
||||
ExistingFileAlertView(
|
||||
path: path,
|
||||
onUseExisting: {
|
||||
viewModel.showExistingFileAlert = false
|
||||
if !viewModel.pendingVersion.isEmpty && !viewModel.pendingLanguage.isEmpty {
|
||||
Task {
|
||||
await viewModel.createCompletedTask(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onRedownload: {
|
||||
viewModel.showExistingFileAlert = false
|
||||
if !viewModel.pendingVersion.isEmpty && !viewModel.pendingLanguage.isEmpty {
|
||||
if confirmRedownload {
|
||||
viewModel.showRedownloadConfirm = true
|
||||
} else {
|
||||
viewModel.startDownload(viewModel.pendingVersion, viewModel.pendingLanguage)
|
||||
}
|
||||
}
|
||||
},
|
||||
onCancel: {
|
||||
viewModel.showExistingFileAlert = false
|
||||
},
|
||||
iconImage: viewModel.iconImage
|
||||
)
|
||||
.background(Color.black.opacity(0.3))
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
.alert("确认重新下载", isPresented: $viewModel.showRedownloadConfirm) {
|
||||
|
||||
@@ -112,6 +112,8 @@ struct DownloadManagerView: View {
|
||||
Button("关闭") {
|
||||
dismiss()
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.red)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
|
||||
@@ -443,10 +443,6 @@ struct ProductRow: View {
|
||||
let isCurrentProduct: Bool
|
||||
@Binding var expandedProducts: Set<String>
|
||||
|
||||
private var completedPackagesCount: Int {
|
||||
product.packages.filter(\.downloaded).count
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Button(action: {
|
||||
@@ -467,7 +463,7 @@ struct ProductRow: View {
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(completedPackagesCount)/\(product.packages.count)")
|
||||
Text("\(product.completedPackages)/\(product.totalPackages)")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
|
||||
106
Adobe Downloader/Views/ExistingFileAlertView.swift
Normal file
106
Adobe Downloader/Views/ExistingFileAlertView.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ExistingFileAlertView: View {
|
||||
let path: URL
|
||||
let onUseExisting: () -> Void
|
||||
let onRedownload: () -> Void
|
||||
let onCancel: () -> Void
|
||||
let iconImage: NSImage?
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
Group {
|
||||
if let iconImage = iconImage {
|
||||
Image(nsImage: iconImage)
|
||||
.resizable()
|
||||
.interpolation(.high)
|
||||
.scaledToFit()
|
||||
} else {
|
||||
Image(systemName: "app.fill")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(width: 64, height: 64)
|
||||
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.font(.system(size: 24))
|
||||
.foregroundColor(.orange)
|
||||
.offset(x: 10, y: 4)
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
|
||||
Text("安装程序已存在")
|
||||
.font(.headline)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack {
|
||||
Text(path.path)
|
||||
.foregroundColor(.blue)
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.activateFileViewerSelecting([path])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VStack(spacing: 16) {
|
||||
Button(action: onUseExisting) {
|
||||
Label("使用现有程序", systemImage: "checkmark.circle")
|
||||
.frame(minWidth: 0,maxWidth: 260)
|
||||
.frame(height: 32)
|
||||
.font(.system(size: 14))
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.blue)
|
||||
|
||||
Button(action: onRedownload) {
|
||||
Label("重新下载", systemImage: "arrow.down.circle")
|
||||
.frame(minWidth: 0,maxWidth: 260)
|
||||
.frame(height: 32)
|
||||
.font(.system(size: 14))
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.green)
|
||||
|
||||
Button(action: onCancel) {
|
||||
Label("取消", systemImage: "xmark.circle")
|
||||
.frame(minWidth: 0, maxWidth: 260)
|
||||
.frame(height: 32)
|
||||
.font(.system(size: 14))
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(.red)
|
||||
.keyboardShortcut(.cancelAction)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color(NSColor.windowBackgroundColor))
|
||||
.cornerRadius(12)
|
||||
.shadow(radius: 10)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ExistingFileAlertView(
|
||||
path: URL(fileURLWithPath: "/Users/username/Downloads/Adobe/Adobe Downloader PHSP_25.0-en_US-macuniversal"),
|
||||
onUseExisting: {},
|
||||
onRedownload: {},
|
||||
onCancel: {},
|
||||
iconImage: NSImage(named: "PHSP")
|
||||
)
|
||||
.background(Color.black.opacity(0.3))
|
||||
}
|
||||
|
||||
#Preview("Dark Mode") {
|
||||
ExistingFileAlertView(
|
||||
path: URL(fileURLWithPath: "/Users/username/Downloads/Adobe/Adobe Downloader PHSP_25.0-en_US-macuniversal"),
|
||||
onUseExisting: {},
|
||||
onRedownload: {},
|
||||
onCancel: {},
|
||||
iconImage: NSImage(named: "PHSP")
|
||||
)
|
||||
.background(Color.black.opacity(0.3))
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
@@ -14,16 +14,16 @@ struct InstallProgressView: View {
|
||||
let onRetry: (() -> Void)?
|
||||
|
||||
private var isCompleted: Bool {
|
||||
progress >= 1.0 || status == "安装完成"
|
||||
progress >= 1.0 || status == String(localized: "安装完成")
|
||||
}
|
||||
|
||||
private var isFailed: Bool {
|
||||
status.contains("失败")
|
||||
status.contains(String(localized: "失败"))
|
||||
}
|
||||
|
||||
private var progressText: String {
|
||||
if isCompleted {
|
||||
return "安装完成"
|
||||
return String(localized: "安装完成")
|
||||
} else {
|
||||
return "\(Int(progress * 100))%"
|
||||
}
|
||||
@@ -51,11 +51,11 @@ struct InstallProgressView: View {
|
||||
|
||||
private var statusTitle: String {
|
||||
if isCompleted {
|
||||
return "\(productName) 安装完成"
|
||||
return String(localized: "\(productName) 安装完成")
|
||||
} else if isFailed {
|
||||
return "\(productName) 安装失败"
|
||||
return String(localized: "\(productName) 安装失败")
|
||||
} else {
|
||||
return "正在安装 \(productName)"
|
||||
return String(localized: "正在安装 \(productName)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ struct InstallProgressView: View {
|
||||
LogSection(logs: networkManager.installationLogs)
|
||||
|
||||
if isFailed {
|
||||
ErrorSection(status: status)
|
||||
ErrorSection(
|
||||
status: status, isFailed: isFailed
|
||||
)
|
||||
}
|
||||
|
||||
ButtonSection(
|
||||
@@ -89,7 +91,7 @@ struct InstallProgressView: View {
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
.frame(minWidth: 500, minHeight: 300)
|
||||
.frame(minWidth: 500, minHeight: 400)
|
||||
.background(Color(NSColor.windowBackgroundColor))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
@@ -155,28 +157,61 @@ private struct LogSection: View {
|
||||
|
||||
private struct ErrorSection: View {
|
||||
let status: String
|
||||
let isFailed: Bool
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("错误详情:")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fontWeight(.medium)
|
||||
Text(status)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(8)
|
||||
.background(Color.secondary.opacity(0.1))
|
||||
.cornerRadius(6)
|
||||
if isFailed {
|
||||
HStack {
|
||||
Text("自行安装命令:")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fontWeight(.medium)
|
||||
CommandPopover()
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
|
||||
private struct CommandSection: View {
|
||||
let command: String
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("错误详情:")
|
||||
Text("自行安装命令:")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fontWeight(.medium)
|
||||
|
||||
Text(status)
|
||||
Text(command)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.frame(maxWidth: .infinity,alignment: .leading)
|
||||
.frame(minHeight: 200)
|
||||
.padding(8)
|
||||
.background(Color.secondary.opacity(0.1))
|
||||
.cornerRadius(6)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.frame(maxHeight: 100)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +255,36 @@ private struct ButtonSection: View {
|
||||
}
|
||||
}
|
||||
|
||||
private struct CommandPopover: View {
|
||||
@EnvironmentObject private var networkManager: NetworkManager
|
||||
@State private var showPopover = false
|
||||
|
||||
var body: some View {
|
||||
Button(action: { showPopover.toggle() }) {
|
||||
Image(systemName: "terminal.fill")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Button("复制命令") {
|
||||
|
||||
}
|
||||
|
||||
Text(networkManager.installCommand)
|
||||
.font(.system(.caption, design: .monospaced))
|
||||
.foregroundColor(.secondary)
|
||||
.textSelection(.enabled)
|
||||
.padding(8)
|
||||
.background(Color.secondary.opacity(0.1))
|
||||
.cornerRadius(6)
|
||||
}
|
||||
.padding()
|
||||
.frame(width: 400)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("安装中带日志") {
|
||||
let networkManager = NetworkManager()
|
||||
return InstallProgressView(
|
||||
@@ -260,6 +325,8 @@ private struct ButtonSection: View {
|
||||
)
|
||||
.environmentObject(networkManager)
|
||||
.onAppear {
|
||||
networkManager.installCommand = "sudo \"/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/Setup\" --install=1 --driverXML=\"/Users/demo/Downloads/Adobe Photoshop/driver.xml\""
|
||||
|
||||
let previewLogs = [
|
||||
"正在准备安装...",
|
||||
"Progress: 10%",
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"(退出代码: %d)" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "(Exit Code: %d)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/" : {
|
||||
|
||||
},
|
||||
@@ -34,6 +44,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"%@ 安装失败" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%@ Install failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%@ 安装完成" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%@ Install completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%lld" : {
|
||||
|
||||
},
|
||||
@@ -72,6 +102,9 @@
|
||||
},
|
||||
"Adobe Downloader" : {
|
||||
|
||||
},
|
||||
"Adobe Downloader %@" : {
|
||||
|
||||
},
|
||||
"Adobe Downloader 已为你默认设定如下值" : {
|
||||
"localizations" : {
|
||||
@@ -355,12 +388,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"在以下位置找到现有的安装程序:" : {
|
||||
"复制命令" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Locate the existing installer at:"
|
||||
"value" : "Copy"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"失败" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,6 +428,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"安装完成" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"安装已取消" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Cancelled"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"安装程序已存在" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -395,6 +458,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"安装程序调用失败,请联系X1a0He" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "The installation program failed to call, please contact X1a0He"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"尝试使用不同的搜索关键词" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -476,6 +549,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"找不到安装程序" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Installer not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"按名称" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -556,6 +639,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"更新设置" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Update settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"服务器响应无效" : {
|
||||
"comment" : "Invalid response",
|
||||
"localizations" : {
|
||||
@@ -604,6 +697,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"权限被拒绝" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Permission denied"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"检查更新..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Check for updates…"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"检测到Setup文件尚未备份,如果你需要安装程序,则Setup必须被处理,点击确定后你需要输入密码,Adobe Downloader将自动处理并备份为Setup.original" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -625,6 +738,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在准备..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparing..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在准备安装..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Preparing..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在加载..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -635,6 +768,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在处理 %@ 的包信息..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Processing package for %@..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在安装 %@" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Installing %@"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在安装包..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Installing packages..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"正在重试安装..." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Retrying installation..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"没有找到产品" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -769,6 +942,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"自动下载最新版本" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Automatically download updates"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"自动检查更新版本" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Automatically check for updates"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"自行安装命令:" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Self-installation command:"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"语言:" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -779,6 +982,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"请求超时,请检查网络连接后重试" : {
|
||||
"comment" : "Network timeout",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Request timed out, please check the network connection and try again"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"选择" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@@ -861,6 +1075,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"重试失败,需要重新输入密码" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Retry failed, need to re-enter password"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"错误详情:" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
|
||||
38
appcast.xml
Normal file
38
appcast.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
|
||||
<channel>
|
||||
<title>Adobe Downloader</title>
|
||||
<item>
|
||||
<title>1.0.1</title>
|
||||
<pubDate>Thu, 07 Nov 2024 16:06:42 +0800</pubDate>
|
||||
<sparkle:version>101</sparkle:version>
|
||||
<sparkle:shortVersionString>1.0.1</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>
|
||||
<enclosure
|
||||
url="https://raw.githubusercontent.com/X1a0He/Adobe-Downloader/refs/heads/main/Adobe%20Downloader.dmg"
|
||||
length="2531087" type="application/octet-stream"
|
||||
sparkle:edSignature="aEktEis1fZBGVe1BeYRkWtr+6pAYF1a3bjT9tjP3Jha+kdvft1xXAtUjX0m76emFCzPi6M+GYEYuxeAE44rFDQ=="/>
|
||||
<description><![CDATA[
|
||||
<style>ul{margin-top: 0;margin-bottom: 7;padding-left: 18;}</style>
|
||||
<h5>Adobe Downloader 更新日志: </h1>
|
||||
<ul>
|
||||
<li>修复了当系统版本低于 macOS 14.6 时无法打开程序的问题,现已支持 macOS 13.0 以上</li>
|
||||
<li>增加 Sparkle 用于检测更新</li>
|
||||
<li>当默认目录为 未选择 时,将 下载 文件夹作为默认目录</li>
|
||||
<li>当通过 Adobe Downloader 安装遇到权限问题时,提供终端命令让用户自行安装</li>
|
||||
<li>调整了文件已存在的 UI 显示</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h5>Adobe Downloader Changes: </h1>
|
||||
<ul>
|
||||
<li>Support macOS 13.0 and above</li>
|
||||
<li>Added Sparkle for checking update</li>
|
||||
<li>When the default directory is not selected, the Downloads folder will be used as the default directory</li>
|
||||
<li>When installing via Adobe Downloader and encountering permission issues, provide terminal commands to allow users to</li>
|
||||
<li>install by themselves</li>
|
||||
<li>Adjusted the UI display of existing files</li>
|
||||
</ul>
|
||||
]]></description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
18
readme-en.md
18
readme-en.md
@@ -6,7 +6,7 @@
|
||||
|
||||
## Before Use
|
||||
|
||||
**🍎Only for macOS 14+.**
|
||||
**🍎Only for macOS 13.0+.**
|
||||
|
||||
> **If you like Adobe Downloader, or it helps you, please Star🌟 it.**
|
||||
>
|
||||
@@ -21,21 +21,21 @@
|
||||
> 4. ⚠️⚠️⚠️ **All Adobe apps in Adobe Downloader are from official Adobe channels and are not cracked versions.**
|
||||
> 5. ❌❌❌ **Do not use an external hard drive or any USB to store it, as this will cause permission issues, I do not have
|
||||
the patience to solve any about permission issues**
|
||||
> 6. ❌❌❌ **Due to permission reasons, there may be problems with installation on hackintosh**
|
||||
|
||||
## 📔Latest Log
|
||||
|
||||
- For historical update logs, please go to [Update Log](update-log.md)
|
||||
|
||||
- 2024-11-06 15:50 Update Log
|
||||
- 2024-11-07 16:00 Update Log
|
||||
|
||||
```markdown
|
||||
1. Added default configuration settings and prompts when the program is started for the first time
|
||||
2. Added optional architecture downloads, please select in settings
|
||||
3. Fixed the problem of version detection error \(only checks whether the file exists, not whether it is complete\)
|
||||
4. Removed the language selection and directory selection on the main interface and moved them to settings
|
||||
5. Added architecture prompts on the version selection page
|
||||
6. Removed the installer mechanism, and now no installer will be generated
|
||||
7. Added Adobe Creative Cloud installation detection, which cannot be used before installation
|
||||
1. Support macOS 13.0 and above
|
||||
2. Added Sparkle for checking update
|
||||
3. When the default directory is not selected, the Downloads folder will be used as the default directory
|
||||
4. When installing via Adobe Downloader and encountering permission issues, provide terminal commands to allow users to
|
||||
install by themselves
|
||||
5. Adjusted the UI display of existing files
|
||||
```
|
||||
|
||||
### Language friendly
|
||||
|
||||
17
readme.md
17
readme.md
@@ -6,7 +6,7 @@
|
||||
|
||||
## 使用须知
|
||||
|
||||
**🍎仅支持 macOS 14+.**
|
||||
**🍎仅支持 macOS 13.0+**
|
||||
|
||||
> **如果你也喜欢 Adobe Downloader, 或者对你又帮助, 请 Star 仓库吧 🌟, 你的支持是我更新的动力**
|
||||
>
|
||||
@@ -20,21 +20,20 @@
|
||||
的 [adobe-packager](https://github.com/Drovosek01/adobe-packager)
|
||||
> 4. ⚠️⚠️⚠️ **Adobe Downloader 中的所有 Adobe 应用均来自 Adobe 官方渠道,并非破解版本。**
|
||||
> 5. ❌❌❌ **不要将下载目录设置为外接移动硬盘或者USB设备,这会导致出现权限问题,我并没有时间也没有耐心处理任何权限问题**
|
||||
> 6. ❌❌❌ **由于权限原因,可能会在黑苹果上出现无法安装的问题**
|
||||
|
||||
## 📔 最新日志
|
||||
|
||||
- 更多关于 App 的更新日志,请查看 [Update Log](update-log.md)
|
||||
|
||||
- 2024-11-06 15:50 更新日志
|
||||
- 2024-11-07 16:00 更新日志
|
||||
|
||||
```markdown
|
||||
1. 增加程序首次启动时的默认配置设定与提示
|
||||
2. 增加可选架构下载,请在设置中进行选择
|
||||
3. 修复了版本已存在检测错误的问题 \(仅检测文件是否存在,并不会检测是否完整\)
|
||||
4. 移除主界面的语言选择和目录选择,移动到了设置中
|
||||
5. 版本选择页面增加架构提示
|
||||
6. 移除了安装程序的机制,现在不会再生成安装程序
|
||||
7. 增加了Adobe Creative Cloud安装检测,未安装前无法使用
|
||||
1. 修复了当系统版本低于 macOS 14.6 时无法打开程序的问题,现已支持 macOS 13.0 以上
|
||||
2. 增加 Sparkle 用于检测更新
|
||||
3. 当默认目录为 未选择 时,将 下载 文件夹作为默认目录
|
||||
4. 当通过 Adobe Downloader 安装遇到权限问题时,提供终端命令让用户自行安装
|
||||
5. 调整了文件已存在的 UI 显示
|
||||
```
|
||||
|
||||
### 语言支持
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
# Change Log
|
||||
|
||||
- 2024-11-07 16:00 更新日志
|
||||
|
||||
```markdown
|
||||
1. 修复了当系统版本低于 macOS 14.6 时无法打开程序的问题,现已支持 macOS 13.0 以上
|
||||
2. 增加 Sparkle 用于检测更新
|
||||
3. 当默认目录为 未选择 时,将 下载 文件夹作为默认目录
|
||||
4. 当通过 Adobe Downloader 安装遇到权限问题时,提供终端命令让用户自行安装
|
||||
5. 调整了文件已存在的 UI 显示
|
||||
|
||||
====================
|
||||
|
||||
1. Support macOS 13.0 and above
|
||||
2. Added Sparkle for checking update
|
||||
3. When the default directory is not selected, the Downloads folder will be used as the default directory
|
||||
4. When installing via Adobe Downloader and encountering permission issues, provide terminal commands to allow users to
|
||||
install by themselves
|
||||
5. Adjusted the UI display of existing files
|
||||
```
|
||||
|
||||
- 2024-11-06 15:50 更新日志
|
||||
|
||||
```markdown
|
||||
1. 增加程序首次启动时的默认配置设定与提示
|
||||
2. 增加可选架构下载,请在设置中进行选择
|
||||
3. 修复了版本已存在检测错误的问题 \(仅检测文件是否存在,并不会检测是否完整\)
|
||||
3. 修复了版本已存在检测错误的问题 (仅检测文件是否存在,并不会检测是否完整)
|
||||
4. 移除主界面的语言选择和目录选择,移动到了设置中
|
||||
5. 版本选择页面增加架构提示
|
||||
6. 移除了安装程序的机制,现在不会再生成安装程序
|
||||
@@ -15,7 +34,7 @@
|
||||
|
||||
1. Added default configuration settings and prompts when the program is started for the first time
|
||||
2. Added optional architecture downloads, please select in settings
|
||||
3. Fixed the problem of version detection error \(only checks whether the file exists, not whether it is complete\)
|
||||
3. Fixed the problem of version detection error (only checks whether the file exists, not whether it is complete)
|
||||
4. Removed the language selection and directory selection on the main interface and moved them to settings
|
||||
5. Added architecture prompts on the version selection page
|
||||
6. Removed the installer mechanism, and now no installer will be generated
|
||||
|
||||
Reference in New Issue
Block a user