Optimize: The display of the About page, Language selection page, Version selection page, and Settings page.

This commit is contained in:
X1a0He
2024-11-01 14:34:59 +08:00
parent c22a3fe7a0
commit 6b56029c55
8 changed files with 318 additions and 87 deletions

50
.gitignore vendored
View File

@@ -1,6 +1,48 @@
.idea/
Adobe-Downloader.xcodeproj
Adobe-Downloader.xcodeproj/*.workspace
# Xcode
.DS_Store
*.DS_Store
project.xcworkspace
.idea/
## User settings
xcuserdata/
*.xcuserstate
## Xcode Workspace
*.xcworkspace
*.xcodeproj/project.xcworkspace/
*.xcodeproj/xcuserdata/
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
*.xcuserstate
.xcuserstate
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
.build/

View File

@@ -29,36 +29,34 @@ struct ContentView: View {
var body: some View {
VStack(spacing: 0) {
HStack(spacing: 20) {
HStack {
Text("Adobe Downloader")
.font(.title2)
.fontWeight(.bold)
}
.frame(minWidth: 200)
HStack {
SettingsView(
useDefaultLanguage: $useDefaultLanguage,
useDefaultDirectory: $useDefaultDirectory,
onSelectLanguage: selectLanguage,
onSelectDirectory: selectDirectory
)
}
HStack(spacing: 16) {
Text("Adobe Downloader")
.font(.title2)
.fontWeight(.bold)
.frame(width: 180)
SettingsView(
useDefaultLanguage: $useDefaultLanguage,
useDefaultDirectory: $useDefaultDirectory,
onSelectLanguage: selectLanguage,
onSelectDirectory: selectDirectory
)
.frame(maxWidth: .infinity)
HStack(spacing: 8) {
SearchField(text: $searchText)
.frame(width: 160)
.frame(width: 140)
Button(action: refreshData) {
Image(systemName: "arrow.clockwise")
.imageScale(.large)
.imageScale(.medium)
}
.disabled(isRefreshing)
.buttonStyle(.borderless)
Button(action: { showDownloadManager.toggle() }) {
Image(systemName: "arrow.down.circle")
.imageScale(.large)
.imageScale(.medium)
}
.buttonStyle(.borderless)
.overlay(
@@ -66,18 +64,18 @@ struct ContentView: View {
if !networkManager.downloadTasks.isEmpty {
Text("\(networkManager.downloadTasks.count)")
.font(.caption2)
.padding(4)
.padding(3)
.background(Color.blue)
.clipShape(Circle())
.foregroundColor(.white)
.offset(x: 10, y: -10)
.offset(x: 8, y: -8)
}
}
)
}
.frame(width: 220)
.frame(width: 200)
}
.padding(.horizontal)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(Color(NSColor.windowBackgroundColor))

View File

@@ -13,14 +13,12 @@ struct AboutView: View {
.tabItem {
Label("General", systemImage: "gear")
}
AboutAppView()
.tabItem {
Label("About", systemImage: "info.circle")
}
}
.frame(width: 375, height: 150)
.padding()
}
}
@@ -33,25 +31,25 @@ struct GeneralSettingsView: View {
var body: some View {
Form {
GroupBox(label: Text("下载设置")) {
GroupBox(label: Text("下载设置").padding(.bottom, 8)) {
VStack(alignment: .leading, spacing: 12) {
//
HStack {
Toggle("使用默认语言", isOn: $useDefaultLanguage)
.padding(.leading, 5)
Spacer()
Text(getLanguageName(code: defaultLanguage))
.foregroundColor(.secondary)
Button("选择") {
showLanguagePicker = true
}
.padding(.trailing, 5)
.buttonStyle(.borderless)
}
Divider()
//
HStack {
Toggle("使用默认目录", isOn: $useDefaultDirectory)
.padding(.leading, 5)
Spacer()
Text(formatPath(defaultDirectory))
.foregroundColor(.secondary)
@@ -60,6 +58,7 @@ struct GeneralSettingsView: View {
Button("选择") {
selectDirectory()
}
.padding(.trailing, 5)
.buttonStyle(.borderless)
}
}
@@ -67,6 +66,7 @@ struct GeneralSettingsView: View {
}
}
.padding()
.frame(maxHeight: .infinity, alignment: .top)
.sheet(isPresented: $showLanguagePicker) {
LanguagePickerView(languages: AppStatics.supportedLanguages) { language in
defaultLanguage = language
@@ -112,13 +112,23 @@ struct AboutAppView: View {
Text("By X1a0He. ❤️ Love from China. ❤️")
.font(.subheadline)
.foregroundColor(.secondary)
Link("Github: Adobe Downloader",
destination: URL(string: "https://github.com/X1a0He/Adobe-Downloader")!)
.font(.caption)
.foregroundColor(.blue)
Link("Thanks Drovosek01: adobe-packager",
destination: URL(string: "https://github.com/Drovosek01/adobe-packager")!)
.font(.caption)
.foregroundColor(.blue)
Text("Released under GPLv3.")
.font(.caption)
.foregroundColor(.secondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding()
.fixedSize(horizontal: true, vertical: true)
}
}

View File

@@ -10,6 +10,19 @@ struct LanguagePickerView: View {
let onLanguageSelected: (String) -> Void
@Environment(\.dismiss) private var dismiss
@AppStorage("defaultLanguage") private var defaultLanguage: String = "zh_CN"
@State private var searchText: String = ""
private var filteredLanguages: [(code: String, name: String)] {
guard !searchText.isEmpty else {
return languages
}
let searchTerms = searchText.lowercased()
return languages.filter { language in
language.name.lowercased().contains(searchTerms) ||
language.code.lowercased().contains(searchTerms)
}
}
var body: some View {
VStack(spacing: 0) {
@@ -25,41 +38,118 @@ struct LanguagePickerView: View {
.padding()
.background(Color(NSColor.controlBackgroundColor))
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.secondary)
TextField("搜索语言", text: $searchText)
.textFieldStyle(.plain)
if !searchText.isEmpty {
Button(action: { searchText = "" }) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
}
}
.padding(8)
.background(Color(NSColor.controlBackgroundColor))
.cornerRadius(6)
.padding(.horizontal)
.padding(.vertical, 8)
Divider()
ScrollView {
LazyVGrid(
columns: [GridItem(.flexible())],
spacing: 8
) {
ForEach(languages, id: \.code) { language in
Button(action: {
defaultLanguage = language.code
onLanguageSelected(language.code)
dismiss()
}) {
HStack {
Text(language.name)
.frame(maxWidth: .infinity, alignment: .leading)
if defaultLanguage == language.code {
Image(systemName: "checkmark")
.foregroundColor(.blue)
}
LazyVStack(spacing: 0) {
ForEach(Array(filteredLanguages.enumerated()), id: \.element.code) { index, language in
LanguageRow(
language: language,
isSelected: language.code == defaultLanguage,
onSelect: {
defaultLanguage = language.code
onLanguageSelected(language.code)
dismiss()
}
.padding(.horizontal)
.padding(.vertical, 8)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.background(
RoundedRectangle(cornerRadius: 6)
.fill(defaultLanguage == language.code ? Color.blue.opacity(0.1) : Color.clear)
)
if index < filteredLanguages.count - 1 {
Divider()
.padding(.leading, 44)
}
}
}
.padding()
}
if filteredLanguages.isEmpty {
ContentUnavailableView(
"未找到语言",
systemImage: "magnifyingglass",
description: Text("尝试其他搜索关键词")
)
}
}
.frame(width: 300, height: 400)
.frame(width: 320, height: 400)
}
}
struct LanguageRow: View {
let language: (code: String, name: String)
let isSelected: Bool
let onSelect: () -> Void
var body: some View {
Button(action: onSelect) {
HStack(spacing: 12) {
Image(systemName: getLanguageIcon(language.code))
.foregroundColor(.blue)
.frame(width: 24)
Text(language.name)
.frame(maxWidth: .infinity, alignment: .leading)
Text(language.code)
.font(.caption)
.foregroundColor(.secondary)
if isSelected {
Image(systemName: "checkmark")
.foregroundColor(.blue)
.frame(width: 20)
}
}
.padding(.horizontal)
.padding(.vertical, 10)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.background(isSelected ? Color.blue.opacity(0.1) : Color.clear)
}
private func getLanguageIcon(_ code: String) -> String {
switch code {
case "zh_CN", "zh_TW":
return "character.textbox"
case "en_US", "en_GB":
return "a.square"
case "ja_JP":
return "j.square"
case "ko_KR":
return "k.square"
case "fr_FR":
return "f.square"
case "de_DE":
return "d.square"
case "es_ES":
return "e.square"
case "it_IT":
return "i.square"
case "ru_RU":
return "r.square"
case "ALL":
return "globe"
default:
return "character.square"
}
}
}

View File

@@ -18,7 +18,6 @@ struct SettingsView: View {
var body: some View {
HStack(spacing: 12) {
//
HStack(spacing: 4) {
Toggle(isOn: $useDefaultLanguage) {
Text("语言:")
@@ -40,7 +39,6 @@ struct SettingsView: View {
Divider()
.frame(height: 16)
//
HStack(spacing: 4) {
Toggle(isOn: $useDefaultDirectory) {
Text("目录:")

View File

@@ -9,10 +9,27 @@ struct VersionPickerView: View {
let product: Product
let onVersionSelected: (String) -> Void
@Environment(\.dismiss) private var dismiss
@AppStorage("defaultDirectory") private var defaultDirectory: String = ""
@AppStorage("useDefaultDirectory") private var useDefaultDirectory: Bool = true
@AppStorage("defaultLanguage") private var defaultLanguage: String = "zh_CN"
private var sortedVersions: [(version: String, platform: String)] {
private var sortedVersions: [(version: String, platform: String, exists: Bool)] {
product.versions
.map { (version: $0.key, platform: $0.value.apPlatform) }
.map { version -> (version: String, platform: String, exists: Bool) in
let installerPath: String
let appName = "Install \(product.sapCode)_\(version.key)-\(defaultLanguage)-\(version.value.apPlatform).app"
if useDefaultDirectory && !defaultDirectory.isEmpty {
installerPath = (defaultDirectory as NSString).appendingPathComponent(appName)
} else {
let downloadsPath = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first?.path ?? ""
installerPath = (downloadsPath as NSString).appendingPathComponent(appName)
}
return (
version: version.key,
platform: version.value.apPlatform,
exists: FileManager.default.fileExists(atPath: installerPath)
)
}
.sorted { $0.version.compare($1.version, options: .numeric) == .orderedDescending }
}
@@ -34,36 +51,65 @@ struct VersionPickerView: View {
}
.padding()
.background(Color(NSColor.controlBackgroundColor))
Divider()
List {
ForEach(sortedVersions, id: \.version) { version in
Button(action: {
onVersionSelected(version.version)
dismiss()
}) {
HStack(spacing: 12) {
VStack(alignment: .leading, spacing: 4) {
Text(version.version)
.font(.system(.body, design: .monospaced))
Text(getPlatformDisplayName(version.platform))
ScrollView(showsIndicators: false) {
LazyVStack(spacing: 0) {
ForEach(sortedVersions, id: \.version) { version in
Button(action: {
onVersionSelected(version.version)
dismiss()
}) {
HStack(spacing: 16) {
VStack(alignment: .leading, spacing: 4) {
Text(version.version)
.font(.system(.body, design: .monospaced))
.fontWeight(.medium)
.lineLimit(1)
HStack(spacing: 6) {
Image(systemName: getPlatformIcon(version.platform))
.foregroundColor(.secondary)
Text(getPlatformDisplayName(version.platform))
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(1)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
if version.exists {
Text("已下载")
.font(.caption)
.foregroundColor(.green)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Color.green.opacity(0.1))
.cornerRadius(4)
}
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Image(systemName: "chevron.right")
.font(.caption)
.foregroundColor(.secondary)
.padding(.horizontal)
.padding(.vertical, 12)
.contentShape(Rectangle())
}
.contentShape(Rectangle())
.buttonStyle(.plain)
.background(Color(NSColor.controlBackgroundColor).opacity(0.01))
.cornerRadius(8)
.padding(.horizontal, 8)
.padding(.vertical, 2)
Divider()
}
.buttonStyle(.plain)
.padding(.vertical, 4)
}
.padding(.vertical, 8)
}
}
.frame(width: 300, height: 400)
.frame(width: 360, height: 400)
.background(Color(NSColor.windowBackgroundColor))
}
private func getPlatformDisplayName(_ platform: String) -> String {
@@ -78,6 +124,19 @@ struct VersionPickerView: View {
return platform
}
}
private func getPlatformIcon(_ platform: String) -> String {
switch platform {
case "macuniversal":
return "cpu"
case "macarm64":
return "memorychip"
case "osx10-64", "osx10":
return "desktopcomputer"
default:
return "questionmark.circle"
}
}
}
#Preview {
@@ -95,6 +154,22 @@ struct VersionPickerView: View {
apPlatform: "macuniversal",
dependencies: [],
buildGuid: ""
),
"24.6.0": Product.ProductVersion(
sapCode: "PHSP",
baseVersion: "24.6.0",
productVersion: "24.6.0",
apPlatform: "macuniversal",
dependencies: [],
buildGuid: ""
),
"24.5.0": Product.ProductVersion(
sapCode: "PHSP",
baseVersion: "24.5.0",
productVersion: "24.5.0",
apPlatform: "macuniversal",
dependencies: [],
buildGuid: ""
)
],
icons: []

View File

@@ -65,9 +65,15 @@
}
}
}
},
"Github: Adobe Downloader" : {
},
"Released under GPLv3." : {
},
"Thanks Drovosek01: adobe-packager" : {
},
"Welcome to Adobe Downloader" : {
@@ -125,6 +131,12 @@
},
"尝试使用不同的搜索关键词" : {
},
"尝试其他搜索关键词" : {
},
"已下载" : {
},
"已完成" : {
@@ -134,6 +146,9 @@
},
"搜索应用" : {
},
"搜索语言" : {
},
"是否要安装 %@?" : {
@@ -143,6 +158,9 @@
},
"服务器响应无效" : {
"comment" : "Invalid response"
},
"未找到语言" : {
},
"正在下载 %@ (%d/%d)" : {
"comment" : "Download status downloading",