diff --git a/src/main/java/edu/ntnu/idi/idatt/Launcher.java b/src/main/java/edu/ntnu/idi/idatt/Launcher.java index 18a6b15..f13f7fd 100644 --- a/src/main/java/edu/ntnu/idi/idatt/Launcher.java +++ b/src/main/java/edu/ntnu/idi/idatt/Launcher.java @@ -2,9 +2,9 @@ import edu.ntnu.idi.idatt.storage.CSVtoJSON; import edu.ntnu.idi.idatt.view.SceneManager; -import edu.ntnu.idi.idatt.view.primary.PrimaryController; -import edu.ntnu.idi.idatt.view.primary.PrimaryModel; -import edu.ntnu.idi.idatt.view.primary.PrimaryView; +import edu.ntnu.idi.idatt.view.entry.StartController; +import edu.ntnu.idi.idatt.view.entry.StartModel; +import edu.ntnu.idi.idatt.view.entry.StartView; import javafx.application.Application; import javafx.stage.Stage; @@ -25,9 +25,9 @@ public void start(Stage stage) { stage.setHeight(700); stage.setTitle("Stock Game"); - PrimaryModel model = new PrimaryModel(); - PrimaryView view = new PrimaryView(); - PrimaryController controller = new PrimaryController(model); + StartModel model = new StartModel(); + StartView view = new StartView(); + StartController controller = new StartController(model); view.setModel(model); view.setController(controller); diff --git a/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java b/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java new file mode 100644 index 0000000..c8a2863 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java @@ -0,0 +1,31 @@ +package edu.ntnu.idi.idatt.session; + +import edu.ntnu.idi.idatt.model.player.Player; + +public class UserSession { + + // Singleton instance + private static UserSession INSTANCE; + + // Disable constructor initialization. + private UserSession() { + } + + public static UserSession getInstance() { + if (INSTANCE == null) { + INSTANCE = new UserSession(); + } + return INSTANCE; + } + + private Player player; + + public Player getPlayer() { + return player; + } + + public void setPlayer(Player player) { + this.player = player; + } + +} diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractView.java b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractView.java index 18d51a2..b4f96ec 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractView.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractView.java @@ -36,11 +36,18 @@ public abstract class AbstractView { /** * Constructor for AbstractView. */ - public AbstractView(T type) { + protected AbstractView(T type) { instance = type; instance.getChildren().add(this.createContent()); } + /** + * Constructor for AbstractView without initialization. + */ + protected AbstractView() { + + } + /** * Getter for current view instance. * @@ -50,6 +57,13 @@ public T getInstance() { return instance; } + /** + * Setter for current view instance. + */ + public void setInstance(T instance) { + this.instance = instance; + } + /** * Abstract method for creating view content. */ diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java new file mode 100644 index 0000000..1b7b889 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java @@ -0,0 +1,100 @@ +package edu.ntnu.idi.idatt.view.components; + +import javafx.beans.property.SimpleBooleanProperty; +import javafx.geometry.Pos; +import javafx.scene.Parent; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +public abstract class AbstractViewUI extends AbstractView { + + private VBox navigation; + private HBox header; + private HBox toolbar; + private SimpleBooleanProperty isMenuVisible = new SimpleBooleanProperty(false); + + public AbstractViewUI() { + HBox wrapper = new HBox(); + BorderPane layout = new BorderPane(); + + createUIComponents(); + navigation.getChildren().add(createNavigation()); + header.getChildren().add(createHeader()); + toolbar.getChildren().add(createToolbar()); + + layout.setTop(header); + layout.setBottom(toolbar); + layout.setCenter(createContent()); + + HBox.setHgrow(layout, Priority.ALWAYS); + wrapper.getChildren().addAll(navigation, layout); + + this.setInstance(new StackPane()); + + Parent menu = createMenu(); + StackPane.setAlignment(menu, Pos.CENTER_RIGHT); + menu.setVisible(false); + + Region disableMenu = new Region(); + disableMenu.setVisible(false); + + disableMenu.setOnMouseClicked(e -> { + menu.setVisible(false); + disableMenu.setVisible(false); + }); + + isMenuVisible.addListener((observer, oldVal, newVal) -> { + menu.setVisible(true); + disableMenu.setVisible(true); + }); + + this.getInstance().getChildren().addAll(wrapper, disableMenu, menu); + } + + public void createUIComponents() { + navigation = new VBox(); + navigation.setMaxHeight(Double.MAX_VALUE); + navigation.getStyleClass().add("dark"); + navigation.setPrefWidth(150); + + header = new HBox(); + header.getStyleClass().add("light"); + header.setPrefHeight(80); + + toolbar = new HBox(); + toolbar.getStyleClass().add("light"); + HBox.setHgrow(toolbar, Priority.ALWAYS); + toolbar.setPrefHeight(80); + } + + public abstract Parent createContent(); + + public abstract Parent createNavigation(); + + public abstract Parent createHeader(); + + public abstract Parent createToolbar(); + + public abstract Parent createMenu(); + + public VBox getNavigation() { + return navigation; + } + + public HBox getHeader() { + return header; + } + + public HBox getToolbar() { + return toolbar; + } + + public void toggleMenu() { + isMenuVisible.set(!isMenuVisible.get()); + } + +} diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/IconComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/IconComponent.java new file mode 100644 index 0000000..a3ef67a --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/IconComponent.java @@ -0,0 +1,32 @@ +package edu.ntnu.idi.idatt.view.components.elements; + +import edu.ntnu.idi.idatt.view.components.primitives.ActionEventHandler; +import javafx.scene.control.Button; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.StackPane; + +public class IconComponent extends StackPane { + + private Button icon; + + public IconComponent(Image image, String description, int size) { + + ImageView iv = new ImageView(); + iv.setImage(image); + iv.setFitHeight(size); // TODO: Fix? + iv.setFitWidth(size); + + icon = new Button(description, iv); + icon.getStyleClass().clear(); // Remove parent buffers in case. + icon.getStyleClass().add("icon"); + icon.setMaxHeight(Double.MAX_VALUE); + + this.getChildren().add(icon); + } + + public void onIconClick(ActionEventHandler handler) { + this.icon.setOnAction(e -> handler.handle()); + } + +} diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java new file mode 100644 index 0000000..0e56051 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java @@ -0,0 +1,45 @@ +package edu.ntnu.idi.idatt.view.components.elements; + +import edu.ntnu.idi.idatt.view.components.primitives.ActionEventHandler; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.geometry.Pos; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.layout.HBox; + +public class SearchBarComponent extends HBox { + + private final StringProperty query = new SimpleStringProperty(); + private final IconComponent searchIcon; + + public SearchBarComponent(String placeholder) { + + HBox wrapper = new HBox(); + wrapper.getStyleClass().add("searchbar"); + wrapper.setAlignment(Pos.CENTER); + + TextField searchBar = new TextField(); + searchBar.getStyleClass().add("searchbar-field"); + searchBar.setPromptText(placeholder); + searchBar.setMaxHeight(Double.MAX_VALUE); + searchBar.textProperty().bindBidirectional(query); + searchBar.setFocusTraversable(false); + + Image image = new Image(this.getClass().getResource("/icons/search.png/").toExternalForm()); + searchIcon = new IconComponent(image, null, 32); + + wrapper.getChildren().addAll(searchBar, searchIcon); + + this.getChildren().addAll(wrapper); + } + + public String getQuery() { + return query.get(); + } + + public void onSearchQuery(ActionEventHandler handler) { + this.searchIcon.onIconClick(() -> handler.handle()); + } + +} diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/primitives/ActionEventHandler.java b/src/main/java/edu/ntnu/idi/idatt/view/components/primitives/ActionEventHandler.java new file mode 100644 index 0000000..a42993d --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/primitives/ActionEventHandler.java @@ -0,0 +1,6 @@ +package edu.ntnu.idi.idatt.view.components.primitives; + +@FunctionalInterface +public interface ActionEventHandler { + void handle(); +} diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryController.java b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java similarity index 64% rename from src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryController.java rename to src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java index 2fe27fa..52f7eeb 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryController.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java @@ -1,16 +1,20 @@ -package edu.ntnu.idi.idatt.view.primary; +package edu.ntnu.idi.idatt.view.entry; import java.io.File; import java.math.BigDecimal; +import edu.ntnu.idi.idatt.model.player.Player; +import edu.ntnu.idi.idatt.session.UserSession; +import edu.ntnu.idi.idatt.view.SceneManager; import edu.ntnu.idi.idatt.view.components.AbstractController; +import edu.ntnu.idi.idatt.view.primary.MainView; import javafx.stage.FileChooser; -public class PrimaryController extends AbstractController { +public class StartController extends AbstractController { private File csv; - public PrimaryController(PrimaryModel model) { + public StartController(StartModel model) { super(model); } @@ -35,8 +39,9 @@ public void initializeGame() { return; } + BigDecimal balance = null; try { - BigDecimal balance = new BigDecimal(model.getBalance().get()); + balance = new BigDecimal(model.getBalance().get()); } catch (NumberFormatException e) { model.getError().set("The balance must be a number format!"); return; @@ -46,6 +51,10 @@ public void initializeGame() { model.getError().set("Specify the stocks .csv file!"); return; } + + UserSession.getInstance().setPlayer(new Player(model.getName().get(), balance)); + SceneManager.switchTo(new MainView().getInstance()); + } } diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryModel.java b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartModel.java similarity index 88% rename from src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryModel.java rename to src/main/java/edu/ntnu/idi/idatt/view/entry/StartModel.java index 440ea91..e1b0f92 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryModel.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartModel.java @@ -1,10 +1,10 @@ -package edu.ntnu.idi.idatt.view.primary; +package edu.ntnu.idi.idatt.view.entry; import edu.ntnu.idi.idatt.view.components.Model; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -public class PrimaryModel implements Model { +public class StartModel implements Model { private final StringProperty name = new SimpleStringProperty(); private final StringProperty balance = new SimpleStringProperty(); diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryView.java b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartView.java similarity index 94% rename from src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryView.java rename to src/main/java/edu/ntnu/idi/idatt/view/entry/StartView.java index c107572..60180b1 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/PrimaryView.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartView.java @@ -1,4 +1,4 @@ -package edu.ntnu.idi.idatt.view.primary; +package edu.ntnu.idi.idatt.view.entry; import java.util.List; @@ -15,7 +15,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -public class PrimaryView extends AbstractView { +public class StartView extends AbstractView { // Globlal variables for model implementation private TextField nameField; @@ -27,7 +27,7 @@ public class PrimaryView extends AbstractView { private Button csvButton; private Button startButton; - public PrimaryView() { + public StartView() { super(new StackPane()); this.getInstance().getStyleClass().add("dark"); } @@ -106,14 +106,14 @@ public Parent createContent() { return root; } - public void setModel(PrimaryModel model) { + public void setModel(StartModel model) { this.nameField.textProperty().bindBidirectional(model.getName()); this.balanceField.textProperty().bindBidirectional(model.getBalance()); this.errorLabel.textProperty().bind(model.getError()); this.fileLabel.textProperty().bind(model.getFileName()); } - public void setController(PrimaryController controller) { + public void setController(StartController controller) { this.csvButton.setOnAction(e -> controller.obtainCSVFile()); this.startButton.setOnAction(e -> controller.initializeGame()); } diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/MainView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/MainView.java index cede902..d3a151d 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/MainView.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/MainView.java @@ -1,34 +1,114 @@ package edu.ntnu.idi.idatt.view.primary; -import edu.ntnu.idi.idatt.view.components.AbstractView; +import edu.ntnu.idi.idatt.session.UserSession; +import edu.ntnu.idi.idatt.view.components.AbstractViewUI; +import edu.ntnu.idi.idatt.view.components.elements.IconComponent; +import edu.ntnu.idi.idatt.view.components.elements.SearchBarComponent; +import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; -import javafx.scene.transform.Scale; +import javafx.scene.layout.VBox; +public class MainView extends AbstractViewUI { -public class MainView extends AbstractView { + @Override + public Parent createContent() { + StackPane root = new StackPane(); + root.getStyleClass().add("primary"); + return root; + } - public MainView() { - super(new StackPane()); - this.getInstance().getStyleClass().add("light"); - } + @Override + public Parent createNavigation() { + VBox navigation = new VBox(); + Label title = new Label("Title"); + title.getStyleClass().add("big-text-32"); - @Override - public Parent createContent() { - StackPane menu = new StackPane(); - menu.getStyleClass().add("dark"); - menu.setScaleX(menu.getScaleX()*0.75); - Scale scale = new Scale(-2.0, 1.0, 0, 0); - menu.getTransforms().add(scale); + Label newspaper = new Label(" • Newspaper"); + newspaper.getStyleClass().add("med-text-16"); - StackPane background = new StackPane(); - background.getStyleClass().add("primary"); - StackPane.setAlignment(background, Pos.CENTER); - background.setScaleY(background.getScaleY()*0.80); - StackPane main = new StackPane(background, menu); + navigation.getChildren().addAll(title, newspaper); + return navigation; + } + @Override + public Parent createHeader() { + this.getHeader().setAlignment(Pos.CENTER); + SearchBarComponent bar = new SearchBarComponent("Search after stocks.."); + bar.onSearchQuery(() -> System.out.println(bar.getQuery())); + HBox.setMargin(bar, new Insets(20)); + return bar; + } + + @Override + public Parent createToolbar() { + HBox bar = new HBox(); + bar.setAlignment(Pos.CENTER); + bar.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(bar, Priority.ALWAYS); + + Label balance = new Label(" Money: " + UserSession.getInstance().getPlayer().getMoney().toString() + " USD"); + balance.getStyleClass().add("med-text-16"); + + Region filler = new Region(); + HBox.setHgrow(filler, Priority.ALWAYS); + + VBox infoWrapper = new VBox(); + infoWrapper.setAlignment(Pos.CENTER); + + Label playerStatus = new Label(); + playerStatus.setText("Status:" + UserSession.getInstance().getPlayer().getStatus()); + playerStatus.getStyleClass().add("med-text-16"); + + Label playerNetWorth = new Label(); + playerNetWorth.setText("Net Worth: " + UserSession.getInstance().getPlayer().getNetWorth().toString() + " USD"); + playerNetWorth.getStyleClass().add("med-text-16"); + + infoWrapper.getChildren().addAll(playerStatus, playerNetWorth); + + HBox iconWrapper = new HBox(); + iconWrapper.setAlignment(Pos.CENTER); + + Image userImg = new Image(this.getClass().getResource("/icons/user.png").toExternalForm()); + Image quitImg = new Image(this.getClass().getResource("/icons/quit.png").toExternalForm()); + + IconComponent userIcon = new IconComponent(userImg, null, 44); + IconComponent quitIcon = new IconComponent(quitImg, null, 44); + + userIcon.onIconClick(() -> toggleMenu()); + + iconWrapper.getChildren().addAll(userIcon, quitIcon); + + bar.getChildren().addAll(balance, filler, infoWrapper, iconWrapper); + return bar; + } + + @Override + public Parent createMenu() { + VBox menu = new VBox(); + menu.setMaxSize(300, Double.MAX_VALUE); + menu.getStyleClass().add("dark"); + menu.setAlignment(Pos.TOP_CENTER); + + Image menuImg = new Image(this.getClass().getResource("/icons/user.png").toExternalForm()); + IconComponent menuIcon = new IconComponent(menuImg, "Account", 60); + menuIcon.getStyleClass().add("big-text-32"); + + Label portfolio = new Label(" • Portfolio"); + portfolio.getStyleClass().add("med-text-16"); + + Label transactions = new Label(" • Transactions"); + transactions.getStyleClass().add("med-text-16"); + + menu.getChildren().addAll(menuIcon, portfolio, transactions); + + return menu; + } - return main; - } } diff --git a/src/main/resources/icons/portfolio.png b/src/main/resources/icons/portfolio.png new file mode 100644 index 0000000..2f33093 Binary files /dev/null and b/src/main/resources/icons/portfolio.png differ diff --git a/src/main/resources/icons/quit.png b/src/main/resources/icons/quit.png new file mode 100644 index 0000000..f577227 Binary files /dev/null and b/src/main/resources/icons/quit.png differ diff --git a/src/main/resources/icons/search.png b/src/main/resources/icons/search.png new file mode 100644 index 0000000..a206015 Binary files /dev/null and b/src/main/resources/icons/search.png differ diff --git a/src/main/resources/icons/user.png b/src/main/resources/icons/user.png new file mode 100644 index 0000000..0534bdd Binary files /dev/null and b/src/main/resources/icons/user.png differ diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png deleted file mode 100644 index a8980fe..0000000 Binary files a/src/main/resources/logo.png and /dev/null differ diff --git a/src/main/resources/stonks.png b/src/main/resources/stonks.png deleted file mode 100644 index db95b50..0000000 Binary files a/src/main/resources/stonks.png and /dev/null differ diff --git a/src/main/resources/themes/default.css b/src/main/resources/themes/default.css index 2e79159..a372c2b 100644 --- a/src/main/resources/themes/default.css +++ b/src/main/resources/themes/default.css @@ -30,7 +30,6 @@ -fx-font-size: 16px; -fx-font-weight: 700; -fx-text-fill: #EEEEEE; - -fx-padding: 30px; } /* ======================= @@ -51,3 +50,26 @@ -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.4), 8, 0.4, 0, 4); -fx-translate-y: 1; } + +.icon { + -fx-border-radius: 20; + -fx-padding: 5; + -fx-cursor: hand; +} + +.searchbar { + -fx-background-color: #FFFFFF; + -fx-background-radius: 20; + -fx-border-radius: 20; + -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 6, 0.3, 0, 2); +} + +.searchbar-field { + -fx-font-size: 16px; + -fx-text-fill: black; + -fx-background-color: #FFFFFF; + -fx-background-radius: 20; + -fx-border-radius: 20; + -fx-cursor: hand; +} +