Remove unused files: old UI, build scripts, fonts, test files

Remove old widget-based Python UI (replaced by QML), unused build
scripts, NL/variable/webfont variants, old shaders, PNG icons
(replaced by SVGs), and standalone test files. Add build.bat and
build.spec for the bootstrapper build system.
This commit is contained in:
Your Name
2026-02-18 22:25:04 +02:00
parent d509eb5efb
commit 02ef33023d
62 changed files with 131 additions and 1290 deletions

View File

@@ -1,210 +0,0 @@
"""
Modern Components Library.
==========================
Contains custom-painted widgets that move beyond the standard 'amateur' Qt look.
Implements smooth animations, hardware acceleration, and glassmorphism.
"""
from PySide6.QtWidgets import (
QPushButton, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QGraphicsDropShadowEffect, QFrame, QAbstractButton
)
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve, Property, QRect, QPoint, Signal, Slot
from PySide6.QtGui import QPainter, QColor, QBrush, QPen, QLinearGradient, QFont
from src.ui.styles import Theme
class GlassButton(QPushButton):
"""A premium button with gradient hover effects and smooth scaling."""
def __init__(self, text, parent=None, accent_color=Theme.ACCENT_CYAN):
super().__init__(text, parent)
self.accent = QColor(accent_color)
self.setCursor(Qt.PointingHandCursor)
self.setFixedHeight(40)
self._hover_opacity = 0.0
self.setStyleSheet(f"""
QPushButton {{
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid {Theme.BORDER_SUBTLE};
color: {Theme.TEXT_SECONDARY};
border-radius: 8px;
padding: 0 20px;
font-size: 13px;
font-weight: 600;
}}
""")
# Hover Animation
self.anim = QPropertyAnimation(self, b"hover_opacity")
self.anim.setDuration(200)
self.anim.setStartValue(0.0)
self.anim.setEndValue(1.0)
self.anim.setEasingCurve(QEasingCurve.OutCubic)
@Property(float)
def hover_opacity(self): return self._hover_opacity
@hover_opacity.setter
def hover_opacity(self, value):
self._hover_opacity = value
self.update()
def enterEvent(self, event):
self.anim.setDirection(QPropertyAnimation.Forward)
self.anim.start()
super().enterEvent(event)
def leaveEvent(self, event):
self.anim.setDirection(QPropertyAnimation.Backward)
self.anim.start()
super().leaveEvent(event)
def paintEvent(self, event):
"""Custom paint for the glow effect."""
super().paintEvent(event)
if self._hover_opacity > 0:
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Subtle Glow Border
color = QColor(self.accent)
color.setAlphaF(self._hover_opacity * 0.5)
painter.setPen(QPen(color, 1.5))
painter.setBrush(Qt.NoBrush)
painter.drawRoundedRect(self.rect().adjusted(1,1,-1,-1), 8, 8)
# Text Glow color shift
self.setStyleSheet(f"""
QPushButton {{
background-color: rgba(255, 255, 255, {0.05 + (self._hover_opacity * 0.05)});
border: 1px solid {Theme.BORDER_SUBTLE};
color: white;
border-radius: 8px;
padding: 0 20px;
font-size: 13px;
font-weight: 600;
}}
""")
class ModernSwitch(QAbstractButton):
"""A sleek iOS-style toggle switch."""
def __init__(self, parent=None, active_color=Theme.ACCENT_GREEN):
super().__init__(parent)
self.setCheckable(True)
self.setFixedSize(44, 24)
self._thumb_pos = 3.0
self.active_color = QColor(active_color)
self.anim = QPropertyAnimation(self, b"thumb_pos")
self.anim.setDuration(200)
self.anim.setEasingCurve(QEasingCurve.InOutCubic)
@Property(float)
def thumb_pos(self): return self._thumb_pos
@thumb_pos.setter
def thumb_pos(self, value):
self._thumb_pos = value
self.update()
def nextCheckState(self):
super().nextCheckState()
self.anim.stop()
if self.isChecked():
self.anim.setEndValue(23.0)
else:
self.anim.setEndValue(3.0)
self.anim.start()
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Background
bg_color = QColor("#2d2d3d")
if self.isChecked():
bg_color = self.active_color
painter.setBrush(bg_color)
painter.setPen(Qt.NoPen)
painter.drawRoundedRect(self.rect(), 12, 12)
# Thumb
painter.setBrush(Qt.white)
painter.drawEllipse(QPoint(self._thumb_pos + 9, 12), 9, 9)
class ModernFrame(QFrame):
"""A base frame with rounded corners and a shadow."""
def __init__(self, parent=None):
super().__init__(parent)
self.setObjectName("premiumFrame")
self.setStyleSheet(f"""
#premiumFrame {{
background-color: {Theme.BG_CARD};
border: 1px solid {Theme.BORDER_SUBTLE};
border-radius: 12px;
}}
""")
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(25)
self.shadow.setXOffset(0)
self.shadow.setYOffset(8)
self.shadow.setColor(QColor(0, 0, 0, 180))
self.setGraphicsEffect(self.shadow)
from PySide6.QtWidgets import (
QPushButton, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QGraphicsDropShadowEffect, QFrame, QAbstractButton, QSlider
)
class ModernSlider(QSlider):
"""A custom painted modern slider with a glowing knob."""
def __init__(self, orientation=Qt.Horizontal, parent=None):
super().__init__(orientation, parent)
self.setStyleSheet(f"""
QSlider::groove:horizontal {{
border: 1px solid {Theme.BG_DARK};
height: 4px;
background: {Theme.BG_DARK};
margin: 2px 0;
border-radius: 2px;
}}
QSlider::handle:horizontal {{
background: {Theme.ACCENT_CYAN};
border: 2px solid white;
width: 16px;
height: 16px;
margin: -7px 0;
border-radius: 8px;
}}
QSlider::add-page:horizontal {{
background: {Theme.BG_DARK};
}}
QSlider::sub-page:horizontal {{
background: {Theme.ACCENT_CYAN};
border-radius: 2px;
}}
""")
class FramelessWindow(QWidget):
"""Base class for all premium windows to handle dragging and frameless logic."""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.NoDropShadowWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self._drag_pos = None
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.move(event.globalPosition().toPoint() - self._drag_pos)
event.accept()

View File

@@ -1,109 +0,0 @@
"""
Loader Widget Module.
=====================
Handles the application initialization and model checks.
Refactored for 2026 Premium Aesthetics.
"""
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel, QProgressBar
from PySide6.QtCore import Qt, QThread, Signal
from PySide6.QtGui import QFont
import os
import logging
from faster_whisper import download_model
from src.core.paths import get_models_path
from src.ui.styles import Theme, StyleGenerator, load_modern_fonts
from src.ui.components import FramelessWindow, ModernFrame
class DownloadWorker(QThread):
"""Background worker for model downloads."""
progress = Signal(str, int)
download_finished = Signal()
error = Signal(str)
def run(self):
try:
model_path = get_models_path()
self.progress.emit("Verifying AI Core...", 10)
os.environ["HF_HOME"] = str(model_path)
self.progress.emit("Downloading Model...", 30)
download_model("small", output_dir=str(model_path))
self.progress.emit("System Ready!", 100)
self.download_finished.emit()
except Exception as e:
logging.error(f"Loader failed: {e}")
self.error.emit(str(e))
class LoaderWidget(FramelessWindow):
"""
Premium bootstrapper UI.
Inherits from FramelessWindow for rounded glass look.
"""
ready_signal = Signal()
def __init__(self):
super().__init__()
self.setFixedSize(400, 180)
# Main Layout
self.root = QVBoxLayout(self)
self.root.setContentsMargins(10, 10, 10, 10)
# Glass Card
self.card = ModernFrame()
self.card.setStyleSheet(StyleGenerator.get_glass_card(radius=20))
self.root.addWidget(self.card)
# Content Layout
self.layout = QVBoxLayout(self.card)
self.layout.setContentsMargins(30,30,30,30)
self.layout.setSpacing(15)
# App Title/Brand
self.brand = QLabel("WHISPER VOICE")
self.brand.setFont(load_modern_fonts())
self.brand.setStyleSheet(f"color: {Theme.ACCENT_CYAN}; font-weight: 900; letter-spacing: 4px; font-size: 14px;")
self.brand.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.brand)
# Status Label
self.status_label = QLabel("INITIALIZING...")
self.status_label.setStyleSheet(f"color: {Theme.TEXT_SECONDARY}; font-weight: 600; font-size: 11px;")
self.status_label.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.status_label)
# Progress Bar (Modern Slim style)
self.progress_bar = QProgressBar()
self.progress_bar.setFixedHeight(4)
self.progress_bar.setStyleSheet(f"""
QProgressBar {{
background-color: {Theme.BG_DARK};
border-radius: 2px;
border: none;
text-align: center;
color: transparent;
}}
QProgressBar::chunk {{
background-color: {Theme.ACCENT_CYAN};
border-radius: 2px;
}}
""")
self.layout.addWidget(self.progress_bar)
# Start Worker
self.worker = DownloadWorker()
self.worker.progress.connect(self.update_progress)
self.worker.download_finished.connect(self.on_finished)
self.worker.start()
def update_progress(self, text: str, percent: int):
self.status_label.setText(text.upper())
self.progress_bar.setValue(percent)
def on_finished(self):
self.ready_signal.emit()
self.close()

View File

@@ -1,105 +0,0 @@
"""
Overlay Window Module.
======================
Premium High-Fidelity Overlay for Whisper Voice.
Features glassmorphism, pulsating status indicators, and smart positioning.
"""
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel
from PySide6.QtCore import Qt, Slot, QPoint, QPropertyAnimation, QEasingCurve
from PySide6.QtGui import QColor, QFont, QGuiApplication
from src.ui.visualizer import AudioVisualizer
from src.ui.styles import Theme, StyleGenerator, load_modern_fonts
from src.ui.components import FramelessWindow, ModernFrame
class OverlayWindow(FramelessWindow):
"""
The main transparent overlay (The Pill).
Refactored for 2026 Premium Aesthetics.
"""
def __init__(self):
super().__init__()
self.setFixedSize(320, 95)
# Main Layout
self.master_layout = QVBoxLayout(self)
self.master_layout.setContentsMargins(10, 10, 10, 10)
# The Glass Pill Container
self.pill = ModernFrame()
self.pill.setStyleSheet(StyleGenerator.get_glass_card(radius=24))
self.master_layout.addWidget(self.pill)
# Layout inside the pill
self.layout = QHBoxLayout(self.pill)
self.layout.setContentsMargins(20, 10, 20, 10)
self.layout.setSpacing(15)
# Status Visualization (Left Dot)
self.status_dot = QWidget()
self.status_dot.setFixedSize(14, 14)
self.status_dot.setStyleSheet(f"background-color: {Theme.ACCENT_CYAN}; border-radius: 7px; border: 2px solid white;")
self.layout.addWidget(self.status_dot)
# Text/Visualizer Stack
self.content_stack = QVBoxLayout()
self.content_stack.setSpacing(2)
self.content_stack.setContentsMargins(0, 0, 0, 0)
self.status_label = QLabel("READY")
self.status_label.setFont(load_modern_fonts())
self.status_label.setStyleSheet(f"color: white; font-weight: 800; font-size: 11px; letter-spacing: 2px;")
self.content_stack.addWidget(self.status_label)
self.visualizer = AudioVisualizer()
self.visualizer.setFixedHeight(30)
self.content_stack.addWidget(self.visualizer)
self.layout.addLayout(self.content_stack)
# Animations
self.pulse_timer = None # Use style-based pulsing to avoid window flags issues
# Initial State
self.hide()
self.first_show = True
def showEvent(self, event):
"""Handle positioning and config updates."""
from src.core.config import ConfigManager
config = ConfigManager()
self.setWindowOpacity(config.get("opacity"))
if self.first_show:
self.center_above_taskbar()
self.first_show = False
super().showEvent(event)
def center_above_taskbar(self):
screen = QGuiApplication.primaryScreen()
if not screen: return
avail_rect = screen.availableGeometry()
x = avail_rect.x() + (avail_rect.width() - self.width()) // 2
y = avail_rect.bottom() - self.height() - 15
self.move(x, y)
@Slot(str)
def update_status(self, text: str):
"""Updates the status text and visual indicator."""
self.status_label.setText(text.upper())
if "RECORDING" in text.upper():
color = Theme.ACCENT_GREEN
elif "THINKING" in text.upper():
color = Theme.ACCENT_PURPLE
else:
color = Theme.ACCENT_CYAN
self.status_dot.setStyleSheet(f"background-color: {color}; border-radius: 7px; border: 2px solid white;")
@Slot(float)
def update_visualizer(self, amp: float):
self.visualizer.set_amplitude(amp)

Binary file not shown.

View File

@@ -1,50 +0,0 @@
#version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
float time;
float aberration; // 0.0 to 1.0, controlled by Audio Amplitude
};
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
void main() {
// 1. Calculate Distortion Offset based on Amplitude (aberration)
// We warp the UVs slightly away from center
vec2 uv = qt_TexCoord0;
vec2 dist = uv - 0.5;
// 2. Chromatic Aberration
// Red Channel shifts OUT
// Blue Channel shifts IN
float strength = aberration * 0.02; // Max shift 2% of texture size
vec2 rUV = uv + (dist * strength);
vec2 bUV = uv - (dist * strength);
// Sample texture? We don't have a texture input (source is empty Item), we are generating visuals.
// Wait, ShaderEffect usually works on sourceItem.
// Here we are generating NOISE on top of a gradient.
// So we apply Aberration to the NOISE function?
// Or do we want to aberrate the pixels UNDERNEATH?
// ShaderEffect with no source property renders purely procedural content.
// Let's create layered procedural noise with channel offsets
float nR = rand(rUV + vec2(time * 0.01, 0.0));
float nG = rand(uv + vec2(time * 0.01, 0.0)); // Green is anchor
float nB = rand(bUV + vec2(time * 0.01, 0.0));
// Also modulate alpha by aberration - higher volume = more intense grain?
// Or maybe just pure glitch.
vec4 grainColor = vec4(nR, nG, nB, 1.0);
// Mix it with opacity
fragColor = grainColor * qt_Opacity;
}

Binary file not shown.

View File

@@ -1,25 +0,0 @@
#version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
float time;
};
// High-quality pseudo-random function
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
void main() {
// Dynamic Noise based on Time
// We add 'time' to the coordinate to animate the grain
float noise = rand(qt_TexCoord0 + vec2(time * 0.01, time * 0.02));
// Output grayscale noise with alpha modulation
// We want white noise, applied with qt_Opacity
fragColor = vec4(noise, noise, noise, 1.0) * qt_Opacity;
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 KiB

View File

@@ -1,236 +0,0 @@
"""
Settings Window Module.
=======================
Manages the application configuration UI.
Refactored for 2026 Premium Aesthetics with Sidebar navigation.
"""
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QStackedWidget,
QLabel, QComboBox, QFormLayout, QFrame, QMessageBox, QScrollArea
)
from PySide6.QtCore import Qt, Signal, Slot, QSize
from PySide6.QtGui import QFont, QIcon
from src.core.config import ConfigManager
from src.ui.styles import Theme, StyleGenerator, load_modern_fonts
from src.ui.components import FramelessWindow, ModernFrame, GlassButton, ModernSwitch, ModernSlider
import sounddevice as sd
class SettingsWindow(FramelessWindow):
"""
The main settings dialog.
Refactored with 2026 Premium Sidebar Layout.
"""
settings_changed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.config = ConfigManager()
self.setFixedSize(700, 500)
# Main Container
self.bg_frame = ModernFrame()
self.bg_frame.setStyleSheet(StyleGenerator.get_glass_card(radius=20))
self.root_layout = QVBoxLayout(self)
self.root_layout.setContentsMargins(10, 10, 10, 10)
self.root_layout.addWidget(self.bg_frame)
# Title Bar Area (Inside glass card)
self.title_layout = QHBoxLayout()
self.title_layout.setContentsMargins(20, 15, 20, 0)
title_lbl = QLabel("PREMIUM SETTINGS")
title_lbl.setFont(load_modern_fonts())
title_lbl.setStyleSheet(f"color: white; font-weight: 900; font-size: 14px; letter-spacing: 2px;")
self.title_layout.addWidget(title_lbl)
self.title_layout.addStretch()
self.btn_close = GlassButton("×", accent_color="#ff4b4b")
self.btn_close.setFixedSize(30, 30)
self.btn_close.clicked.connect(self.close)
self.title_layout.addWidget(self.btn_close)
# Central Layout (Sidebar + Content)
self.content_layout = QHBoxLayout()
self.content_layout.setContentsMargins(10, 10, 10, 10)
self.content_layout.setSpacing(10)
# 1. SIDEBAR
self.sidebar = QWidget()
self.sidebar.setFixedWidth(160)
self.sidebar_layout = QVBoxLayout(self.sidebar)
self.sidebar_layout.setContentsMargins(0, 10, 0, 10)
self.sidebar_layout.setSpacing(8)
self.nav_general = GlassButton("General")
self.nav_audio = GlassButton("Audio")
self.nav_visuals = GlassButton("Visuals")
self.nav_advanced = GlassButton("Advanced/AI")
self.sidebar_layout.addWidget(self.nav_general)
self.sidebar_layout.addWidget(self.nav_audio)
self.sidebar_layout.addWidget(self.nav_visuals)
self.sidebar_layout.addWidget(self.nav_advanced)
self.sidebar_layout.addStretch()
self.btn_save = GlassButton("SAVE CHANGES", accent_color=Theme.ACCENT_GREEN)
self.btn_save.clicked.connect(self.save_settings)
self.sidebar_layout.addWidget(self.btn_save)
# 2. CONTENT STACK
self.stack = QStackedWidget()
self.stack.setStyleSheet("background: transparent;")
# Connect sidebar to stack
self.nav_general.clicked.connect(lambda: self.stack.setCurrentIndex(0))
self.nav_audio.clicked.connect(lambda: self.stack.setCurrentIndex(1))
self.nav_visuals.clicked.connect(lambda: self.stack.setCurrentIndex(2))
self.nav_advanced.clicked.connect(lambda: self.stack.setCurrentIndex(3))
# Main Layout Assembly
self.inner_layout = QVBoxLayout(self.bg_frame)
self.inner_layout.addLayout(self.title_layout)
self.inner_layout.addLayout(self.content_layout)
self.content_layout.addWidget(self.sidebar)
self.content_layout.addWidget(self.stack)
self.setup_pages()
self.load_values()
def setup_pages(self):
"""Creates the settings pages."""
# --- GENERAL ---
self.page_general = QWidget()
l1 = QFormLayout(self.page_general)
l1.setVerticalSpacing(20)
self.inp_hotkey = QComboBox()
self.inp_hotkey.addItems(["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "caps lock"])
self.inp_hotkey.setStyleSheet(f"background: {Theme.BG_DARK}; border-radius: 4px; padding: 5px; color: white;")
l1.addRow(self.create_lbl("Global Hotkey:"), self.inp_hotkey)
self.chk_top = ModernSwitch()
l1.addRow(self.create_lbl("Always on Top:"), self.chk_top)
self.stack.addWidget(self.page_general)
# --- AUDIO ---
self.page_audio = QWidget()
l2 = QFormLayout(self.page_audio)
l2.setVerticalSpacing(15)
self.inp_device = QComboBox()
self.inp_device.setStyleSheet(f"background: {Theme.BG_DARK}; border-radius: 4px; padding: 5px; color: white;")
self.populate_audio_devices()
l2.addRow(self.create_lbl("Input Device:"), self.inp_device)
self.sld_threshold = ModernSlider(Qt.Horizontal)
self.sld_threshold.setRange(1, 25)
self.lbl_threshold = self.create_lbl("2%")
self.sld_threshold.valueChanged.connect(lambda v: self.lbl_threshold.setText(f"{v}%"))
l2.addRow(self.create_lbl("Noise Gate:"), self.sld_threshold)
l2.addRow("", self.lbl_threshold)
self.sld_duration = ModernSlider(Qt.Horizontal)
self.sld_duration.setRange(5, 50)
self.lbl_duration = self.create_lbl("1.0s")
self.sld_duration.valueChanged.connect(lambda v: self.lbl_duration.setText(f"{v/10}s"))
l2.addRow(self.create_lbl("Auto-Submit:"), self.sld_duration)
l2.addRow("", self.lbl_duration)
self.stack.addWidget(self.page_audio)
# --- VISUALS ---
self.page_visuals = QWidget()
l3 = QFormLayout(self.page_visuals)
l3.setVerticalSpacing(20)
self.inp_style = QComboBox()
self.inp_style.addItem("Neon Line (Recommended)", "line")
self.inp_style.addItem("Classic Bars", "bar")
self.inp_style.setStyleSheet(f"background: {Theme.BG_DARK}; border-radius: 4px; padding: 5px; color: white;")
l3.addRow(self.create_lbl("Visualizer:"), self.inp_style)
self.sld_opacity = ModernSlider(Qt.Horizontal)
self.sld_opacity.setRange(40, 100)
self.lbl_opacity = self.create_lbl("100%")
self.sld_opacity.valueChanged.connect(lambda v: self.lbl_opacity.setText(f"{v}%"))
l3.addRow(self.create_lbl("Opacity:"), self.sld_opacity)
l3.addRow("", self.lbl_opacity)
self.stack.addWidget(self.page_visuals)
# --- ADVANCED ---
self.page_adv = QWidget()
l4 = QFormLayout(self.page_adv)
l4.setVerticalSpacing(15)
self.inp_model = QComboBox()
self.inp_model.setStyleSheet(f"background: {Theme.BG_DARK}; border-radius: 4px; padding: 5px; color: white;")
for id, name in [("tiny", "Tiny (Fast)"), ("base", "Base"), ("small", "Small (Default)"), ("medium", "Medium"), ("large-v3", "Large V3")]:
self.inp_model.addItem(name, id)
l4.addRow(self.create_lbl("Model:"), self.inp_model)
info = QLabel("Large models provide higher accuracy but require significant RAM/VRAM.")
info.setWordWrap(True)
info.setStyleSheet(f"color: {Theme.TEXT_SECONDARY}; font-style: italic; font-size: 11px;")
l4.addRow("", info)
self.stack.addWidget(self.page_adv)
def create_lbl(self, text):
lbl = QLabel(text)
lbl.setStyleSheet(f"color: {Theme.TEXT_SECONDARY}; font-weight: 600; font-size: 13px;")
return lbl
def populate_audio_devices(self):
try:
self.inp_device.addItem("System Default", -1)
for i, dev in enumerate(sd.query_devices()):
if dev['max_input_channels'] > 0:
self.inp_device.addItem(dev['name'], i)
except: pass
def load_values(self):
self.inp_hotkey.setCurrentText(self.config.get("hotkey"))
self.chk_top.setChecked(self.config.get("always_on_top"))
dev_id = self.config.get("input_device")
idx = self.inp_device.findData(dev_id if dev_id is not None else -1)
if idx >= 0: self.inp_device.setCurrentIndex(idx)
self.sld_threshold.setValue(int(self.config.get("silence_threshold") * 100))
self.sld_duration.setValue(int(self.config.get("silence_duration") * 10))
idx = self.inp_style.findData(self.config.get("visualizer_style"))
if idx >= 0: self.inp_style.setCurrentIndex(idx)
self.sld_opacity.setValue(int(self.config.get("opacity") * 100))
idx = self.inp_model.findData(self.config.get("model_size"))
if idx >= 0: self.inp_model.setCurrentIndex(idx)
def save_settings(self):
updates = {
"hotkey": self.inp_hotkey.currentText(),
"always_on_top": self.chk_top.isChecked(),
"input_device": self.inp_device.currentData() if self.inp_device.currentData() != -1 else None,
"silence_threshold": self.sld_threshold.value() / 100.0,
"silence_duration": self.sld_duration.value() / 10.0,
"visualizer_style": self.inp_style.currentData(),
"opacity": self.sld_opacity.value() / 100.0,
"model_size": self.inp_model.currentData()
}
new_model = updates["model_size"]
if new_model != self.config.get("model_size"):
QMessageBox.information(self, "Model Updated", f"Downloaded {new_model} on next launch.")
self.config.set_bulk(updates)
self.settings_changed.emit()
self.close()

View File

@@ -1,62 +0,0 @@
"""
Style Engine Module.
====================
Centralized design system for the 2026 Premium UI.
Defines color palettes, glassmorphism templates, and modern font loading.
"""
from PySide6.QtGui import QColor, QFont, QFontDatabase
import os
class Theme:
"""Premium Dark Theme Palette (2026 Edition)."""
# Backgrounds
BG_DARK = "#0d0d12" # Deep cosmic black
BG_CARD = "#16161e" # Slightly lighter for components
BG_GLASS = "rgba(22, 22, 30, 0.7)" # Semi-transparent for glass effect
# Neons & Accents
ACCENT_CYAN = "#00f2ff" # Electric cyan
ACCENT_PURPLE = "#7000ff" # Deep cyber purple
ACCENT_GREEN = "#00ff88" # Mint neon
# Text
TEXT_PRIMARY = "#ffffff" # Pure white
TEXT_SECONDARY = "#9499b0" # Muted blue-gray
TEXT_MUTED = "#565f89" # Darker blue-gray
# Borders
BORDER_SUBTLE = "rgba(100, 100, 150, 0.2)"
BORDER_GLOW = "rgba(0, 242, 255, 0.5)"
class StyleGenerator:
"""Generates QSS strings for complex effects."""
@staticmethod
def get_glass_card(radius=12, border=True):
"""Returns QSS for a glassmorphism card."""
border_css = f"border: 1px solid {Theme.BORDER_SUBTLE};" if border else "border: none;"
return f"""
background-color: {Theme.BG_GLASS};
border-radius: {radius}px;
{border_css}
"""
@staticmethod
def get_glow_border(color=Theme.ACCENT_CYAN):
"""Returns QSS for a glowing border state."""
return f"border: 1px solid {color};"
def load_modern_fonts():
"""Attempts to load a modern font stack for the 2026 look."""
# Preferred order: Segoe UI Variable, Inter, Segoe UI, sans-serif
families = ["Segoe UI Variable Text", "Inter", "Segoe UI", "sans-serif"]
for family in families:
font = QFont(family, 10)
if QFontDatabase.families().count(family) > 0:
return font
# Absolute fallback
return QFont("Arial", 10)

View File

@@ -1,117 +0,0 @@
"""
Audio Visualizer Module.
========================
High-Fidelity rendering for the 2026 Premium UI.
Supports 'Classic Bars' and 'Neon Line' with smooth curves and glows.
"""
from PySide6.QtWidgets import QWidget
from PySide6.QtCore import Qt, QTimer, Slot, QRectF, QPointF
from PySide6.QtGui import QPainter, QBrush, QColor, QPainterPath, QPen, QLinearGradient
import random
from src.ui.styles import Theme
class AudioVisualizer(QWidget):
"""
A premium audio visualizer with smooth physics and neon aesthetics.
"""
def __init__(self, parent=None):
super().__init__(parent)
self.amplitude = 0.0
self.bars = 12
self.history = [0.0] * self.bars
# High-refresh timer for silky smooth motion
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_animation)
self.timer.start(16) # ~60 FPS
@Slot(float)
def set_amplitude(self, amp: float):
self.amplitude = amp
def update_animation(self):
self.history.pop(0)
# Smooth interpolation + noise
jitter = random.uniform(0.01, 0.03)
# Decay logic: Gravity-like pull
self.history.append(max(self.amplitude, jitter))
self.update()
def paintEvent(self, event):
from src.core.config import ConfigManager
style = ConfigManager().get("visualizer_style")
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
w, h = self.width(), self.height()
painter.translate(0, h / 2)
if style == "bar":
self._draw_bars(painter, w, h)
else:
self._draw_line(painter, w, h)
def _draw_bars(self, painter, w, h):
bar_w = w / self.bars
spacing = 3
for i, val in enumerate(self.history):
bar_h = val * (h * 0.9)
x = i * bar_w
# Gradient Bar
grad = QLinearGradient(0, -bar_h/2, 0, bar_h/2)
grad.setColorAt(0, QColor(Theme.ACCENT_PURPLE))
grad.setColorAt(1, QColor(Theme.ACCENT_CYAN))
painter.setBrush(grad)
painter.setPen(Qt.NoPen)
painter.drawRoundedRect(QRectF(x + spacing, -bar_h/2, bar_w - spacing*2, bar_h), 3, 3)
def _draw_line(self, painter, w, h):
path = QPainterPath()
points = len(self.history)
dx = w / (points - 1)
path.moveTo(0, 0)
def get_path(multi):
p = QPainterPath()
p.moveTo(0, 0)
for i in range(points):
curr_x = i * dx
curr_y = -self.history[i] * (h * 0.45) * multi
if i == 0:
p.moveTo(curr_x, curr_y)
else:
prev_x = (i-1) * dx
# Simple lerp or quadTo for smoothness
p.lineTo(curr_x, curr_y)
return p
# Draw Top & Bottom
p_top = get_path(1)
p_bot = get_path(-1)
# Glow layer
glow_pen = QPen(QColor(Theme.ACCENT_CYAN))
glow_pen.setWidth(4)
glow_alpha = QColor(Theme.ACCENT_CYAN)
glow_alpha.setAlpha(60)
glow_pen.setColor(glow_alpha)
painter.setPen(glow_pen)
painter.drawPath(p_top)
painter.drawPath(p_bot)
# Core layer
core_pen = QPen(Qt.white)
core_pen.setWidth(2)
painter.setPen(core_pen)
painter.drawPath(p_top)
painter.drawPath(p_bot)