feat(CustomSettings): Added custom settings View.

This commit is contained in:
X1a0He
2025-04-06 10:23:29 +08:00
parent 8a73709fb1
commit 7f704d0125
9 changed files with 255 additions and 41 deletions

View File

@@ -9,6 +9,7 @@ struct Adobe_DownloaderApp: App {
@State private var showLanguagePicker = false
@State private var showCreativeCloudAlert = false
@State private var showBackupResultAlert = false
@State private var showSettingsView = false
@StateObject private var backupResult = BackupResult()
@@ -61,7 +62,7 @@ struct Adobe_DownloaderApp: App {
BlurView()
.ignoresSafeArea()
ContentView()
ContentView(showSettingsView: $showSettingsView)
.environmentObject(globalNetworkManager)
.frame(minWidth: 792, minHeight: 600)
.tint(.blue)
@@ -105,6 +106,10 @@ struct Adobe_DownloaderApp: App {
}
}
}
.sheet(isPresented: $showSettingsView) {
CustomSettingsView(updater: updaterController.updater)
.interactiveDismissDisabled(false)
}
}
}
.windowStyle(.hiddenTitleBar)
@@ -112,12 +117,15 @@ struct Adobe_DownloaderApp: App {
.commands {
CommandGroup(after: .appInfo) {
CheckForUpdatesView(updater: updaterController.updater)
Divider()
Button("设置...") {
showSettingsView = true
}
.keyboardShortcut(",", modifiers: .command)
}
}
Settings {
AboutView(updater: updaterController.updater)
}
}
private func setupApplication() async {

View File

@@ -7,6 +7,7 @@ struct ContentView: View {
@State private var showDownloadManager = false
@State private var searchText = ""
@State private var currentApiVersion = StorageData.shared.apiVersion
@Binding var showSettingsView: Bool
private var filteredProducts: [UniqueProduct] {
if searchText.isEmpty { return globalUniqueProducts }
@@ -17,7 +18,7 @@ struct ContentView: View {
}
private func openSettings() {
NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
showSettingsView = true
}
private func refreshData() {

View File

@@ -63,7 +63,7 @@ class NetworkManager: ObservableObject {
}
func startDownload(productId: String, selectedVersion: String, language: String, destinationURL: URL) async throws {
// globalCcmResult productId ProductInfo
guard let productInfo = globalCcmResult.products.first(where: { $0.id == productId }) else {
guard let productInfo = globalCcmResult.products.first(where: { $0.id == productId && $0.version == selectedVersion }) else {
throw NetworkError.productNotFound
}
@@ -289,7 +289,7 @@ class NetworkManager: ObservableObject {
!$0.status.isCompleted
}) { return task.directory }
let platform = globalProducts.first(where: { $0.id == productId })?.platforms.first?.id ?? "unknown"
let platform = globalProducts.first(where: { $0.id == productId && $0.version == version })?.platforms.first?.id ?? "unknown"
let fileName = productId == "APRO"
? "Adobe Downloader \(productId)_\(version)_\(platform).dmg"
: "Adobe Downloader \(productId)_\(version)-\(language)-\(platform)"

View File

@@ -165,12 +165,12 @@ class NewDownloadUtils {
let isCore = packageType == "core"
let condition = package["Condition"] as? String ?? ""
let targetArchitecture = StorageData.shared.downloadAppleSilicon ? "arm64" : "x64"
if isCore {
if condition.isEmpty {
shouldKeep = true
} else {
if condition.contains("[OSArchitecture]==\(AppStatics.architectureSymbol)") {
if condition.contains("[OSArchitecture]==\(targetArchitecture)") {
shouldKeep = true
}
if condition.contains("[installLanguage]==\(task.language)") || task.language == "ALL" {
@@ -266,8 +266,9 @@ class NewDownloadUtils {
if dependencyToDownload.sapCode == productInfo.id {
if isCore {
let targetArchitecture = StorageData.shared.downloadAppleSilicon ? "arm64" : "x64"
shouldDownload = condition.isEmpty ||
condition.contains("[OSArchitecture]==\(AppStatics.architectureSymbol)") ||
condition.contains("[OSArchitecture]==\(targetArchitecture)") ||
condition.contains(installLanguage) || task.language == "ALL"
} else {
shouldDownload = condition.contains(installLanguage) || task.language == "ALL"
@@ -715,8 +716,8 @@ class NewDownloadUtils {
func generateDriverXML(version: String, language: String, productInfo: Product, displayName: String) -> String {
// platform languageSet
guard let platform = globalProducts.first(where: { $0.id == productInfo.id })?.platforms.first?.id,
let languageSet = globalProducts.first(where: { $0.id == productInfo.id })?.platforms.first?.languageSet else {
guard let platform = globalProducts.first(where: { $0.id == productInfo.id && $0.version == version })?.platforms.first?.id,
let languageSet = globalProducts.first(where: { $0.id == productInfo.id && $0.version == version })?.platforms.first?.languageSet else {
return ""
}

View File

@@ -284,8 +284,7 @@ class NewJSONParser {
let baseVersion = dep["baseVersion"] as? String else {
return Product.Platform.LanguageSet.Dependency(sapCode: "",baseVersion: "",productVersion: "",buildGuid: "")
}
let targetPlatform = AppStatics.isAppleSilicon ? "macarm64" : "osx10-64"
let targetPlatform = StorageData.shared.downloadAppleSilicon ? "macarm64" : "osx10-64"
let cacheKey = DependencyCacheKey(sapCode: sapCode, targetPlatform: targetPlatform)
if let cachedDependency = globalDependencyCache[cacheKey] {

View File

@@ -127,7 +127,7 @@ final class AppCardViewModel: ObservableObject {
}
func getDestinationURL(version: String, language: String) async throws -> URL {
let platform = globalProducts.first(where: { $0.id == uniqueProduct.id })?.platforms.first?.id ?? "unknown"
let platform = globalProducts.first(where: { $0.id == uniqueProduct.id && $0.version == version })?.platforms.first?.id ?? "unknown"
let installerName = uniqueProduct.id == "APRO"
? "Adobe Downloader \(uniqueProduct.id)_\(version)_\(platform).dmg"
: "Adobe Downloader \(uniqueProduct.id)_\(version)-\(language)-\(platform)"

View File

@@ -0,0 +1,177 @@
//
// CleanupView.swift
// Adobe Downloader
//
// Created by X1a0He on 4/6/25.
//
import SwiftUI
import Sparkle
struct CustomSettingsView: View {
@State private var selectedTab = "general_settings"
@Environment(\.presentationMode) var presentationMode
@Environment(\.colorScheme) var colorScheme
private let updater: SPUUpdater
init(updater: SPUUpdater) {
self.updater = updater
}
var body: some View {
ZStack {
BlurView()
.ignoresSafeArea()
ZStack(alignment: .topTrailing) {
VStack(spacing: 0) {
HStack {
HStack(spacing: 0) {
SquareTabButton(
imageName: "gear",
title: "通用",
isSelected: selectedTab == "general_settings"
) {
withAnimation(.easeInOut(duration: 0.15)) {
selectedTab = "general_settings"
}
}
.accessibilityLabel("通用")
SquareTabButton(
imageName: "trash",
title: "清理工具",
isSelected: selectedTab == "cleanup_view"
) {
withAnimation(.easeInOut(duration: 0.15)) {
selectedTab = "cleanup_view"
}
}
.accessibilityLabel("清理工具")
SquareTabButton(
imageName: "questionmark.circle",
title: "常见问题",
isSelected: selectedTab == "qa_view"
) {
withAnimation(.easeInOut(duration: 0.15)) {
selectedTab = "qa_view"
}
}
.accessibilityLabel("常见问题")
SquareTabButton(
imageName: "info.circle",
title: "关于",
isSelected: selectedTab == "about_app"
) {
withAnimation(.easeInOut(duration: 0.15)) {
selectedTab = "about_app"
}
}
.accessibilityLabel("关于")
}
.padding(.leading, 8)
Spacer()
}
.padding(.top, 10)
.padding(.bottom, 6)
Divider()
.opacity(0.6)
ScrollView {
ZStack {
if selectedTab == "general_settings" {
GeneralSettingsView(updater: updater)
.transition(contentTransition)
.id("general_settings")
} else if selectedTab == "cleanup_view" {
CleanupView()
.transition(contentTransition)
.id("cleanup_view")
} else if selectedTab == "qa_view" {
QAView()
.transition(contentTransition)
.id("qa_view")
} else if selectedTab == "about_app" {
AboutAppView()
.transition(contentTransition)
.id("about_app")
}
}
.frame(maxWidth: .infinity)
}
.background(Color.clear)
}
Button(action: {
withAnimation {
presentationMode.wrappedValue.dismiss()
}
}) {
Image(systemName: "xmark")
.font(.system(size: 11, weight: .bold))
.foregroundColor(.gray)
.frame(width: 20, height: 20)
.background(
Circle()
.fill(colorScheme == .dark ?
Color.gray.opacity(0.3) :
Color.gray.opacity(0.15))
)
.help("关闭")
}
.buttonStyle(PlainButtonStyle())
.keyboardShortcut(.escape, modifiers: [])
.padding(.top, 10)
.padding(.trailing, 10)
}
}
.frame(width: 600, height: 830)
.onAppear {
selectedTab = "general_settings"
}
}
private var contentTransition: AnyTransition {
.asymmetric(
insertion: .opacity.combined(with: .scale(scale: 0.98)).animation(.easeInOut(duration: 0.2)),
removal: .opacity.animation(.easeInOut(duration: 0.1))
)
}
}
struct SquareTabButton: View {
let imageName: String
let title: String
let isSelected: Bool
let action: () -> Void
@Environment(\.colorScheme) var colorScheme
var body: some View {
Button(action: action) {
VStack(spacing: 4) {
ZStack {
if isSelected {
RoundedRectangle(cornerRadius: 6)
.fill(Color.blue.opacity(0.2))
.frame(width: 40, height: 40)
}
Image(systemName: imageName)
.font(.system(size: isSelected ? 18 : 17))
.foregroundColor(isSelected ? .blue : colorScheme == .dark ? .white : .black)
}
Text(title)
.font(.system(size: 12, weight: isSelected ? .medium : .regular))
.foregroundColor(isSelected ? .blue : colorScheme == .dark ? .white : .primary)
}
.frame(width: 70)
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
}
}

View File

@@ -148,33 +148,18 @@ struct ToolbarView: View {
BeautifulSearchField(text: $searchText)
.frame(maxWidth: 200)
if #available(macOS 14.0, *) {
SettingsLink {
ZStack {
Circle()
.fill(Color.secondary.opacity(0.1))
.frame(width: 34, height: 34)
Image(systemName: "gearshape")
.font(.system(size: 15, weight: .medium))
.foregroundColor(.secondary)
}
Button(action: openSettings) {
ZStack {
Circle()
.fill(Color.secondary.opacity(0.1))
.frame(width: 34, height: 34)
Image(systemName: "gearshape")
.font(.system(size: 15, weight: .medium))
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
} else {
Button(action: openSettings) {
ZStack {
Circle()
.fill(Color.secondary.opacity(0.1))
.frame(width: 34, height: 34)
Image(systemName: "gearshape")
.font(.system(size: 15, weight: .medium))
.foregroundColor(.secondary)
}
}
.buttonStyle(.plain)
}
.buttonStyle(.plain)
Button(action: onRefresh) {
ZStack {

View File

@@ -1065,6 +1065,17 @@
}
}
},
"可选模块" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Modules"
}
}
}
},
"命令已复制到剪贴板" : {
"localizations" : {
"en" : {
@@ -2078,6 +2089,17 @@
}
}
},
"未对 Setup 组件进行处理或者 Setup 组件不存在,无法使用安装功能\n你可以通过设置页面再次对 Setup 组件进行处理" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The Setup component has not been processed or does not exist, so the installation function cannot be used. You can process the Setup component again through the settings page."
}
}
}
},
"未对 Setup 组件进行处理或者 Setup 组件不存在,无法使用安装功能\n你可以通过设置页面对 Setup 组件进行处理" : {
"localizations" : {
"en" : {
@@ -2175,6 +2197,17 @@
}
}
},
"查看持久化文件" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "View persistent files"
}
}
}
},
"检查中" : {
"localizations" : {
"en" : {
@@ -2975,6 +3008,16 @@
}
}
},
"设置..." : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Settings…"
}
}
}
},
"请求超时,请检查网络连接后重试" : {
"comment" : "Network timeout",
"localizations" : {