VIDOKS 8bafe167ac Initial commit - PedaloLauncher with Microsoft Auth
- Modern Microsoft OAuth2 authentication
- Always-available connect button (never gets disabled)
- Dynamic port allocation (25565-25575) for Edge compatibility
- Auto-connect to PEDALO server (pedalo.vidoks.fr:25565)
- Dark theme UI with modern design
- Version management with auto-download
- Fixed browser closure handling

Features:
 Button always clickable - no more gray/disabled state
 Compatible with Microsoft Edge, Chrome, Firefox
 Automatic port conflict resolution
 Clear error messages and user guidance
 Professional launcher interface

Ready for PEDALO server deployment!
2025-09-05 02:00:17 +02:00

704 lines
32 KiB
Java

// 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<String> 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<String> 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<String> getInstalledVersions() {
List<String> 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);
}
}