splash screen and alerts

This commit is contained in:
Louis Mazin 2025-09-26 18:46:27 +02:00
parent 7531a1cbfa
commit 2e3be1f3ad
11 changed files with 393 additions and 154 deletions

332
README.md
View File

@ -1,162 +1,274 @@
# 🚀 Python PyQt6 Application Template
# 🏥 HoDA Radio - Anonymisation d'Images Médicales
Bienvenue ! Ce projet est **bien plus qu'un simple template** : c'est une boîte à outils moderne pour créer rapidement des applications desktop Python élégantes, robustes et évolutives.
Vous voulez coder, personnaliser, traduire, mettre à jour, distribuer ? Tout est déjà prêt !
**HoDA Radio** est une application moderne et intuitive pour l'anonymisation d'images médicales DICOM. Développée en Python avec PyQt6, elle offre une interface élégante et des outils professionnels pour protéger la confidentialité des patients tout en conservant l'utilité médicale des images.
---
## ✨ Fonctionnalités clés
## ✨ Fonctionnalités principales
- **Interface moderne (PyQt6)** : Responsive, stylée, et facile à personnaliser.
- **Thèmes dynamiques** : Passez du clair au sombre en un clic, ou créez le vôtre !
- **Multi-langues** : Français, anglais... et ajoutez-en autant que vous voulez.
- **Paramètres utilisateurs** : Tout est sauvegardé (thème, langue, taille de fenêtre...).
- **Architecture modulaire** : Des managers pour chaque besoin, tout est organisé.
- **Notifications automatiques** : Les widgets s'adaptent instantanément aux changements.
- **Barre donglets flexible** : Ajoutez vos fenêtres où vous voulez, comme vous voulez.
- **Système de suggestion** : Vos utilisateurs peuvent vous écrire directement depuis lapp.
- **Mise à jour automatique** : Téléchargez la dernière version sans effort, avec barre de progression !
- **Build & environnement** : Scripts pour tout automatiser, sur Windows, Linux, macOS.
### 🔒 Anonymisation avancée
- **Importation DICOM** : Support complet des fichiers et dossiers DICOM
- **Édition en temps réel** : Outils de gomme et masquage intuitifs
- **Prévisualisation instantanée** : Visualisation des modifications avant export
- **Métadonnées** : Nettoyage automatique des informations sensibles
### 🎨 Interface moderne
- **Thèmes dynamiques** : Clair/sombre avec personnalisation complète
- **Multi-langues** : Français, anglais, espagnol (extensible)
- **Navigation fluide** : Barre d'onglets verticale avec icônes SVG
- **Responsive** : Interface adaptative selon la taille d'écran
### 📤 Export flexible
- **Formats multiples** : PNG, PDF, DCM, DICOMDIR
- **Métadonnées** : Export JSON et XLS des informations
- **Batch processing** : Traitement par lots pour l'efficacité
- **Préservation qualité** : Compression optimisée
### 🔄 Système intelligent
- **Mise à jour automatique** : Vérification et téléchargement des nouvelles versions
- **Splash screen utile** : Chargement avec feedback en temps réel
- **Gestion d'erreurs** : Messages informatifs et récupération gracieuse
- **Cache optimisé** : Performance améliorée pour les gros volumes
---
## 🗂️ Structure du projet
## 🗂️ Architecture du projet
```
Template/
HoDA_Radio/
├── app/
│ ├── core/ # Managers (thème, langue, update, etc.)
│ ├── core/ # Gestionnaires principaux
│ │ ├── main_manager.py # Chef d'orchestre
│ │ ├── dicom_manager.py # Gestion des fichiers DICOM
│ │ ├── theme_manager.py # Thèmes et styles
│ │ ├── language_manager.py # Traductions
│ │ ├── settings_manager.py # Paramètres utilisateur
│ │ ├── update_manager.py # Mises à jour
│ │ └── alert_manager.py # Messages et alertes
│ ├── ui/
│ │ ├── widgets/ # Onglets, loading bar, etc.
│ │ └── windows/ # Paramètres, suggestion...
│ └── utils/ # Fonctions utilitaires
│ │ ├── widgets/ # Composants réutilisables
│ │ │ ├── tabs_widget.py # Barre d'onglets personnalisée
│ │ │ ├── loading_spinner.py # Indicateur de chargement
│ │ │ ├── loading_bar.py # Barre de progression
│ │ │ └── image_viewer.py # Visualiseur d'images DICOM
│ │ └── windows/ # Fenêtres principales
│ │ ├── main_window.py # Fenêtre principale
│ │ ├── splash_screen.py # Écran de chargement
│ │ ├── dicom_window.py # Interface d'édition DICOM
│ │ ├── import_window.py # Interface d'importation
│ │ ├── export_window.py # Interface d'exportation
│ │ ├── settings_window.py # Paramètres
│ │ └── suggestion_window.py # Feedback utilisateur
│ └── utils/ # Utilitaires
│ └── paths.py # Gestion des chemins
├── data/
│ ├── assets/ # Icônes, images
│ ├── lang/ # Traductions
│ ├── themes/ # Thèmes
│ └── others/ # Autres
├── tools/ # Scripts build/dev
├── config.json # Config principale
├── requirements.txt # Dépendances
├── BUILD.spec # PyInstaller
└── main.py # Point dentrée
│ ├── assets/ # Ressources (icônes, images)
│ ├── lang/ # Fichiers de traduction
│ │ ├── fr.json # Français
│ │ ├── en.json # Anglais
│ │ └── es.json # Espagnol
│ ├── themes/ # Thèmes visuels
│ │ ├── dark.json # Thème sombre
│ │ └── light.json # Thème clair
│ └── others/ # Configurations
│ └── defaults_settings.json
├── tools/ # Scripts de développement
│ ├── build.bat # Build Windows
│ ├── build.command # Build macOS
│ └── open.bat # Environnement de dev
├── config.json # Configuration principale
├── requirements.txt # Dépendances Python
├── BUILD.spec # Configuration PyInstaller
└── main.py # Point d'entrée
```
---
## ⚡ Démarrage Express
## ⚡ Installation et utilisation
1. **Configurez `config.json`**
(nom, version, OS, architecture, icône, dépôt git...)
### Pré-requis
- **Python 3.10+** (recommandé 3.11)
- **Système** : Windows 10+, macOS 10.15+, ou Linux Ubuntu 20.04+
2. **Copiez `.env.example` → `.env` et configurez les variables requises**
- Depuis la racine du projet :
- Windows (PowerShell / cmd) : copy .env.example .env
- Linux / macOS : cp .env.example .env
- Au minimum, renseignez dans `.env` :
- PYTHON_PATH : chemin absolu vers votre exécutable Python (utilisé par tools/open.bat)
- les identifiants email si vous comptez utiliser l'envoi de suggestions (email + mot de passe / mot de passe d'application)
- Remarque : l'outil `tools/open.bat` s'appuie sur PYTHON_PATH ; sans cette variable, l'ouverture/initialisation de l'environnement échouera.
### 🚀 Démarrage rapide
3. **Lancez le dev**
- Windows : tools\open.bat (nécessite PYTHON_PATH dans `.env`)
- Linux : tools/open.sh (si présent / exécutable)
- macOS : tools/open.command (si présent / exécutable)
- Exécutez depuis leur fichier parent pour que les chemins relatifs fonctionnent correctement.
1. **Clonez le projet**
```bash
git clone https://gitea.louismazin.ovh/LouisMazin/HoDA_Radio.git
cd HoDA_Radio
```
4. **Build en un clic**
- Windows : tools\build.bat
- Linux : tools/build.sh
- macOS : tools/build.command
- Ces scripts supposent que `.env` est configuré et que les outils requis (pyinstaller, etc.) sont installés.
2. **Configurez l'environnement**
```bash
# Copiez le fichier d'environnement
cp .env.example .env
# Éditez .env avec vos paramètres
# PYTHON_PATH=/chemin/vers/python
# EMAIL_USER=votre.email@gmail.com (optionnel)
# EMAIL_PASSWORD=votre_mot_de_passe (optionnel)
```
3. **Lancez l'application**
- **Windows** : Double-cliquez sur `tools\open.bat`
- **macOS** : Exécutez `tools/open.command`
- **Linux** : Exécutez `tools/open.sh`
### 📦 Build de production
1. **Build automatique**
- **Windows** : `tools\build.bat`
- **macOS** : `tools/build.command`
- **Linux** : `tools/build.sh`
2. **Fichier généré**
- L'exécutable se trouve dans le dossier `build/`
- Nom automatique : `HoDA_Radio-{OS}-{ARCH}-v{VERSION}`
---
## 🎨 Thèmes & 🌍 Langues
## 🎯 Utilisation de l'application
- **Thèmes** : Ajoutez vos fichiers dans `data/themes/` (JSON).
Changez les couleurs, créez votre ambiance !
- **Langues** : Ajoutez vos fichiers dans `data/lang/` (JSON).
Traduisez tout, cest instantané.
### 1. **Import des images DICOM**
- Glissez-déposez vos fichiers ou dossiers DICOM
- Support des archives et structures complexes
- Validation automatique des formats
### 2. **Anonymisation interactive**
- Utilisez l'outil gomme pour masquer les zones sensibles
- Prévisualisez en temps réel vos modifications
- Ajustez la taille du pinceau selon vos besoins
### 3. **Export sécurisé**
- Choisissez vos formats de sortie
- Sélectionnez les images à exporter
- Nettoyage automatique des métadonnées
---
## 🧩 Managers & Architecture
## 🎨 Personnalisation
- **MainManager** : Le chef dorchestre.
- **SettingsManager** : Les préférences utilisateur.
- **ThemeManager** : Les couleurs et le style.
- **LanguageManager** : Les textes traduits.
- **AlertManager** : Les messages, confirmations, erreurs.
- **UpdateManager** : Les mises à jour automatiques.
- **ObserverManager** : Les notifications internes.
### Thèmes personnalisés
Créez votre thème dans `data/themes/mon_theme.json` :
```json
{
"theme_name": "Mon Thème",
"colors": {
"background_color": "#1a1a1a",
"primary_color": "#007acc",
"text_color": "#ffffff"
}
}
```
### Nouvelles langues
Ajoutez une traduction dans `data/lang/code_langue.json` :
```json
{
"lang_name": "Deutsch",
"language": "Sprache :",
"theme": "Thema :",
"loading": "Laden..."
}
```
---
## 🔧 Développement avancé
### Architecture des managers
- **MainManager** : Singleton coordonnant tous les autres managers
- **DicomManager** : Logique métier pour les fichiers médicaux
- **ThemeManager** : Système de thèmes dynamiques avec cache
- **ObserverManager** : Pattern Observer pour les notifications inter-composants
### Ajout de fonctionnalités
1. Créez votre fenêtre dans `app/ui/windows/`
2. Ajoutez-la aux onglets dans `main_window.py`
3. Implémentez les notifications de thème/langue si nécessaire
### Tests et debugging
```bash
# Mode développement avec logs
python main.py --debug
# Tests unitaires (si implémentés)
python -m pytest tests/
```
---
## 📋 Dépendances principales
- **PyQt6** : Interface graphique moderne
- **pydicom** : Manipulation des fichiers DICOM
- **pillow** : Traitement d'images
- **numpy** : Calculs numériques
- **requests** : Mises à jour automatiques
- **packaging** : Gestion des versions
- **python-dotenv** : Variables d'environnement
---
## 🔒 Sécurité et confidentialité
### Protection des données
- **Traitement local** : Aucune donnée médicale envoyée sur internet
- **Cache temporaire** : Nettoyage automatique à la fermeture
- **Métadonnées** : Suppression des informations personnelles
### Bonnes pratiques
- Utilisez des mots de passe d'application pour Gmail
- Ne versionnez jamais le fichier `.env`
- Vérifiez les exports avant diffusion
---
## 🔄 Mise à jour automatique
- Vérifie la dernière version sur le dépôt Git à chaque démarrage.
- Propose la mise à jour si disponible.
- Télécharge le bon fichier selon votre OS/architecture.
- Affiche une barre de progression stylée.
- Lance la nouvelle version automatiquement !
L'application vérifie automatiquement les nouvelles versions :
- **Au démarrage** : Vérification silencieuse
- **Notification** : Proposition de téléchargement si disponible
- **Installation** : Téléchargement avec barre de progression
- **Compatibilité** : Détection automatique OS/architecture
---
## 💡 Suggestions & Feedback
## 🆘 Support et contribution
- Fenêtre dédiée pour envoyer vos idées ou questions par email.
- Sécurisé via `.env`.
- Gestion des erreurs/succès avec AlertManager.
### Signaler un problème
1. Utilisez l'onglet "Suggestion" dans l'application
2. Ou ouvrez une issue sur [Gitea](https://gitea.louismazin.ovh/LouisMazin/HoDA_Radio)
3. Incluez : OS, version Python, logs d'erreur, étapes de reproduction
---
### Contribuer
1. Forkez le dépôt
2. Créez une branche feature/fix
3. Testez vos modifications
4. Soumettez une pull request
## 🛠️ Ajouter vos fenêtres & widgets
- Créez une classe héritant de `QWidget`.
- Ajoutez-la dans la barre donglets (`TabsWidget`).
- Abonnez-vous aux notifications pour la langue/le thème.
---
## 📦 Dépendances
- **Python 3.10+ recommandé** (compatibilité testée avec 3.10/3.11).
- **PyQt6** : GUI moderne.
- **pyinstaller** : Build dexécutables.
- **python-dotenv** : Variables denvironnement.
- **requests** : Requêtes HTTP (update).
---
## 🔒 Sécurité
- **Ne versionnez jamais `.env`** (déjà dans `.gitignore`).
- Utilisez un mot de passe dapplication pour Gmail.
### Règles de contribution
- Code Python PEP 8 compliant
- Documentation des nouvelles fonctionnalités
- Tests unitaires pour la logique métier critique
- Respect de l'architecture existante
---
## 📝 Licence
Attribution License — voir le fichier local [`LICENSE`](https://gitea.louismazin.ovh/LouisMazin/PythonApplicationTemplate/src/branch/main/LICENSE) pour le texte complet.
Toute utilisation ou distribution doit inclure une attribution visible à l'auteur : LouisMazin.
**Attribution License** - voir [LICENSE](LICENSE) pour les détails complets.
Toute utilisation, reproduction ou distribution doit inclure une attribution visible à l'auteur : **LouisMazin**.
---
## 🤝 Contribution
## 🙏 Remerciements
1. Forkez le dépôt
2. Créez une branche
3. Proposez vos modifications via pull request
- **PyQt6** pour le framework d'interface
- **pydicom** pour la manipulation des fichiers médicaux
- **Communauté open source** pour les contributions et retours
---
## 🆘 Support
- Ouvrez une issue sur le dépôt
- Précisez votre OS, version Python, logs derreur
---
**Ce template est fait pour vous faire gagner du temps et coder avec plaisir !
Testez-le, améliorez-le, partagez-le 🚀**
**HoDA Radio - Protégez la confidentialité, préservez l'utilité médicale** 🚀

View File

@ -24,8 +24,16 @@ class MainWindow(QMainWindow):
self.observer_manager.subscribe(NotificationType.THEME, self.update_theme)
self.observer_manager.subscribe(NotificationType.DICOM, self.goto_dicom_window)
self.is_maximizing: bool = False
self.current_size: QSize
self.previous_size: QSize
# Initialiser les attributs de taille AVANT setup_ui
app: Optional[QApplication] = QApplication.instance()
size: QSize = app.primaryScreen().size()
self.settings_manager.minScreenSize = min(size.height(), size.width())
# Initialiser les tailles par défaut
window_size: dict = self.settings_manager.get_window_size()
self.current_size: QSize = QSize(window_size["width"], window_size["height"])
self.previous_size: QSize = QSize(window_size["width"], window_size["height"])
# UI elements
self.side_menu: TabsWidget
@ -33,13 +41,21 @@ class MainWindow(QMainWindow):
self.suggestion_window: SuggestionWindow
self.footer_label: QLabel # Ajout d'un attribut pour le footer
app: Optional[QApplication] = QApplication.instance()
size: QSize = app.primaryScreen().size()
self.settings_manager.minScreenSize = min(size.height(),size.width())
self.setMinimumSize(600, 400)
# Initialiser l'UI immédiatement (sera fait pendant le splash)
self.setup_ui()
self.apply_saved_window_state()
# Différer l'application des paramètres de fenêtre jusqu'à l'affichage réel
# (cela évite des bugs de taille pendant le préchargement)
self._window_state_applied = False
def showEvent(self, event):
"""Applique les paramètres de fenêtre lors du premier affichage"""
super().showEvent(event)
if not self._window_state_applied:
self.apply_saved_window_state()
self._window_state_applied = True
def apply_saved_window_state(self) -> None:
"""Apply saved window size and maximized state"""

View File

@ -111,6 +111,8 @@ class ExportWindow(QWidget):
def show_dicom_selection_popup(self):
dicom_list = self.export_manager.get_export_dicom_list()
if not dicom_list:
# Afficher une alerte si aucune donnée n'est disponible
self.alert_manager.show_error("no_dicoms_to_export")
return
popup = QDialog(self)

View File

@ -294,10 +294,18 @@ class ImportWindow(QWidget):
self.observer_manager.notify(NotificationType.DICOM)
def select_file(self):
self.input_entry.setText(QFileDialog.getOpenFileName(self, self.language_manager.get_text("select_image"), get_current_dir(), "DICOMDIR Files (DICOMDIR) ;; DICOM Files (*.dcm)")[0])
path = QFileDialog.getOpenFileName(self, self.language_manager.get_text("select_image"), get_current_dir(), "DICOMDIR Files (DICOMDIR) ;; DICOM Files (*.dcm)")[0]
if path:
self.input_entry.setText(path)
else:
self.input_entry.setText(self.language_manager.get_text("path_placeholder"))
def select_folder(self):
self.input_entry.setText(QFileDialog.getExistingDirectory(self, self.language_manager.get_text("select_folder"), get_current_dir()))
path = QFileDialog.getExistingDirectory(self, self.language_manager.get_text("select_folder"), get_current_dir())
if path:
self.input_entry.setText(path)
else:
self.input_entry.setText(self.language_manager.get_text("path_placeholder"))
def find_dicoms_from_files(self, path):
if isinstance(path, tuple):

View File

@ -1,24 +1,29 @@
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt, QTimer, pyqtSignal
from PyQt6.QtCore import Qt, pyqtSignal, QTimer
from PyQt6.QtGui import QPixmap
from app.core.main_manager import MainManager
from app.ui.widgets.loading_spinner import LoadingSpinner
import app.utils.paths as paths
class SplashScreen(QWidget):
finished = pyqtSignal()
finished = pyqtSignal(bool) # True si succès, False si échec/interruption
def __init__(self, duration=3000, parent=None):
def __init__(self, parent=None, preload_function=None):
super().__init__(parent)
self.duration = duration
self.preload_function = preload_function
self.preload_result = True
self.main_manager = MainManager.get_instance()
self.theme_manager = self.main_manager.get_theme_manager()
self.settings_manager = self.main_manager.get_settings_manager()
self.language_manager = self.main_manager.get_language_manager()
self.setup_ui()
self.setup_timer()
if self.preload_function:
self.start_preloading()
else:
# Pas de préchargement, fermer immédiatement
QTimer.singleShot(100, lambda: self.finished.emit(True))
def setup_ui(self):
# Configuration de la fenêtre
@ -38,6 +43,12 @@ class SplashScreen(QWidget):
self.load_splash_image()
layout.addWidget(self.image_label)
# Texte de progression
self.progress_label = QLabel("Chargement...")
self.progress_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.progress_label.setStyleSheet("font-size: 14px; color: #666;")
layout.addWidget(self.progress_label)
# Spinner de chargement
self.spinner = LoadingSpinner(50, self)
spinner_layout = QVBoxLayout()
@ -51,6 +62,38 @@ class SplashScreen(QWidget):
# Centrer la fenêtre
self.center_on_screen()
def start_preloading(self):
"""Démarre le préchargement avec un délai pour permettre l'affichage du splash"""
# Laisser le temps au splash de s'afficher
QTimer.singleShot(200, self.do_preloading)
def do_preloading(self):
"""Effectue le préchargement dans le thread principal"""
try:
# Fonction callback pour mettre à jour le texte
def progress_callback(text):
self.progress_label.setText(text)
# Traiter les événements pour que l'UI se mette à jour
from PyQt6.QtWidgets import QApplication
QApplication.processEvents()
# Appeler la fonction de préchargement
success = self.preload_function(progress_callback)
self.preload_result = success
except Exception:
self.preload_result = False
# Attendre un peu puis fermer
QTimer.singleShot(300, self.close_splash)
def close_splash(self):
"""Ferme le splash screen et émet le signal"""
if hasattr(self, 'spinner'):
self.spinner.stop()
self.finished.emit(self.preload_result)
self.close()
def load_splash_image(self):
"""Charge l'image splash depuis la config"""
try:
@ -111,20 +154,6 @@ class SplashScreen(QWidget):
y = (screen_geometry.height() - self.height()) // 2
self.move(x, y)
def setup_timer(self):
"""Configure le timer pour fermer automatiquement le splash screen"""
self.timer = QTimer()
self.timer.timeout.connect(self.close_splash)
self.timer.start(self.duration)
def close_splash(self):
"""Ferme le splash screen et émet le signal"""
if hasattr(self, 'spinner'):
self.spinner.stop()
self.timer.stop()
self.finished.emit()
self.close()
def show_splash(self):
"""Affiche le splash screen"""
self.show()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -73,5 +73,10 @@
"error_loading_image": "Error loading image : {x}.",
"export_metadata_error": "Error exporting metadata. Some files may have been exported.",
"export_partial_success": "Export partially successful. Some files could not be exported.",
"choose_export_destination": "Choose export destination folder"
"choose_export_destination": "Choose export destination folder",
"loading": "Loading...",
"checking_updates": "Checking for updates...",
"initializing": "Initializing...",
"loading_complete": "Loading complete",
"no_dicoms_to_export": "No DICOM files available for export. Please import DICOM files first."
}

View File

@ -73,5 +73,10 @@
"error_loading_image": "Error al cargar la imagen: {x}.",
"export_metadata_error": "Error al exportar metadatos. Algunos archivos pueden haber sido exportados.",
"export_partial_success": "Exportación parcialmente exitosa. Algunos archivos no pudieron ser exportados.",
"choose_export_destination": "Elige la carpeta de destino para la exportación"
"choose_export_destination": "Elige la carpeta de destino para la exportación",
"loading": "Cargando...",
"checking_updates": "Verificando actualizaciones...",
"initializing": "Inicializando...",
"loading_complete": "Carga completa",
"no_dicoms_to_export": "No hay archivos DICOM disponibles para exportar. Por favor, importe archivos DICOM primero."
}

View File

@ -73,5 +73,10 @@
"error_loading_image": "Erreur lors du chargement de l'image : {x}.",
"export_metadata_error": "Erreur lors de l'exportation des métadonnées. Certains fichiers ont pu être exportés.",
"export_partial_success": "Exportation partiellement réussie. Certains fichiers n'ont pas pu être exportés.",
"choose_export_destination": "Choisissez le dossier de destination pour l'exportation"
"choose_export_destination": "Choisissez le dossier de destination pour l'exportation",
"loading": "Chargement...",
"checking_updates": "Vérification des mises à jour...",
"initializing": "Initialisation de l'interface...",
"loading_complete": "Chargement terminé",
"no_dicoms_to_export": "Aucun fichier DICOM disponible pour l'exportation. Veuillez d'abord importer des fichiers DICOM."
}

81
main.py
View File

@ -6,11 +6,54 @@ from app.ui.main_window import MainWindow
from app.ui.windows.splash_screen import SplashScreen
from app.core.main_manager import MainManager
# Variable globale pour stocker la fenêtre préchargée
preloaded_window = None
def preload_application(progress_callback):
"""
Fonction de préchargement qui s'exécute pendant l'affichage du splash screen
Args:
progress_callback: Fonction pour mettre à jour le texte de progression
Returns:
bool: True si tout s'est bien passé, False sinon
"""
global preloaded_window
try:
main_manager = MainManager.get_instance()
language_manager = main_manager.get_language_manager()
update_manager = main_manager.get_update_manager()
# Étape 1: Vérification des mises à jour
progress_callback(language_manager.get_text("checking_updates"))
# Vérifier s'il y a une mise à jour
if update_manager.check_for_update():
# Une mise à jour est en cours de téléchargement, on ferme l'app
return False
# Étape 2: Initialisation de la fenêtre principale
progress_callback(language_manager.get_text("initializing"))
# Créer la fenêtre principale avec tous ses composants
preloaded_window = MainWindow()
# Étape 3: Finalisation
progress_callback(language_manager.get_text("loading_complete"))
return True
except Exception:
return False
def main() -> int:
global preloaded_window
main_manager: MainManager = MainManager.get_instance()
theme_manager = main_manager.get_theme_manager()
settings_manager = main_manager.get_settings_manager()
update_manager = main_manager.get_update_manager()
app: QApplication = QApplication(sys.argv)
app.setStyleSheet(theme_manager.get_sheet())
@ -22,24 +65,38 @@ def main() -> int:
use_splash = splash_image_path and paths.Path(splash_image_path).exists()
if use_splash:
# Créer et afficher le splash screen
splash = SplashScreen(duration=1500)
# Créer et afficher le splash screen avec préchargement
splash = SplashScreen(preload_function=preload_application)
splash.show_splash()
# Connecter le signal finished pour créer et afficher la fenêtre principale
def show_main_window():
if update_manager.check_for_update():
# Connecter le signal finished pour afficher la fenêtre principale préchargée
def on_splash_finished(success):
global preloaded_window
if not success:
# Le préchargement a échoué ou une mise à jour est en cours
app.quit()
return
window: MainWindow = MainWindow()
window.show()
# Afficher la fenêtre préchargée
if preloaded_window:
preloaded_window.show()
else:
# Fallback si le préchargement a échoué
window = MainWindow()
window.show()
splash.finished.connect(show_main_window)
splash.finished.connect(on_splash_finished)
else:
# Pas de splash screen, vérifier les mises à jour puis afficher la fenêtre principale
if update_manager.check_for_update():
# Pas de splash screen, exécuter le préchargement directement
def dummy_progress(text):
pass # Pas de callback de progression sans splash
success = preload_application(dummy_progress)
if not success:
return 0
window: MainWindow = MainWindow()
# Utiliser la fenêtre préchargée ou en créer une nouvelle
window = preloaded_window if preloaded_window else MainWindow()
window.show()
return app.exec()