<script lang="ts">
|
import { onMount } from 'svelte'
|
import { Events, Call } from '@wailsio/runtime'
|
import FloatingIndicator from './components/indicator/FloatingIndicator.svelte'
|
import SettingsWindow from './components/settings/SettingsWindow.svelte'
|
import OnboardingView from './components/onboarding/OnboardingView.svelte'
|
import UpdateDialog from './components/update/UpdateDialog.svelte'
|
import { engineStatus } from './lib/stores/app'
|
import { indicatorVisible, indicatorStatus, indicatorVolume, hotkeyName } from './lib/stores/indicator'
|
import { updateAvailable, type UpdateInfo } from './lib/stores/update'
|
import { deviceName, engineHardwareInfo } from './lib/stores/app'
|
import { setLocale, localeRevision } from './lib/i18n'
|
import { languageMode, languageID, effectiveLanguageID, uiLocale } from './lib/stores/config'
|
import type { UILocale } from './lib/stores/config'
|
|
let isIndicatorRoute = $state(window.location.hash === '#/indicator')
|
let showUpdateDialog = $state(false)
|
let languageReady = $state(false)
|
let showOnboarding = $state(false)
|
|
onMount(() => {
|
Call.ByName('voicesnap/services.ConfigService.GetLanguageSettings').then((settings: any) => {
|
applyLanguageSettings(settings)
|
}).catch(() => {
|
languageReady = true
|
})
|
|
Events.On('indicator:show', (ev: any) => {
|
indicatorVisible.set(true)
|
if (ev?.data?.status) {
|
indicatorStatus.set(ev.data.status)
|
}
|
})
|
|
Events.On('indicator:hide', () => {
|
indicatorVisible.set(false)
|
})
|
|
Events.On('indicator:status', (ev: any) => {
|
const data = ev?.data
|
if (data?.status) {
|
indicatorStatus.set(data.status)
|
}
|
if (data?.hotkeyName) {
|
hotkeyName.set(data.hotkeyName)
|
}
|
})
|
|
Events.On('indicator:volume', (ev: any) => {
|
indicatorVolume.set(ev?.data ?? 0)
|
})
|
|
Events.On('engine:status', (ev: any) => {
|
const data = ev?.data
|
if (data?.status) {
|
engineStatus.set(data.status as any)
|
if (data.status === 'ready') {
|
showOnboarding = false
|
}
|
}
|
if (data?.hardwareInfo) {
|
engineHardwareInfo.set(data.hardwareInfo)
|
}
|
})
|
|
Events.On('device:changed', (ev: any) => {
|
if (ev?.data?.name) {
|
deviceName.set(ev.data.name)
|
}
|
})
|
|
Events.On('update:available', (ev: any) => {
|
const data = ev?.data as UpdateInfo
|
updateAvailable.set(data)
|
showUpdateDialog = true
|
})
|
|
window.addEventListener('hashchange', () => {
|
isIndicatorRoute = window.location.hash === '#/indicator'
|
})
|
|
// Query engine status on mount (events emitted before frontend load are lost)
|
Call.ByName('voicesnap/services.EngineService.GetStatus').then((data: any) => {
|
if (data?.status) {
|
engineStatus.set(data.status as any)
|
if (data.status === 'ready') {
|
showOnboarding = false
|
}
|
}
|
if (data?.hardwareInfo) {
|
engineHardwareInfo.set(data.hardwareInfo)
|
}
|
})
|
|
refreshCurrentModelAvailability()
|
|
// Load actual hotkey name from backend (store default is generic "Ctrl")
|
Call.ByName('voicesnap/services.HotkeyService.GetHotkeyName').then((name: any) => {
|
if (name) {
|
hotkeyName.set(name)
|
}
|
})
|
})
|
|
function applyLanguageSettings(settings: any) {
|
const mode = settings?.languageMode === 'manual' ? 'manual' : 'auto'
|
const configured = typeof settings?.languageID === 'string' && settings.languageID ? settings.languageID : 'zh-CN'
|
const effective = typeof settings?.effectiveLanguageID === 'string' && settings.effectiveLanguageID ? settings.effectiveLanguageID : configured
|
const locale = typeof settings?.uiLocale === 'string' && settings.uiLocale ? settings.uiLocale : 'en'
|
languageMode.set(mode)
|
languageID.set(configured)
|
effectiveLanguageID.set(effective)
|
uiLocale.set(locale as UILocale)
|
setLocale(locale)
|
languageReady = true
|
}
|
|
async function refreshCurrentModelAvailability() {
|
try {
|
const current: any = await Call.ByName('voicesnap/services.EngineService.GetCurrentModelStatus')
|
if (!current?.installed) {
|
const hasAnyInstalled: any = await Call.ByName('voicesnap/services.EngineService.HasAnyInstalledModel')
|
showOnboarding = !hasAnyInstalled
|
if (!hasAnyInstalled) {
|
engineStatus.set('need_model')
|
}
|
} else {
|
showOnboarding = false
|
}
|
} catch {
|
try {
|
const exists: any = await Call.ByName('voicesnap/services.EngineService.ModelExists')
|
if (!exists) {
|
const hasAnyInstalled: any = await Call.ByName('voicesnap/services.EngineService.HasAnyInstalledModel')
|
.catch(() => false)
|
showOnboarding = !hasAnyInstalled
|
if (!hasAnyInstalled) {
|
engineStatus.set('need_model')
|
}
|
}
|
} catch {}
|
}
|
}
|
</script>
|
|
{#if isIndicatorRoute}
|
<FloatingIndicator />
|
{:else}
|
{#if languageReady}
|
{#key $localeRevision}
|
{#if showOnboarding && $engineStatus === 'need_model'}
|
<OnboardingView />
|
{:else}
|
<SettingsWindow />
|
{/if}
|
{/key}
|
{/if}
|
|
{#if showUpdateDialog && $updateAvailable}
|
<UpdateDialog
|
info={$updateAvailable}
|
onclose={() => { showUpdateDialog = false }}
|
/>
|
{/if}
|
{/if}
|