more beauty

This commit is contained in:
2026-01-10 13:31:11 +01:00
parent 1855810c14
commit 8739455231
2 changed files with 130 additions and 33 deletions

72
main.py
View File

@@ -1,14 +1,15 @@
# main.py
import sys
import os
import time
from PyQt6.QtWidgets import QApplication
from PyQt6.QtGui import QPixmap, QFont, QIcon
from PyQt6.QtCore import qInstallMessageHandler, QTimer, Qt
# Config zuerst!
from config import qt_message_handler, LOG_FILE
from PyQt6.QtWidgets import QApplication, QSplashScreen
from PyQt6.QtGui import QPixmap, QFont
from PyQt6.QtCore import qInstallMessageHandler
from ui import UffWindow
from ui import UffWindow, ModernSplashScreen, ModelLoaderThread
qInstallMessageHandler(qt_message_handler)
os.environ["QT_LOGGING_RULES"] = "qt.text.font.db=false;qt.qpa.fonts=false"
@@ -18,18 +19,61 @@ if __name__ == "__main__":
app = QApplication(sys.argv)
app.setFont(QFont("Segoe UI", 10))
splash = None
if os.path.exists("assets/uff_banner.jpeg"):
try:
splash = QSplashScreen(QPixmap("assets/uff_banner.jpeg"))
splash.show()
except: pass
# 1. ICON SETZEN (Für die ganze App)
# Wenn assets/icon.png existiert, wird es genutzt.
if os.path.exists("assets/icon.png"):
app_icon = QIcon("assets/icon.png")
app.setWindowIcon(app_icon)
window = UffWindow(splash)
window.show()
window.start_model_loading()
# 2. SPLASH SCREEN ERSTELLEN
splash_pix = QPixmap("assets/uff_banner.jpeg")
# Falls kein Bild da ist, nehmen wir ein leeres (damit es nicht crasht)
if splash_pix.isNull():
splash_pix = QPixmap(600, 400)
splash_pix.fill(Qt.GlobalColor.white)
splash = ModernSplashScreen(splash_pix)
splash.show()
# 3. LADEN SIMULIEREN & STARTEN
# Wir nutzen einen kleinen Trick, um den Start visuell zu "begleiten"
splash.set_progress(10, "Lade Konfiguration...")
app.processEvents()
time.sleep(0.3) # Nur für den Effekt
splash.set_progress(30, "Verbinde Datenbank...")
app.processEvents()
# Hauptfenster erstellen (aber noch versteckt lassen)
window = UffWindow()
splash.set_progress(50, "Lade Benutzeroberfläche...")
app.processEvents()
time.sleep(0.2)
# 4. DAS SCHWERE KI-MODELL LADEN
splash.set_progress(60, "Lade KI-Modell (das dauert kurz)...")
app.processEvents()
# Wir starten den Thread, aber wir müssen warten bis er fertig ist,
# bevor wir den Splash schließen.
loader = ModelLoaderThread()
def on_loaded(model):
splash.set_progress(100, "Fertig!")
app.processEvents()
time.sleep(0.5) # Kurz warten bei 100%
window.on_model_loaded(model) # Modell an Fenster übergeben
window.show() # Fenster zeigen
splash.finish(window) # Splash schließen
loader.model_loaded.connect(on_loaded)
loader.start()
sys.exit(app.exec())
except Exception as e:
import traceback
print("CRITICAL MAIN CRASH:")

89
ui.py
View File

@@ -1,26 +1,76 @@
# ui.py
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
import os
from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QLabel, QFileDialog,
QProgressBar, QMessageBox, QListWidget, QListWidgetItem,
QSplitter, QFrame, QScrollArea, QStyle, QGraphicsDropShadowEffect)
from PyQt6.QtCore import Qt, QUrl, QThread, pyqtSignal
from PyQt6.QtGui import QDesktopServices, QColor, QFont
QSplitter, QFrame, QScrollArea, QStyle, QGraphicsDropShadowEffect,
QSplashScreen) # QSplashScreen hier wichtig
from PyQt6.QtCore import Qt, QUrl, QThread, pyqtSignal, QRect
from PyQt6.QtGui import QDesktopServices, QColor, QFont, QPainter, QIcon, QPixmap # Painter & Icon neu
from sentence_transformers import SentenceTransformer
from database import DatabaseHandler
from indexer import IndexerThread
from config import STYLESHEET
# Thread zum Laden des Modells (UI-Helper)
# --- NEU: Ein moderner Splash Screen mit Ladebalken ---
class ModernSplashScreen(QSplashScreen):
def __init__(self, pixmap):
super().__init__(pixmap)
self.progress = 0
self.message = "Initialisiere..."
# Schriftart für den Ladetext
self.font = QFont("Segoe UI", 10, QFont.Weight.Bold)
def set_progress(self, value, text):
self.progress = value
self.message = text
self.repaint() # Erzwingt neuzeichnen
def drawContents(self, painter):
# 1. Das normale Bild zeichnen
super().drawContents(painter)
# 2. Ladebalken-Hintergrund (unten)
# Wir malen direkt auf das Bild
bg_rect = self.rect()
bar_height = 20
# Position: Ganz unten am Bild
bar_rect = QRect(0, bg_rect.height() - bar_height, bg_rect.width(), bar_height)
# Hintergrund des Balkens (dunkelgrau)
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QColor(50, 50, 50))
painter.drawRect(bar_rect)
# 3. Der Fortschritt (türkis/blau)
# Breite basierend auf % berechnen
progress_width = int(bg_rect.width() * (self.progress / 100))
prog_rect = QRect(0, bg_rect.height() - bar_height, progress_width, bar_height)
painter.setBrush(QColor("#3498db")) # UFF-Blau
painter.drawRect(prog_rect)
# 4. Text zeichnen (zentriert über dem Balken oder darin)
painter.setPen(QColor("white"))
painter.setFont(self.font)
# Text etwas oberhalb des Balkens zeichnen
text_rect = QRect(0, bg_rect.height() - bar_height - 30, bg_rect.width(), 25)
painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter, self.message)
# --- Thread zum Laden des Modells ---
class ModelLoaderThread(QThread):
model_loaded = pyqtSignal(object)
def run(self):
try:
# Das ist der schwere Teil, der dauert
model = SentenceTransformer('all-MiniLM-L6-v2')
self.model_loaded.emit(model)
except: self.model_loaded.emit(None)
except:
self.model_loaded.emit(None)
# Widget für einzelne Ergebnisse
# --- SearchResultItem (Unverändert, aber der Vollständigkeit halber hier) ---
class SearchResultItem(QFrame):
def __init__(self, filename, filepath, snippet, parent=None):
super().__init__(parent)
@@ -76,16 +126,21 @@ class SearchResultItem(QFrame):
target = self.filepath.split(" :: ")[0] if " :: " in self.filepath else self.filepath
QDesktopServices.openUrl(QUrl.fromLocalFile(target))
# --- Das Hauptfenster ---
class UffWindow(QMainWindow):
def __init__(self, splash=None):
def __init__(self):
super().__init__()
self.splash = splash
self.db = DatabaseHandler()
self.initUI()
# NEU: Icon setzen
if os.path.exists("assets/uff_icon.jpeg"):
self.setWindowIcon(QIcon("assets/uff_icon.jpeg"))
self.load_saved_folders()
def initUI(self):
self.setWindowTitle("UFF Search")
self.setWindowTitle("UFF Search v1.0")
self.resize(1100, 750)
self.setStyleSheet(STYLESHEET)
@@ -158,7 +213,7 @@ class UffWindow(QMainWindow):
search_box.addWidget(self.btn_go)
status_box = QHBoxLayout()
self.lbl_status = QLabel("Modell wird geladen...")
self.lbl_status = QLabel("Bereit.")
self.lbl_status.setObjectName("StatusLabel")
self.prog = QProgressBar()
self.prog.hide()
@@ -187,14 +242,8 @@ class UffWindow(QMainWindow):
self.btn_go.setEnabled(enabled)
self.folder_list.setEnabled(enabled)
def start_model_loading(self):
if self.splash: self.splash.showMessage("Lade KI-Modell...", Qt.AlignmentFlag.AlignBottom, Qt.GlobalColor.white)
self.loader = ModelLoaderThread()
self.loader.model_loaded.connect(self.on_model_loaded)
self.loader.start()
# Methoden für Model Loading (wird jetzt von main gesteuert)
def on_model_loaded(self, model):
if self.splash: self.splash.finish(self)
if not model:
QMessageBox.critical(self, "Fehler", "Modell konnte nicht geladen werden.")
return
@@ -202,6 +251,10 @@ class UffWindow(QMainWindow):
self.lbl_status.setText("Bereit für deine Suche.")
self.set_ui_enabled(True)
# ... RESTLICHE METHODEN (search, add_folder etc.) bleiben gleich wie vorher ...
# (Kopiere hier einfach die Methoden aus deiner alten ui.py rein,
# search, load_saved_folders, add_new_folder, delete_selected_folder, rescan, start_idx, cancel_idx, idx_done)
def search(self):
query = self.input.text()
if not query: return