For example, the LoggedInView listens for two kinds of property changes; - * it can use the property name to distinguish which property has changed.
* @param propertyName the label for the property that was changed */ public void firePropertyChanged(String propertyName) { diff --git a/src/main/java/interface_adapter/joke/JokeController.java b/src/main/java/interface_adapter/joke/JokeController.java new file mode 100644 index 000000000..70889dc48 --- /dev/null +++ b/src/main/java/interface_adapter/joke/JokeController.java @@ -0,0 +1,27 @@ +package interface_adapter.joke; + +import use_case.joke.JokeInputBoundary; +import use_case.joke.JokeInputData; + +/** + * The controller for the Joke Use Case. + */ +public class JokeController { + + private final JokeInputBoundary jokeUseCaseInteractor; + + public JokeController(JokeInputBoundary jokeUseCaseInteractor) { + this.jokeUseCaseInteractor = jokeUseCaseInteractor; + } + + /** + * Executes the Joke Use Case. + * @param actionType the type of action (e.g., "generate", "search", "favorite") + * @param query the search query for finding a joke, if applicable + */ + public void execute(String actionType, String query) { + JokeInputData jokeInputData = new JokeInputData(actionType, query); + + jokeUseCaseInteractor.execute(jokeInputData); + } +} diff --git a/src/main/java/interface_adapter/joke/JokePresenter.java b/src/main/java/interface_adapter/joke/JokePresenter.java new file mode 100644 index 000000000..91898ffd7 --- /dev/null +++ b/src/main/java/interface_adapter/joke/JokePresenter.java @@ -0,0 +1,40 @@ +package interface_adapter.joke; + +import interface_adapter.ViewManagerModel; +import use_case.joke.JokeOutputBoundary; +import use_case.joke.JokeOutputData; + +/** + * The Presenter for the Joke Use Case. + */ +public class JokePresenter implements JokeOutputBoundary { + + private final JokeViewModel jokeViewModel; + private final ViewManagerModel viewManagerModel; + + public JokePresenter(ViewManagerModel viewManagerModel, JokeViewModel jokeViewModel) { + this.viewManagerModel = viewManagerModel; + this.jokeViewModel = jokeViewModel; + } + + @Override + public void prepareSuccessView(JokeOutputData response) { + // Update the JokeState with the new joke + JokeState jokeState = jokeViewModel.getState(); + jokeState.setJokeText(response.getJokeText()); + jokeState.setFavoriteStatus(response.isFavorite()); + jokeViewModel.setState(jokeState); + jokeViewModel.firePropertyChanged(); + + viewManagerModel.setState(jokeViewModel.getViewName()); + viewManagerModel.firePropertyChanged(); + } + + @Override + public void prepareFailView(String error) { + JokeState jokeState = jokeViewModel.getState(); + jokeState.setErrorMessage(error); + jokeViewModel.setState(jokeState); + jokeViewModel.firePropertyChanged("error"); + } +} diff --git a/src/main/java/interface_adapter/joke/JokeState.java b/src/main/java/interface_adapter/joke/JokeState.java new file mode 100644 index 000000000..97277eb1e --- /dev/null +++ b/src/main/java/interface_adapter/joke/JokeState.java @@ -0,0 +1,25 @@ +package interface_adapter.joke; + +/** + * The state for the Joke View Model. + */ +public class JokeState { + private String jokeText = ""; + private String errorMessage; + + public String getJokeText() { + return jokeText; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setJokeText(String jokeText) { + this.jokeText = jokeText; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/interface_adapter/joke/JokeViewModel.java b/src/main/java/interface_adapter/joke/JokeViewModel.java new file mode 100644 index 000000000..2e036a31e --- /dev/null +++ b/src/main/java/interface_adapter/joke/JokeViewModel.java @@ -0,0 +1,14 @@ +package interface_adapter.joke; + +import interface_adapter.ViewModel; + +/** + * The View Model for the Joke View. + */ +public class JokeViewModel extends ViewModelFor example, the LoggedInView listens for two kinds of property changes; + * it can use the property name to distinguish which property has changed.
+ * @param propertyName the label for the property that was changed + */ + public void firePropertyChanged(String propertyName) { + this.support.firePropertyChange(propertyName, null, this.state); + } + + /** + * Adds a PropertyChangeListener to this ViewModel. + * @param listener The PropertyChangeListener to be added + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + this.support.addPropertyChangeListener(listener); + } +} diff --git a/src/main/java/view/helper_functions/LabelTextPanel.java b/src/main/java/view/helper_functions/LabelTextPanel.java new file mode 100644 index 000000000..0b74cc6cb --- /dev/null +++ b/src/main/java/view/helper_functions/LabelTextPanel.java @@ -0,0 +1,15 @@ +package view.helper_functions; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/** + * A panel containing a label and a text field. + */ +public class LabelTextPanel extends JPanel { + public LabelTextPanel(JLabel label, JTextField textField) { + this.add(label); + this.add(textField); + } +} \ No newline at end of file diff --git a/src/main/java/view/joke_view/JokeFrameBuilder.java b/src/main/java/view/joke_view/JokeFrameBuilder.java new file mode 100644 index 000000000..d3ff33ab4 --- /dev/null +++ b/src/main/java/view/joke_view/JokeFrameBuilder.java @@ -0,0 +1,64 @@ +package view.joke_view; + +import data_access.ExplanationDataAccessObject; +import data_access.MockExplanationDataAccessObject; +import use_case.explanation.*; +import use_case.explanation.adapter.ExplanationController; +import use_case.explanation.adapter.ExplanationPresenter; + +import javax.swing.*; + +public class JokeFrameBuilder { +// public static final int HEIGHT = 300; +// public static final int WIDTH = 400; + // joke/user factory made before +// private final JokeFactory jokeFactory = new JokeFactory(); + + private JokeView jokeView; + private JokeViewModel jokeViewModel; + // view doesn't change, so don't need ViewManager(cardPanel, cardLayout, viewManagerModel); + + //TODO change mock + private final ExplanationDataAccessInterface explanationDataAccessObject = new ExplanationDataAccessObject(); + + public JokeFrameBuilder() { + } + + public JokeFrameBuilder addJokeView() { + jokeViewModel = new JokeViewModel(); + jokeView = new JokeView(jokeViewModel); + return this; + } + + public JokeFrameBuilder setJokeContent(String content) { + jokeViewModel.getState().setJokeContent(content); + jokeViewModel.firePropertyChanged(); + return this; + } + + public JokeFrameBuilder addExplanationUseCase() { + final ExplanationOutputBoundary explanationOutputBoundary = new ExplanationPresenter(jokeViewModel); + final ExplanationInputBoundary explanationInteractor = new ExplanationInteractor( + explanationDataAccessObject, explanationOutputBoundary); + + final ExplanationController explanationController = new ExplanationController(explanationInteractor); + jokeView.setExplanationController(explanationController); + return this; + } + + //TODO do this + public JokeFrameBuilder addAddToFavUseCase() { + return this; + } + + public JFrame build() { + final JFrame frame = new JFrame("Joke"); + + //TODO may need to change + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + + frame.add(jokeView); + + return frame; + } +} diff --git a/src/main/java/view/joke_view/JokeState.java b/src/main/java/view/joke_view/JokeState.java new file mode 100644 index 000000000..4b9a4b4f2 --- /dev/null +++ b/src/main/java/view/joke_view/JokeState.java @@ -0,0 +1,31 @@ +package view.joke_view; + +public class JokeState { + // info that can change + private String jokeContent = ""; + private String explanation = ""; + + @Override + public String toString() { + return "JokeState{" + + "jokeContent='" + getJokeContent() + '\'' + + ", explanation='" + getExplanation() + '\'' + + '}'; + } + + public String getExplanation() { + return explanation; + } + + public void setExplanation(String explanation) { + this.explanation = explanation; + } + + public String getJokeContent() { + return jokeContent; + } + + public void setJokeContent(String jokeContent) { + this.jokeContent = jokeContent; + } +} diff --git a/src/main/java/view/joke_view/JokeView.java b/src/main/java/view/joke_view/JokeView.java new file mode 100644 index 000000000..011abcdb7 --- /dev/null +++ b/src/main/java/view/joke_view/JokeView.java @@ -0,0 +1,161 @@ +package view.joke_view; + +import use_case.add_to_fav.AddController; +import use_case.explanation.adapter.ExplanationController; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +public class JokeView extends JPanel implements PropertyChangeListener, ActionListener { + + private final String viewName; + private final JokeViewModel jokeViewModel; + + private final JTextArea jokeContent = new JTextArea(3, 20); + private final JTextArea explanation = new JTextArea(10, 20); + + // Controllers + // each function of a controller is a button + private final JButton explain; + private final JButton addToFav; + private AddController addController; + private ExplanationController explanationController; + + public JokeView(JokeViewModel jokeViewModel) { + + this.jokeViewModel = jokeViewModel; + this.jokeViewModel.addPropertyChangeListener(this); + this.viewName = jokeViewModel.getViewName(); + + final JLabel title = new JLabel(JokeViewModel.TITLE_LABEL); + title.setAlignmentX(Component.CENTER_ALIGNMENT); + final JLabel explanationLabel = new JLabel(JokeViewModel.EXPLANATION_LABEL); + explanationLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + + final JPanel buttons = new JPanel(); + explain = new JButton(JokeViewModel.EXPLANATION_BUTTON_LABEL); + buttons.add(explain); + addToFav = new JButton(JokeViewModel.ADD_BUTTON_LABEL); + buttons.add(addToFav); + + explain.addActionListener( + evt -> { + if (evt.getSource().equals(explain)) { + final JokeState currentState = jokeViewModel.getState(); + + explanationController.execute( + currentState.getJokeContent() + ); + } + } + ); + + addToFav.addActionListener( + evt -> { + if (evt.getSource().equals(addToFav)) { + final JokeState currentState = jokeViewModel.getState(); + //can change depending on how addController is implemented + addController.execute( + currentState.getJokeContent(), + currentState.getExplanation(), + null); + } + } + ); + + // a smaller (than view) observer pattern + jokeContent.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final JokeState currentState = jokeViewModel.getState(); + currentState.setJokeContent(jokeContent.getText()); + jokeViewModel.setState(currentState); + } + + @Override + public void insertUpdate(DocumentEvent e) { + documentListenerHelper(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + documentListenerHelper(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + documentListenerHelper(); + } + }); + + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + explanation.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final JokeState currentState = jokeViewModel.getState(); + currentState.setExplanation(explanation.getText()); + jokeViewModel.setState(currentState); + } + + @Override + public void insertUpdate(DocumentEvent e) { + documentListenerHelper(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + documentListenerHelper(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + documentListenerHelper(); + } + }); + + this.add(title); + this.add(jokeContent); + this.add(explanationLabel); + this.add(explanation); + this.add(buttons); + } + + /** + * React to a button click that results in evt. + * @param evt the ActionEvent to react to + */ + public void actionPerformed(ActionEvent evt) { + System.out.println("Click " + evt.getActionCommand()); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final JokeState state = (JokeState) evt.getNewValue(); + setFields(state); + } + + private void setFields(JokeState state) { + jokeContent.setText(state.getJokeContent()); + explanation.setText(state.getExplanation()); + } + + public String getViewName() { + return viewName; + } + + public void setExplanationController(ExplanationController explanationController) { + this.explanationController = explanationController; + } + + public void setAddController(AddController addController) { + this.addController = addController; + } +} diff --git a/src/main/java/view/joke_view/JokeViewModel.java b/src/main/java/view/joke_view/JokeViewModel.java new file mode 100644 index 000000000..24b37f21f --- /dev/null +++ b/src/main/java/view/joke_view/JokeViewModel.java @@ -0,0 +1,18 @@ +package view.joke_view; + +import view.ViewModel; + + +public class JokeViewModel extends ViewModel