Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Clipbara/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ final class AppState {
}
}

/// Shared paste path for panel and pinboard cards.
/// - Parameter asPlainText: `nil` resolves from the setting combined with the Shift modifier.
func paste(_ item: ClipboardItem, asPlainText: Bool? = nil) {
clipboardMonitor.skipNextChange()
pasteService.paste(item: item, asPlainText: asPlainText)
hidePanel()
}

func hidePanel() {
previewItem = nil
panelToast = nil
Expand Down
29 changes: 28 additions & 1 deletion Clipbara/Services/PasteService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,34 @@ struct PasteService {

private static let tempDir = NSTemporaryDirectory() + "Clipbara/"

func paste(item: ClipboardItem) {
/// Backing key for the "Always Paste as Plain Text" setting (Settings > General).
nonisolated static let alwaysPlainTextDefaultsKey = "alwaysPastePlainText"

/// Whether stripping formatting is meaningful for this item (RTF/HTML only).
static func supportsPlainText(_ item: ClipboardItem) -> Bool {
switch item.contentType {
case .richText, .html:
return !(item.textContent?.isEmpty ?? true)
default:
return false
}
}

/// Combines the setting with the Shift modifier using XOR.
/// Setting off: Shift strips formatting. Setting on: Shift keeps formatting.
static func resolvePlainText() -> Bool {
let always = UserDefaults.standard.bool(forKey: alwaysPlainTextDefaultsKey)
let shiftHeld = NSEvent.modifierFlags.contains(.shift)
return always != shiftHeld
}

/// - Parameter asPlainText: `nil` resolves from the setting combined with the Shift modifier.
func paste(item: ClipboardItem, asPlainText: Bool? = nil) {
if asPlainText ?? Self.resolvePlainText(), Self.supportsPlainText(item) {
pastePlainText(item: item)
return
}

let pasteboard = NSPasteboard.general
pasteboard.clearContents()

Expand Down
7 changes: 6 additions & 1 deletion Clipbara/Views/ClipboardCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ struct ClipboardCardView: View {

@ViewBuilder
private var menuItems: some View {
Button("Paste") { onPaste(item) }
if PasteService.supportsPlainText(item) {
Button("Paste with Formatting") { appState.paste(item, asPlainText: false) }
Button("Paste as Plain Text") { appState.paste(item, asPlainText: true) }
} else {
Button("Paste") { onPaste(item) }
}
if showsManagementMenu {
Divider()
Button("Rename") {
Expand Down
18 changes: 18 additions & 0 deletions Clipbara/Views/Settings/GeneralSettingsTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct GeneralSettingsTab: View {
@Environment(\.modelContext) private var modelContext
@Environment(AppState.self) private var appState
@AppStorage("historyLimit") private var historyLimit: Int = 500
@AppStorage(PasteService.alwaysPlainTextDefaultsKey) private var alwaysPastePlainText: Bool = false
@State private var launchAtLogin: Bool = SMAppService.mainApp.status == .enabled
@State private var transferMessage: String?
@State private var showTransferAlert = false
Expand Down Expand Up @@ -35,6 +36,23 @@ struct GeneralSettingsTab: View {
}
}

Section("Pasting") {
HStack {
VStack(alignment: .leading, spacing: 2) {
HStack(spacing: 5) {
Text("Always Paste as Plain Text")
InfoHoverButton(text: "Removes fonts, colors, and links from rich text and HTML clips, pasting only the text.")
}
Text("Hold \u{21e7} while pasting to switch for a single paste.")
.font(.system(size: 11))
.foregroundStyle(.secondary)
}
Spacer()
Toggle("", isOn: $alwaysPastePlainText)
.labelsHidden()
}
}

Section("Backup") {
LabeledContent("Export history, pinboards, and settings to a JSON file.") {
Button("Export\u{2026}") { exportHistory() }
Expand Down
Loading