Add back local profile for tvOS

This commit is contained in:
世界
2026-01-01 19:47:49 +08:00
parent 9b179fe5cd
commit 55e01a89b5
7 changed files with 200 additions and 184 deletions
@@ -1,109 +1,129 @@
#if os(iOS) || os(macOS)
import Foundation
import Library
import SwiftUI
import Foundation
import Library
import SwiftUI
@MainActor
public struct EditProfileContentView: View {
public struct Context: Codable, Hashable {
public let profileID: Int64
public let readOnly: Bool
@MainActor
public struct EditProfileContentView: View {
public struct Context: Codable, Hashable {
public let profileID: Int64
public let readOnly: Bool
}
private let readOnly: Bool
@StateObject private var viewModel: EditProfileContentViewModel
public init(_ context: Context?) {
readOnly = context?.readOnly == true
_viewModel = StateObject(wrappedValue: EditProfileContentViewModel(profileID: context?.profileID))
}
@Environment(\.dismiss) private var dismiss
@Environment(\.profileEditor) private var profileEditor
public var body: some View {
Group {
if viewModel.isLoading {
ProgressView().onAppear {
Task {
await viewModel.loadContent()
}
}
} else {
editorView
.onChangeCompat(of: viewModel.profileContent) {
viewModel.markAsChanged()
}
}
}
private let readOnly: Bool
@StateObject private var viewModel: EditProfileContentViewModel
public init(_ context: Context?) {
readOnly = context?.readOnly == true
_viewModel = StateObject(wrappedValue: EditProfileContentViewModel(profileID: context?.profileID))
}
@Environment(\.dismiss) private var dismiss
@Environment(\.profileEditor) private var profileEditor
public var body: some View {
Group {
if viewModel.isLoading {
ProgressView().onAppear {
Task {
await viewModel.loadContent()
.alert($viewModel.alert)
.navigationTitle(navigationTitle)
#if os(macOS)
.toolbar {
ToolbarItemGroup(placement: .navigation) {
if !readOnly {
Button {
Task {
await viewModel.saveContent()
}
} label: {
Label("Save", image: "save")
}
.disabled(!viewModel.isChanged)
} else {
Button {
NSPasteboard.general.setString(viewModel.profileContent, forType: .fileContents)
} label: {
Label("Copy", systemImage: "clipboard.fill")
}
}
} else {
editorView
.onChangeCompat(of: viewModel.profileContent) {
viewModel.markAsChanged()
}
}
}
.alert($viewModel.alert)
.navigationTitle(navigationTitle)
#elseif os(iOS)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
if !readOnly {
Button("Save") {
Task {
await viewModel.saveContent()
}
}.disabled(!viewModel.isChanged)
} else {
Button("Copy") {
UIPasteboard.general.string = viewModel.profileContent
}
}
}
}
.navigationBarTitleDisplayMode(.inline)
#elseif os(tvOS)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
if !readOnly {
TVToolbarButton(title: String(localized: "Save"), isEnabled: viewModel.isChanged) {
Task {
await viewModel.saveContent()
}
}
}
}
}
#endif
}
private var navigationTitle: String {
if readOnly {
return String(localized: "View Content")
} else {
return String(localized: "Edit Content")
}
}
@ViewBuilder
private var editorView: some View {
if let profileEditor {
profileEditor(
readOnly ? .constant(viewModel.profileContent) : $viewModel.profileContent,
!readOnly
)
#if os(macOS)
.toolbar {
ToolbarItemGroup(placement: .navigation) {
if !readOnly {
Button {
Task {
await viewModel.saveContent()
}
} label: {
Label("Save", image: "save")
}
.disabled(!viewModel.isChanged)
} else {
Button {
NSPasteboard.general.setString(viewModel.profileContent, forType: .fileContents)
} label: {
Label("Copy", systemImage: "clipboard.fill")
}
}
}
}
#elseif os(iOS)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
if !readOnly {
Button("Save") {
Task {
await viewModel.saveContent()
}
}.disabled(!viewModel.isChanged)
} else {
Button("Copy") {
UIPasteboard.general.string = viewModel.profileContent
}
}
}
}
.navigationBarTitleDisplayMode(.inline)
.frame(maxWidth: .infinity, maxHeight: .infinity)
#endif
} else {
defaultEditorView
}
}
private var navigationTitle: String {
if readOnly {
return String(localized: "View Content")
} else {
return String(localized: "Edit Content")
@ViewBuilder
private var defaultEditorView: some View {
#if os(tvOS)
ScrollView {
TextField("", text: readOnly ? .constant(viewModel.profileContent) : $viewModel.profileContent, axis: .vertical)
.lineLimit(1000)
.font(Font.system(.caption2, design: .monospaced))
.autocorrectionDisabled(true)
.disabled(readOnly)
}
}
@ViewBuilder
private var editorView: some View {
if let profileEditor {
profileEditor(
readOnly ? .constant(viewModel.profileContent) : $viewModel.profileContent,
!readOnly
)
#if os(macOS)
.frame(maxWidth: .infinity, maxHeight: .infinity)
#endif
} else {
defaultEditorView
}
}
@ViewBuilder
private var defaultEditorView: some View {
#else
Group {
if readOnly {
TextEditor(text: .constant(viewModel.profileContent))
@@ -117,7 +137,6 @@
.textContentType(.init(rawValue: ""))
.padding()
#endif
}
#endif
}
#endif
}