import QtQuick import QtQuick.Controls import QtQuick.Effects import QtQuick.Particles import Qt5Compat.GraphicalEffects ApplicationWindow { id: root width: 460 * (ui ? ui.uiScale : 1.0) height: 180 * (ui ? ui.uiScale : 1.0) visible: true flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool color: "transparent" title: "WhisperVoice" Accessible.name: "WhisperVoice Overlay" FontLoader { id: jetBrainsMono source: "fonts/ttf/JetBrainsMono-Bold.ttf" } property real shimmerPos: -0.5 property real windowOpacity: ui.getSetting("opacity") property real uiScale: Number(ui.getSetting("ui_scale")) // Bind Scale Connections { target: ui function onSettingChanged(key, value) { if (key === "opacity") windowOpacity = value if (key === "ui_scale") uiScale = Number(value) } } // Visibility Logic property bool isActive: ui.isRecording || ui.isProcessing SequentialAnimation { running: !ui.reduceMotion loops: Animation.Infinite PauseAnimation { duration: 3000 } NumberAnimation { target: root; property: "shimmerPos" from: -0.5; to: 1.5; duration: 1500 easing.type: Easing.InOutQuad } } // Container Item { id: mainContainer width: 380 height: 100 anchors.centerIn: parent // Scale & Opacity Transform scale: root.isActive ? root.uiScale : 0.8 opacity: root.isActive ? root.windowOpacity : 0.0 visible: opacity > 0.01 // Optimization // Motion.dev-like Spring Animation Behavior on scale { SpringAnimation { spring: 3; damping: 0.25; epsilon: 0.005 } } Behavior on opacity { NumberAnimation { duration: 300; easing.type: Easing.OutCubic } } // --- SHADOW --- Item { anchors.fill: bgRect layer.enabled: true layer.effect: MultiEffect { shadowEnabled: true shadowColor: "#A0000000" shadowBlur: 0.4 autoPaddingEnabled: true } } // --- CHASSIS VISUALS (Hidden Source) --- Item { id: contentSource anchors.fill: bgRect visible: false // A. Gradient Background Rectangle { anchors.fill: parent gradient: Gradient { GradientStop { position: 0.0; color: "#CC101015" } GradientStop { position: 1.0; color: "#CC050505" } } } // B. Animated Gradient Blobs ShaderEffect { anchors.fill: parent opacity: 0.4 visible: !ui.reduceMotion property real time: 0 fragmentShader: "gradient_blobs.qsb" NumberAnimation on time { from: 0; to: 1000; duration: 100000; loops: Animation.Infinite } } // C. Glow Shader ShaderEffect { anchors.fill: parent opacity: 0.04 visible: !ui.reduceMotion property real time: 0 property real intensity: ui.amplitude fragmentShader: "glow.qsb" NumberAnimation on time { from: 0; to: 100; duration: 10000; loops: Animation.Infinite } } // D. Particles ParticleSystem { id: particles anchors.fill: parent running: !ui.reduceMotion ItemParticle { system: particles delegate: Rectangle { width: 2; height: 2; radius: 1; color: "#10ffffff" } } Emitter { anchors.fill: parent; emitRate: 15; lifeSpan: 4000; size: 4; sizeVariation: 2 velocity: AngleDirection { angle: -90; angleVariation: 180; magnitude: 5 } acceleration: PointDirection { y: -2 } } } // E. Shimmer Rectangle { width: parent.width * 0.4; height: parent.height * 2.5 rotation: 25; anchors.centerIn: parent x: (root.shimmerPos * parent.width * 2) - width; y: -height/4 gradient: Gradient { orientation: Gradient.Horizontal GradientStop { position: 0.0; color: "transparent" } GradientStop { position: 0.5; color: "#15ffffff" } GradientStop { position: 1.0; color: "transparent" } } opacity: 0.8 } // F. CRT Shader Effect (Overlay on chassis ONLY) ShaderEffect { anchors.fill: parent visible: !ui.reduceMotion property real time: 0 fragmentShader: "crt.qsb" NumberAnimation on time { from: 0; to: 100; duration: 5000; loops: Animation.Infinite } } } // --- MASK --- Rectangle { id: contentMask anchors.fill: bgRect radius: height / 2 visible: false; color: "white" smooth: true; antialiasing: true } // --- COMPOSITED CHASSIS --- OpacityMask { anchors.fill: bgRect source: contentSource maskSource: contentMask } // --- BORDER & INTERACTION --- Rectangle { id: bgRect anchors.fill: parent radius: height / 2 color: "transparent" border.width: 1 border.color: Qt.rgba(1, 1, 1, 0.22) MouseArea { anchors.fill: parent; hoverEnabled: true cursorShape: pressed ? Qt.ClosedHandCursor : Qt.PointingHandCursor onPressed: root.startSystemMove() } Rectangle { anchors.fill: parent anchors.margins: ui.isRecording ? -(ui.amplitude * 3) : 0 radius: parent.radius color: "transparent" border.width: ui.isRecording ? 3 : 1.5 border.color: ui.isRecording ? "#A0ff4b4b" : "#6000f2ff" Behavior on anchors.margins { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } Behavior on border.width { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } SequentialAnimation on border.color { running: ui.isRecording && !ui.reduceMotion loops: Animation.Infinite ColorAnimation { from: "#A0ff4b4b"; to: "#C0ff6b6b"; duration: 800 } ColorAnimation { from: "#C0ff6b6b"; to: "#A0ff4b4b"; duration: 800 } } } } // --- MICROPHONE ICON (Enhanced) --- Item { id: micContainer width: 80; height: 80 anchors.left: parent.left anchors.leftMargin: 10 anchors.verticalCenter: parent.verticalCenter activeFocusOnTab: true Accessible.name: ui.isRecording ? "Stop recording" : "Start recording" Accessible.role: Accessible.Button Keys.onReturnPressed: ui.toggleRecordingRequested() Keys.onSpacePressed: ui.toggleRecordingRequested() // Make entire button scale with amplitude scale: ui.isRecording ? (1.0 + ui.amplitude * 0.12) : 1.0 Behavior on scale { NumberAnimation { duration: 150; easing.type: Easing.OutCubic } } // MouseArea at parent level to avoid layer blocking MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor onClicked: { console.log("Microphone clicked! Emitting signal...") ui.toggleRecordingRequested() } } layer.enabled: true layer.effect: MultiEffect { shadowEnabled: true shadowColor: ui.isRecording ? "#FF00a0ff" : "#FF00f2ff" shadowBlur: 1.0 shadowOpacity: ui.isRecording ? 1.0 : 0.5 } Rectangle { id: micCircle anchors.fill: parent radius: width / 2 gradient: Gradient { GradientStop { position: 0.0; color: "#40ffffff" } GradientStop { position: 1.0; color: "#10ffffff" } } border.width: 2; border.color: "#60ffffff" SequentialAnimation on scale { running: ui.isRecording && !ui.reduceMotion loops: Animation.Infinite NumberAnimation { from: 1.0; to: 1.08; duration: 600; easing.type: Easing.InOutQuad } NumberAnimation { from: 1.08; to: 1.0; duration: 600; easing.type: Easing.InOutQuad } } Image { id: micIcon anchors.centerIn: parent width: 40 height: 40 source: "microphone.svg" smooth: true antialiasing: true mipmap: true fillMode: Image.PreserveAspectFit } } // Focus ring Rectangle { anchors.fill: micCircle anchors.margins: -4 radius: width / 2 color: "transparent" border.width: 2 border.color: "#B794F6" // SettingsStyle.accent equivalent visible: micContainer.activeFocus } } // --- RAINBOW WAVEFORM (Shader) --- Item { id: waveformContainer anchors.left: micContainer.right anchors.leftMargin: 10 anchors.right: parent.right anchors.rightMargin: 80 anchors.verticalCenter: parent.verticalCenter height: 90 ShaderEffect { anchors.fill: parent visible: !ui.reduceMotion property real time: 0 property real amplitude: ui.amplitude fragmentShader: "rainbow_wave.qsb" NumberAnimation on time { from: 0; to: 1000; duration: 100000; loops: Animation.Infinite } layer.enabled: true layer.effect: MultiEffect { shadowEnabled: true shadowColor: Qt.hsla((Date.now() / 100) % 1.0, 1.0, 0.6, 1.0) shadowBlur: 1.0; shadowOpacity: 1.0 } } } // --- RECORDING TIMER --- Item { id: recordingTimerContainer anchors.right: parent.right anchors.rightMargin: 20 anchors.verticalCenter: parent.verticalCenter width: 60; height: 30 property int recordingSeconds: 0 Connections { target: ui function onIsRecordingChanged() { if (!ui.isRecording) recordingTimerContainer.recordingSeconds = 0 } } Timer { interval: 1000; running: ui.isRecording; repeat: true onTriggered: recordingTimerContainer.recordingSeconds++ } // Triple-layer glow for REALLY strong effect layer.enabled: true layer.effect: MultiEffect { shadowEnabled: true shadowColor: ui.isRecording ? "#FFff0000" : "#FFffffff" shadowBlur: 1.0 shadowOpacity: 1.0 shadowHorizontalOffset: 0 shadowVerticalOffset: 0 } Item { anchors.fill: parent layer.enabled: true layer.effect: MultiEffect { shadowEnabled: true shadowColor: ui.isRecording ? "#FFff3030" : "#FFe0e0e5" shadowBlur: 0.8 shadowOpacity: 1.0 } Text { anchors.centerIn: parent text: { var mins = Math.floor(recordingTimerContainer.recordingSeconds / 60) var secs = recordingTimerContainer.recordingSeconds % 60 return (mins < 10 ? "0" : "") + mins + ":" + (secs < 10 ? "0" : "") + secs } color: ui.isRecording ? "#ffffff" : "#ffffff" font.family: jetBrainsMono.name; font.pixelSize: 16; font.bold: true; font.letterSpacing: 2 style: Text.Outline styleColor: ui.isRecording ? "#ff0000" : "#808085" Accessible.role: Accessible.StaticText Accessible.name: "Recording time: " + text SequentialAnimation on opacity { running: ui.isRecording && !ui.reduceMotion; loops: Animation.Infinite NumberAnimation { from: 1.0; to: 0.7; duration: 800 } NumberAnimation { from: 0.7; to: 1.0; duration: 800 } } } } } } }