Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ dependencies {
implementation 'com.google.code.gson:gson:2.13.1'
implementation 'org.apache.commons:commons-lang3:3.17.0'
implementation 'com.google.guava:guava:33.4.8-jre'
implementation 'io.github.mkpaz:atlantafx-base:2.0.1'
implementation platform('org.kordamp.ikonli:ikonli-bom:12.4.0')
implementation 'org.kordamp.ikonli:ikonli-fluentui-pack:12.4.0'
implementation 'org.kordamp.ikonli:ikonli-javafx:12.4.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.synops.replayreader.core;

import atlantafx.base.theme.PrimerDark;
import atlantafx.base.theme.PrimerLight;
import com.synops.replayreader.common.i18n.I18nUtils;
import com.synops.replayreader.ui.util.UiUtil;
import java.io.IOException;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
Expand Down Expand Up @@ -41,10 +44,13 @@ public void onApplicationEvent(StageReadyEvent event) {
fxmlLoader.setControllerFactory(applicationContext::getBean);
Parent parent = fxmlLoader.load();
var stage = event.getStage();
// Application.setUserAgentStylesheet(new PrimerDark().getUserAgentStylesheet());
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
stage.setScene(new Scene(parent, applicationWidth, applicationHeight));
stage.setResizable(false);
stage.setTitle(resourceBundle.getString("main.title"));
UiUtil.setDefaultIcon(stage);
UiUtil.setDefaultStyle(stage);
stage.show();
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package com.synops.replayreader.core.configuration;

import com.synops.replayreader.clan.comparator.ClanListComparator;
import com.synops.replayreader.clan.util.ClanStringConverter;
import com.synops.replayreader.common.comparator.SortingComparators;
import com.synops.replayreader.core.service.DialogService;
import com.synops.replayreader.core.service.DialogServiceImpl;
import com.synops.replayreader.core.service.NotificationService;
import com.synops.replayreader.core.service.NotificationServiceImpl;
import com.synops.replayreader.maps.comparator.MapsComparator;
import com.synops.replayreader.common.comparator.SortingComparators;
import com.synops.replayreader.replay.controller.ReplayController;
import com.synops.replayreader.replay.service.ReplayModelBuilder;
import com.synops.replayreader.replay.service.ReplayReader;
import com.synops.replayreader.replay.service.ReplayService;
import com.synops.replayreader.replay.service.ReplayServiceImpl;
import com.synops.replayreader.clan.util.ClanStringConverter;
import com.synops.replayreader.ui.util.DragDropSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -28,6 +30,11 @@ public DialogService dialogService() {
return new DialogServiceImpl();
}

@Bean
public NotificationService notificationService() {
return new NotificationServiceImpl();
}

@Bean
public ClanStringConverter clanStringConverter() {
return new ClanStringConverter();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.synops.replayreader.core.service;

import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.StackPane;

public interface NotificationService {

void alert(String message, StackPane stackPane);

void information(String message, StackPane stackPane);

void warning(String message, StackPane stackPane);

void confirmation(String message, StackPane stackPane);

void notify(String message, AlertType alertType, StackPane stackPane);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.synops.replayreader.core.service;

import atlantafx.base.controls.Notification;
import atlantafx.base.theme.Styles;
import atlantafx.base.util.Animations;
import java.util.HashMap;
import java.util.Map;
import javafx.animation.PauseTransition;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import org.kordamp.ikonli.fluentui.FluentUiRegularAL;
import org.kordamp.ikonli.fluentui.FluentUiRegularMZ;
import org.kordamp.ikonli.javafx.FontIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NotificationServiceImpl implements NotificationService {

private static final Logger LOGGER = LoggerFactory.getLogger(NotificationServiceImpl.class);
private static final int NOTIFICATION_SPACING = 10;
private static final int DEFAULT_BOTTOM_MARGIN = 40;

private final Map<StackPane, ObservableList<Notification>> activeNotifications = new HashMap<>();

public void alert(String message, StackPane stackPane) {
notify(message, AlertType.ERROR, stackPane);
}

public void information(String message, StackPane stackPane) {
notify(message, AlertType.INFORMATION, stackPane);
}

public void warning(String message, StackPane stackPane) {
notify(message, AlertType.WARNING, stackPane);
}

public void confirmation(String message, StackPane stackPane) {
notify(message, AlertType.CONFIRMATION, stackPane);
}

public void notify(String message, AlertType alertType, StackPane stackPane) {
var notificationList = activeNotifications.computeIfAbsent(stackPane,
_ -> FXCollections.observableArrayList());

var fontIcon = switch (alertType) {
case NONE -> null;
case INFORMATION -> FluentUiRegularAL.INFO_16;
case WARNING -> FluentUiRegularMZ.WARNING_16;
case CONFIRMATION -> FluentUiRegularAL.CHECKMARK_CIRCLE_16;
case ERROR -> FluentUiRegularAL.ERROR_CIRCLE_16;
};

var notification = new Notification(message, fontIcon != null ? new FontIcon(fontIcon) : null);
notification.getStyleClass().add(Styles.ELEVATED_1);
notification.setPrefHeight(Region.USE_PREF_SIZE);
notification.setMaxHeight(Region.USE_PREF_SIZE);

StackPane.setAlignment(notification, Pos.BOTTOM_RIGHT);

int notificationCount = notificationList.size();
int bottomMargin = (int) (DEFAULT_BOTTOM_MARGIN + (notificationCount * (
notification.prefHeight(-1) + NOTIFICATION_SPACING)));

StackPane.setMargin(notification, new Insets(0, 10, bottomMargin, 0));

var style = switch (alertType) {
case NONE -> null;
case INFORMATION -> Styles.ACCENT;
case WARNING -> Styles.WARNING;
case CONFIRMATION -> Styles.SUCCESS;
case ERROR -> Styles.DANGER;
};

if (style != null) {
notification.getStyleClass().add(style);
}

notificationList.add(notification);
notification.setOnClose(_ -> {
removeNotification(notification, stackPane);
});
var in = Animations.slideInDown(notification, Duration.millis(250));
stackPane.getChildren().add(notification);
in.playFromStart();
LOGGER.debug("Notification: {}", message);

scheduleAutoClose(notification, stackPane);
}

private void removeNotification(Notification notification, StackPane stackPane) {
var notificationList = activeNotifications.get(stackPane);
if (notificationList == null) {
return;
}

var out = Animations.slideOutDown(notification, Duration.millis(250));
out.setOnFinished(_ -> {
stackPane.getChildren().remove(notification);
notificationList.remove(notification);
repositionNotifications(notificationList);
});
out.playFromStart();
}

private void repositionNotifications(ObservableList<Notification> notificationList) {
for (int i = 0; i < notificationList.size(); i++) {
var notification = notificationList.get(i);
int bottomMargin = (int) (DEFAULT_BOTTOM_MARGIN + (i * (notification.prefHeight(-1)
+ NOTIFICATION_SPACING)));

var moveUp = Animations.fadeIn(notification, Duration.millis(150));
StackPane.setMargin(notification, new Insets(0, 10, bottomMargin, 0));
moveUp.playFromStart();
}
}

private void scheduleAutoClose(Notification notification, StackPane stackPane) {
var delay = new PauseTransition(Duration.seconds(5));
delay.setOnFinished(_ -> removeNotification(notification, stackPane));
delay.play();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.synops.replayreader.common.util.LogUtil;
import com.synops.replayreader.core.event.ReplayProgressEvent;
import com.synops.replayreader.core.service.DialogService;
import com.synops.replayreader.core.service.NotificationService;
import com.synops.replayreader.maps.comparator.MapsComparator;
import com.synops.replayreader.maps.ui.MapListCell;
import com.synops.replayreader.player.comparator.PlayerListComparatorLong;
Expand Down Expand Up @@ -40,16 +41,15 @@
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.info.BuildProperties;
import org.springframework.lang.Nullable;
Expand All @@ -74,12 +74,13 @@ public class MainViewController {
private final StringProperty selectedVehicle = new SimpleStringProperty("");
private final StringProperty selectedClan = new SimpleStringProperty("");
private final BuildProperties buildProperties;
private final NotificationService notificationService;
@Value("${replay-reader.config.max-players}")
private int MAX_PLAYERS;
@Value("${replay-reader.config.max-clans}")
private int MAX_CLANS;
@FXML
private AnchorPane root;
private StackPane root;
@FXML
private ChoiceBox<String> sortingChoiceBox;
@FXML
Expand Down Expand Up @@ -158,7 +159,8 @@ public MainViewController(ReplayService replayService, @Nullable HostServices ho
DialogService dialogService, UpdateClient updateClient, ResourceBundle resourceBundle,
ClanStringConverter clanStringConverter, ClanListComparator clanListComparator,
SortingComparators sortingComparators, MapsComparator mapsComparator,
DragDropSupport dragDropSupport, BuildProperties buildProperties) {
DragDropSupport dragDropSupport, BuildProperties buildProperties,
NotificationService notificationService) {
this.replayService = replayService;
this.hostServices = hostServices;
this.dialogService = dialogService;
Expand All @@ -170,6 +172,7 @@ public MainViewController(ReplayService replayService, @Nullable HostServices ho
this.mapsComparator = mapsComparator;
this.dragDropSupport = dragDropSupport;
this.buildProperties = buildProperties;
this.notificationService = notificationService;
}

@FXML
Expand Down Expand Up @@ -446,8 +449,7 @@ private void checkForUpdate() {
MessageFormat.format(resourceBundle.getString("update.new-version"),
versionResponse.tagName().substring(1)), () -> openUrl(REPLAY_RELEASES_URL));
} else {
dialogService.alert(AlertType.INFORMATION,
resourceBundle.getString("update.latest-already"));
notificationService.information(resourceBundle.getString("update.latest-already"), root);
}
})).doOnError(dialogService::showAlertError).subscribe();
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/synops/replayreader/ui/util/UiUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ public static void setDefaultIcon(Stage stage) {
stage.getIcons().add(
new Image(Objects.requireNonNull(stage.getClass().getResourceAsStream("/image/icon.png"))));
}

public static void setDefaultStyle(Stage stage) {
stage.getScene().getStylesheets().add("/css/theme.css");
}
}
Empty file.
10 changes: 5 additions & 5 deletions src/main/resources/views/main.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.control.ProgressBar?>
<AnchorPane xmlns:fx="http://javafx.com/fxml"
<?import javafx.scene.layout.StackPane?>
<StackPane xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
minWidth="800.0" prefHeight="583.0" prefWidth="1199.0"
fx:controller="com.synops.replayreader.ui.controller.MainViewController"
fx:id="root">
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0">
<VBox>
<MenuBar>
<Menu text="%main.menu.file">
<MenuItem fx:id="exitApplication" text="%main.menu.file.exit"/>
Expand Down Expand Up @@ -144,7 +144,7 @@
</GridPane>
</AnchorPane>
</HBox>
<ToolBar prefHeight="40">
<ToolBar prefHeight="30.0" maxHeight="30.0" minHeight="30.0">
<Label text="%main.footer.drag">
<font>
<Font name="System Bold" size="12.0"/>
Expand All @@ -158,4 +158,4 @@
<Label fx:id="progressLabel" prefHeight="17.0" prefWidth="183.0" GridPane.columnIndex="1"/>
</ToolBar>
</VBox>
</AnchorPane>
</StackPane>