From 0d4106f5626c9bc06187eff92729ad5cc1bd6acc Mon Sep 17 00:00:00 2001 From: Khalid CHENOUNA Date: Fri, 6 Dec 2024 21:18:17 +0100 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lioration=20du=20code=20et=20des=20menu?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ButtonHoverAnimationListener.java | 59 +++++- .../monkhanny/dorfromantik/game/Pocket.java | 2 - .../dorfromantik/game/ScoreManager.java | 42 ----- .../gui/GameModeSelectionPanel.java | 168 ++++++++++++------ .../GameModeHoverEffectMouseListener.java | 5 + .../dorfromantik/utils/Database.java | 59 +++--- 6 files changed, 210 insertions(+), 125 deletions(-) diff --git a/src/fr/monkhanny/dorfromantik/controller/ButtonHoverAnimationListener.java b/src/fr/monkhanny/dorfromantik/controller/ButtonHoverAnimationListener.java index 3cbdc74..1690f05 100644 --- a/src/fr/monkhanny/dorfromantik/controller/ButtonHoverAnimationListener.java +++ b/src/fr/monkhanny/dorfromantik/controller/ButtonHoverAnimationListener.java @@ -7,17 +7,61 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +/** + * Listener pour animer un bouton lorsqu'il est survolé par la souris. + * Cette classe permet d'agrandir ou de réduire la taille de la police et de changer la couleur du bouton + * lorsque la souris entre ou sort de la zone du bouton. + * + * @version 1.0 + * @author Moncef STITI, Lenny FOULOU + */ public class ButtonHoverAnimationListener implements ActionListener { - private int step = 0; + /* + * Compteur d'étapes pour l'animation + */ + private int step; + + /* + * Incrément de mise à l'échelle à chaque étape + */ private final float scaleIncrement; + + /* + * Indique si la souris entre ou quitte le bouton + */ private final boolean entering; + + /* + * Référence au bouton à animer + */ private final JButton button; + + /* + * Couleur d'origine du bouton + */ private final Color originalColor; + + /* + * Police d'origine du bouton + */ private final Font originalFont; + + /* + * Échelle actuelle de la police + */ private float currentScale = 1.0f; + /** + * Constructeur pour initialiser les variables du listener. + * + * @param entering Indique si la souris entre ou quitte le bouton + * @param button Référence au bouton à animer + * @param originalColor Couleur d'origine du bouton + * @param originalFont Police d'origine du bouton + */ public ButtonHoverAnimationListener(boolean entering, JButton button, Color originalColor, Font originalFont) { + this.step = 0; this.entering = entering; this.button = button; this.originalColor = originalColor; @@ -25,18 +69,29 @@ public class ButtonHoverAnimationListener implements ActionListener { this.scaleIncrement = (Options.HOVER_FONT_SCALE - 1.0f) / Options.ANIMATION_STEPS; } + /** + * Méthode appelée à chaque étape de l'animation. + * Modifie la taille de la police et la couleur du bouton en fonction de l'état de l'animation. + * + * @param e l'événement d'action qui est émis par le Timer + */ @Override public void actionPerformed(ActionEvent e) { + // Calcul de la nouvelle échelle en fonction de l'état "entrant" ou "sortant" currentScale = entering ? (1.0f + step * scaleIncrement) : (Options.HOVER_FONT_SCALE - step * scaleIncrement); + // Modification de la couleur du bouton en fonction de l'état "entrant" ou "sortant" button.setForeground(entering ? Options.BUTTON_HOVER_COLOR : originalColor); + // Application de la nouvelle taille de police au bouton button.setFont(originalFont.deriveFont(originalFont.getSize2D() * currentScale)); + // Incrémente le compteur d'étapes step++; + // Si le nombre d'étapes est atteint, arrête le Timer et réinitialise les éléments si la souris sort if (step >= Options.ANIMATION_STEPS) { ((Timer) e.getSource()).stop(); if (!entering) { - button.setFont(originalFont); // Restore the original font + button.setFont(originalFont); // Restauration de la police originale si la souris quitte le bouton } } } diff --git a/src/fr/monkhanny/dorfromantik/game/Pocket.java b/src/fr/monkhanny/dorfromantik/game/Pocket.java index 95ad266..3416270 100644 --- a/src/fr/monkhanny/dorfromantik/game/Pocket.java +++ b/src/fr/monkhanny/dorfromantik/game/Pocket.java @@ -1,8 +1,6 @@ package fr.monkhanny.dorfromantik.game; import fr.monkhanny.dorfromantik.enums.Biome; -import fr.monkhanny.dorfromantik.enums.TileOrientation; -import java.awt.Point; import java.util.*; /** diff --git a/src/fr/monkhanny/dorfromantik/game/ScoreManager.java b/src/fr/monkhanny/dorfromantik/game/ScoreManager.java index 433d2ff..f75ad9b 100644 --- a/src/fr/monkhanny/dorfromantik/game/ScoreManager.java +++ b/src/fr/monkhanny/dorfromantik/game/ScoreManager.java @@ -57,14 +57,12 @@ public class ScoreManager { newPocket.addTile(tile); pockets.add(newPocket); biomeToPocketMap.put(biome, newPocket); - System.out.println("New pocket created with biome: " + biome); } } } // Recalculer le score après avoir ajouté la tuile recalculateScore(); - System.out.println("Current Score: " + currentScore); } /** @@ -82,46 +80,6 @@ public class ScoreManager { } return null; } - - - - - /** - * Finds a pocket connected to the given tile with the specified biome. - * - * @param tile The tile to check connections for. - * @param biome The biome to match. - * @return The connected pocket, or null if none found. - */ - private Pocket findConnectedPocket(Tile tile, Biome biome) { - for (Pocket pocket : pockets) { - if (pocket.getBiome() == biome) { - for (Tile pocketTile : pocket.getTiles()) { - if (pocketTile.isAdjacentTo(tile) && sharesBiome(tile, pocketTile, biome)) { - return pocket; - } - } - } - } - return null; - } - - /** - * Checks if two tiles share a biome on any of their sides. - * - * @param tile1 The first tile. - * @param tile2 The second tile. - * @param biome The biome to match. - * @return True if the tiles share the given biome on a connecting side. - */ - private boolean sharesBiome(Tile tile1, Tile tile2, Biome biome) { - for (TileOrientation orientation : TileOrientation.values()) { - if (tile1.getBiome(orientation) == biome && tile2.getBiome(orientation.oppositeOrientation()) == biome) { - return true; - } - } - return false; - } /** * Recalculates the score based on the current pockets. diff --git a/src/fr/monkhanny/dorfromantik/gui/GameModeSelectionPanel.java b/src/fr/monkhanny/dorfromantik/gui/GameModeSelectionPanel.java index 51ead2c..b645b34 100644 --- a/src/fr/monkhanny/dorfromantik/gui/GameModeSelectionPanel.java +++ b/src/fr/monkhanny/dorfromantik/gui/GameModeSelectionPanel.java @@ -33,10 +33,11 @@ public class GameModeSelectionPanel extends JPanel { private JSpinner startDateSpinner; private JSpinner endDateSpinner; private ActionListener buttonListener; + private JCheckBox developerSeriesCheckBox; public GameModeSelectionPanel(ActionListener buttonListener, JFrame gameModeFrame, MainMenu mainMenu) { this.buttonListener = buttonListener; - + // Initialize database try { database = new Database(); @@ -45,7 +46,7 @@ public class GameModeSelectionPanel extends JPanel { JOptionPane.showMessageDialog(null, "Erreur de connexion à la base de données", "Erreur", JOptionPane.ERROR_MESSAGE); return; } - + setLayout(new BorderLayout()); // Background setup @@ -62,7 +63,7 @@ public class GameModeSelectionPanel extends JPanel { background.add(mainPanel, BorderLayout.CENTER); // Title - titleLabel = new Title("Choisissez un série", 60f, Color.WHITE); + titleLabel = new Title("Choisissez une série", 60f, Color.WHITE); mainPanel.add(titleLabel, createGridBagConstraints(0, 0, 2)); mainPanel.add(Box.createVerticalStrut(30), createGridBagConstraints(0, 1, 1)); @@ -75,6 +76,7 @@ public class GameModeSelectionPanel extends JPanel { modePanel = new JPanel(); modePanel.setOpaque(false); seriesButtons = new ArrayList<>(); + // Pagination panel JPanel paginationPanel = createPaginationPanel(); @@ -87,112 +89,170 @@ public class GameModeSelectionPanel extends JPanel { mainPanel.add(Box.createVerticalStrut(30), createGridBagConstraints(0, 5, 1)); - // Seed input and start button + // Seed input and start button anchored at the bottom JPanel seedPanel = createSeedPanel(buttonListener); - mainPanel.add(seedPanel, createGridBagConstraints(0, 6, 2)); + background.add(seedPanel, BorderLayout.SOUTH); } public void loadSeriesForCurrentPage() { // Clear existing buttons modePanel.removeAll(); seriesButtons.clear(); - + // Récupérer les dates des spinners Date startDate = (Date) startDateSpinner.getValue(); Date endDate = (Date) endDateSpinner.getValue(); - + // Calculer le lendemain de la date de fin Calendar cal = Calendar.getInstance(); cal.setTime(endDate); - cal.add(Calendar.DAY_OF_MONTH, 1); // Ajouter un jour pour obtenir le lendemain - Date nextDay = cal.getTime(); // Le lendemain de endDate - + cal.add(Calendar.DAY_OF_MONTH, 1); + Date nextDay = cal.getTime(); + + // Vérifier si la case à cocher est sélectionnée + boolean onlyDeveloperCreated = developerSeriesCheckBox.isSelected(); + // Get paginated series - List series = database.getSeriesByDateRangePaginated(startDate, nextDay, - currentPage, - itemsPerPage); - + List series = database.getSeriesByDateRangePaginated(startDate, nextDay, currentPage, itemsPerPage, onlyDeveloperCreated); + // Si aucune série n'est trouvée pour la période donnée, afficher un message if (series.isEmpty()) { - JOptionPane.showMessageDialog(this, "Aucune série pour la période donnée", - "Avertissement", JOptionPane.WARNING_MESSAGE); + JOptionPane.showMessageDialog(this, "Aucune série pour la période donnée", "Avertissement", JOptionPane.WARNING_MESSAGE); + currentPage = 1; // Reset current page to 1 if no series is available + updatePageLabelAndButtons(1, 1); // Mettre à jour le label et désactiver les boutons return; } - + // Calculate grid layout dimensions int buttonCount = series.size(); - int columns = Math.min(buttonCount, 5); // Maximum 5 buttons per row + int columns = Math.min(buttonCount, 5); int rows = (int) Math.ceil((double) buttonCount / columns); - - modePanel.setLayout(new GridLayout(rows, columns, 20, 10)); // Add spacing between buttons - + + modePanel.setLayout(new GridLayout(rows, columns, 20, 10)); + for (String seriesName : series) { JButton seriesButton = createGameModeButton(seriesName, buttonListener); modePanel.add(seriesButton); seriesButtons.add(seriesButton); } - + // Update page label - int totalSeries = database.countSeriesByDateRange(startDate, nextDay); + int totalSeries = database.countSeriesByDateRange(startDate, nextDay, onlyDeveloperCreated); int totalPages = (int) Math.ceil((double) totalSeries / itemsPerPage); - pageLabel.setText("Page " + currentPage + " / " + totalPages); - - // Enable/disable pagination buttons - prevButton.setEnabled(currentPage > 1); - nextButton.setEnabled(currentPage < totalPages); - + + // Assurez-vous que totalPages est au moins 1 + totalPages = Math.max(totalPages, 1); + currentPage = Math.min(currentPage, totalPages); // Assurez-vous que la page actuelle ne dépasse pas le nombre total de pages + updatePageLabelAndButtons(currentPage, totalPages); + // Refresh the panel modePanel.revalidate(); modePanel.repaint(); } + private void updatePageLabelAndButtons(int currentPage, int totalPages) { + pageLabel.setText("Page " + currentPage + " / " + totalPages); + + // Enable/disable pagination buttons + prevButton.setEnabled(currentPage > 1); + nextButton.setEnabled(currentPage < totalPages); + + // Show/Hide pagination buttons if there is only one page + boolean multiplePages = totalPages > 1; + prevButton.setVisible(multiplePages); + nextButton.setVisible(multiplePages); + pageLabel.setVisible(multiplePages); + } + + + private JPanel createDateFilterPanel() { - JPanel datePanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + // Création du panneau de date avec un BoxLayout vertical pour un meilleur agencement + JPanel datePanel = new JPanel(); datePanel.setOpaque(false); + datePanel.setLayout(new BoxLayout(datePanel, BoxLayout.Y_AXIS)); + // Panneau contenant les spinners de date + JPanel dateSpinnersPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10)); + dateSpinnersPanel.setOpaque(false); + JLabel startLabel = new JLabel("Date de début:"); startLabel.setForeground(Color.WHITE); - + startLabel.setFont(new Font("Arial", Font.BOLD, 16)); + JLabel endLabel = new JLabel("Date de fin:"); endLabel.setForeground(Color.WHITE); - - // Créer des spinners pour les dates de début et de fin + endLabel.setFont(new Font("Arial", Font.BOLD, 16)); + + // Créer les spinners pour les dates de début et de fin Calendar cal = Calendar.getInstance(); Date endDate = cal.getTime(); cal.add(Calendar.DAY_OF_YEAR, -30); Date startDate = cal.getTime(); - SpinnerDateModel startDateModel = new SpinnerDateModel( - startDate, // Date par défaut (30 jours avant aujourd'hui) - null, // Pas de date minimale - endDate, // Date maximale = aujourd'hui - Calendar.DAY_OF_MONTH // Unité de changement - ); + SpinnerDateModel startDateModel = new SpinnerDateModel(startDate, null, endDate, Calendar.DAY_OF_MONTH); startDateSpinner = new JSpinner(startDateModel); - startDateSpinner.setEditor(new JSpinner.DateEditor(startDateSpinner, "yyyy-MM-dd")); - - SpinnerDateModel endDateModel = new SpinnerDateModel( - endDate, // Date par défaut = aujourd'hui - null, // Pas de date minimale - endDate, // Date maximale = aujourd'hui - Calendar.DAY_OF_MONTH // Unité de changement - ); + startDateSpinner.setEditor(new JSpinner.DateEditor(startDateSpinner, "dd-MM-yyyy")); + stylizeDateSpinner(startDateSpinner); + + SpinnerDateModel endDateModel = new SpinnerDateModel(endDate, null, endDate, Calendar.DAY_OF_MONTH); endDateSpinner = new JSpinner(endDateModel); - endDateSpinner.setEditor(new JSpinner.DateEditor(endDateSpinner, "yyyy-MM-dd")); + endDateSpinner.setEditor(new JSpinner.DateEditor(endDateSpinner, "dd-MM-yyyy")); + stylizeDateSpinner(endDateSpinner); + + dateSpinnersPanel.add(startLabel); + dateSpinnersPanel.add(startDateSpinner); + dateSpinnersPanel.add(endLabel); + dateSpinnersPanel.add(endDateSpinner); + // Ajouter la case à cocher pour les séries créées par les développeurs + developerSeriesCheckBox = new JCheckBox("Inclure seulement les séries créées par les développeurs"); + developerSeriesCheckBox.setOpaque(false); + developerSeriesCheckBox.setForeground(Color.WHITE); + developerSeriesCheckBox.setFont(new Font("Arial", Font.BOLD, 16)); + developerSeriesCheckBox.setAlignmentX(Component.CENTER_ALIGNMENT); + + // Créer un bouton de filtre JButton filterButton = new JButton("Filtrer"); + filterButton.setFont(new Font("Arial", Font.BOLD, 16)); + filterButton.setBackground(new Color(70, 130, 180)); + filterButton.setForeground(Color.WHITE); + filterButton.setFocusPainted(false); + filterButton.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(new Color(255, 255, 255, 120), 2), + BorderFactory.createEmptyBorder(5, 15, 5, 15) + )); + filterButton.setAlignmentX(Component.CENTER_ALIGNMENT); filterButton.addActionListener(new GameModeFilterButtonActionListener(this)); - - datePanel.add(startLabel); - datePanel.add(startDateSpinner); - datePanel.add(endLabel); - datePanel.add(endDateSpinner); + + // Ajouter les composants au panneau principal de filtre + datePanel.add(dateSpinnersPanel); + datePanel.add(Box.createVerticalStrut(10)); + datePanel.add(developerSeriesCheckBox); + datePanel.add(Box.createVerticalStrut(15)); datePanel.add(filterButton); - + return datePanel; } + private void stylizeDateSpinner(JSpinner spinner) { + JComponent editor = spinner.getEditor(); + if (editor instanceof JSpinner.DefaultEditor) { + JSpinner.DefaultEditor defaultEditor = (JSpinner.DefaultEditor) editor; + JTextField textField = defaultEditor.getTextField(); + textField.setFont(new Font("Arial", Font.PLAIN, 16)); + textField.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(new Color(255, 255, 255, 120), 2), + BorderFactory.createEmptyBorder(5, 10, 5, 10) + )); + textField.setBackground(new Color(40, 40, 40)); // Fond doux pour les spinners + textField.setForeground(Color.WHITE); // Texte blanc pour une meilleure lisibilité + textField.setCaretColor(Color.WHITE); // Curseur blanc + } + } + + private JPanel createPaginationPanel() { JPanel paginationPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); paginationPanel.setOpaque(false); diff --git a/src/fr/monkhanny/dorfromantik/listeners/GameModeHoverEffectMouseListener.java b/src/fr/monkhanny/dorfromantik/listeners/GameModeHoverEffectMouseListener.java index 6fed1b4..0ae6609 100644 --- a/src/fr/monkhanny/dorfromantik/listeners/GameModeHoverEffectMouseListener.java +++ b/src/fr/monkhanny/dorfromantik/listeners/GameModeHoverEffectMouseListener.java @@ -5,6 +5,9 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JButton; +import fr.monkhanny.dorfromantik.enums.Sounds; +import fr.monkhanny.dorfromantik.utils.MusicPlayer; + public class GameModeHoverEffectMouseListener extends MouseAdapter { private Color defaultColor; private Color hoverColor; @@ -20,6 +23,8 @@ public class GameModeHoverEffectMouseListener extends MouseAdapter { public void mouseEntered(MouseEvent e) { if (e.getSource() instanceof JButton button) { button.setBackground(hoverColor); + MusicPlayer.loadSound(Sounds.SOUNDS1); // Charge le son + MusicPlayer.playSound(); // Joue le son } } diff --git a/src/fr/monkhanny/dorfromantik/utils/Database.java b/src/fr/monkhanny/dorfromantik/utils/Database.java index 1aff9e3..bb9c27d 100644 --- a/src/fr/monkhanny/dorfromantik/utils/Database.java +++ b/src/fr/monkhanny/dorfromantik/utils/Database.java @@ -133,14 +133,19 @@ public class Database { } // New method to count series within a date range - public int countSeriesByDateRange(Date startDate, Date endDate) { + public int countSeriesByDateRange(Date startDate, Date endDate, boolean onlyDeveloperCreated) { int count = 0; try { - String query = "SELECT COUNT(*) as series_count FROM Series WHERE creation_date BETWEEN ? AND ?"; + // Construire la requête SQL en fonction du filtre "created_by_developer" + String query = "SELECT COUNT(*) as series_count FROM Series WHERE creation_date BETWEEN ? AND ? " + + (onlyDeveloperCreated ? "AND created_by_developer = TRUE " : ""); + + // Préparer l'instruction PreparedStatement statement = this.database.prepareStatement(query); statement.setDate(1, new java.sql.Date(startDate.getTime())); statement.setDate(2, new java.sql.Date(endDate.getTime())); - + + // Exécuter la requête et récupérer le résultat ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { count = resultSet.getInt("series_count"); @@ -150,38 +155,42 @@ public class Database { } return count; } + // New method to get paginated series within a date range public List getSeriesByDateRangePaginated(Date startDate, Date endDate, - int page, int itemsPerPage) { - List series = new ArrayList<>(); - try { - String query = "SELECT name FROM Series " + + int page, int itemsPerPage, + boolean onlyDeveloperCreated) { + List series = new ArrayList<>(); + try { + String query = "SELECT name FROM Series " + "WHERE creation_date BETWEEN ? AND ? " + + (onlyDeveloperCreated ? "AND created_by_developer = TRUE " : "") + "ORDER BY " + " CASE " + - " WHEN name LIKE 'Série custom%' THEN CAST(REGEXP_SUBSTR(name, '[0-9]+') AS UNSIGNED) " + // Extraction numérique pour 'Série custom' + " WHEN name LIKE 'Série custom%' THEN CAST(REGEXP_SUBSTR(name, '[0-9]+') AS UNSIGNED) " + " ELSE NULL " + - " END ASC, " + // Tri par numéro pour 'Série custom' - " created_by_developer DESC, " + // Tri par développeur ou joueur - " name ASC " + // Tri alphabétique + " END ASC, " + + " created_by_developer DESC, " + + " name ASC " + "LIMIT ? OFFSET ?"; - - PreparedStatement statement = this.database.prepareStatement(query); - statement.setDate(1, new java.sql.Date(startDate.getTime())); - statement.setDate(2, new java.sql.Date(endDate.getTime())); - statement.setInt(3, itemsPerPage); - statement.setInt(4, (page - 1) * itemsPerPage); - - ResultSet resultSet = statement.executeQuery(); - while (resultSet.next()) { - series.add(resultSet.getString("name")); - } - } catch (SQLException e) { - e.printStackTrace(); + + PreparedStatement statement = this.database.prepareStatement(query); + statement.setDate(1, new java.sql.Date(startDate.getTime())); + statement.setDate(2, new java.sql.Date(endDate.getTime())); + statement.setInt(3, itemsPerPage); + statement.setInt(4, (page - 1) * itemsPerPage); + + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + series.add(resultSet.getString("name")); } - return series; + } catch (SQLException e) { + e.printStackTrace(); } + return series; +} + // Optional: Method to get series within a specific number of days public List getRecentSeries(int days) {