diff --git a/app/components/live-atc/cockpit/BugReportDialog.vue b/app/components/live-atc/cockpit/BugReportDialog.vue new file mode 100644 index 0000000..e6dcabe --- /dev/null +++ b/app/components/live-atc/cockpit/BugReportDialog.vue @@ -0,0 +1,154 @@ + + + diff --git a/app/components/live-atc/cockpit/DebugPanel.vue b/app/components/live-atc/cockpit/DebugPanel.vue new file mode 100644 index 0000000..e486b26 --- /dev/null +++ b/app/components/live-atc/cockpit/DebugPanel.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/app/components/live-atc/cockpit/FlightInfoSheet.vue b/app/components/live-atc/cockpit/FlightInfoSheet.vue new file mode 100644 index 0000000..1aae952 --- /dev/null +++ b/app/components/live-atc/cockpit/FlightInfoSheet.vue @@ -0,0 +1,98 @@ + + + diff --git a/app/components/live-atc/cockpit/SettingsSheet.vue b/app/components/live-atc/cockpit/SettingsSheet.vue new file mode 100644 index 0000000..8260d42 --- /dev/null +++ b/app/components/live-atc/cockpit/SettingsSheet.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/app/composables/useDebugSimulation.ts b/app/composables/useDebugSimulation.ts index 62635b3..9ec17da 100644 --- a/app/composables/useDebugSimulation.ts +++ b/app/composables/useDebugSimulation.ts @@ -25,8 +25,6 @@ export function useDebugSimulation( } = engine const { setLastTransmission, clearLog, startDemoFlight } = deps - const debugMode = ref(true) - const simulationRunning = ref(false) const simulationTrace = ref([]) const simulationError = ref('') @@ -297,7 +295,6 @@ export function useDebugSimulation( simulationTrace.value = [] simulationError.value = '' recordedAtcStates.clear() - debugMode.value = true try { simulationTrace.value.push({ @@ -418,7 +415,6 @@ export function useDebugSimulation( } return { - debugMode, simulationRunning, simulationTrace, simulationError, diff --git a/app/pages/live-atc.vue b/app/pages/live-atc.vue index 328c00c..80b7475 100644 --- a/app/pages/live-atc.vue +++ b/app/pages/live-atc.vue @@ -488,564 +488,41 @@ - - + :engine="engine" + :session-label="sessionLabel" + :set-last-transmission="setLastTransmission" + :clear-log="clearLog" + :start-demo-flight="startDemoFlight" + /> - - - - - - - - - -
- - Flight info -
- -
- -
-
-

Active flight

-

{{ flightContext.callsign || 'N/A' }}

-

{{ flightContext.dep }} → {{ flightContext.dest }}

-
-
- - {{ flags.in_air ? 'IN-AIR' : 'GROUND' }} - -
- - EMERG - - - {{ flags.current_unit }} - -
-
-
- -
-
-

Stand

-

{{ vars.stand }}

-
-
-

Runway

-

{{ vars.runway }}

-
-
-

Squawk

-

{{ vars.squawk }}

-
-
-

SID

-

{{ vars.sid }}

-
-
- -
-
-

{{ flags.radio_checks_done || 0 }}

-

Radio Checks

-
-
-

{{ flags.off_schema_count || 0 }}

-

Off-Schema

-
-
-

{{ log.length }}

-

Transmissions

-
-
- - - Select new flight - -
-
-
- - - - - -
- - Settings -
- -
- -
- -
- - - -
-
- -
-
- - {{ speechSpeedLabel }} -
- -
- -
- - - - -
- -
-
-

Voice input

-

- Pre-recording keeps the mic listening in the background so the start of your transmission isn't clipped. -

-
- -
-
- - {{ prerecSeconds.toFixed(1) }}s -
- -
-
-
-
-
- - - - - - - Fehler melden - - -
- -

Danke! Bug Report wurde gesendet.

-
- -
- - - Abbrechen - - - Bug melden - - -
-
+ @@ -1134,8 +611,11 @@ import PttPad from '~/components/live-atc/cockpit/PttPad.vue' import { useAtisPlayback } from '~/composables/useAtisPlayback' import { usePttRecording } from '~/composables/usePttRecording' import { useBugReport } from '~/composables/useBugReport' -import { useDebugSimulation } from '~/composables/useDebugSimulation' import { useSimBridgeSync } from '~/composables/useSimBridgeSync' +import FlightInfoSheet from '~/components/live-atc/cockpit/FlightInfoSheet.vue' +import SettingsSheet from '~/components/live-atc/cockpit/SettingsSheet.vue' +import BugReportDialog from '~/components/live-atc/cockpit/BugReportDialog.vue' +import DebugPanel from '~/components/live-atc/cockpit/DebugPanel.vue' import { CHAIN_GROUPS, DRILL_SCENARIOS } from '../../shared/constants/scenarios' import FlightSourceStep from '~/components/live-atc/FlightSourceStep.vue' import FlightSelectStep from '~/components/live-atc/FlightSelectStep.vue' @@ -1287,27 +767,10 @@ const radioEffectsEnabled = ref(true) const readbackEnabled = ref(false) // ── Bug Report ─────────────────────────────────────────────────────────────── -const { - showBugReportDialog, - bugReportComment, - bugReportContact, - bugReportScreenshot, - bugReportArrows, - bugReportLoading, - bugReportCapturing, - bugReportError, - bugReportSuccess, - bugReportCanvasRef, - bugReportImgRef, - setupAnnotationCanvas, - onCanvasMouseDown, - onCanvasMouseMove, - onCanvasMouseUp, - onCanvasMouseLeave, - undoLastArrow, - openBugReport, - submitBugReport, -} = useBugReport(engine, { activeScenario }) +// Owned here rather than by the dialog: the HUD button starts the screenshot +// capture before the dialog ever renders. The dialog gets the whole handle. +const bugReport = useBugReport(engine, { activeScenario }) +const { bugReportCapturing, openBugReport } = bugReport // Layout / view state const activeTab = ref<'funk' | 'log'>('funk') @@ -1321,9 +784,11 @@ const showExpectedComm = computed( // Overlays / sheets opened from HUD controls const showFlightSheet = ref(false) const showSettingsSheet = ref(false) -const showDebugDrawer = ref(false) const hudStatusMenu = ref(false) +/** The one gate for developer tooling: DebugPanel is not mounted while this is off. */ +const debugMode = ref(true) + type PmTab = { id: 'funk' | 'log' label: string @@ -1595,25 +1060,6 @@ const { restoreBugReportState, } = session -// Debug drawer: scripted simulation + decision-trace inspectors. -const { - debugMode, - simulationRunning, - simulationTrace, - simulationError, - simulationStepCount, - completedPilotSteps, - timelineSteps, - timelineUsedFallback, - traceAutoSelection, - traceFallback, - debugState, - debugNextStates, - describeElimination, - formatTracePayload, - runFullSimulation, -} = useDebugSimulation(engine, { setLastTransmission, clearLog, startDemoFlight }) - onUnmounted(() => { stopAtisLoop() stopPrerecCapture() @@ -2263,110 +1709,6 @@ onUnmounted(() => { .pm-log-tab { display: none !important; } - /* No bottom nav on desktop: drop the FAB back down to the corner. */ - .debug-fab { - bottom: calc(env(safe-area-inset-bottom) + 16px); - } - .debug-drawer { - bottom: calc(env(safe-area-inset-bottom) + 16px); - } } -/* ========================================================================= - * Debug FAB + drawer (left, non-blocking, can stay open in parallel) - * ======================================================================= */ -.debug-fab { - position: fixed; - left: 16px; - /* Clear the mobile bottom nav (~64px) by default; desktop overrides below. */ - bottom: calc(env(safe-area-inset-bottom) + 78px); - z-index: 60; - display: inline-flex; - align-items: center; - justify-content: center; - width: 48px; - height: 48px; - border-radius: 16px; - border: 1px solid rgba(249, 115, 22, 0.45); - background: rgba(249, 115, 22, 0.16); - color: #fdba74; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); - cursor: pointer; - transition: background 160ms ease, color 160ms ease, transform 160ms ease, border-color 160ms ease; -} -.debug-fab:hover { - background: rgba(249, 115, 22, 0.26); - color: #fed7aa; - transform: translateY(-1px); -} -.debug-fab.is-open { - background: rgba(249, 115, 22, 0.35); - border-color: rgba(249, 115, 22, 0.7); - color: #fff; -} - -.debug-drawer { - position: fixed; - top: 72px; - left: 12px; - bottom: calc(env(safe-area-inset-bottom) + 76px); - width: min(420px, calc(100vw - 24px)); - z-index: 55; - display: flex; - flex-direction: column; - border-radius: 18px; - border: 1px solid rgba(255, 255, 255, 0.12); - background: rgba(8, 13, 24, 0.96); - box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6); - backdrop-filter: blur(14px); - pointer-events: auto; -} -.debug-drawer-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - padding: 12px 14px; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); -} -.debug-drawer-close { - display: inline-flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - border-radius: 8px; - color: rgba(255, 255, 255, 0.6); - background: transparent; - transition: background 120ms ease, color 120ms ease; -} -.debug-drawer-close:hover { - background: rgba(255, 255, 255, 0.08); - color: #fff; -} -.debug-drawer-body { - padding: 12px 14px; - overflow-y: auto; - -webkit-overflow-scrolling: touch; -} - -.debug-drawer-enter-active, -.debug-drawer-leave-active { - transition: transform 220ms ease, opacity 220ms ease; -} -.debug-drawer-enter-from, -.debug-drawer-leave-to { - transform: translateX(-12px); - opacity: 0; -} - -@media (max-width: 640px) { - .debug-drawer { - top: 64px; - left: 8px; - right: 8px; - width: auto; - bottom: calc(env(safe-area-inset-bottom) + 84px); - } -}