feat: Samsung lock screen face widget, voice assistant services, PiP mode and gitignore installers
Add Samsung proprietary Face Widget (lock screen/AOD) with terminal status display. Add voice interaction services (AgentVoiceInteractionService, RecognitionService) for digital assistant registration. Add PiP mode with voice/expand actions. Add session-state proxy, voice transcript routes, window controls component. Ignore installers/ directory.
This commit is contained in:
@@ -11,6 +11,7 @@ import TerminalFabStack from './components/transcript-debug/TerminalFabStack.vue
|
||||
import PwaInstallBanner from './components/PwaInstallBanner.vue'
|
||||
import HooksApprovalModal from './components/HooksApprovalModal.vue'
|
||||
import ServerConfigDialog from './components/ServerConfigDialog.vue'
|
||||
import WindowControls from './components/WindowControls.vue'
|
||||
import { useGlobalApproval } from './composables/useGlobalApproval'
|
||||
import { initWebMCP, getWebMCP } from './services/webmcp'
|
||||
import { initTorch, destroyTorch } from './services/torch'
|
||||
@@ -20,7 +21,7 @@ import { setResponseControls } from './services/tools/handlers/responseHandlers'
|
||||
import { useCanvasStore } from './stores/canvas'
|
||||
import { useProjectCanvasStore } from './stores/projectCanvas'
|
||||
import { useSessionState } from './stores/session-state'
|
||||
import { isTauri } from './lib/tauri'
|
||||
import { isTauri, isMobileTauri, getTauriNotification } from './lib/tauri'
|
||||
import { useServerConfig } from './stores/server-config'
|
||||
|
||||
const route = useRoute()
|
||||
@@ -35,7 +36,7 @@ const showVoice = ref(false)
|
||||
const showTranscriptDebug = ref(false)
|
||||
const showDebugConsole = ref(false)
|
||||
const toolbarVisible = ref(true)
|
||||
const forceWco = ref(false)
|
||||
const forceWco = ref(isTauri && !isMobileTauri())
|
||||
const debugLogs = ref<Array<{ type: string; message: string; time: string }>>([])
|
||||
|
||||
// Intercept console.log for debug panel
|
||||
@@ -222,6 +223,31 @@ function syncThemeColor() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// Bridge for Android widget navigation (called from MainActivity via evaluateJavascript)
|
||||
;(window as any).__WIDGET_NAVIGATE__ = (route: string) => {
|
||||
router.push(route)
|
||||
return true
|
||||
}
|
||||
|
||||
// Bridge for Android voice assistant — opens FloatingTranscriptDebug on the target terminal
|
||||
;(window as any).__VOICE_OPEN_TERMINAL__ = (ephemeralSessionId: string) => {
|
||||
const entry = sessionState.terminalRegistry.find(
|
||||
t => t.ephemeralSessionId === ephemeralSessionId
|
||||
)
|
||||
if (entry && transcriptDebugRef.value) {
|
||||
transcriptDebugRef.value.switchToTerminal(entry.transcriptSessionId)
|
||||
showTranscriptDebug.value = true
|
||||
return true
|
||||
}
|
||||
// Fallback: open on first terminal
|
||||
if (sessionState.terminalRegistry.length && transcriptDebugRef.value) {
|
||||
transcriptDebugRef.value.switchToTerminal(sessionState.terminalRegistry[0].transcriptSessionId)
|
||||
showTranscriptDebug.value = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Sync Windows titlebar color with CSS variable
|
||||
syncThemeColor()
|
||||
|
||||
@@ -287,6 +313,34 @@ onMounted(async () => {
|
||||
await torchReady
|
||||
})
|
||||
|
||||
async function sendTestNotification() {
|
||||
const title = 'Agent UI'
|
||||
const body = 'Test notification from Agent UI — all platforms!'
|
||||
|
||||
if (isTauri) {
|
||||
try {
|
||||
const { isPermissionGranted, requestPermission, sendNotification } = await getTauriNotification()
|
||||
let granted = await isPermissionGranted()
|
||||
if (!granted) {
|
||||
const perm = await requestPermission()
|
||||
granted = perm === 'granted'
|
||||
}
|
||||
if (granted) {
|
||||
sendNotification({ title, body })
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[Notification] Tauri plugin failed:', e)
|
||||
}
|
||||
} else if ('Notification' in window) {
|
||||
if (Notification.permission === 'granted') {
|
||||
new Notification(title, { body })
|
||||
} else if (Notification.permission !== 'denied') {
|
||||
const perm = await Notification.requestPermission()
|
||||
if (perm === 'granted') new Notification(title, { body })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('mousemove', trackMouse)
|
||||
document.removeEventListener('keydown', handleGlobalKeydown)
|
||||
@@ -367,6 +421,12 @@ if (serverConfig) {
|
||||
</svg>
|
||||
<span v-if="totalPending > 0" class="approval-count">{{ totalPending }}</span>
|
||||
</button>
|
||||
<button class="refresh-btn" @click="sendTestNotification" title="Test notification">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
|
||||
<path d="M13.73 21a2 2 0 0 1-3.46 0"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="refresh-btn" @click="hardRefresh" title="Hard refresh (Ctrl+F5)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/>
|
||||
@@ -375,6 +435,7 @@ if (serverConfig) {
|
||||
</button>
|
||||
<span class="wco-dot" :class="{ on: forceWco }" @click="forceWco = !forceWco"></span>
|
||||
<TorchButton />
|
||||
<WindowControls />
|
||||
</div>
|
||||
</header>
|
||||
<main class="app-main">
|
||||
@@ -503,9 +564,9 @@ if (serverConfig) {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 1rem;
|
||||
padding-top: calc(0.5rem + env(safe-area-inset-top, 0px));
|
||||
padding-left: calc(1rem + env(safe-area-inset-left, 0px));
|
||||
padding-right: calc(1rem + env(safe-area-inset-right, 0px));
|
||||
padding-top: calc(0.5rem + var(--sat, env(safe-area-inset-top, 0px)));
|
||||
padding-left: calc(1rem + var(--sal, env(safe-area-inset-left, 0px)));
|
||||
padding-right: calc(1rem + var(--sar, env(safe-area-inset-right, 0px)));
|
||||
background: var(--bg-primary);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
@@ -537,6 +598,7 @@ if (serverConfig) {
|
||||
min-height: 32px;
|
||||
max-height: 32px;
|
||||
padding: 0 0.5rem;
|
||||
padding-right: 0;
|
||||
border-bottom: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user