diff --git a/README.md b/README.md index 7ca6260..5624ed0 100644 --- a/README.md +++ b/README.md @@ -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 d’onglets flexible** : Ajoutez vos fenĂȘtres oĂč vous voulez, comme vous voulez. -- **SystĂšme de suggestion** : Vos utilisateurs peuvent vous Ă©crire directement depuis l’app. -- **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 d’entrĂ©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, c’est 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 d’orchestre. -- **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 d’onglets (`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 d’exĂ©cutables. -- **python-dotenv** : Variables d’environnement. -- **requests** : RequĂȘtes HTTP (update). - ---- - -## 🔒 SĂ©curitĂ© - -- **Ne versionnez jamais `.env`** (dĂ©jĂ  dans `.gitignore`). -- Utilisez un mot de passe d’application 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 d’erreur - ---- - -**Ce template est fait pour vous faire gagner du temps et coder avec plaisir ! -Testez-le, amĂ©liorez-le, partagez-le 🚀** \ No newline at end of file +**HoDA Radio - ProtĂ©gez la confidentialitĂ©, prĂ©servez l'utilitĂ© mĂ©dicale** 🚀 \ No newline at end of file diff --git a/app/ui/main_window.py b/app/ui/main_window.py index fa68f34..af55f3d 100644 --- a/app/ui/main_window.py +++ b/app/ui/main_window.py @@ -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""" diff --git a/app/ui/windows/export_window.py b/app/ui/windows/export_window.py index 25dd71a..f0b382e 100644 --- a/app/ui/windows/export_window.py +++ b/app/ui/windows/export_window.py @@ -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) diff --git a/app/ui/windows/import_window.py b/app/ui/windows/import_window.py index 6a0b63f..82a93ac 100644 --- a/app/ui/windows/import_window.py +++ b/app/ui/windows/import_window.py @@ -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): diff --git a/app/ui/windows/splash_screen.py b/app/ui/windows/splash_screen.py index 459752e..bd38e53 100644 --- a/app/ui/windows/splash_screen.py +++ b/app/ui/windows/splash_screen.py @@ -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() diff --git a/data/assets/mia.png b/data/assets/mia.png deleted file mode 100644 index 89673dc..0000000 Binary files a/data/assets/mia.png and /dev/null differ diff --git a/data/assets/splash.png b/data/assets/splash.png index bdb7096..89673dc 100644 Binary files a/data/assets/splash.png and b/data/assets/splash.png differ diff --git a/data/lang/en.json b/data/lang/en.json index 2d75877..4fe3c34 100644 --- a/data/lang/en.json +++ b/data/lang/en.json @@ -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." } \ No newline at end of file diff --git a/data/lang/es.json b/data/lang/es.json index 557bc1f..8a51b00 100644 --- a/data/lang/es.json +++ b/data/lang/es.json @@ -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." } \ No newline at end of file diff --git a/data/lang/fr.json b/data/lang/fr.json index 805b6d3..410d317 100644 --- a/data/lang/fr.json +++ b/data/lang/fr.json @@ -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." } \ No newline at end of file diff --git a/main.py b/main.py index 7e71c1e..ed74ac3 100644 --- a/main.py +++ b/main.py @@ -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()