diff --git a/src/mathquiz/gui_1/gui_1/ChangePasswordDialog.java b/src/mathquiz/gui_1/gui_1/ChangePasswordDialog.java new file mode 100644 index 0000000..a2e7f0e --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/ChangePasswordDialog.java @@ -0,0 +1,186 @@ +package mathquiz.gui; + +import mathquiz.backend.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Change Password Dialog + */ +public class ChangePasswordDialog extends JDialog { + private JPasswordField newPasswordField; + private JPasswordField confirmPasswordField; + private JButton okButton; + private JButton cancelButton; + private JLabel messageLabel; + + public ChangePasswordDialog(JFrame parent) { + super(parent, "Change Password", true); + initializeComponents(); + setupLayout(); + setupEventHandlers(); + setLocationRelativeTo(parent); + setSize(400, 300); + setResizable(false); + } + + private void initializeComponents() { + newPasswordField = new JPasswordField(20); + confirmPasswordField = new JPasswordField(20); + okButton = new JButton("OK"); + cancelButton = new JButton("Cancel"); + messageLabel = new JLabel("", JLabel.CENTER); + + messageLabel.setForeground(Color.RED); + okButton.setPreferredSize(new Dimension(80, 30)); + cancelButton.setPreferredSize(new Dimension(80, 30)); + } + + private void setupLayout() { + setLayout(new BorderLayout()); + + // Input panel + JPanel inputPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(10, 10, 10, 10); + + gbc.gridx = 0; gbc.gridy = 0; + inputPanel.add(new JLabel("New Password:"), gbc); + gbc.gridx = 1; + inputPanel.add(newPasswordField, gbc); + + gbc.gridx = 0; gbc.gridy = 1; + inputPanel.add(new JLabel("Confirm Password:"), gbc); + gbc.gridx = 1; + inputPanel.add(confirmPasswordField, gbc); + + // Password requirement description + JPanel requirementPanel = new JPanel(); + JLabel requirementLabel = new JLabel("Password requirements: 6-10 characters, must include uppercase, lowercase and digits"); + requirementLabel.setForeground(Color.BLUE); + requirementLabel.setFont(new Font("Arial", Font.PLAIN, 12)); + requirementPanel.add(requirementLabel); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(okButton); + buttonPanel.add(cancelButton); + + // Message panel + JPanel messagePanel = new JPanel(); + messagePanel.add(messageLabel); + + // Create main content panel + JPanel mainContentPanel = new JPanel(); + mainContentPanel.setLayout(new BoxLayout(mainContentPanel, BoxLayout.Y_AXIS)); + mainContentPanel.add(inputPanel); + mainContentPanel.add(requirementPanel); + + // Create bottom panel with buttons and message + JPanel bottomPanel = new JPanel(); + bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); + bottomPanel.add(buttonPanel); + bottomPanel.add(messagePanel); + + // Assemble + add(mainContentPanel, BorderLayout.CENTER); + add(bottomPanel, BorderLayout.SOUTH); + + setSize(400, 300); + } + + private void setupEventHandlers() { + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePassword(); + } + }); + + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + + // Enter key handling + confirmPasswordField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePassword(); + } + }); + } + + private void changePassword() { + String newPassword = new String(newPasswordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + if (newPassword.isEmpty() || confirmPassword.isEmpty()) { + showMessage("Please fill in all fields", Color.RED); + return; + } + + if (!newPassword.equals(confirmPassword)) { + showMessage("New passwords do not match", Color.RED); + return; + } + + if (!isValidPassword(newPassword)) { + showMessage("New password does not meet requirements: 6-10 characters, must include uppercase, lowercase and digits", Color.RED); + return; + } + + try { + UserService userService = new UserService(); + String currentUser = mathquiz.gui.QuizSession.getInstance().getCurrentUser(); + + userService.setPassword(currentUser, newPassword); + showMessage("Password changed successfully", Color.GREEN); + + // Close dialog after delay + Timer timer = new Timer(1000, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + timer.setRepeats(false); + timer.start(); + + } catch (Exception ex) { + showMessage("Password change failed: " + ex.getMessage(), Color.RED); + } + } + + private boolean isValidPassword(String password) { + if (password.length() < 6 || password.length() > 10) { + return false; + } + + boolean hasUpperCase = false; + boolean hasLowerCase = false; + boolean hasDigit = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) { + hasUpperCase = true; + } else if (Character.isLowerCase(c)) { + hasLowerCase = true; + } else if (Character.isDigit(c)) { + hasDigit = true; + } + } + + return hasUpperCase && hasLowerCase && hasDigit; + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/GradeSelectionPanel.java b/src/mathquiz/gui_1/gui_1/GradeSelectionPanel.java new file mode 100644 index 0000000..ee14e88 --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/GradeSelectionPanel.java @@ -0,0 +1,152 @@ +package mathquiz.gui; + +import mathquiz.AccountType; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Grade Selection Panel + */ +public class GradeSelectionPanel extends JPanel { + private final MainFrame mainFrame; + private JButton primaryButton; + private JButton middleButton; + private JButton highButton; + private JButton logoutButton; + private JButton changePasswordButton; + private JLabel messageLabel; + + public GradeSelectionPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + primaryButton = new JButton("Primary School"); + middleButton = new JButton("Middle School"); + highButton = new JButton("High School"); + logoutButton = new JButton("Logout"); + changePasswordButton = new JButton("Change Password"); + messageLabel = new JLabel("Please select your grade level", JLabel.CENTER); + + messageLabel.setFont(new Font("Arial", Font.BOLD, 16)); + messageLabel.setForeground(Color.BLUE); + + // Set button styles + primaryButton.setPreferredSize(new Dimension(150, 60)); + middleButton.setPreferredSize(new Dimension(150, 60)); + highButton.setPreferredSize(new Dimension(150, 60)); + logoutButton.setPreferredSize(new Dimension(120, 40)); + changePasswordButton.setPreferredSize(new Dimension(150, 40)); + + primaryButton.setFont(new Font("Arial", Font.BOLD, 16)); + middleButton.setFont(new Font("Arial", Font.BOLD, 16)); + highButton.setFont(new Font("Arial", Font.BOLD, 16)); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + // Title + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("Math Quiz System", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 24)); + titlePanel.add(titleLabel); + + // Message panel + JPanel messagePanel = new JPanel(); + messagePanel.add(messageLabel); + + // Grade selection panel + JPanel gradePanel = new JPanel(new GridLayout(1, 3, 20, 20)); + gradePanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + gradePanel.add(primaryButton); + gradePanel.add(middleButton); + gradePanel.add(highButton); + + // Bottom button panel + JPanel bottomPanel = new JPanel(new FlowLayout()); + bottomPanel.add(changePasswordButton); + bottomPanel.add(logoutButton); + + // Assemble + mainPanel.add(titlePanel, BorderLayout.NORTH); + mainPanel.add(messagePanel, BorderLayout.NORTH); + mainPanel.add(gradePanel, BorderLayout.CENTER); + mainPanel.add(bottomPanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void setupEventHandlers() { + primaryButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + selectGrade(AccountType.PRIMARY); + } + }); + + middleButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + selectGrade(AccountType.MIDDLE); + } + }); + + highButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + selectGrade(AccountType.HIGH); + } + }); + + changePasswordButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + changePassword(); + } + }); + + logoutButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + logout(); + } + }); + } + + private void selectGrade(AccountType grade) { + // Save selected grade to global state + QuizSession.getInstance().setAccountType(grade); + showMessage("Selected " + grade.displayName() + " grade", Color.GREEN); + + // Jump to question count input interface + mainFrame.showQuestionCountPanel(); + } + + private void changePassword() { + // Show change password dialog + ChangePasswordDialog dialog = new ChangePasswordDialog(mainFrame); + dialog.setVisible(true); + } + + private void logout() { + // Clear session information + QuizSession.getInstance().clear(); + + // Return to login interface + mainFrame.showLoginPanel(); + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/LoginPanel.java b/src/mathquiz/gui_1/gui_1/LoginPanel.java new file mode 100644 index 0000000..5b01b0b --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/LoginPanel.java @@ -0,0 +1,196 @@ +package mathquiz.gui; + +import mathquiz.backend.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Login Panel + */ +public class LoginPanel extends JPanel { + private final MainFrame mainFrame; + private JTextField usernameField; + private JTextField emailField; + private JPasswordField passwordField; + private JButton loginButton; + private JButton registerButton; + private JLabel messageLabel; + + public LoginPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + // Create components + usernameField = new JTextField(20); + emailField = new JTextField(20); + passwordField = new JPasswordField(20); + loginButton = new JButton("Login"); + registerButton = new JButton("Register"); + messageLabel = new JLabel("", JLabel.CENTER); + + messageLabel.setForeground(Color.RED); + + // Set component styles + loginButton.setPreferredSize(new Dimension(100, 35)); + registerButton.setPreferredSize(new Dimension(100, 35)); + } + + private void setupLayout() { + setLayout(new BorderLayout()); + + // Title panel + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("Math Quiz System", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 28)); + titleLabel.setForeground(new Color(0, 102, 204)); + titlePanel.add(titleLabel); + + // Main content panel with centered layout + JPanel contentPanel = new JPanel(new GridBagLayout()); + contentPanel.setBackground(new Color(248, 249, 250)); + contentPanel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40)); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(15, 15, 15, 15); + + // Username input with centered alignment + gbc.gridx = 0; gbc.gridy = 0; + gbc.anchor = GridBagConstraints.CENTER; + JLabel usernameLabel = new JLabel("Username:"); + usernameLabel.setFont(new Font("Arial", Font.BOLD, 14)); + contentPanel.add(usernameLabel, gbc); + + gbc.gridx = 1; gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + usernameField.setPreferredSize(new Dimension(200, 30)); + usernameField.setFont(new Font("Arial", Font.PLAIN, 14)); + contentPanel.add(usernameField, gbc); + + // Email input with centered alignment + gbc.gridx = 0; gbc.gridy = 1; + gbc.fill = GridBagConstraints.NONE; + gbc.anchor = GridBagConstraints.CENTER; + JLabel emailLabel = new JLabel("Email:"); + emailLabel.setFont(new Font("Arial", Font.BOLD, 14)); + contentPanel.add(emailLabel, gbc); + + gbc.gridx = 1; gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + emailField.setPreferredSize(new Dimension(200, 30)); + emailField.setFont(new Font("Arial", Font.PLAIN, 14)); + contentPanel.add(emailField, gbc); + + // Password input with centered alignment + gbc.gridx = 0; gbc.gridy = 2; + gbc.fill = GridBagConstraints.NONE; + gbc.anchor = GridBagConstraints.CENTER; + JLabel passwordLabel = new JLabel("Password:"); + passwordLabel.setFont(new Font("Arial", Font.BOLD, 14)); + contentPanel.add(passwordLabel, gbc); + + gbc.gridx = 1; gbc.gridy = 2; + gbc.fill = GridBagConstraints.HORIZONTAL; + passwordField.setPreferredSize(new Dimension(200, 30)); + passwordField.setFont(new Font("Arial", Font.PLAIN, 14)); + contentPanel.add(passwordField, gbc); + + // Buttons panel with centered alignment + gbc.gridx = 0; gbc.gridy = 3; + gbc.gridwidth = 2; + gbc.fill = GridBagConstraints.NONE; + gbc.anchor = GridBagConstraints.CENTER; + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.setOpaque(false); + buttonPanel.add(loginButton); + buttonPanel.add(registerButton); + contentPanel.add(buttonPanel, gbc); + + // Message panel + gbc.gridx = 0; gbc.gridy = 4; + gbc.gridwidth = 2; + JPanel messagePanel = new JPanel(); + messagePanel.setOpaque(false); + messagePanel.add(messageLabel); + contentPanel.add(messagePanel, gbc); + + // Assemble main panel + add(titlePanel, BorderLayout.NORTH); + add(contentPanel, BorderLayout.CENTER); + } + + private void setupEventHandlers() { + loginButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + performLogin(); + } + }); + + registerButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.showRegisterPanel(); + } + }); + + // Enter key login + passwordField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + performLogin(); + } + }); + } + + private void performLogin() { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + String password = new String(passwordField.getPassword()); + + if (username.isEmpty() || email.isEmpty() || password.isEmpty()) { + showMessage("Please enter username, email and password", Color.RED); + return; + } + + if (!isValidEmail(email)) { + showMessage("Please enter a valid email address", Color.RED); + return; + } + + try { + UserService userService = new UserService(); + if (userService.login(email, password)) { + // Set current user in session + QuizSession.getInstance().setCurrentUser(email); + showMessage("Login successful", Color.GREEN); + mainFrame.showGradeSelectionPanel(); + } else { + showMessage("Email or password is incorrect", Color.RED); + } + } catch (Exception ex) { + showMessage("Login failed: " + ex.getMessage(), Color.RED); + } + } + + private boolean isValidEmail(String email) { + return email.contains("@") && email.contains("."); + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } + + public void clearFields() { + emailField.setText(""); + passwordField.setText(""); + messageLabel.setText(""); + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/MainFrame.java b/src/mathquiz/gui_1/gui_1/MainFrame.java new file mode 100644 index 0000000..7368d3e --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/MainFrame.java @@ -0,0 +1,108 @@ +package mathquiz.gui; + +import java.awt.*; +import javax.swing.*; + +/** + * Main Window Class - Math Quiz System GUI Main Interface + */ +public class MainFrame extends JFrame { + private CardLayout cardLayout; + private JPanel mainPanel; + + // Various interface panels + private LoginPanel loginPanel; + private RegisterPanel registerPanel; + private PasswordSetupPanel passwordSetupPanel; + private GradeSelectionPanel gradeSelectionPanel; + private QuestionCountPanel questionCountPanel; + private QuizPanel quizPanel; + private ResultPanel resultPanel; + + public MainFrame() { + initializeFrame(); + createPanels(); + setupLayout(); + showLoginPanel(); + } + + private void initializeFrame() { + setTitle("Math Quiz System"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(800, 600); + setLocationRelativeTo(null); + setResizable(false); + + // Set UTF-8 encoding + System.setProperty("file.encoding", "UTF-8"); + } + + private void createPanels() { + cardLayout = new CardLayout(); + mainPanel = new JPanel(cardLayout); + + // Create various panels + loginPanel = new LoginPanel(this); + registerPanel = new RegisterPanel(this); + passwordSetupPanel = new PasswordSetupPanel(this); + gradeSelectionPanel = new GradeSelectionPanel(this); + questionCountPanel = new QuestionCountPanel(this); + quizPanel = new QuizPanel(this); + resultPanel = new ResultPanel(this); + + // Add panels to main panel + mainPanel.add(loginPanel, "LOGIN"); + mainPanel.add(registerPanel, "REGISTER"); + mainPanel.add(passwordSetupPanel, "PASSWORD_SETUP"); + mainPanel.add(gradeSelectionPanel, "GRADE_SELECTION"); + mainPanel.add(questionCountPanel, "QUESTION_COUNT"); + mainPanel.add(quizPanel, "QUIZ"); + mainPanel.add(resultPanel, "RESULT"); + } + + private void setupLayout() { + add(mainPanel); + } + + // Methods to show various panels + public void showLoginPanel() { + cardLayout.show(mainPanel, "LOGIN"); + } + + public void showRegisterPanel() { + cardLayout.show(mainPanel, "REGISTER"); + } + + public void showPasswordSetupPanel(String email) { + passwordSetupPanel.setEmail(email); + cardLayout.show(mainPanel, "PASSWORD_SETUP"); + } + + public void showGradeSelectionPanel() { + cardLayout.show(mainPanel, "GRADE_SELECTION"); + } + + public void showQuestionCountPanel() { + questionCountPanel.updateGradeDisplay(); + cardLayout.show(mainPanel, "QUESTION_COUNT"); + } + + public void showQuizPanel() { + quizPanel.startQuiz(); + cardLayout.show(mainPanel, "QUIZ"); + } + + public void showResultPanel(int score, int total) { + resultPanel.setScore(score, total); + cardLayout.show(mainPanel, "RESULT"); + } + + // Get references to various panels for use by other panels + public LoginPanel getLoginPanel() { return loginPanel; } + public RegisterPanel getRegisterPanel() { return registerPanel; } + public PasswordSetupPanel getPasswordSetupPanel() { return passwordSetupPanel; } + public GradeSelectionPanel getGradeSelectionPanel() { return gradeSelectionPanel; } + public QuestionCountPanel getQuestionCountPanel() { return questionCountPanel; } + public QuizPanel getQuizPanel() { return quizPanel; } + public ResultPanel getResultPanel() { return resultPanel; } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/PasswordSetupPanel.java b/src/mathquiz/gui_1/gui_1/PasswordSetupPanel.java new file mode 100644 index 0000000..015da60 --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/PasswordSetupPanel.java @@ -0,0 +1,224 @@ +package mathquiz.gui; + +import mathquiz.backend.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Password Setup Panel + */ +public class PasswordSetupPanel extends JPanel { + private final MainFrame mainFrame; + private JPasswordField passwordField; + private JPasswordField confirmPasswordField; + private JButton setPasswordButton; + private JButton backButton; + private JLabel messageLabel; + private JLabel emailLabel; + + private String email; + + public PasswordSetupPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + passwordField = new JPasswordField(20); + confirmPasswordField = new JPasswordField(20); + setPasswordButton = new JButton("Set Password"); + backButton = new JButton("Back"); + messageLabel = new JLabel("", JLabel.CENTER); + emailLabel = new JLabel("", JLabel.CENTER); + + messageLabel.setForeground(Color.RED); + emailLabel.setFont(new Font("Arial", Font.BOLD, 14)); + + setPasswordButton.setPreferredSize(new Dimension(120, 35)); + backButton.setPreferredSize(new Dimension(100, 35)); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + // Title + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("Set Password", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 20)); + titlePanel.add(titleLabel); + + // Email display + JPanel emailPanel = new JPanel(); + emailPanel.add(emailLabel); + + // Input panel + JPanel inputPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(10, 10, 10, 10); + + gbc.gridx = 0; gbc.gridy = 0; + inputPanel.add(new JLabel("New Password:"), gbc); + gbc.gridx = 1; + inputPanel.add(passwordField, gbc); + + gbc.gridx = 0; gbc.gridy = 1; + inputPanel.add(new JLabel("Confirm Password:"), gbc); + gbc.gridx = 1; + inputPanel.add(confirmPasswordField, gbc); + + // Password requirement description + JPanel requirementPanel = new JPanel(); + JLabel requirementLabel = new JLabel("Password requirements: 6-10 characters, must include uppercase, lowercase and digits"); + requirementLabel.setForeground(Color.BLUE); + requirementPanel.add(requirementLabel); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(setPasswordButton); + buttonPanel.add(backButton); + + // Message panel + JPanel messagePanel = new JPanel(); + messagePanel.add(messageLabel); + + // Create a proper layout structure + JPanel container = new JPanel(new BorderLayout()); + + // Add title at top + container.add(titlePanel, BorderLayout.NORTH); + + // Create center panel with email, input, and requirements + JPanel centerPanel = new JPanel(); + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); + centerPanel.add(emailPanel); + centerPanel.add(inputPanel); + centerPanel.add(requirementPanel); + + // Add center panel to container + container.add(centerPanel, BorderLayout.CENTER); + + // Create bottom panel with buttons and message + JPanel bottomPanel = new JPanel(); + bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); + bottomPanel.add(buttonPanel); + bottomPanel.add(messagePanel); + + // Add bottom panel to container + container.add(bottomPanel, BorderLayout.SOUTH); + + add(container); + } + + private void setupEventHandlers() { + setPasswordButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setPassword(); + } + }); + + backButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.showLoginPanel(); + } + }); + + // Enter key handling + confirmPasswordField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setPassword(); + } + }); + } + + private void setPassword() { + String password = new String(passwordField.getPassword()); + String confirmPassword = new String(confirmPasswordField.getPassword()); + + if (password.isEmpty() || confirmPassword.isEmpty()) { + showMessage("Please enter password", Color.RED); + return; + } + + if (!password.equals(confirmPassword)) { + showMessage("Passwords do not match", Color.RED); + return; + } + + if (!isValidPassword(password)) { + showMessage("Password does not meet requirements: 6-10 characters, must include uppercase, lowercase and digits", Color.RED); + return; + } + + try { + UserService userService = new UserService(); + userService.setPassword(email, password); + + // Set user session after successful password setup + QuizSession.getInstance().setCurrentUser(email); + + showMessage("Password set successfully!", Color.GREEN); + + // Delay jump to grade selection interface + Timer timer = new Timer(1000, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.showGradeSelectionPanel(); + } + }); + timer.setRepeats(false); + timer.start(); + + } catch (Exception ex) { + showMessage("Password setup failed: " + ex.getMessage(), Color.RED); + } + } + + private boolean isValidPassword(String password) { + if (password.length() < 6 || password.length() > 10) { + return false; + } + + boolean hasUpperCase = false; + boolean hasLowerCase = false; + boolean hasDigit = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) { + hasUpperCase = true; + } else if (Character.isLowerCase(c)) { + hasLowerCase = true; + } else if (Character.isDigit(c)) { + hasDigit = true; + } + } + + return hasUpperCase && hasLowerCase && hasDigit; + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } + + public void setEmail(String email) { + this.email = email; + emailLabel.setText("Set password for " + email); + } + + public void reset() { + passwordField.setText(""); + confirmPasswordField.setText(""); + messageLabel.setText(""); + email = null; + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/QuestionCountPanel.java b/src/mathquiz/gui_1/gui_1/QuestionCountPanel.java new file mode 100644 index 0000000..33ebe35 --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/QuestionCountPanel.java @@ -0,0 +1,152 @@ +package mathquiz.gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Question Count Input Panel + */ +public class QuestionCountPanel extends JPanel { + private final MainFrame mainFrame; + private JTextField countField; + private JButton startButton; + private JButton backButton; + private JLabel messageLabel; + private JLabel gradeLabel; + + public QuestionCountPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + countField = new JTextField(10); + startButton = new JButton("Confirm & Start Quiz"); + backButton = new JButton("Back"); + messageLabel = new JLabel("", JLabel.CENTER); + gradeLabel = new JLabel("", JLabel.CENTER); + + messageLabel.setForeground(Color.RED); + gradeLabel.setFont(new Font("Arial", Font.BOLD, 16)); + gradeLabel.setForeground(Color.BLUE); + + startButton.setPreferredSize(new Dimension(120, 35)); + backButton.setPreferredSize(new Dimension(100, 35)); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + // Title + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("Set Question Count", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 20)); + titlePanel.add(titleLabel); + + // Grade display + JPanel gradePanel = new JPanel(); + gradePanel.add(gradeLabel); + + // Input panel + JPanel inputPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(20, 10, 20, 10); + + gbc.gridx = 0; gbc.gridy = 0; + inputPanel.add(new JLabel("Question Count (10-30):"), gbc); + gbc.gridx = 1; + inputPanel.add(countField, gbc); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(startButton); + buttonPanel.add(backButton); + + // Message panel + JPanel messagePanel = new JPanel(); + messagePanel.add(messageLabel); + + // Assemble + mainPanel.add(titlePanel, BorderLayout.NORTH); + mainPanel.add(gradePanel, BorderLayout.NORTH); + mainPanel.add(inputPanel, BorderLayout.CENTER); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + mainPanel.add(messagePanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void setupEventHandlers() { + startButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + startQuiz(); + } + }); + + backButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.showGradeSelectionPanel(); + } + }); + + // Enter key handling + countField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + startQuiz(); + } + }); + } + + private void startQuiz() { + String countText = countField.getText().trim(); + + if (countText.isEmpty()) { + showMessage("Please enter question count", Color.RED); + return; + } + + try { + int count = Integer.parseInt(countText); + + if (count < 10 || count > 30) { + showMessage("Question count must be between 10-30", Color.RED); + return; + } + + // Save question count to session + QuizSession.getInstance().setQuestionCount(count); + + // Jump to quiz interface + mainFrame.showQuizPanel(); + + } catch (NumberFormatException e) { + showMessage("Please enter a valid number", Color.RED); + } + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } + + public void updateGradeDisplay() { + QuizSession session = QuizSession.getInstance(); + if (session.getAccountType() != null) { + gradeLabel.setText("Current Grade: " + ((mathquiz.AccountType) session.getAccountType()).displayName()); + } + } + + public void reset() { + countField.setText(""); + messageLabel.setText(""); + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/QuizPanel.java b/src/mathquiz/gui_1/gui_1/QuizPanel.java new file mode 100644 index 0000000..feaa38a --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/QuizPanel.java @@ -0,0 +1,315 @@ +package mathquiz.gui; + +import mathquiz.backend.QuizService; +import mathquiz.backend.Question; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +/** + * Quiz Panel + */ +public class QuizPanel extends JPanel { + private final MainFrame mainFrame; + private JLabel questionLabel; + private JLabel progressLabel; + private JRadioButton optionA; + private JRadioButton optionB; + private JRadioButton optionC; + private JRadioButton optionD; + private ButtonGroup optionGroup; + private JButton submitButton; + private JButton quitButton; + + private QuizService quizService; + private List questions; + private int currentQuestionIndex; + private int correctAnswers; + + public QuizPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + // Set font for better math symbol support + Font mathFont = new Font("Arial Unicode MS", Font.PLAIN, 16); + Font largeFont = new Font("Arial Unicode MS", Font.BOLD, 18); + + questionLabel = new JLabel("", JLabel.CENTER); + questionLabel.setFont(largeFont); + progressLabel = new JLabel("", JLabel.CENTER); + progressLabel.setFont(mathFont); + + optionA = new JRadioButton(); + optionA.setFont(mathFont); + optionB = new JRadioButton(); + optionB.setFont(mathFont); + optionC = new JRadioButton(); + optionC.setFont(mathFont); + optionD = new JRadioButton(); + optionD.setFont(mathFont); + + submitButton = new JButton("Submit Answer"); + submitButton.setFont(mathFont); + quitButton = new JButton("Quit Quiz"); + quitButton.setFont(mathFont); + + // Set styles + questionLabel.setFont(new Font("Arial", Font.BOLD, 16)); + progressLabel.setFont(new Font("Arial", Font.BOLD, 14)); + progressLabel.setForeground(Color.BLUE); + + optionA.setFont(new Font("Arial", Font.PLAIN, 14)); + optionB.setFont(new Font("Arial", Font.PLAIN, 14)); + optionC.setFont(new Font("Arial", Font.PLAIN, 14)); + optionD.setFont(new Font("Arial", Font.PLAIN, 14)); + + submitButton.setPreferredSize(new Dimension(120, 35)); + quitButton.setPreferredSize(new Dimension(120, 35)); + + // Create button group + optionGroup = new ButtonGroup(); + optionGroup.add(optionA); + optionGroup.add(optionB); + optionGroup.add(optionC); + optionGroup.add(optionD); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.setBackground(new Color(248, 249, 250)); + + // Progress panel with styling + JPanel progressPanel = new JPanel(); + progressPanel.setBackground(new Color(0, 102, 204)); + progressPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); + progressLabel.setForeground(Color.WHITE); + progressPanel.add(progressLabel); + + // Question panel with better styling + JPanel questionPanel = new JPanel(new BorderLayout()); + questionPanel.setBackground(Color.WHITE); + questionPanel.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(new Color(200, 200, 200), 1), + BorderFactory.createEmptyBorder(30, 30, 30, 30) + )); + questionLabel.setForeground(new Color(51, 51, 51)); + questionPanel.add(questionLabel, BorderLayout.CENTER); + + // Options panel with better styling + JPanel optionsPanel = new JPanel(new GridLayout(4, 1, 15, 15)); + optionsPanel.setBackground(Color.WHITE); + optionsPanel.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(new Color(200, 200, 200), 1), + BorderFactory.createEmptyBorder(20, 30, 20, 30) + )); + + // Style radio buttons + optionA.setBackground(Color.WHITE); + optionA.setForeground(new Color(51, 51, 51)); + optionB.setBackground(Color.WHITE); + optionB.setForeground(new Color(51, 51, 51)); + optionC.setBackground(Color.WHITE); + optionC.setForeground(new Color(51, 51, 51)); + optionD.setBackground(Color.WHITE); + optionD.setForeground(new Color(51, 51, 51)); + + optionsPanel.add(optionA); + optionsPanel.add(optionB); + optionsPanel.add(optionC); + optionsPanel.add(optionD); + + // Button panel with styling + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.setBackground(new Color(248, 249, 250)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + // Style buttons + submitButton.setBackground(new Color(0, 102, 204)); + submitButton.setForeground(Color.WHITE); + submitButton.setBorderPainted(false); + submitButton.setFocusPainted(false); + + quitButton.setBackground(new Color(108, 117, 125)); + quitButton.setForeground(Color.WHITE); + quitButton.setBorderPainted(false); + quitButton.setFocusPainted(false); + + buttonPanel.add(submitButton); + buttonPanel.add(quitButton); + + // Create center panel with question and options + JPanel centerPanel = new JPanel(new BorderLayout()); + centerPanel.setBackground(new Color(248, 249, 250)); + centerPanel.add(questionPanel, BorderLayout.NORTH); + centerPanel.add(optionsPanel, BorderLayout.CENTER); + + // Assemble + mainPanel.add(progressPanel, BorderLayout.NORTH); + mainPanel.add(centerPanel, BorderLayout.CENTER); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void setupEventHandlers() { + submitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + submitAnswer(); + } + }); + + quitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + quitQuiz(); + } + }); + } + + public void startQuiz() { + try { + QuizSession session = QuizSession.getInstance(); + + // Debug information + System.out.println("Debug - Session info:"); + System.out.println("Current User: " + session.getCurrentUser()); + System.out.println("Account Type: " + session.getAccountType()); + System.out.println("Question Count: " + session.getQuestionCount()); + + if (session.getCurrentUser() == null) { + JOptionPane.showMessageDialog(this, "User session not found. Please login again.", "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showLoginPanel(); + return; + } + + if (session.getAccountType() == null) { + JOptionPane.showMessageDialog(this, "Account type not set. Please select grade again.", "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showGradeSelectionPanel(); + return; + } + + quizService = new QuizService(); + questions = quizService.generateQuestions((mathquiz.AccountType) session.getAccountType(), session.getQuestionCount()); + + if (questions == null || questions.isEmpty()) { + JOptionPane.showMessageDialog(this, "No questions generated. Please try again.", "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showQuestionCountPanel(); + return; + } + + currentQuestionIndex = 0; + correctAnswers = 0; + + displayCurrentQuestion(); + + } catch (Exception e) { + System.err.println("Quiz generation error: " + e.getMessage()); + e.printStackTrace(); + JOptionPane.showMessageDialog(this, "Failed to generate questions: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showQuestionCountPanel(); + } + } + + private void displayCurrentQuestion() { + if (currentQuestionIndex >= questions.size()) { + // Quiz ended, show result + showResult(); + return; + } + + Question question = questions.get(currentQuestionIndex); + + // Update progress + progressLabel.setText("Question " + (currentQuestionIndex + 1) + " of " + questions.size()); + + // Display question with proper font and HTML rendering + String questionText = question.getQuestion(); + // Convert ASCII symbols to proper math symbols for display + questionText = questionText.replace("*", "×").replace("/", "÷"); + questionLabel.setText("
" + questionText + "
"); + + // Display options + optionA.setText("A. " + question.getOptionA()); + optionB.setText("B. " + question.getOptionB()); + optionC.setText("C. " + question.getOptionC()); + optionD.setText("D. " + question.getOptionD()); + + // Clear selection + optionGroup.clearSelection(); + + // Update button state + submitButton.setEnabled(true); + } + + private void submitAnswer() { + if (questions == null || questions.isEmpty()) { + JOptionPane.showMessageDialog(this, "No questions available. Please try again.", "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showQuestionCountPanel(); + return; + } + + if (!optionA.isSelected() && !optionB.isSelected() && + !optionC.isSelected() && !optionD.isSelected()) { + JOptionPane.showMessageDialog(this, "Please select an answer", "Hint", JOptionPane.WARNING_MESSAGE); + return; + } + + if (currentQuestionIndex >= questions.size()) { + JOptionPane.showMessageDialog(this, "Question index out of bounds. Please try again.", "Error", JOptionPane.ERROR_MESSAGE); + mainFrame.showQuestionCountPanel(); + return; + } + + Question question = questions.get(currentQuestionIndex); + String selectedAnswer = getSelectedAnswer(); + + // Check if answer is correct + if (selectedAnswer.equals(question.getCorrectAnswer())) { + correctAnswers++; + } + + // Next question + currentQuestionIndex++; + displayCurrentQuestion(); + } + + private String getSelectedAnswer() { + if (optionA.isSelected()) return "A"; + if (optionB.isSelected()) return "B"; + if (optionC.isSelected()) return "C"; + if (optionD.isSelected()) return "D"; + return ""; + } + + private void showResult() { + int totalQuestions = questions.size(); + int score = correctAnswers; // 答对的题目数量 + + System.out.println("Quiz completed:"); + System.out.println("Correct answers: " + correctAnswers); + System.out.println("Total questions: " + totalQuestions); + System.out.println("Score: " + score + " out of " + totalQuestions); + + mainFrame.showResultPanel(score, totalQuestions); + } + + private void quitQuiz() { + int result = JOptionPane.showConfirmDialog(this, + "Are you sure you want to quit the quiz?", "Confirm Quit", + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + + if (result == JOptionPane.YES_OPTION) { + mainFrame.showGradeSelectionPanel(); + } + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/QuizSession.java b/src/mathquiz/gui_1/gui_1/QuizSession.java new file mode 100644 index 0000000..f75745f --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/QuizSession.java @@ -0,0 +1,56 @@ +package mathquiz.gui; + +import mathquiz.AccountType; + +/** + * Quiz Session Management Class + * Singleton pattern, manages current user session information + */ +public class QuizSession { + private static QuizSession instance; + + private String currentUser; + private AccountType accountType; + private int questionCount; + + private QuizSession() { + // Private constructor + } + + public static QuizSession getInstance() { + if (instance == null) { + instance = new QuizSession(); + } + return instance; + } + + public String getCurrentUser() { + return currentUser; + } + + public void setCurrentUser(String currentUser) { + this.currentUser = currentUser; + } + + public AccountType getAccountType() { + return accountType; + } + + public void setAccountType(AccountType accountType) { + this.accountType = accountType; + } + + public int getQuestionCount() { + return questionCount; + } + + public void setQuestionCount(int questionCount) { + this.questionCount = questionCount; + } + + public void clear() { + currentUser = null; + accountType = null; + questionCount = 0; + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/RegisterPanel.java b/src/mathquiz/gui_1/gui_1/RegisterPanel.java new file mode 100644 index 0000000..2e54aa1 --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/RegisterPanel.java @@ -0,0 +1,233 @@ +package mathquiz.gui; + +import mathquiz.backend.EmailService; +import mathquiz.backend.UserService; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Registration Panel + */ +public class RegisterPanel extends JPanel { + private final MainFrame mainFrame; + private JTextField usernameField; + private JTextField emailField; + private JTextField verificationCodeField; + private JButton sendCodeButton; + private JButton registerButton; + private JButton backButton; + private JLabel messageLabel; + private JLabel statusLabel; + + private String currentEmail; + private String sentVerificationCode; + + public RegisterPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + usernameField = new JTextField(20); + emailField = new JTextField(20); + verificationCodeField = new JTextField(20); + sendCodeButton = new JButton("Send Code"); + registerButton = new JButton("Complete Registration"); + backButton = new JButton("Back to Login"); + messageLabel = new JLabel("", JLabel.CENTER); + statusLabel = new JLabel("Please enter username and email address to get verification code", JLabel.CENTER); + + messageLabel.setForeground(Color.RED); + statusLabel.setForeground(Color.BLUE); + + // Set component styles + sendCodeButton.setPreferredSize(new Dimension(120, 35)); + registerButton.setPreferredSize(new Dimension(150, 35)); + backButton.setPreferredSize(new Dimension(120, 35)); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + // Title + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("User Registration", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 20)); + titlePanel.add(titleLabel); + + // Input panel + JPanel inputPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(10, 10, 10, 10); + + gbc.gridx = 0; gbc.gridy = 0; + inputPanel.add(new JLabel("Username:"), gbc); + gbc.gridx = 1; + inputPanel.add(usernameField, gbc); + gbc.gridx = 2; + inputPanel.add(new JLabel(""), gbc); // Empty space for alignment + + gbc.gridx = 0; gbc.gridy = 1; + inputPanel.add(new JLabel("Email Address:"), gbc); + gbc.gridx = 1; + inputPanel.add(emailField, gbc); + gbc.gridx = 2; + inputPanel.add(sendCodeButton, gbc); + + gbc.gridx = 0; gbc.gridy = 2; + inputPanel.add(new JLabel("Verification Code:"), gbc); + gbc.gridx = 1; + inputPanel.add(verificationCodeField, gbc); + gbc.gridx = 2; + inputPanel.add(registerButton, gbc); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(backButton); + + // Message panel + JPanel messagePanel = new JPanel(new BorderLayout()); + messagePanel.add(statusLabel, BorderLayout.NORTH); + messagePanel.add(messageLabel, BorderLayout.SOUTH); + + // Assemble + mainPanel.add(titlePanel, BorderLayout.NORTH); + mainPanel.add(inputPanel, BorderLayout.CENTER); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + mainPanel.add(messagePanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void setupEventHandlers() { + sendCodeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + sendVerificationCode(); + } + }); + + registerButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + completeRegistration(); + } + }); + + backButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.showLoginPanel(); + } + }); + + // Enter key handling + verificationCodeField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + completeRegistration(); + } + }); + } + + private void sendVerificationCode() { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + + if (username.isEmpty()) { + showMessage("Please enter username", Color.RED); + return; + } + + if (email.isEmpty()) { + showMessage("Please enter email address", Color.RED); + return; + } + + if (!isValidEmail(email)) { + showMessage("Please enter a valid email address", Color.RED); + return; + } + + try { + EmailService emailService = new EmailService(); + String verificationCode = emailService.sendVerificationCode(email); + + currentEmail = email; + sentVerificationCode = verificationCode; + + showMessage("Verification code has been sent to your email, please check", Color.GREEN); + statusLabel.setText("Verification code sent, please enter code to complete registration"); + statusLabel.setForeground(Color.GREEN); + + // Disable send button, enable register button + sendCodeButton.setEnabled(false); + registerButton.setEnabled(true); + verificationCodeField.setEnabled(true); + + } catch (Exception ex) { + showMessage("Failed to send verification code: " + ex.getMessage(), Color.RED); + } + } + + private void completeRegistration() { + String username = usernameField.getText().trim(); + String email = emailField.getText().trim(); + String code = verificationCodeField.getText().trim(); + + if (username.isEmpty() || email.isEmpty() || code.isEmpty()) { + showMessage("Please enter username, email and verification code", Color.RED); + return; + } + + if (!email.equals(currentEmail)) { + showMessage("Email address does not match", Color.RED); + return; + } + + if (!code.equals(sentVerificationCode)) { + showMessage("Verification code is incorrect", Color.RED); + return; + } + + try { + UserService userService = new UserService(); + userService.registerUser(email, username); + + showMessage("Registration successful! Please set password", Color.GREEN); + mainFrame.showPasswordSetupPanel(email); + + } catch (Exception ex) { + showMessage("Registration failed: " + ex.getMessage(), Color.RED); + } + } + + private boolean isValidEmail(String email) { + return email.contains("@") && email.contains("."); + } + + private void showMessage(String message, Color color) { + messageLabel.setText(message); + messageLabel.setForeground(color); + } + + public void reset() { + emailField.setText(""); + verificationCodeField.setText(""); + messageLabel.setText(""); + statusLabel.setText("Please enter email address to get verification code"); + statusLabel.setForeground(Color.BLUE); + sendCodeButton.setEnabled(true); + registerButton.setEnabled(false); + verificationCodeField.setEnabled(false); + currentEmail = null; + sentVerificationCode = null; + } +} \ No newline at end of file diff --git a/src/mathquiz/gui_1/gui_1/ResultPanel.java b/src/mathquiz/gui_1/gui_1/ResultPanel.java new file mode 100644 index 0000000..315e601 --- /dev/null +++ b/src/mathquiz/gui_1/gui_1/ResultPanel.java @@ -0,0 +1,126 @@ +package mathquiz.gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Result Panel + */ +public class ResultPanel extends JPanel { + private final MainFrame mainFrame; + private JLabel scoreLabel; + private JLabel messageLabel; + private JButton continueButton; + private JButton exitButton; + + public ResultPanel(MainFrame mainFrame) { + this.mainFrame = mainFrame; + initializeComponents(); + setupLayout(); + setupEventHandlers(); + } + + private void initializeComponents() { + setLayout(new BorderLayout()); + + scoreLabel = new JLabel("", JLabel.CENTER); + messageLabel = new JLabel("", JLabel.CENTER); + continueButton = new JButton("Continue Quiz"); + exitButton = new JButton("Logout"); + + // Set styles + scoreLabel.setFont(new Font("Arial", Font.BOLD, 24)); + messageLabel.setFont(new Font("Arial", Font.PLAIN, 16)); + + continueButton.setPreferredSize(new Dimension(120, 40)); + exitButton.setPreferredSize(new Dimension(120, 40)); + } + + private void setupLayout() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + // Title + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("Quiz Results", JLabel.CENTER); + titleLabel.setFont(new Font("Arial", Font.BOLD, 20)); + titlePanel.add(titleLabel); + + // Score display panel + JPanel scorePanel = new JPanel(new BorderLayout()); + scorePanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + scorePanel.add(scoreLabel, BorderLayout.CENTER); + scorePanel.add(messageLabel, BorderLayout.SOUTH); + + // Button panel + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(continueButton); + buttonPanel.add(exitButton); + + // Assemble + mainPanel.add(titlePanel, BorderLayout.NORTH); + mainPanel.add(scorePanel, BorderLayout.CENTER); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void setupEventHandlers() { + continueButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + continueQuiz(); + } + }); + + exitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + exitQuiz(); + } + }); + } + + public void setScore(int score, int totalQuestions) { + // Calculate percentage + int percentage = (int) Math.round((double) score / totalQuestions * 100); + + // Display score with percentage (without % symbol) + scoreLabel.setText("Your Score: " + score + "/" + totalQuestions + " (" + percentage + ")"); + + // Display different messages based on percentage + String message; + Color color; + + if (percentage >= 90) { + message = "Excellent! You answered " + score + " out of " + totalQuestions + " questions correctly"; + color = Color.GREEN; + } else if (percentage >= 80) { + message = "Good! You answered " + score + " out of " + totalQuestions + " questions correctly"; + color = Color.BLUE; + } else if (percentage >= 70) { + message = "Pass! You answered " + score + " out of " + totalQuestions + " questions correctly"; + color = Color.ORANGE; + } else { + message = "Need improvement! You answered " + score + " out of " + totalQuestions + " questions correctly"; + color = Color.RED; + } + + messageLabel.setText(message); + messageLabel.setForeground(color); + } + + private void continueQuiz() { + // Return to grade selection interface + mainFrame.showGradeSelectionPanel(); + } + + private void exitQuiz() { + // Clear session information + QuizSession.getInstance().clear(); + + // Return to login interface + mainFrame.showLoginPanel(); + } +} \ No newline at end of file