Files
sing-box-for-apple/ApplicationLibrary/Views/Profile/EditProfileContentView.swift
T
2023-07-29 09:44:31 +08:00

137 lines
4.3 KiB
Swift

#if os(iOS) || os(macOS)
import Foundation
import Library
import SwiftUI
public struct EditProfileContentView: View {
#if os(macOS)
public static let windowID = "edit-profile-content"
#endif
public struct Context: Codable, Hashable {
public let profileID: Int64
public let readOnly: Bool
}
private let profileID: Int64?
private let readOnly: Bool
public init(_ context: Context?) {
profileID = context?.profileID
readOnly = context?.readOnly == true
}
@Environment(\.dismiss) private var dismiss
@State private var isLoading = true
@State private var profile: Profile!
@State private var profileContent: String = ""
@State private var isChanged = false
@State private var alert: Alert?
public var body: some View {
viewBuilder {
if isLoading {
ProgressView().onAppear {
Task.detached {
loadContent()
}
}
} else {
viewBuilder {
if readOnly {
TextEditor(text: .constant(profileContent))
} else {
TextEditor(text: $profileContent)
}
}
.font(Font.system(.caption2, design: .monospaced))
.autocorrectionDisabled()
#if os(iOS)
.textInputAutocapitalization(.none)
.background(Color(UIColor.secondarySystemGroupedBackground))
#elseif os(macOS)
.padding()
#endif
.onChange(of: profileContent) { _ in
isChanged = true
}
}
}
.alertBinding($alert)
.navigationTitle(navigationTitle)
#if os(macOS)
.toolbar {
ToolbarItemGroup(placement: .navigation) {
if !readOnly {
Button(action: {
Task.detached {
saveContent()
}
}, label: {
Image("save", label: Text("Save"))
})
.disabled(!isChanged)
}
}
}
#elseif os(iOS)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
if !readOnly {
Button("Save") {
Task.detached {
saveContent()
}
}.disabled(!isChanged)
}
}
}
.navigationBarTitleDisplayMode(.inline)
#endif
}
private var navigationTitle: String {
if readOnly {
return "View Content"
} else {
return "Edit Content"
}
}
private func loadContent() {
do {
try loadContent0()
} catch {
alert = Alert(error, dismiss.callAsFunction)
}
}
private func loadContent0() throws {
guard let profileID else {
throw NSError(domain: "Context destroyed", code: 0)
}
guard let profile = try ProfileManager.get(profileID) else {
throw NSError(domain: "Profile missing", code: 0)
}
profileContent = try profile.read()
self.profile = profile
isLoading = false
}
private func saveContent() {
guard let profile else {
return
}
do {
try profile.write(profileContent)
} catch {
alert = Alert(error)
return
}
isChanged = false
}
}
#endif