// src/com/minecraftlauncher/ui/LauncherFrame.java package com.minecraftlauncher.ui; import com.minecraftlauncher.auth.ModernAuthManager; import com.minecraftlauncher.game.GameLauncher; import com.minecraftlauncher.model.Account; import javax.swing.*; import javax.swing.Timer; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.Arrays; import java.util.ArrayList; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class LauncherFrame extends JFrame { // Gestionnaires réels private ModernAuthManager authManager; private GameLauncher gameLauncher; private Account currentAccount; // Composants UI private JLabel userLabel; private JButton loginButton; private JComboBox versionComboBox; private JButton downloadButton; private JButton launchButton; private JButton versionsButton; private JLabel statusLabel; private JLabel serverInfoLabel; public LauncherFrame() { initializeComponents(); setupLayout(); setupEventListeners(); // Initialisation des gestionnaires réels authManager = new ModernAuthManager(); gameLauncher = new GameLauncher(); // Charger les versions disponibles loadAvailableVersions(); } private void initializeComponents() { // Configuration de base setTitle("Le Launcher du PEDALO"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(700, 650); setLocationRelativeTo(null); setResizable(true); setMinimumSize(new Dimension(650, 600)); // Thème sombre moderne setupModernTheme(); // Composants d'authentification avec style moderne userLabel = new JLabel("Non connecte"); userLabel.setFont(new Font("SansSerif", Font.BOLD, 15)); userLabel.setForeground(new Color(239, 68, 68)); // Rouge moderne userLabel.setBorder(BorderFactory.createEmptyBorder(8, 12, 8, 12)); userLabel.setOpaque(true); userLabel.setBackground(new Color(55, 65, 81)); userLabel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(75, 85, 99), 1), BorderFactory.createEmptyBorder(8, 12, 8, 12))); loginButton = new JButton("Se connecter à Microsoft"); styleModernButton(loginButton, new Color(37, 99, 235), new Color(29, 78, 216)); // Bleu moderne loginButton.setFont(new Font("SansSerif", Font.BOLD, 13)); loginButton.setPreferredSize(new Dimension(250, 40)); // Composants de version avec style moderne versionComboBox = new JComboBox<>(); versionComboBox.setEnabled(false); styleModernComboBox(versionComboBox); versionComboBox.setPreferredSize(new Dimension(200, 35)); downloadButton = new JButton("Chargement..."); downloadButton.setEnabled(false); styleModernButton(downloadButton, new Color(249, 115, 22), new Color(234, 88, 12)); // Orange moderne downloadButton.setPreferredSize(new Dimension(150, 35)); launchButton = new JButton("🚀 REJOINDRE LE SERVEUR PEDALO"); launchButton.setEnabled(false); styleModernButton(launchButton, new Color(34, 197, 94), new Color(22, 163, 74)); // Vert moderne launchButton.setFont(new Font("SansSerif", Font.BOLD, 16)); launchButton.setPreferredSize(new Dimension(300, 50)); // Effet de brillance launchButton.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(74, 222, 128), 2), BorderFactory.createEmptyBorder(5, 20, 5, 20))); versionsButton = new JButton("📦 Toutes les Versions"); styleModernButton(versionsButton, new Color(99, 102, 241), new Color(79, 70, 229)); // Indigo moderne versionsButton.setPreferredSize(new Dimension(150, 35)); // Label d'information serveur fixe serverInfoLabel = new JLabel("🌐 Connexion automatique au serveur : pedalo.vidoks.fr:25565"); serverInfoLabel.setFont(new Font("SansSerif", Font.BOLD, 14)); serverInfoLabel.setForeground(new Color(34, 197, 94)); // Vert serverInfoLabel.setHorizontalAlignment(SwingConstants.CENTER); serverInfoLabel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(34, 197, 94), 2), BorderFactory.createEmptyBorder(10, 15, 10, 15))); serverInfoLabel.setOpaque(true); serverInfoLabel.setBackground(new Color(21, 128, 61, 20)); statusLabel = new JLabel("🚀 Prêt - Cliquez sur 'Se connecter' pour rejoindre le serveur PEDALO"); statusLabel.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15)); statusLabel.setFont(new Font("SansSerif", Font.PLAIN, 12)); statusLabel.setForeground(new Color(156, 163, 175)); statusLabel.setOpaque(true); statusLabel.setBackground(new Color(17, 24, 39)); statusLabel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, new Color(75, 85, 99)), BorderFactory.createEmptyBorder(10, 15, 10, 15))); } // Méthodes de stylisation moderne private void setupModernTheme() { // Couleur de fond principale - thème sombre moderne getContentPane().setBackground(new Color(17, 24, 39)); // Gray-900 // Configuration globale des composants pour thème sombre uniforme UIManager.put("Panel.background", new Color(17, 24, 39)); UIManager.put("Label.foreground", new Color(243, 244, 246)); // Boîtes de dialogue et menus déroulants UIManager.put("OptionPane.background", new Color(17, 24, 39)); UIManager.put("OptionPane.messageForeground", new Color(243, 244, 246)); UIManager.put("OptionPane.messageBackground", new Color(17, 24, 39)); UIManager.put("Button.background", new Color(55, 65, 81)); UIManager.put("Button.foreground", new Color(243, 244, 246)); // ComboBox thème sombre - Fix pour éviter blanc sur blanc UIManager.put("ComboBox.background", new Color(31, 41, 55)); UIManager.put("ComboBox.foreground", new Color(243, 244, 246)); UIManager.put("ComboBox.selectionBackground", new Color(37, 99, 235)); UIManager.put("ComboBox.selectionForeground", Color.WHITE); UIManager.put("ComboBox.buttonBackground", new Color(55, 65, 81)); UIManager.put("ComboBox.disabledBackground", new Color(55, 65, 81)); UIManager.put("ComboBox.disabledForeground", new Color(156, 163, 175)); // Menu popup pour ComboBox UIManager.put("PopupMenu.background", new Color(31, 41, 55)); UIManager.put("MenuItem.background", new Color(31, 41, 55)); UIManager.put("MenuItem.foreground", new Color(243, 244, 246)); UIManager.put("MenuItem.selectionBackground", new Color(55, 65, 81)); UIManager.put("MenuItem.selectionForeground", Color.WHITE); // Scrollbars UIManager.put("ScrollBar.background", new Color(31, 41, 55)); UIManager.put("ScrollBar.thumb", new Color(75, 85, 99)); UIManager.put("ScrollBar.thumbShadow", new Color(55, 65, 81)); UIManager.put("ScrollBar.thumbHighlight", new Color(107, 114, 128)); // Curseur personnalisé setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); // AJOUT : Fix supplémentaire pour ComboBox fixComboBoxUIManager(); } // NOUVELLE METHODE : Fix pour ComboBox private void fixComboBoxUIManager() { // Désactiver les couleurs par défaut qui peuvent interférer UIManager.put("ComboBox.border", BorderFactory.createEmptyBorder()); UIManager.put("ComboBox.borderSelectionColor", null); UIManager.put("ComboBox.buttonDarkShadow", new Color(75, 85, 99)); UIManager.put("ComboBox.buttonHighlight", new Color(107, 114, 128)); UIManager.put("ComboBox.buttonShadow", new Color(55, 65, 81)); UIManager.put("ComboBox.focus", new Color(37, 99, 235)); // Force les couleurs pour la liste popup UIManager.put("List.background", new Color(31, 41, 55)); UIManager.put("List.foreground", new Color(243, 244, 246)); UIManager.put("List.selectionBackground", new Color(37, 99, 235)); UIManager.put("List.selectionForeground", Color.WHITE); UIManager.put("List.focusCellHighlightBorder", BorderFactory.createEmptyBorder()); } private void styleModernButton(JButton button, Color bgColor, Color hoverColor) { button.setBackground(bgColor); button.setForeground(Color.WHITE); button.setFocusPainted(false); button.setBorderPainted(false); button.setFont(new Font("SansSerif", Font.BOLD, 12)); button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // Bordures arrondies avec padding button.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(bgColor.brighter(), 1), BorderFactory.createEmptyBorder(8, 16, 8, 16))); // Effet hover button.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent evt) { button.setBackground(hoverColor); } public void mouseExited(java.awt.event.MouseEvent evt) { button.setBackground(bgColor); } }); } // METHODE MODIFIEE : Fix pour ComboBox private void styleModernComboBox(JComboBox comboBox) { // Configuration de base comboBox.setBackground(new Color(31, 41, 55)); comboBox.setForeground(new Color(243, 244, 246)); comboBox.setFont(new Font("SansSerif", Font.PLAIN, 12)); comboBox.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(75, 85, 99), 1), BorderFactory.createEmptyBorder(5, 10, 5, 10))); // SOLUTION : Renderer personnalisé avec couleurs forcées comboBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); // CORRECTION : Force les couleurs explicitement if (isSelected) { setBackground(new Color(37, 99, 235)); // Bleu pour sélection setForeground(Color.WHITE); } else { setBackground(new Color(31, 41, 55)); // Fond sombre setForeground(new Color(243, 244, 246)); // Texte clair } // IMPORTANT : Force l'opacité pour que les couleurs s'appliquent setOpaque(true); setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); return this; } }); // AJOUT : Configuration supplémentaire pour éviter les conflits UIManager comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.FALSE); // AJOUT : Listener pour forcer le style au focus comboBox.addFocusListener(new java.awt.event.FocusAdapter() { @Override public void focusGained(java.awt.event.FocusEvent evt) { comboBox.setBackground(new Color(31, 41, 55)); comboBox.setForeground(new Color(243, 244, 246)); } }); } private JLabel createSectionTitle(String title, String icon) { JLabel label = new JLabel(icon + " " + title); label.setFont(new Font("SansSerif", Font.BOLD, 14)); label.setForeground(new Color(147, 197, 253)); // Blue-300 label.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); return label; } private void setupLayout() { setLayout(new BorderLayout()); // Panel principal avec thème sombre JPanel mainPanel = new JPanel(new GridBagLayout()); mainPanel.setBackground(new Color(17, 24, 39)); mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 25, 20, 25)); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(8, 8, 8, 8); // Section authentification avec design moderne gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; JLabel authTitle = createSectionTitle("Authentification", "🔐"); mainPanel.add(authTitle, gbc); gbc.gridy = 1; gbc.gridwidth = 1; mainPanel.add(userLabel, gbc); gbc.gridx = 1; mainPanel.add(loginButton, gbc); // Séparateur moderne gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.HORIZONTAL; JSeparator sep1 = new JSeparator(); sep1.setForeground(new Color(75, 85, 99)); sep1.setBackground(new Color(75, 85, 99)); gbc.insets = new Insets(15, 0, 15, 0); mainPanel.add(sep1, gbc); gbc.insets = new Insets(8, 8, 8, 8); // Section versions avec design moderne gbc.gridy = 3; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.NONE; JLabel versionTitle = createSectionTitle("Gestion des Versions Minecraft", "📦"); mainPanel.add(versionTitle, gbc); gbc.gridy = 4; gbc.gridwidth = 1; JLabel versionLabel = new JLabel("Version:"); versionLabel.setForeground(new Color(209, 213, 219)); versionLabel.setFont(new Font("SansSerif", Font.PLAIN, 12)); mainPanel.add(versionLabel, gbc); gbc.gridx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; mainPanel.add(versionComboBox, gbc); gbc.gridx = 0; gbc.gridy = 5; gbc.fill = GridBagConstraints.NONE; mainPanel.add(downloadButton, gbc); gbc.gridx = 1; mainPanel.add(versionsButton, gbc); // Séparateur moderne gbc.gridx = 0; gbc.gridy = 6; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.HORIZONTAL; JSeparator sep2 = new JSeparator(); sep2.setForeground(new Color(75, 85, 99)); sep2.setBackground(new Color(75, 85, 99)); gbc.insets = new Insets(15, 0, 15, 0); mainPanel.add(sep2, gbc); gbc.insets = new Insets(8, 8, 8, 8); // Information serveur fixe gbc.gridy = 7; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(15, 0, 15, 0); mainPanel.add(serverInfoLabel, gbc); gbc.insets = new Insets(8, 8, 8, 8); // Bouton de lancement avec style spécial gbc.gridy = 8; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(20, 0, 10, 0); launchButton.setPreferredSize(new Dimension(300, 50)); mainPanel.add(launchButton, gbc); gbc.insets = new Insets(8, 8, 8, 8); add(mainPanel, BorderLayout.CENTER); // Barre de statut add(statusLabel, BorderLayout.SOUTH); } private void setupEventListeners() { loginButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { performAuthentication(); } }); versionComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateVersionStatus(); } }); downloadButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { downloadSelectedVersion(); } }); launchButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { launchMinecraft(); } }); versionsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showAllVersionsDialog(); } }); } private void loadAvailableVersions() { SwingUtilities.invokeLater(() -> statusLabel.setText("Chargement des versions installées...")); new Thread(() -> { try { // Charger uniquement les versions installées List installedVersions = getInstalledVersions(); SwingUtilities.invokeLater(() -> { versionComboBox.removeAllItems(); if (installedVersions.isEmpty()) { versionComboBox.addItem("Aucune version installée"); versionComboBox.setEnabled(false); downloadButton.setEnabled(false); statusLabel.setText("Aucune version installée - Utilisez \"📦 Toutes les Versions\" pour en télécharger"); } else { for (String version : installedVersions) { versionComboBox.addItem(version); } versionComboBox.setEnabled(true); downloadButton.setEnabled(true); updateVersionStatus(); statusLabel.setText("✅ " + installedVersions.size() + " version(s) installée(s) - Prêt pour l'authentification !"); } }); } catch (Exception e) { SwingUtilities.invokeLater(() -> { statusLabel.setText("Erreur de chargement des versions installées"); DarkThemeUtils.showDarkOptionPane(this, "Impossible de charger les versions installées :\n\n" + e.getMessage(), "Erreur de Chargement", JOptionPane.ERROR_MESSAGE); }); } }).start(); } private List getInstalledVersions() { List versions = new ArrayList<>(); Path versionsDir = Paths.get(System.getProperty("user.home") + "/.minecraft", "versions"); try { if (Files.exists(versionsDir) && Files.isDirectory(versionsDir)) { Files.list(versionsDir) .filter(Files::isDirectory) .forEach(versionDir -> { String versionName = versionDir.getFileName().toString(); Path jarFile = versionDir.resolve(versionName + ".jar"); Path jsonFile = versionDir.resolve(versionName + ".json"); // Vérifier que les fichiers essentiels existent if (Files.exists(jarFile) && Files.exists(jsonFile)) { versions.add(versionName); } }); } } catch (Exception e) { System.err.println("[ERROR] Erreur lors de la lecture des versions installées: " + e.getMessage()); } versions.sort(String::compareTo); return versions; } private void performAuthentication() { // LE BOUTON NE SE DÉSACTIVE JAMAIS - Solution simple ! statusLabel.setText("🔐 Ouverture du navigateur pour l'authentification Microsoft... (Vous pouvez recliquer si besoin)"); new Thread(() -> { try { Account account = authManager.authenticate(); currentAccount = account; SwingUtilities.invokeLater(() -> { userLabel.setText("👤 " + account.getUsername()); userLabel.setForeground(new Color(34, 197, 94)); userLabel.setBackground(new Color(21, 128, 61, 20)); loginButton.setText("🔁 Reconnexion"); launchButton.setEnabled(true); statusLabel.setText("✅ Authentification réussie - Prêt à rejoindre le serveur PEDALO !"); }); } catch (Exception e) { SwingUtilities.invokeLater(() -> { // Messages d'erreur informatifs if (e.getMessage() != null && e.getMessage().contains("Timeout")) { statusLabel.setText("⏱️ Navigateur fermé ou délai expiré - Cliquez à nouveau quand vous voulez"); } else if (e.getMessage() != null && e.getMessage().contains("fermé")) { statusLabel.setText("🌐 Navigateur fermé - Recliquez pour relancer l'authentification"); } else if (e.getMessage() != null && e.getMessage().contains("occupé")) { statusLabel.setText("⚠️ Port occupé - Attendez 2 secondes et recliquez"); } else if (e.getMessage() != null && e.getMessage().contains("annulée")) { statusLabel.setText("🔄 Authentification annulée - Recliquez quand vous voulez"); } else { statusLabel.setText("❌ Erreur d'authentification - Recliquez pour réessayer"); } System.out.println("[INFO] Authentification échouée: " + e.getMessage()); System.out.println("[INFO] Vous pouvez recliquer sur le bouton à tout moment pour réessayer"); }); } }).start(); } private void updateVersionStatus() { String selectedVersion = (String) versionComboBox.getSelectedItem(); if (selectedVersion != null) { String status = gameLauncher.getVersionStatus(selectedVersion); if (status.startsWith("Non telechargee")) { downloadButton.setText("📥 Telecharger"); styleModernButton(downloadButton, new Color(249, 115, 22), new Color(234, 88, 12)); // Orange } else if (status.startsWith("Telechargee")) { downloadButton.setText("🔄 Retelecharger (" + status + ")"); styleModernButton(downloadButton, new Color(34, 197, 94), new Color(22, 163, 74)); // Vert } else { downloadButton.setText("🔧 Reparer (" + status + ")"); styleModernButton(downloadButton, new Color(239, 68, 68), new Color(220, 38, 38)); // Rouge } } } private void downloadSelectedVersion() { String selectedVersion = (String) versionComboBox.getSelectedItem(); if (selectedVersion == null) return; downloadButton.setEnabled(false); statusLabel.setText("[DL] Telechargement en cours... Veuillez patienter"); new Thread(() -> { try { boolean success = gameLauncher.downloadVersion(selectedVersion); SwingUtilities.invokeLater(() -> { downloadButton.setEnabled(true); if (success) { statusLabel.setText("[OK] Telechargement termine avec succes !"); updateVersionStatus(); // Plus de popup de téléchargement réussi } else { statusLabel.setText("[ERROR] Echec du telechargement - Veuillez reessayer"); DarkThemeUtils.showDarkOptionPane(this, "Erreur lors du téléchargement de " + selectedVersion + "\n\n" + "Consultez la console pour plus de détails.\n" + "Essayez de retélécharger la version.", "Erreur de Téléchargement", JOptionPane.ERROR_MESSAGE); } }); } catch (Exception e) { SwingUtilities.invokeLater(() -> { downloadButton.setEnabled(true); statusLabel.setText("[ERROR] Erreur de telechargement"); DarkThemeUtils.showDarkOptionPane(LauncherFrame.this, "Erreur de téléchargement:\n\n" + e.getMessage(), "Erreur de Téléchargement", JOptionPane.ERROR_MESSAGE); }); } }).start(); } private void launchMinecraft() { if (currentAccount == null) { DarkThemeUtils.showDarkOptionPane(this, "Vous devez vous connecter avant de lancer Minecraft.\n\n" + "Cliquez sur 'Se connecter avec Microsoft' pour commencer.\n" + "L'authentification est automatique et sécurisée !", "Connexion Requise", JOptionPane.WARNING_MESSAGE); return; } String selectedVersion = (String) versionComboBox.getSelectedItem(); if (selectedVersion == null) { DarkThemeUtils.showDarkOptionPane(this, "Veuillez sélectionner une version de Minecraft à lancer.\n\n" + "Choisissez une version dans le menu déroulant ci-dessus.", "Version Requise", JOptionPane.WARNING_MESSAGE); return; } String status = gameLauncher.getVersionStatus(selectedVersion); if (status.startsWith("Non téléchargée")) { DarkThemeUtils.showDarkOptionPane(this, "La version " + selectedVersion + " n'est pas encore téléchargée.\n\n" + "Veuillez la télécharger avant de lancer le jeu.\n" + "Cliquez sur le bouton 'Télécharger' ci-dessus.", "Téléchargement Requis", JOptionPane.WARNING_MESSAGE); return; } launchButton.setEnabled(false); statusLabel.setText("🚀 Connexion au serveur PEDALO en cours..."); new Thread(() -> { try { // Configuration serveur fixe gameLauncher.setServerInfo("pedalo.vidoks.fr", "25565"); boolean success = gameLauncher.launchGame(selectedVersion, currentAccount); SwingUtilities.invokeLater(() -> { if (success) { statusLabel.setText("✅ Connexion au serveur PEDALO réussie ! Bon jeu !"); launchButton.setEnabled(true); // Plus de popup de lancement réussi } else { statusLabel.setText("[ERROR] Echec du lancement - Verifiez les prerequis"); launchButton.setEnabled(true); DarkThemeUtils.showDarkOptionPane(this, "Erreur lors du lancement de Minecraft.\n\n" + "Vérifiez les prérequis :\n" + " - Java est installé (java -version)\n" + " - RAM suffisante (2GB minimum)\n" + " - Espace disque disponible\n" + " - Antivirus n'interfère pas\n\n" + "Consultez les logs dans la console", "Erreur de Lancement", JOptionPane.ERROR_MESSAGE); } }); } catch (Exception e) { SwingUtilities.invokeLater(() -> { launchButton.setEnabled(true); statusLabel.setText("[ERROR] Erreur critique de lancement"); DarkThemeUtils.showDarkOptionPane(this, "Erreur critique de lancement :\n\n" + e.getMessage() + "\n\n" + "Consultez la console pour plus de détails.\n" + "Essayez de retélécharger la version.", "Erreur Critique", JOptionPane.ERROR_MESSAGE); }); } }).start(); } private void showAllVersionsDialog() { new VersionsTabDialog(this, gameLauncher).setVisible(true); } // Méthodes pour les popups modernes private void showSuccessDialog(String title, String mainMessage, String details, String uuid) { JPanel panel = new JPanel(new BorderLayout(10, 15)); panel.setBackground(Color.WHITE); panel.setBorder(BorderFactory.createEmptyBorder(20, 25, 20, 25)); // Titre avec icône de succès JLabel titleLabel = new JLabel("✓ " + mainMessage); titleLabel.setFont(new Font("SansSerif", Font.BOLD, 18)); titleLabel.setForeground(new Color(22, 163, 74)); // Vert succès titleLabel.setHorizontalAlignment(SwingConstants.CENTER); // Message de détails JTextArea detailsArea = new JTextArea(details); detailsArea.setFont(new Font("SansSerif", Font.PLAIN, 13)); detailsArea.setForeground(new Color(55, 65, 81)); detailsArea.setBackground(Color.WHITE); detailsArea.setEditable(false); detailsArea.setOpaque(false); detailsArea.setLineWrap(true); detailsArea.setWrapStyleWord(true); // UUID (optionnel, en petit) JLabel uuidLabel = new JLabel("UUID: " + uuid); uuidLabel.setFont(new Font("Monospaced", Font.PLAIN, 10)); uuidLabel.setForeground(new Color(107, 114, 128)); // Gris uuidLabel.setHorizontalAlignment(SwingConstants.CENTER); // Panel pour l'icône de succès JPanel iconPanel = new JPanel(); iconPanel.setBackground(Color.WHITE); JLabel iconLabel = new JLabel("✓"); iconLabel.setFont(new Font("SansSerif", Font.BOLD, 48)); iconLabel.setForeground(new Color(22, 163, 74)); iconPanel.add(iconLabel); panel.add(iconPanel, BorderLayout.NORTH); panel.add(titleLabel, BorderLayout.CENTER); JPanel bottomPanel = new JPanel(new BorderLayout(5, 5)); bottomPanel.setBackground(Color.WHITE); bottomPanel.add(detailsArea, BorderLayout.CENTER); bottomPanel.add(uuidLabel, BorderLayout.SOUTH); panel.add(bottomPanel, BorderLayout.SOUTH); JOptionPane.showMessageDialog(this, panel, title, JOptionPane.PLAIN_MESSAGE); } private void showErrorDialog(String title, String mainMessage, String details) { JPanel panel = new JPanel(new BorderLayout(10, 15)); panel.setBackground(Color.WHITE); panel.setBorder(BorderFactory.createEmptyBorder(20, 25, 20, 25)); // Titre avec icône d'erreur JLabel titleLabel = new JLabel("✗ " + mainMessage); titleLabel.setFont(new Font("SansSerif", Font.BOLD, 18)); titleLabel.setForeground(new Color(220, 38, 38)); // Rouge erreur titleLabel.setHorizontalAlignment(SwingConstants.CENTER); // Message de détails JTextArea detailsArea = new JTextArea(details); detailsArea.setFont(new Font("SansSerif", Font.PLAIN, 13)); detailsArea.setForeground(new Color(55, 65, 81)); detailsArea.setBackground(Color.WHITE); detailsArea.setEditable(false); detailsArea.setOpaque(false); detailsArea.setLineWrap(true); detailsArea.setWrapStyleWord(true); // Panel pour l'icône d'erreur JPanel iconPanel = new JPanel(); iconPanel.setBackground(Color.WHITE); JLabel iconLabel = new JLabel("✗"); iconLabel.setFont(new Font("SansSerif", Font.BOLD, 48)); iconLabel.setForeground(new Color(220, 38, 38)); iconPanel.add(iconLabel); panel.add(iconPanel, BorderLayout.NORTH); panel.add(titleLabel, BorderLayout.CENTER); panel.add(detailsArea, BorderLayout.SOUTH); JOptionPane.showMessageDialog(this, panel, title, JOptionPane.PLAIN_MESSAGE); } }