d94054dd1a
- 项目从 SPM (Sources/VODManager/) 迁移到 Xcode 构建系统 (VODManager.xcodeproj) - 源码目录从 Sources/VODManager/ 迁移至 VODManager/VODManager/ - 用 Localizable.xcstrings 替代旧的 .lproj/Localizable.strings 文件 - 删除已废弃的 apps/web、apps/server、docker 目录及相关文档 - RTL 侧边栏修复:切语言时用 .id() 强制重建 NavigationSplitView - 视频库无账号时不发起 API 请求和重试 - 无账号时显示 ContentUnavailableView 提示
169 lines
5.6 KiB
Swift
169 lines
5.6 KiB
Swift
import SwiftUI
|
|
import SwiftData
|
|
|
|
struct AccountListView: View {
|
|
@EnvironmentObject var accountStore: AccountStore
|
|
@Query(sort: \Account.createdAt, order: .reverse) private var accounts: [Account]
|
|
@State private var editingAccount: Account?
|
|
@State private var showAddForm = false
|
|
@State private var errorMessage: String?
|
|
|
|
var body: some View {
|
|
VStack {
|
|
HStack {
|
|
Spacer()
|
|
Button("account.add") {
|
|
showAddForm = true
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
}
|
|
.padding()
|
|
|
|
if let error = errorMessage {
|
|
HStack {
|
|
Text(error)
|
|
.foregroundStyle(.red)
|
|
Button {
|
|
NSPasteboard.general.clearContents()
|
|
NSPasteboard.general.setString(error, forType: .string)
|
|
} label: {
|
|
Image(systemName: "doc.on.doc")
|
|
}
|
|
.buttonStyle(.borderless)
|
|
.help("error.copy_help")
|
|
Spacer()
|
|
}
|
|
.padding(.horizontal)
|
|
}
|
|
|
|
List(accounts) { account in
|
|
HStack {
|
|
VStack(alignment: .leading) {
|
|
Text(account.name)
|
|
.font(.headline)
|
|
Text("\(account.accessKeyId) / \(account.region)")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
if account.isActive {
|
|
Text("account.active")
|
|
.font(.caption)
|
|
.foregroundStyle(.green)
|
|
} else {
|
|
Button("btn.switch") {
|
|
Task { await accountStore.switchActive(account) }
|
|
}
|
|
.buttonStyle(.borderless)
|
|
}
|
|
|
|
Button("btn.edit") {
|
|
editingAccount = account
|
|
}
|
|
.buttonStyle(.borderless)
|
|
|
|
Button("btn.delete") {
|
|
Task { await accountStore.deleteAccount(account) }
|
|
}
|
|
.buttonStyle(.borderless)
|
|
.foregroundStyle(.red)
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
}
|
|
.sheet(item: $editingAccount) { account in
|
|
AccountFormView(account: account)
|
|
}
|
|
.sheet(isPresented: $showAddForm) {
|
|
AccountFormView(account: nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AccountFormView: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
@EnvironmentObject var accountStore: AccountStore
|
|
@Query(sort: \Account.createdAt, order: .reverse) private var accounts: [Account]
|
|
|
|
var account: Account?
|
|
|
|
@State private var name = ""
|
|
@State private var accessKeyId = ""
|
|
@State private var accessKeySecret = ""
|
|
@State private var region = "cn-shanghai"
|
|
@State private var endpoint = ""
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 16) {
|
|
Text(account == nil ? "account.add_title" : "account.edit_title")
|
|
.font(.title2)
|
|
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
Text("account.name")
|
|
TextField("account.name_placeholder", text: $name)
|
|
.textFieldStyle(.roundedBorder)
|
|
|
|
Text("account.access_key_id")
|
|
TextField("account.access_key_id_placeholder", text: $accessKeyId)
|
|
.textFieldStyle(.roundedBorder)
|
|
|
|
Text(account == nil ? "account.access_key_secret" : "account.access_key_secret_edit")
|
|
SecureField("account.access_key_secret_placeholder", text: $accessKeySecret)
|
|
.textFieldStyle(.roundedBorder)
|
|
|
|
Text("account.region")
|
|
TextField("account.region_placeholder", text: $region)
|
|
.textFieldStyle(.roundedBorder)
|
|
|
|
Text("account.endpoint")
|
|
TextField("account.endpoint_placeholder", text: $endpoint)
|
|
.textFieldStyle(.roundedBorder)
|
|
}
|
|
|
|
HStack {
|
|
Spacer()
|
|
Button("btn.cancel") {
|
|
dismiss()
|
|
}
|
|
Button("btn.save") {
|
|
Task { await save() }
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
}
|
|
}
|
|
.padding()
|
|
.frame(minWidth: 450)
|
|
.onAppear {
|
|
if let account = account {
|
|
name = account.name
|
|
accessKeyId = account.accessKeyId
|
|
region = account.region
|
|
endpoint = account.endpoint ?? ""
|
|
}
|
|
}
|
|
}
|
|
|
|
private func save() async {
|
|
let secret = accessKeySecret.isEmpty ? (account?.accessKeySecret ?? "") : accessKeySecret
|
|
let newAccount = Account(
|
|
id: account?.id ?? UUID(),
|
|
name: name,
|
|
accessKeyId: accessKeyId,
|
|
accessKeySecret: secret,
|
|
region: region,
|
|
endpoint: endpoint.isEmpty ? nil : endpoint,
|
|
isActive: account?.isActive ?? (accounts.isEmpty ? true : false),
|
|
createdAt: account?.createdAt ?? Date(),
|
|
updatedAt: Date()
|
|
)
|
|
if account != nil {
|
|
await accountStore.updateAccount(newAccount)
|
|
} else {
|
|
await accountStore.addAccount(newAccount)
|
|
}
|
|
dismiss()
|
|
}
|
|
}
|