feat: integrate Tauri v2 with Android widget and voice assistant

- Add Tauri v2 shell (Cargo, tauri.conf.json, capabilities, plugins)
- Migrate all fetch() calls to apiFetch() for Tauri-aware HTTP
- Migrate WebSocket endpoints to resolveEndpoints() for dynamic URLs
- Add ServerConfigDialog for remote server URL configuration
- Add tauri.ts lib with isTauri detection, apiFetch wrapper, plugin helpers
- Add server-config Pinia store with persistence via plugin-store
- Conditional PWA (disabled in Tauri builds)
- Android: home screen transcript widget (last 5 messages, 30s refresh)
- Android: voice command / share activity (SpeechRecognizer + WebSocket)
- Android: signed release APK with auto-copy to installers/
- Remove stale frontend/src-tauri directory
This commit is contained in:
2026-02-23 15:33:43 -06:00
parent 6dc0c5ff6f
commit e1aa8b1bdb
108 changed files with 8155 additions and 151 deletions

View File

@@ -4,7 +4,8 @@
*/
import { ref } from 'vue'
import { endpoints } from '../config/endpoints'
import { resolveEndpoints } from '../config/endpoints'
import { apiFetch } from '@/lib/tauri'
export type WhisperStatus = 'offline' | 'loading' | 'ready'
@@ -28,8 +29,8 @@ const listeners = new Set<TranscriptionCallback>()
function connect() {
if (socket?.readyState === WebSocket.OPEN || socket?.readyState === WebSocket.CONNECTING) return
console.log('[WhisperSocket] Connecting to', endpoints.whisper)
socket = new WebSocket(endpoints.whisper)
console.log('[WhisperSocket] Connecting to', resolveEndpoints().whisper)
socket = new WebSocket(resolveEndpoints().whisper)
const timeout = setTimeout(() => {
if (socket && socket.readyState !== WebSocket.OPEN) {
@@ -86,7 +87,7 @@ function scheduleReconnect() {
async function checkStatusAndConnect() {
try {
const res = await fetch('/api/whisper/status')
const res = await apiFetch('/api/whisper/status')
const data = await res.json()
if (data.running) {
connect()
@@ -148,7 +149,7 @@ export async function reconnect() {
}
try {
const res = await fetch('/api/whisper/toggle', { method: 'POST' })
const res = await apiFetch('/api/whisper/toggle', { method: 'POST' })
const data = await res.json()
if (data.running) {
connect()
@@ -158,7 +159,7 @@ export async function reconnect() {
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 2000))
try {
const s = await fetch('/api/whisper/status')
const s = await apiFetch('/api/whisper/status')
const d = await s.json()
if (d.running) {
connect()