diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 84593ed..84974d5 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -15,6 +15,10 @@ "global-shortcut:allow-unregister-all", "macos-permissions:default", "fs:read-files", - "fs:allow-resource-read-recursive" + "fs:allow-resource-read-recursive", + { + "identifier": "fs:scope", + "allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**/*" }] + } ] } diff --git a/src/components/settings/history/HistorySettings.tsx b/src/components/settings/history/HistorySettings.tsx index 50686dc..4de7170 100644 --- a/src/components/settings/history/HistorySettings.tsx +++ b/src/components/settings/history/HistorySettings.tsx @@ -5,9 +5,13 @@ import { Button } from "../../ui/Button"; import { Copy, Star, Check, Trash2, FolderOpen } from "lucide-react"; import { convertFileSrc } from "@tauri-apps/api/core"; import { listen } from "@tauri-apps/api/event"; +import { platform } from "@tauri-apps/plugin-os"; +import { readFile } from "@tauri-apps/plugin-fs"; import { commands, type HistoryEntry } from "@/bindings"; import { formatDateTime } from "@/utils/dateFormat"; +const IS_LINUX = platform() === "linux"; + interface OpenRecordingsButtonProps { onClick: () => void; label: string; @@ -93,7 +97,14 @@ export const HistorySettings: React.FC = () => { try { const result = await commands.getAudioFilePath(fileName); if (result.status === "ok") { - return convertFileSrc(`${result.data}`, "asset"); + if (IS_LINUX) { + const fileData = await readFile(result.data); + const blob = new Blob([fileData], { type: "audio/wav" }); + + return URL.createObjectURL(blob); + } + + return convertFileSrc(result.data, "asset"); } return null; } catch (error) { @@ -222,12 +233,30 @@ const HistoryEntryComponent: React.FC = ({ const [showCopied, setShowCopied] = useState(false); useEffect(() => { + let cancelled = false; + let urlToRevoke: string | null = null; + const loadAudio = async () => { const url = await getAudioUrl(entry.file_name); - setAudioUrl(url); + + if (!cancelled) { + urlToRevoke = url; + setAudioUrl(url); + } else if (url?.startsWith("blob:")) { + URL.revokeObjectURL(url); + } }; + loadAudio(); - }, [entry.file_name, getAudioUrl]); + + return () => { + cancelled = true; + + if (urlToRevoke?.startsWith("blob:")) { + URL.revokeObjectURL(urlToRevoke); + } + }; + }, [entry.file_name]); const handleCopyText = () => { onCopyText(); diff --git a/src/i18n/locales/pt/translation.json b/src/i18n/locales/pt/translation.json index 47397e8..ced57d1 100644 --- a/src/i18n/locales/pt/translation.json +++ b/src/i18n/locales/pt/translation.json @@ -71,7 +71,11 @@ "grant": "Conceder Permissão", "granted": "Concedido", "waiting": "Aguardando...", - "allGranted": "Tudo pronto!" + "allGranted": "Tudo pronto!", + "errors": { + "checkFailed": "Erro ao verificar permissões. Por favor, tente novamente.", + "requestFailed": "Erro ao solicitar permissão. Por favor, tente novamente." + } } }, "modelSelector": {