- 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!
277 lines
10 KiB
Java
277 lines
10 KiB
Java
// src/com/minecraftlauncher/ui/InstalledVersionsDialog.java
|
|
package com.minecraftlauncher.ui;
|
|
|
|
import javax.swing.*;
|
|
import java.awt.*;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.io.File;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
public class InstalledVersionsDialog extends JDialog {
|
|
private static final String MINECRAFT_DIR = System.getProperty("user.home") + "/.minecraft";
|
|
private JList<String> versionsList;
|
|
private DefaultListModel<String> listModel;
|
|
private JButton deleteButton;
|
|
private JButton refreshButton;
|
|
private JLabel sizeLabel;
|
|
|
|
public InstalledVersionsDialog(JFrame parent) {
|
|
super(parent, "Versions Installées", true);
|
|
initializeComponents();
|
|
setupLayout();
|
|
setupEventListeners();
|
|
loadInstalledVersions();
|
|
|
|
setSize(500, 400);
|
|
setLocationRelativeTo(parent);
|
|
setResizable(true);
|
|
}
|
|
|
|
private void initializeComponents() {
|
|
// Liste des versions
|
|
listModel = new DefaultListModel<>();
|
|
versionsList = new JList<>(listModel);
|
|
versionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
versionsList.setFont(new Font("SansSerif", Font.PLAIN, 12));
|
|
versionsList.setBackground(Color.WHITE);
|
|
versionsList.setForeground(Color.BLACK);
|
|
versionsList.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
|
|
|
// Boutons
|
|
deleteButton = new JButton("Supprimer");
|
|
deleteButton.setEnabled(false);
|
|
styleButton(deleteButton, new Color(220, 38, 38), new Color(185, 28, 28)); // Rouge
|
|
|
|
refreshButton = new JButton("Actualiser");
|
|
styleButton(refreshButton, new Color(37, 99, 235), new Color(29, 78, 216)); // Bleu
|
|
|
|
JButton closeButton = new JButton("Fermer");
|
|
styleButton(closeButton, new Color(107, 114, 128), new Color(75, 85, 99)); // Gris
|
|
|
|
// Label d'information
|
|
sizeLabel = new JLabel("Aucune version installée");
|
|
sizeLabel.setFont(new Font("SansSerif", Font.PLAIN, 11));
|
|
sizeLabel.setForeground(new Color(107, 114, 128));
|
|
|
|
// Événements des boutons
|
|
closeButton.addActionListener(e -> dispose());
|
|
}
|
|
|
|
private void styleButton(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, 11));
|
|
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
button.setBorder(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);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void setupLayout() {
|
|
setLayout(new BorderLayout(10, 10));
|
|
|
|
// Panel principal
|
|
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
|
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
|
|
|
// Titre
|
|
JLabel titleLabel = new JLabel("Versions de Minecraft Installées");
|
|
titleLabel.setFont(new Font("SansSerif", Font.BOLD, 16));
|
|
titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0));
|
|
|
|
// Liste avec scroll
|
|
JScrollPane scrollPane = new JScrollPane(versionsList);
|
|
scrollPane.setBorder(BorderFactory.createLineBorder(new Color(75, 85, 99), 1));
|
|
scrollPane.setPreferredSize(new Dimension(400, 250));
|
|
|
|
// Panel des boutons
|
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
|
|
buttonPanel.add(deleteButton);
|
|
buttonPanel.add(refreshButton);
|
|
buttonPanel.add(new JButton("Fermer") {{
|
|
styleButton(this, new Color(107, 114, 128), new Color(75, 85, 99));
|
|
addActionListener(e -> dispose());
|
|
}});
|
|
|
|
// Panel du bas avec info et boutons
|
|
JPanel bottomPanel = new JPanel(new BorderLayout());
|
|
bottomPanel.add(sizeLabel, BorderLayout.WEST);
|
|
bottomPanel.add(buttonPanel, BorderLayout.EAST);
|
|
|
|
mainPanel.add(titleLabel, BorderLayout.NORTH);
|
|
mainPanel.add(scrollPane, BorderLayout.CENTER);
|
|
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
|
|
|
add(mainPanel);
|
|
}
|
|
|
|
private void setupEventListeners() {
|
|
// Sélection dans la liste
|
|
versionsList.addListSelectionListener(e -> {
|
|
if (!e.getValueIsAdjusting()) {
|
|
deleteButton.setEnabled(versionsList.getSelectedValue() != null);
|
|
}
|
|
});
|
|
|
|
// Bouton supprimer
|
|
deleteButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
deleteSelectedVersion();
|
|
}
|
|
});
|
|
|
|
// Bouton actualiser
|
|
refreshButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
loadInstalledVersions();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void loadInstalledVersions() {
|
|
listModel.clear();
|
|
List<String> installedVersions = getInstalledVersions();
|
|
|
|
if (installedVersions.isEmpty()) {
|
|
sizeLabel.setText("Aucune version installée");
|
|
} else {
|
|
for (String version : installedVersions) {
|
|
listModel.addElement(version);
|
|
}
|
|
|
|
// Calculer la taille totale
|
|
long totalSize = calculateTotalSize(installedVersions);
|
|
String sizeText = formatSize(totalSize);
|
|
sizeLabel.setText(installedVersions.size() + " version(s) - " + sizeText);
|
|
}
|
|
}
|
|
|
|
private List<String> getInstalledVersions() {
|
|
List<String> versions = new ArrayList<>();
|
|
Path versionsDir = Paths.get(MINECRAFT_DIR, "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("Erreur lors de la lecture des versions: " + e.getMessage());
|
|
}
|
|
|
|
versions.sort(String::compareTo);
|
|
return versions;
|
|
}
|
|
|
|
private long calculateTotalSize(List<String> versions) {
|
|
long totalSize = 0;
|
|
for (String version : versions) {
|
|
Path versionDir = Paths.get(MINECRAFT_DIR, "versions", version);
|
|
try {
|
|
totalSize += Files.walk(versionDir)
|
|
.filter(Files::isRegularFile)
|
|
.mapToLong(path -> {
|
|
try {
|
|
return Files.size(path);
|
|
} catch (Exception e) {
|
|
return 0;
|
|
}
|
|
})
|
|
.sum();
|
|
} catch (Exception e) {
|
|
// Ignorer les erreurs pour cette version
|
|
}
|
|
}
|
|
return totalSize;
|
|
}
|
|
|
|
private String formatSize(long bytes) {
|
|
if (bytes < 1024) return bytes + " B";
|
|
if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
|
|
if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
|
|
return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
|
|
}
|
|
|
|
private void deleteSelectedVersion() {
|
|
String selectedVersion = versionsList.getSelectedValue();
|
|
if (selectedVersion == null) return;
|
|
|
|
int result = JOptionPane.showConfirmDialog(
|
|
this,
|
|
"Voulez-vous vraiment supprimer la version " + selectedVersion + " ?\n\n" +
|
|
"Cette action est irréversible.",
|
|
"Confirmer la suppression",
|
|
JOptionPane.YES_NO_OPTION,
|
|
JOptionPane.WARNING_MESSAGE
|
|
);
|
|
|
|
if (result == JOptionPane.YES_OPTION) {
|
|
if (deleteVersion(selectedVersion)) {
|
|
JOptionPane.showMessageDialog(
|
|
this,
|
|
"Version " + selectedVersion + " Supprimée avec succès.",
|
|
"Suppression réussie",
|
|
JOptionPane.INFORMATION_MESSAGE
|
|
);
|
|
loadInstalledVersions(); // Actualiser la liste
|
|
} else {
|
|
JOptionPane.showMessageDialog(
|
|
this,
|
|
"Erreur lors de la suppression de la version " + selectedVersion + ".\n" +
|
|
"Vérifiez que les fichiers ne sont pas en cours d'utilisation.",
|
|
"Erreur de suppression",
|
|
JOptionPane.ERROR_MESSAGE
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean deleteVersion(String version) {
|
|
Path versionDir = Paths.get(MINECRAFT_DIR, "versions", version);
|
|
|
|
try {
|
|
// Supprimer récursivement le dossier de la version
|
|
Files.walk(versionDir)
|
|
.sorted((a, b) -> b.compareTo(a)) // Ordre inverse pour supprimer les fichiers avant les dossiers
|
|
.forEach(path -> {
|
|
try {
|
|
Files.delete(path);
|
|
} catch (Exception e) {
|
|
System.err.println("Impossible de supprimer: " + path);
|
|
}
|
|
});
|
|
return !Files.exists(versionDir);
|
|
} catch (Exception e) {
|
|
System.err.println("[ERROR] Erreur lors de la suppression: " + e.getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
} |