import AppKit import SstData import SstUI import SwiftUI struct NoteView: View { @EnvironmentObject private var model: AppModel @ObservedObject var note: NoteStore @State private var confirmingClear = false private var editedEntry: HistoryEntry? { model.editingEntryID.flatMap { model.historyList.entry(id: $0) } } /// The note, or the transcript being edited. private var text: Binding { if let entry = editedEntry { return Binding( get: { model.historyList.entry(id: entry.id)?.finalText ?? "" }, set: { model.historyList.updateText(id: entry.id, to: $0) }) } return $note.text } var body: some View { VStack(spacing: Layout.panelGap) { header ZStack { PaperBackground() if SnapshotMode.isActive { // ImageRenderer cannot draw an NSView; the snapshot shows the text instead. Text(text.wrappedValue) .textStyle(Typography.reading) .foregroundStyle(Palette.inkPrimary) .padding(Space.s5) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) } else { NoteEditor(text: text, isEditable: editedEntry != nil || !note.isReadOnly) .id(editedEntry?.id) } } footer } .confirmationDialog(Strings.clearNoteConfirm, isPresented: $confirmingClear) { Button(Strings.clear, role: .destructive) { note.text = "" } } .onChange(of: model.section) { _, new in if new != .note { model.editingEntryID = nil } } } private var header: some View { HStack(spacing: Space.s4) { if let entry = editedEntry { SilkLabel("\(Strings.transcript) ยท \(entry.date.formatted(Date.FormatStyle().hour().minute().second().locale(Locale(identifier: "nl_NL"))))") } else { SilkLabel(Strings.note) } Spacer() Text(Strings.characters(text.wrappedValue.count)) .textStyle(Typography.counterSmall) .foregroundStyle(Palette.inkSecondary) Button(Strings.copy) { NSPasteboard.general.clearContents() NSPasteboard.general.setString(text.wrappedValue, forType: .string) } .buttonStyle(KeyButtonStyle()) .disabled(text.wrappedValue.isEmpty) if editedEntry != nil { Button(Strings.done) { model.editingEntryID = nil model.section = .transcripts } .buttonStyle(KeyButtonStyle(kind: .record)) } else { Button(Strings.clear) { confirmingClear = true } .buttonStyle(KeyButtonStyle()) .disabled(note.text.isEmpty) } } } private var footer: some View { Text(footerText) .textStyle(Typography.label) .foregroundStyle(Palette.inkTertiary) .frame(maxWidth: .infinity, alignment: .leading) } private var footerText: String { if editedEntry != nil { return Strings.editingTranscriptHint } return note.isReadOnly ? Strings.noteUnreadable : Strings.noteHint(model.hotkeyBinding.displayName) } }