Ariver
2026-05-18 4ffa57abab0370b5bd8485a51bb333b369682aea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<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'
 
  let isIndicatorRoute = $state(window.location.hash === '#/indicator')
  let showUpdateDialog = $state(false)
 
  onMount(() => {
    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?.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.ModelExists').then((exists: any) => {
      if (!exists) {
        engineStatus.set('need_model')
      }
    })
 
    // 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)
      }
    })
  })
</script>
 
{#if isIndicatorRoute}
  <FloatingIndicator />
{:else}
  {#if $engineStatus === 'need_model'}
    <OnboardingView />
  {:else}
    <SettingsWindow />
  {/if}
 
  {#if showUpdateDialog && $updateAvailable}
    <UpdateDialog
      info={$updateAvailable}
      onclose={() => { showUpdateDialog = false }}
    />
  {/if}
{/if}