feat(kon): replace browser clipboard with arboard

- New copy_to_clipboard Tauri command using arboard 3.6
- Replaced all 5 navigator.clipboard.writeText() calls across
  DictationPage, HistoryPage, FilesPage, and viewer with invoke()
- Native clipboard access independent of WebView permissions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jake
2026-03-16 21:48:19 +00:00
parent 292f9716ff
commit 0bbdbc0591
8 changed files with 22 additions and 6 deletions

View File

@@ -33,3 +33,4 @@ serde_json = "1"
# Async runtime (spawn_blocking for inference)
tokio = { version = "1", features = ["rt", "sync"] }
arboard = "3.6.1"

View File

@@ -0,0 +1,12 @@
use arboard::Clipboard;
/// Copy text to the system clipboard via arboard.
#[tauri::command]
pub fn copy_to_clipboard(text: String) -> Result<(), String> {
let mut clipboard =
Clipboard::new().map_err(|e| format!("Clipboard init failed: {e}"))?;
clipboard
.set_text(&text)
.map_err(|e| format!("Clipboard write failed: {e}"))?;
Ok(())
}

View File

@@ -1,4 +1,5 @@
pub mod audio;
pub mod clipboard;
pub mod llm;
pub mod models;
pub mod transcription;

View File

@@ -68,6 +68,8 @@ pub fn run() {
// Windows
commands::windows::open_task_window,
commands::windows::open_viewer_window,
// Clipboard
commands::clipboard::copy_to_clipboard,
// LLM stubs
commands::llm::download_llm_model,
commands::llm::check_llm_model,

View File

@@ -332,7 +332,7 @@
async function finaliseTranscription() {
if (transcript.trim()) {
if (settings.autoCopy) {
navigator.clipboard.writeText(transcript).catch(() => {});
invoke("copy_to_clipboard", { text: transcript }).catch(() => {});
}
// Save audio if enabled — capture path for history replay
@@ -395,7 +395,7 @@
}
function copyAll() {
if (transcript) navigator.clipboard.writeText(transcript).catch(() => {});
if (transcript) invoke("copy_to_clipboard", { text: transcript }).catch(() => {});
}
function clearTranscript() {

View File

@@ -117,7 +117,7 @@
}
function copyAll() {
if (fileTranscript) navigator.clipboard.writeText(fileTranscript);
if (fileTranscript) invoke("copy_to_clipboard", { text: fileTranscript }).catch(() => {});
}
function handleExport(format) {

View File

@@ -46,7 +46,7 @@
}
function copyItem(item) {
navigator.clipboard.writeText(item.text).catch(() => {});
invoke("copy_to_clipboard", { text: item.text }).catch(() => {});
}
function removeItem(item) {

View File

@@ -1,7 +1,7 @@
<script>
import { onMount, onDestroy } from "svelte";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { convertFileSrc } from "@tauri-apps/api/core";
import { convertFileSrc, invoke } from "@tauri-apps/api/core";
import { formatTime, formatDuration } from "$lib/utils/time.js";
import { PLAYBACK_SPEEDS } from "$lib/utils/constants.js";
@@ -193,7 +193,7 @@
function copySegment(idx) {
if (item?.segments?.[idx]) {
navigator.clipboard.writeText(item.segments[idx].text.trim()).catch(() => {});
invoke("copy_to_clipboard", { text: item.segments[idx].text.trim() }).catch(() => {});
}
}