From be68d4e29910f87839fd04610ab16f12c5770bc2 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 10 Sep 2022 19:20:36 +0200 Subject: [PATCH 1/9] First version of is ready dialog --- .../faforever/client/main/MainController.java | 4 +- .../notification/ImmediateNotification.java | 23 ++- .../ImmediateNotificationController.java | 1 + .../com/faforever/client/theme/UiService.java | 3 +- .../game/IsReadyForGameController.java | 96 ++++++++++ .../game/TournamentGameService.java | 73 ++++++++ .../ui/progress/ProgressCircleIndicator.java | 154 ++++++++++++++++ .../ui/progress/RingProgressIndicator.java | 135 ++++++++++++++ .../progress/RingProgressIndicatorSkin.java | 165 ++++++++++++++++++ src/main/resources/application-local.yml | 1 - src/main/resources/i18n/messages.properties | 4 +- src/main/resources/theme/progress.css | 37 ++++ .../theme/tournaments/is_ready_for_game.fxml | 16 ++ 13 files changed, 705 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java create mode 100644 src/main/java/com/faforever/client/tournament/game/TournamentGameService.java create mode 100644 src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java create mode 100644 src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java create mode 100644 src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java create mode 100644 src/main/resources/theme/progress.css create mode 100644 src/main/resources/theme/tournaments/is_ready_for_game.fxml diff --git a/src/main/java/com/faforever/client/main/MainController.java b/src/main/java/com/faforever/client/main/MainController.java index f319ee2670..c4e9405b77 100644 --- a/src/main/java/com/faforever/client/main/MainController.java +++ b/src/main/java/com/faforever/client/main/MainController.java @@ -472,7 +472,7 @@ private void makePopUpAskingForPreferenceInStartTab(WindowPrefs mainWindow) { }); ImmediateNotification notification = new ImmediateNotification(i18n.get("startTab.title"), i18n.get("startTab.message"), - Severity.INFO, null, Collections.singletonList(saveAction), startTabChooseController.getRoot()); + Severity.INFO, null, Collections.singletonList(saveAction), startTabChooseController.getRoot(), false); notificationService.addNotification(notification); } @@ -594,9 +594,11 @@ private void displayImmediateNotification(ImmediateNotification notification) { .setNotification(notification) .setCloseListener(dialog::close); + dialog.setOverlayClose(notification.isOverlayClose()); dialog.setContent(controller.getDialogLayout()); dialog.setAnimation(AlertAnimation.TOP_ANIMATION); dialog.show(); + } private void displayServerNotification(ImmediateNotification notification) { diff --git a/src/main/java/com/faforever/client/notification/ImmediateNotification.java b/src/main/java/com/faforever/client/notification/ImmediateNotification.java index 96e39117fd..2cb78c9af3 100644 --- a/src/main/java/com/faforever/client/notification/ImmediateNotification.java +++ b/src/main/java/com/faforever/client/notification/ImmediateNotification.java @@ -22,20 +22,37 @@ public class ImmediateNotification { private final Throwable throwable; private final List actions; private final Parent customUI; + /** + * If false notification will not close by clicking beside it. + */ + private final boolean overlayClose; + private Runnable dismissAction; public ImmediateNotification(String title, String text, Severity severity) { this(title, text, severity, null); } public ImmediateNotification(String title, String text, Severity severity, List actions) { - this(title, text, severity, null, actions, null); + this(title, text, severity, null, actions, null, true); } public ImmediateNotification(String title, String text, Severity severity, Throwable throwable, List actions) { - this(title, text, severity, throwable, actions, null); + this(title, text, severity, throwable, actions, null, true); } public ImmediateNotification(String title, String text, Severity severity, List actions, Parent customUI) { - this(title, text, severity, null, actions, customUI); + this(title, text, severity, null, actions, customUI, true); + } + + public ImmediateNotification(String title, String text, Severity severity, Throwable throwable, List actions, Parent customUI) { + this(title, text, severity, throwable, actions, customUI, true); + } + + public void setCloseAction(Runnable dismissAction) { + this.dismissAction = dismissAction; + } + + public void dismiss(){ + dismissAction.run(); } } diff --git a/src/main/java/com/faforever/client/notification/ImmediateNotificationController.java b/src/main/java/com/faforever/client/notification/ImmediateNotificationController.java index 5af3c08f9c..d53cff4d55 100644 --- a/src/main/java/com/faforever/client/notification/ImmediateNotificationController.java +++ b/src/main/java/com/faforever/client/notification/ImmediateNotificationController.java @@ -70,6 +70,7 @@ public ImmediateNotificationController setNotification(ImmediateNotification not if (notification.getCustomUI() != null) { immediateNotificationRoot.getChildren().add(notification.getCustomUI()); } + notification.setCloseAction(this::dismiss); return this; } diff --git a/src/main/java/com/faforever/client/theme/UiService.java b/src/main/java/com/faforever/client/theme/UiService.java index 224ed615ec..402f00460a 100644 --- a/src/main/java/com/faforever/client/theme/UiService.java +++ b/src/main/java/com/faforever/client/theme/UiService.java @@ -390,7 +390,8 @@ private String[] getStylesheets() { getThemeFile("theme/colors.css"), getThemeFile("theme/icons.css"), getSceneStyleSheet(), - getThemeFile("theme/style_extension.css") + getThemeFile("theme/style_extension.css"), + getThemeFile("theme/progress.css") }; } catch (IOException e) { throw new AssetLoadException("Could not retrieve stylesheets", e, "theme.stylesheets.couldNotGet"); diff --git a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java new file mode 100644 index 0000000000..555e196a12 --- /dev/null +++ b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java @@ -0,0 +1,96 @@ +package com.faforever.client.tournament.game; + +import com.faforever.client.fx.Controller; +import com.faforever.client.fx.JavaFxUtil; +import com.faforever.client.i18n.I18n; +import com.faforever.client.ui.progress.RingProgressIndicator; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.util.StringConverter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import lombok.extern.apachecommons.CommonsLog; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.TimerTask; + + +@Slf4j +@Component +@RequiredArgsConstructor +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class IsReadyForGameController implements Controller { + public static final int MILLIS_TIME_BEFORE_CLOSE = 1000; + private final I18n i18n; + public HBox root; + public Label description; + public RingProgressIndicator progressIndicator; + private int timeLeft; + private Timeline queuePopTimeUpdater; + @Setter + private Runnable timedOut; + + + @Override + public void initialize() { + progressIndicator.setProgressLableStringConverter(new StringConverter<>() { + @Override + public String toString(Integer object) { + return i18n.number(timeLeft); + } + + @Override + public Integer fromString(String string) { + throw new UnsupportedOperationException(); + } + }); + } + + + @Override + public Parent getRoot() { + return root; + } + + public void setTimeout(int responseTimeSeconds) { + OffsetDateTime start = OffsetDateTime.now(); + + queuePopTimeUpdater = new Timeline(1, new KeyFrame(javafx.util.Duration.seconds(0), (ActionEvent event) -> { + updateQueue(responseTimeSeconds, start); + }), new KeyFrame(javafx.util.Duration.seconds(1))); + queuePopTimeUpdater.setCycleCount(Timeline.INDEFINITE); + queuePopTimeUpdater.play(); + } + + private void updateQueue(int responseTimeSeconds, OffsetDateTime start) { + OffsetDateTime now = OffsetDateTime.now(); + Duration timeGone = Duration.between(start, now); + final var percent = timeGone.toSeconds() / (double) responseTimeSeconds; + this.timeLeft = (int) (responseTimeSeconds - timeGone.toSeconds()); + progressIndicator.setProgress((int) (percent * 100)); + if(timeLeft <= 0 && queuePopTimeUpdater != null){ + end(); + } + } + + private void end() { + queuePopTimeUpdater.stop(); + try { + Thread.sleep(MILLIS_TIME_BEFORE_CLOSE); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + timedOut.run(); + } +} diff --git a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java new file mode 100644 index 0000000000..6c2895579e --- /dev/null +++ b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java @@ -0,0 +1,73 @@ +package com.faforever.client.tournament.game; + +import com.faforever.client.i18n.I18n; +import com.faforever.client.main.StartTabChooseController; +import com.faforever.client.main.event.NavigateEvent; +import com.faforever.client.main.event.NavigationItem; +import com.faforever.client.notification.Action; +import com.faforever.client.notification.ImmediateNotification; +import com.faforever.client.notification.NotificationService; +import com.faforever.client.notification.Severity; +import com.faforever.client.remote.FafServerAccessor; +import com.faforever.client.theme.UiService; +import com.faforever.client.ui.StageHolder; +import com.faforever.client.user.event.LoginSuccessEvent; +import com.faforever.commons.lobby.IsReadyRequest; +import com.faforever.commons.lobby.LoginSuccessResponse; +import com.faforever.commons.lobby.MatchmakerInfo; +import com.faforever.commons.lobby.ServerMessage; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import javafx.application.Platform; +import javafx.stage.Stage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +@Slf4j +@RequiredArgsConstructor +public class TournamentGameService implements InitializingBean { + private final FafServerAccessor fafServerAccessor; + private final I18n i18n; + private final UiService uiService; + private final NotificationService notificationService; + private ImmediateNotification notification; + + + @Override + public void afterPropertiesSet() throws Exception { + fafServerAccessor.addEventListener(IsReadyRequest.class, this::onReadRequest); + } + + private void onReadRequest(IsReadyRequest isReadyRequest) { + log.info("Tournament game is ready, asking user."); + Stage stage = StageHolder.getStage(); + if (!stage.isFocused() || !stage.isShowing()) { + Platform.runLater(stage::toFront); + } + IsReadyForGameController controller = uiService.loadFxml("theme/tournaments/is_ready_for_game.fxml"); + controller.setTimeout(isReadyRequest.getResponseTimeSeconds()); + controller.setTimedOut(() -> { + respond(false); + if(notification != null){ + Platform.runLater(() -> notification.dismiss()); + } + }); + Action acceptButton = new Action(i18n.get("yes"), event -> respond(true)); + Action rejectButton = new Action(i18n.get("no"), event -> respond(false)); + notification = + new ImmediateNotification(i18n.get("isReady.title"), i18n.get("isReady.message", isReadyRequest.getGameName()), + Severity.INFO, null, List.of(acceptButton, rejectButton), controller.getRoot(), false); + notificationService.addNotification(notification); + } + + private void respond(boolean accepted) { + + } +} diff --git a/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java new file mode 100644 index 0000000000..4974cc8de4 --- /dev/null +++ b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2014, Andrea Vacondio + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.faforever.client.ui.progress; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.ReadOnlyBooleanWrapper; +import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyIntegerWrapper; +import javafx.css.CssMetaData; +import javafx.css.Styleable; +import javafx.css.StyleableDoubleProperty; +import javafx.css.StyleableProperty; +import javafx.css.converter.SizeConverter; +import javafx.scene.control.Control; + + +/** + * Base class for the progress indicator controls represented by circualr shapes + * + * @author Andrea Vacondio + * + */ +abstract class ProgressCircleIndicator extends Control { + private static final int INDETERMINATE_PROGRESS = -1; + + private ReadOnlyIntegerWrapper progress = new ReadOnlyIntegerWrapper(0); + private ReadOnlyBooleanWrapper indeterminate = new ReadOnlyBooleanWrapper(false); + + public ProgressCircleIndicator() { + } + + public int getProgress() { + return progress.get(); + } + + /** + * Set the value for the progress, it cannot be more then 100 (meaning 100%). A negative value means indeterminate progress. + * + * @param progressValue + * @see ProgressCircleIndicator#makeIndeterminate() + */ + public void setProgress(int progressValue) { + progress.set(defaultToHundred(progressValue)); + indeterminate.set(progressValue < 0); + } + + public ReadOnlyIntegerProperty progressProperty() { + return progress.getReadOnlyProperty(); + } + + public boolean isIndeterminate() { + return indeterminate.get(); + } + + public void makeIndeterminate() { + setProgress(INDETERMINATE_PROGRESS); + } + + public ReadOnlyBooleanProperty indeterminateProperty() { + return indeterminate.getReadOnlyProperty(); + } + + private int defaultToHundred(int value) { + if (value > 100) { + return 100; + } + return value; + } + + public final void setInnerCircleRadius(int value) { + innerCircleRadiusProperty().set(value); + } + + public final DoubleProperty innerCircleRadiusProperty() { + return innerCircleRadius; + } + + public final double getInnerCircleRadius() { + return innerCircleRadiusProperty().get(); + } + + /** + * radius of the inner circle + */ + private DoubleProperty innerCircleRadius = new StyleableDoubleProperty(60) { + @Override + public Object getBean() { + return ProgressCircleIndicator.this; + } + + @Override + public String getName() { + return "innerCircleRadius"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INNER_CIRCLE_RADIUS; + } + }; + + private static class StyleableProperties { + private static final CssMetaData INNER_CIRCLE_RADIUS = new CssMetaData( + "-fx-inner-radius", SizeConverter.getInstance(), 60) { + + @Override + public boolean isSettable(ProgressCircleIndicator n) { + return n.innerCircleRadiusProperty() == null || !n.innerCircleRadiusProperty().isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(ProgressCircleIndicator n) { + return (StyleableProperty) n.innerCircleRadiusProperty(); + } + }; + + public static final List> STYLEABLES; + static { + final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); + styleables.add(INNER_CIRCLE_RADIUS); + STYLEABLES = Collections.unmodifiableList(styleables); + } + } + + /** + * @return The CssMetaData associated with this class, which may include the CssMetaData of its super classes. + */ + public static List> getClassCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + @Override + public List> getControlCssMetaData() { + return StyleableProperties.STYLEABLES; + } +} \ No newline at end of file diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java new file mode 100644 index 0000000000..eac14f4d0a --- /dev/null +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014, Andrea Vacondio + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.faforever.client.ui.progress; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.css.CssMetaData; +import javafx.css.Styleable; +import javafx.css.StyleableDoubleProperty; +import javafx.css.StyleableProperty; +import javafx.css.converter.SizeConverter; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.util.StringConverter; + + +/** + * Progress indicator showing a filling arc. + * + * @author Andrea Vacondio + * + */ +public class RingProgressIndicator extends ProgressCircleIndicator { + public ObjectProperty> progressLableStringConverter = new SimpleObjectProperty<>(new StringConverter<>() { + @Override + public String toString(Integer object) { + return String.format("%d%%", object); + } + + @Override + public Integer fromString(String string) { + throw new UnsupportedOperationException(); + } + }); + + public RingProgressIndicator() { + this.getStyleClass().add("ringindicator"); + } + + @Override + protected Skin createDefaultSkin() { + return new RingProgressIndicatorSkin(this); + } + + public final void setRingWidth(int value) { + ringWidthProperty().set(value); + } + + public final DoubleProperty ringWidthProperty() { + return ringWidth; + } + + public final double getRingWidth() { + return ringWidthProperty().get(); + } + + /** + * thickness of the ring indicator. + */ + private DoubleProperty ringWidth = new StyleableDoubleProperty(22) { + @Override + public Object getBean() { + return RingProgressIndicator.this; + } + + @Override + public String getName() { + return "ringWidth"; + } + + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.RING_WIDTH; + } + }; + + private static class StyleableProperties { + private static final CssMetaData RING_WIDTH = new CssMetaData( + "-fx-ring-width", SizeConverter.getInstance(), 22) { + + @Override + public boolean isSettable(RingProgressIndicator n) { + return n.ringWidth == null || !n.ringWidth.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(RingProgressIndicator n) { + return (StyleableProperty) n.ringWidth; + } + }; + + public static final List> STYLEABLES; + static { + final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); + styleables.addAll(ProgressCircleIndicator.getClassCssMetaData()); + styleables.add(RING_WIDTH); + STYLEABLES = Collections.unmodifiableList(styleables); + } + } + + @Override + public List> getControlCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + public StringConverter getProgressLableStringConverter() { + return progressLableStringConverter.get(); + } + + public ObjectProperty> progressLableStringConverterProperty() { + return progressLableStringConverter; + } + + public void setProgressLableStringConverter(StringConverter progressLableStringConverter) { + this.progressLableStringConverter.set(progressLableStringConverter); + } +} \ No newline at end of file diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java new file mode 100644 index 0000000000..41fae77aa5 --- /dev/null +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014, Andrea Vacondio + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.faforever.client.ui.progress; + +import javafx.animation.Animation; +import javafx.animation.Interpolator; +import javafx.animation.RotateTransition; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.Skin; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.shape.Arc; +import javafx.scene.shape.Circle; +import javafx.util.Duration; + +/** + * Skin of the ring progress indicator where an arc grows and by the progress value up to 100% where the arc becomes a ring. + * + * @author Andrea Vacondio + * + */ +public class RingProgressIndicatorSkin implements Skin { + + private final RingProgressIndicator indicator; + private final Label percentLabel = new Label(); + private final Circle innerCircle = new Circle(); + private final Circle outerCircle = new Circle(); + private final StackPane container = new StackPane(); + private final Arc fillerArc = new Arc(); + private final RotateTransition transition = new RotateTransition(Duration.millis(2000), fillerArc); + + public RingProgressIndicatorSkin(final RingProgressIndicator indicator) { + this.indicator = indicator; + initContainer(indicator); + initFillerArc(); + container.widthProperty().addListener((o, oldVal, newVal) -> { + fillerArc.setCenterX(newVal.intValue() / 2); + }); + container.heightProperty().addListener((o, oldVal, newVal) -> { + fillerArc.setCenterY(newVal.intValue() / 2); + }); + innerCircle.getStyleClass().add("ringindicator-inner-circle"); + outerCircle.getStyleClass().add("ringindicator-outer-circle-secondary"); + updateRadii(); + + this.indicator.indeterminateProperty().addListener((o, oldVal, newVal) -> { + initIndeterminate(newVal); + }); + this.indicator.progressProperty().addListener((o, oldVal, newVal) -> { + if (newVal.intValue() >= 0) { + setProgressLabel(newVal.intValue()); + fillerArc.setLength(newVal.intValue() * -3.6); + } + }); + this.indicator.ringWidthProperty().addListener((o, oldVal, newVal) -> { + updateRadii(); + }); + innerCircle.strokeWidthProperty().addListener((e) -> { + updateRadii(); + }); + innerCircle.radiusProperty().addListener((e) -> { + updateRadii(); + }); + initTransition(); + initIndeterminate(indicator.isIndeterminate()); + initLabel(indicator.getProgress()); + indicator.visibleProperty().addListener((o, oldVal, newVal) -> { + if (newVal && this.indicator.isIndeterminate()) { + transition.play(); + } else { + transition.pause(); + } + }); + container.getChildren().addAll(fillerArc, outerCircle, innerCircle, percentLabel); + } + + private void setProgressLabel(int value) { + if (value >= 0) { + percentLabel.setText(indicator.getProgressLableStringConverter().toString(value)); + } + } + + private void initTransition() { + transition.setAutoReverse(false); + transition.setCycleCount(Animation.INDEFINITE); + transition.setDelay(Duration.ZERO); + transition.setInterpolator(Interpolator.LINEAR); + transition.setByAngle(360); + } + + private void initFillerArc() { + fillerArc.setManaged(false); + fillerArc.getStyleClass().add("ringindicator-filler"); + fillerArc.setStartAngle(90); + fillerArc.setLength(indicator.getProgress() * -3.6); + } + + private void initContainer(final RingProgressIndicator indicator) { + container.getStylesheets().addAll(indicator.getStylesheets()); + container.getStyleClass().addAll("circleindicator-container"); + container.setMaxHeight(Region.USE_PREF_SIZE); + container.setMaxWidth(Region.USE_PREF_SIZE); + } + + private void updateRadii() { + double ringWidth = indicator.getRingWidth(); + double innerCircleHalfStrokeWidth = innerCircle.getStrokeWidth() / 2; + double innerCircleRadius = indicator.getInnerCircleRadius(); + outerCircle.setRadius(innerCircleRadius + innerCircleHalfStrokeWidth + ringWidth); + fillerArc.setRadiusY(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); + fillerArc.setRadiusX(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); + fillerArc.setStrokeWidth(ringWidth); + innerCircle.setRadius(innerCircleRadius); + } + + private void initLabel(int value) { + setProgressLabel(value); + percentLabel.getStyleClass().add("circleindicator-label"); + } + + private void initIndeterminate(boolean newVal) { + percentLabel.setVisible(!newVal); + if (newVal) { + fillerArc.setLength(360); + fillerArc.getStyleClass().add("indeterminate"); + if (indicator.isVisible()) { + transition.play(); + } + } else { + fillerArc.getStyleClass().remove("indeterminate"); + fillerArc.setRotate(0); + transition.stop(); + } + } + + @Override + public RingProgressIndicator getSkinnable() { + return indicator; + } + + @Override + public Node getNode() { + return container; + } + + @Override + public void dispose() { + transition.stop(); + } + +} \ No newline at end of file diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index da45f0595d..e2bbcc2077 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -33,7 +33,6 @@ faf-client: base-url: http://localhost:4444 scopes: openid offline public_profile upload_map upload_mod lobby client-id: faf-java-client - timeout-milliseconds: 1500000 logging: level: diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 8f54c0af16..f1e5bce124 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -1240,4 +1240,6 @@ blacklist.mapFolderName.promptText = Full or partial map folder name... hideSingleGames = Hide games with 1 player showGamesWithFriends = Show only games with friends showGeneratedMaps = Show only generated maps -filteredOutItemsCount = {0} from {1} items are filtered out \ No newline at end of file +filteredOutItemsCount = {0} from {1} items are filtered out +isReady.title=Tournament game ready for you +isReady.message=Click 'yes' below to join the upcoming game ''{0}'' diff --git a/src/main/resources/theme/progress.css b/src/main/resources/theme/progress.css new file mode 100644 index 0000000000..685aee0f1a --- /dev/null +++ b/src/main/resources/theme/progress.css @@ -0,0 +1,37 @@ +.circleindicator-container { + circleindicator-color: -fx-accent; + -fx-padding: 5.0; + -fx-background-color: -fx-background; +} +.circleindicator-container > .circleindicator-label { + -fx-font-weight: bold; + -fx-font-size: 2.5em; + -fx-text-fill: circleindicator-color; + -fx-padding: 5.0; +} + +.ringindicator{ + -fx-ring-width: 22.0; + -fx-inner-radius: 60.0; +} +.ringindicator-inner-circle { + -fx-opacity: 0.55; + -fx-stroke: circleindicator-color; + -fx-stroke-width: 8.0px; + -fx-fill: -fx-background; +} +.ringindicator-filler { + -fx-stroke: circleindicator-color; + -fx-fill: -fx-background; + -fx-stroke-line-cap: butt; +} +.ringindicator-outer-circle-secondary { + -fx-opacity: 0.1; + -fx-stroke: circleindicator-color; + -fx-stroke-width: 2.0px; + -fx-fill: -fx-background; +} +.indeterminate { + -fx-opacity: 0.55; + -fx-stroke: linear-gradient(from 0.0% 0.0% to 70.0% 70.0%, circleindicator-color 70.0%, white 75.0%, white); +} \ No newline at end of file diff --git a/src/main/resources/theme/tournaments/is_ready_for_game.fxml b/src/main/resources/theme/tournaments/is_ready_for_game.fxml new file mode 100644 index 0000000000..b3857d50e5 --- /dev/null +++ b/src/main/resources/theme/tournaments/is_ready_for_game.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From cbb399dfed25f757058813b5b3f8ca7dffa01109 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 13 Sep 2022 18:20:34 +0200 Subject: [PATCH 2/9] More towards launching a game+ --- .../faforever/client/game/GameService.java | 27 +++- .../client/remote/FafServerAccessor.java | 4 + .../game/IsReadyForGameController.java | 26 ++-- .../game/TournamentGameService.java | 121 ++++++++++++++---- src/main/resources/i18n/messages.properties | 7 +- .../theme/tournaments/is_ready_for_game.fxml | 27 ++-- 6 files changed, 159 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/faforever/client/game/GameService.java b/src/main/java/com/faforever/client/game/GameService.java index 122b77f803..0bf93d087b 100644 --- a/src/main/java/com/faforever/client/game/GameService.java +++ b/src/main/java/com/faforever/client/game/GameService.java @@ -514,14 +514,29 @@ public CompletableFuture startSearchMatchmaker() { return matchmakerFuture; } + matchmakerFuture = listenToServerInitiatedGame(FAF.getTechnicalName()); + return matchmakerFuture; + } + + public CompletableFuture startListeningToTournamentGame(String featuredModTechnicalName) { + if (isRunning()) { + log.info("Game is running, ignoring tournament search request"); + notificationService.addImmediateWarnNotification("game.gameRunning"); + return completedFuture(null); + } + + return listenToServerInitiatedGame(featuredModTechnicalName); + } + + private CompletableFuture listenToServerInitiatedGame(String featuredModTechnicalName) { if (!preferencesService.isGamePathValid()) { CompletableFuture gameDirectoryFuture = postGameDirectoryChooseEvent(); return gameDirectoryFuture.thenCompose(path -> startSearchMatchmaker()); } - log.info("Matchmaking search has been started"); + log.info("Listening to server made game has been started"); - matchmakerFuture = modService.getFeaturedMod(FAF.getTechnicalName()) + final var matchFuture = modService.getFeaturedMod(featuredModTechnicalName) .thenAccept(featuredModBean -> updateGameIfNecessary(featuredModBean, Set.of())) .thenCompose(aVoid -> fafServerAccessor.startSearchMatchmaker()) .thenCompose(gameLaunchResponse -> downloadMapIfNecessary(gameLaunchResponse.getMapName()) @@ -536,25 +551,25 @@ public CompletableFuture startSearchMatchmaker() { }) .thenCompose(this::startGame)); - matchmakerFuture.whenComplete((aVoid, throwable) -> { + matchFuture.whenComplete((aVoid, throwable) -> { if (throwable != null) { throwable = ConcurrentUtil.unwrapIfCompletionException(throwable); if (throwable instanceof CancellationException) { - log.info("Matchmaking search has been cancelled"); + log.info("Listening to server made game has been cancelled"); if (isRunning()) { notificationService.addServerNotification(new ImmediateNotification(i18n.get("matchmaker.cancelled.title"), i18n.get("matchmaker.cancelled"), Severity.INFO)); gameKilled = true; process.destroy(); } } else { - log.warn("Matchmade game could not be started", throwable); + log.warn("Server initiated game could not be started", throwable); } } else { log.info("Matchmaker queue exited"); } }); - return matchmakerFuture; + return matchFuture; } /** diff --git a/src/main/java/com/faforever/client/remote/FafServerAccessor.java b/src/main/java/com/faforever/client/remote/FafServerAccessor.java index f35f3a4a82..c3233f9ee5 100644 --- a/src/main/java/com/faforever/client/remote/FafServerAccessor.java +++ b/src/main/java/com/faforever/client/remote/FafServerAccessor.java @@ -228,6 +228,10 @@ public void removeFriend(int playerId) { lobbyClient.removeFriend(playerId); } + public void sendIsReady(String requestId) { + lobbyClient.sendReady(requestId); + } + public void removeFoe(int playerId) { lobbyClient.removeFoe(playerId); } diff --git a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java index 555e196a12..ca88efe720 100644 --- a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java +++ b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java @@ -10,8 +10,10 @@ import javafx.event.ActionEvent; import javafx.scene.Node; import javafx.scene.Parent; +import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.util.StringConverter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -24,6 +26,7 @@ import java.time.Duration; import java.time.OffsetDateTime; import java.util.TimerTask; +import java.util.function.Consumer; @Slf4j @@ -31,15 +34,17 @@ @RequiredArgsConstructor @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class IsReadyForGameController implements Controller { - public static final int MILLIS_TIME_BEFORE_CLOSE = 1000; private final I18n i18n; - public HBox root; + public VBox root; public Label description; public RingProgressIndicator progressIndicator; + public Button isReadyButton; private int timeLeft; private Timeline queuePopTimeUpdater; @Setter - private Runnable timedOut; + private Runnable isReadyCallBack; + @Setter + private Runnable dismissCallBack; @Override @@ -86,11 +91,16 @@ private void updateQueue(int responseTimeSeconds, OffsetDateTime start) { private void end() { queuePopTimeUpdater.stop(); - try { - Thread.sleep(MILLIS_TIME_BEFORE_CLOSE); - } catch (InterruptedException e) { - throw new RuntimeException(e); + if(isReadyButton.isDisable()){ + isReadyButton.setText(i18n.get("isReady.launching")); + } else { + dismissCallBack.run(); } - timedOut.run(); + } + + public void onReady() { + isReadyCallBack.run(); + isReadyButton.setDisable(true); + isReadyButton.setText(i18n.get("isReady.waiting")); } } diff --git a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java index 6c2895579e..5b4d42dd8f 100644 --- a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java +++ b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java @@ -1,73 +1,138 @@ package com.faforever.client.tournament.game; +import com.faforever.client.fx.JavaFxUtil; +import com.faforever.client.game.GameService; import com.faforever.client.i18n.I18n; -import com.faforever.client.main.StartTabChooseController; -import com.faforever.client.main.event.NavigateEvent; -import com.faforever.client.main.event.NavigationItem; -import com.faforever.client.notification.Action; import com.faforever.client.notification.ImmediateNotification; import com.faforever.client.notification.NotificationService; import com.faforever.client.notification.Severity; import com.faforever.client.remote.FafServerAccessor; import com.faforever.client.theme.UiService; import com.faforever.client.ui.StageHolder; -import com.faforever.client.user.event.LoginSuccessEvent; +import com.faforever.commons.lobby.GameLaunchResponse; import com.faforever.commons.lobby.IsReadyRequest; -import com.faforever.commons.lobby.LoginSuccessResponse; -import com.faforever.commons.lobby.MatchmakerInfo; -import com.faforever.commons.lobby.ServerMessage; -import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; -import javafx.application.Platform; +import com.faforever.commons.lobby.MatchmakerMatchCancelledResponse; import javafx.stage.Stage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CompletableFuture; @Service @Slf4j @RequiredArgsConstructor public class TournamentGameService implements InitializingBean { + private static final int SAFETY_CLOSE_NOTIFICATION_SECONDS = 200; private final FafServerAccessor fafServerAccessor; private final I18n i18n; + private final Timer timer = new Timer(true); private final UiService uiService; + private final GameService gameService; private final NotificationService notificationService; private ImmediateNotification notification; + private CompletableFuture matchFuture; @Override public void afterPropertiesSet() throws Exception { fafServerAccessor.addEventListener(IsReadyRequest.class, this::onReadRequest); + fafServerAccessor.addEventListener(MatchmakerMatchCancelledResponse.class, this::onMatchCanceled); + fafServerAccessor.addEventListener(GameLaunchResponse.class, this::onGameLaunch); + } + + private void onGameLaunch(GameLaunchResponse gameLaunchResponse) { + if(isTournamentGame(gameLaunchResponse)){ + dismissNotification(); + } + } + + private boolean isTournamentGame(GameLaunchResponse gameLaunchResponse) { + //TODO: implement + return true; + } + + private void onMatchCanceled(MatchmakerMatchCancelledResponse matchmakerMatchCancelledResponse) { + dismissNotification(); + cancelMatch(); + notificationService.addImmediateInfoNotification( + "isReady.matchCanceled" + ); } private void onReadRequest(IsReadyRequest isReadyRequest) { log.info("Tournament game is ready, asking user."); - Stage stage = StageHolder.getStage(); - if (!stage.isFocused() || !stage.isShowing()) { - Platform.runLater(stage::toFront); + if(notification != null){ + log.warn("Tournament ready request ignored because tournament is already in progress."); + respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest); + return; } - IsReadyForGameController controller = uiService.loadFxml("theme/tournaments/is_ready_for_game.fxml"); - controller.setTimeout(isReadyRequest.getResponseTimeSeconds()); - controller.setTimedOut(() -> { - respond(false); - if(notification != null){ - Platform.runLater(() -> notification.dismiss()); - } - }); - Action acceptButton = new Action(i18n.get("yes"), event -> respond(true)); - Action rejectButton = new Action(i18n.get("no"), event -> respond(false)); + bringStageToFront(); + final var controller = initializeIsReadyController(isReadyRequest); notification = new ImmediateNotification(i18n.get("isReady.title"), i18n.get("isReady.message", isReadyRequest.getGameName()), - Severity.INFO, null, List.of(acceptButton, rejectButton), controller.getRoot(), false); + Severity.INFO, null, List.of(), controller.getRoot(), false); notificationService.addNotification(notification); + safetyCloseMechanism(); + } + + private void safetyCloseMechanism() { + final var currentNotification = notification; + timer.schedule(new TimerTask() { + @Override + public void run() { + if(notification != currentNotification){ + return; + } + JavaFxUtil.runLater(()-> dismissNotification()); + } + }, SAFETY_CLOSE_NOTIFICATION_SECONDS * 1000); } - private void respond(boolean accepted) { + private void dismissNotification() { + if(notification == null){ + return; + } + notification.dismiss(); + notification = null; + } + + @NotNull + private IsReadyForGameController initializeIsReadyController(IsReadyRequest isReadyRequest) { + IsReadyForGameController controller = uiService.loadFxml("theme/tournaments/is_ready_for_game.fxml"); + controller.setTimeout(isReadyRequest.getResponseTimeSeconds()); + controller.setIsReadyCallBack(() -> respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest)); + controller.setDismissCallBack(() -> JavaFxUtil.runLater(this::dismissNotification)); + return controller; + } + private static void bringStageToFront() { + Stage stage = StageHolder.getStage(); + if (!stage.isFocused() || !stage.isShowing()) { + JavaFxUtil.runLater(stage::toFront); + } + } + + private void respondToReadyRequest(String requestId, IsReadyRequest isReadyRequest) { + //TODO: Quit tmm queues + matchFuture = gameService.startListeningToTournamentGame(isReadyRequest.getFeaturedMod()); + try{ + fafServerAccessor.sendIsReady(requestId); + }catch (Exception e){ + dismissNotification(); + cancelMatch(); + notificationService.addImmediateErrorNotification(e, "isReady.readyUpFailed"); + } + } + + private void cancelMatch(){ + if (matchFuture != null) { + matchFuture.cancel(false); + } } } diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index f1e5bce124..7761602ddf 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -1242,4 +1242,9 @@ showGamesWithFriends = Show only games with friends showGeneratedMaps = Show only generated maps filteredOutItemsCount = {0} from {1} items are filtered out isReady.title=Tournament game ready for you -isReady.message=Click 'yes' below to join the upcoming game ''{0}'' +isReady.message=Click the button below to join the upcoming game ''{0}'' +isReady.iAmReady=I am ready +isReady.matchCanceled=The tournament match was canceled because other players where not ready +isReady.readyUpFailed=Could not ready up for an unknown reason +isReady.waiting=Waiting for others +isReady.launching=Launching game \ No newline at end of file diff --git a/src/main/resources/theme/tournaments/is_ready_for_game.fxml b/src/main/resources/theme/tournaments/is_ready_for_game.fxml index b3857d50e5..b359e31b7e 100644 --- a/src/main/resources/theme/tournaments/is_ready_for_game.fxml +++ b/src/main/resources/theme/tournaments/is_ready_for_game.fxml @@ -2,15 +2,22 @@ + - - - - - - - - - - + + + + + + + + + + + + + From 01f17e1b810e9cdba120a57e6a1e1b8a76b3ea26 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Sep 2022 22:34:33 +0200 Subject: [PATCH 3/9] Add tests --- .../faforever/client/game/GameService.java | 9 ++- .../client/remote/FafServerAccessor.java | 2 +- .../com/faforever/client/theme/UiService.java | 10 +++ .../game/IsReadyForGameController.java | 15 ++-- .../game/TournamentGameService.java | 20 +---- .../GameDirectoryRequiredHandler.java | 4 +- src/main/resources/i18n/messages.properties | 1 + .../client/game/GameServiceTest.java | 14 ++-- .../client/remote/ServerAccessorTest.java | 2 +- .../game/IsReadyForGameControllerTest.java | 67 +++++++++++++++++ .../game/TournamentGameServiceTest.java | 75 +++++++++++++++++++ 11 files changed, 177 insertions(+), 42 deletions(-) create mode 100644 src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java create mode 100644 src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java diff --git a/src/main/java/com/faforever/client/game/GameService.java b/src/main/java/com/faforever/client/game/GameService.java index 0bf93d087b..cebb7e383f 100644 --- a/src/main/java/com/faforever/client/game/GameService.java +++ b/src/main/java/com/faforever/client/game/GameService.java @@ -536,11 +536,12 @@ private CompletableFuture listenToServerInitiatedGame(String featuredModTe log.info("Listening to server made game has been started"); + final var gameLaunchMessageFuture = fafServerAccessor.getGameLaunchMessage(); final var matchFuture = modService.getFeaturedMod(featuredModTechnicalName) .thenAccept(featuredModBean -> updateGameIfNecessary(featuredModBean, Set.of())) - .thenCompose(aVoid -> fafServerAccessor.startSearchMatchmaker()) - .thenCompose(gameLaunchResponse -> downloadMapIfNecessary(gameLaunchResponse.getMapName()) - .thenCompose(aVoid -> leaderboardService.getActiveLeagueEntryForPlayer(playerService.getCurrentPlayer(), gameLaunchResponse.getLeaderboard())) + .thenCompose(aVoid -> gameLaunchMessageFuture) + .thenCompose((gameLaunchMessage) -> downloadMapIfNecessary(gameLaunchMessage.getMapName()) + .thenCompose(aVoid -> leaderboardService.getActiveLeagueEntryForPlayer(playerService.getCurrentPlayer(),gameLaunchResponse.getLeaderboard())) .thenApply(leagueEntryOptional -> { GameParameters parameters = gameMapper.map(gameLaunchResponse); parameters.setDivision(leagueEntryOptional.map(bean -> bean.getSubdivision().getDivision().getNameKey()) @@ -549,7 +550,7 @@ private CompletableFuture listenToServerInitiatedGame(String featuredModTe .orElse(null)); return parameters; }) - .thenCompose(this::startGame)); + .thenCompose(aVoid -> startGame(gameLaunchMessage))); matchFuture.whenComplete((aVoid, throwable) -> { if (throwable != null) { diff --git a/src/main/java/com/faforever/client/remote/FafServerAccessor.java b/src/main/java/com/faforever/client/remote/FafServerAccessor.java index c3233f9ee5..aa9d8840c8 100644 --- a/src/main/java/com/faforever/client/remote/FafServerAccessor.java +++ b/src/main/java/com/faforever/client/remote/FafServerAccessor.java @@ -212,7 +212,7 @@ public void requestMatchmakerInfo() { lobbyClient.requestMatchmakerInfo(); } - public CompletableFuture startSearchMatchmaker() { + public CompletableFuture getGameLaunchMessage() { return lobbyClient.getEvents() .filter(event -> event instanceof GameLaunchResponse) .next() diff --git a/src/main/java/com/faforever/client/theme/UiService.java b/src/main/java/com/faforever/client/theme/UiService.java index 402f00460a..1c6bb84231 100644 --- a/src/main/java/com/faforever/client/theme/UiService.java +++ b/src/main/java/com/faforever/client/theme/UiService.java @@ -9,6 +9,7 @@ import com.faforever.client.fx.JavaFxUtil; import com.faforever.client.i18n.I18n; import com.faforever.client.preferences.PreferencesService; +import com.faforever.client.ui.StageHolder; import com.faforever.client.ui.dialog.Dialog; import com.faforever.client.ui.dialog.Dialog.DialogTransition; import com.faforever.client.ui.dialog.DialogLayout; @@ -30,6 +31,7 @@ import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.web.WebView; +import javafx.stage.Stage; import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.utils.IOUtils; import org.springframework.beans.factory.DisposableBean; @@ -398,6 +400,14 @@ private String[] getStylesheets() { } } + + public void bringMainStageToFront() { + Stage stage = StageHolder.getStage(); + if ((!stage.isFocused() || !stage.isShowing())) { + JavaFxUtil.runLater(stage::toFront); + } + } + /** * Registers a WebView against the theme service so it can be updated whenever the theme changes. */ diff --git a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java index ca88efe720..d7aff4015d 100644 --- a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java +++ b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java @@ -1,32 +1,26 @@ package com.faforever.client.tournament.game; import com.faforever.client.fx.Controller; -import com.faforever.client.fx.JavaFxUtil; import com.faforever.client.i18n.I18n; import com.faforever.client.ui.progress.RingProgressIndicator; import javafx.animation.KeyFrame; import javafx.animation.Timeline; -import javafx.application.Platform; import javafx.event.ActionEvent; -import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.control.Button; import javafx.scene.control.Label; -import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.util.StringConverter; import lombok.RequiredArgsConstructor; import lombok.Setter; -import lombok.extern.apachecommons.CommonsLog; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.VisibleForTesting; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.time.Duration; import java.time.OffsetDateTime; -import java.util.TimerTask; -import java.util.function.Consumer; @Slf4j @@ -40,9 +34,10 @@ public class IsReadyForGameController implements Controller { public RingProgressIndicator progressIndicator; public Button isReadyButton; private int timeLeft; - private Timeline queuePopTimeUpdater; + @VisibleForTesting + Timeline queuePopTimeUpdater; @Setter - private Runnable isReadyCallBack; + private Runnable readyCallback; @Setter private Runnable dismissCallBack; @@ -99,7 +94,7 @@ private void end() { } public void onReady() { - isReadyCallBack.run(); + readyCallback.run(); isReadyButton.setDisable(true); isReadyButton.setText(i18n.get("isReady.waiting")); } diff --git a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java index 5b4d42dd8f..d61652d58f 100644 --- a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java +++ b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java @@ -47,14 +47,7 @@ public void afterPropertiesSet() throws Exception { } private void onGameLaunch(GameLaunchResponse gameLaunchResponse) { - if(isTournamentGame(gameLaunchResponse)){ - dismissNotification(); - } - } - - private boolean isTournamentGame(GameLaunchResponse gameLaunchResponse) { - //TODO: implement - return true; + dismissNotification(); } private void onMatchCanceled(MatchmakerMatchCancelledResponse matchmakerMatchCancelledResponse) { @@ -72,7 +65,7 @@ private void onReadRequest(IsReadyRequest isReadyRequest) { respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest); return; } - bringStageToFront(); + uiService.bringMainStageToFront(); final var controller = initializeIsReadyController(isReadyRequest); notification = new ImmediateNotification(i18n.get("isReady.title"), i18n.get("isReady.message", isReadyRequest.getGameName()), @@ -106,20 +99,13 @@ private void dismissNotification() { private IsReadyForGameController initializeIsReadyController(IsReadyRequest isReadyRequest) { IsReadyForGameController controller = uiService.loadFxml("theme/tournaments/is_ready_for_game.fxml"); controller.setTimeout(isReadyRequest.getResponseTimeSeconds()); - controller.setIsReadyCallBack(() -> respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest)); + controller.setReadyCallback(() -> respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest)); controller.setDismissCallBack(() -> JavaFxUtil.runLater(this::dismissNotification)); return controller; } - private static void bringStageToFront() { - Stage stage = StageHolder.getStage(); - if (!stage.isFocused() || !stage.isShowing()) { - JavaFxUtil.runLater(stage::toFront); - } - } private void respondToReadyRequest(String requestId, IsReadyRequest isReadyRequest) { - //TODO: Quit tmm queues matchFuture = gameService.startListeningToTournamentGame(isReadyRequest.getFeaturedMod()); try{ fafServerAccessor.sendIsReady(requestId); diff --git a/src/main/java/com/faforever/client/ui/preferences/GameDirectoryRequiredHandler.java b/src/main/java/com/faforever/client/ui/preferences/GameDirectoryRequiredHandler.java index 089416195b..d623935f86 100644 --- a/src/main/java/com/faforever/client/ui/preferences/GameDirectoryRequiredHandler.java +++ b/src/main/java/com/faforever/client/ui/preferences/GameDirectoryRequiredHandler.java @@ -28,10 +28,10 @@ public void afterPropertiesSet() { @Subscribe public void onChooseGameDirectory(GameDirectoryChooseEvent event) { - platformService.askForPath(i18n.get("missingGamePath.chooserTitle")).ifPresent(gameDirectory -> { + platformService.askForPath(i18n.get("missingGamePath.chooserTitle")).ifPresentOrElse(gameDirectory -> { log.info("User selected game directory: {}", gameDirectory); eventBus.post(new GameDirectoryChosenEvent(gameDirectory, event.getFuture())); - }); + }, () -> event.getFuture().ifPresent(pathCompletableFuture -> pathCompletableFuture.completeExceptionally(new Exception(i18n.get("missingGamePath.noSelection"))))); } } diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 7761602ddf..99cc4bda71 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -403,6 +403,7 @@ downloadingModTask.unzipping = Unzipping mod to {0} missingGamePath.notification = Forged Alliance could not be located missingGamePath.locate = Locateā€¦ missingGamePath.chooserTitle = Locate the Forged Alliance directory +missingGamePath.noSelection = Can not continue without a path to Supreme Commander Forged Alliance game path notifications.empty = You don't have any notifications stats.air = Air stats.land = Land diff --git a/src/test/java/com/faforever/client/game/GameServiceTest.java b/src/test/java/com/faforever/client/game/GameServiceTest.java index 54585ab853..ef2df04b92 100644 --- a/src/test/java/com/faforever/client/game/GameServiceTest.java +++ b/src/test/java/com/faforever/client/game/GameServiceTest.java @@ -205,7 +205,7 @@ private void mockMatchmakerChain() { when(modService.getFeaturedMod(FAF.getTechnicalName())) .thenReturn(completedFuture(FeaturedModBeanBuilder.create().defaultValues().get())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(new CompletableFuture<>()); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(new CompletableFuture<>()); } @Test @@ -573,7 +573,7 @@ public void testStartSearchLadder1v1WithLeagueEntry() throws Exception { mockStartGameProcess(gameParameters); LeagueEntryBean leagueEntry = LeagueEntryBeanBuilder.create().defaultValues().get(); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.of(leagueEntry))); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(),null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -582,7 +582,7 @@ public void testStartSearchLadder1v1WithLeagueEntry() throws Exception { instance.startSearchMatchmaker().join(); - verify(fafServerAccessor).startSearchMatchmaker(); + verify(fafServerAccessor).getGameLaunchMessage(); verify(mapService).download(map); verify(replayServer).start(eq(uid), any()); verify(forgedAllianceService).startGameOnline(gameParameters); @@ -608,7 +608,7 @@ public void testStartSearchLadderTwiceReturnsSameFutureWhenSearching() throws Ex mockStartGameProcess(gameParameters); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.empty())); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(), null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -776,7 +776,7 @@ public void startSearchMatchmakerWithGameOptions() throws IOException { when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, "global")).thenReturn(completedFuture(Optional.empty())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); instance.startSearchMatchmaker().join(); verify(forgedAllianceService).startGameOnline(gameParameters); } @@ -799,7 +799,7 @@ public void startSearchMatchmakerThenCancelledWithGame() throws IOException { when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, "global")).thenReturn(completedFuture(Optional.empty())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); CompletableFuture future = instance.startSearchMatchmaker(); when(process.isAlive()).thenReturn(true); future.cancel(false); @@ -821,7 +821,7 @@ public void startSearchMatchmakerThenCancelledNoGame() throws IOException { mockStartGameProcess(gameMapper.map(gameLaunchMessage)); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); instance.startSearchMatchmaker().cancel(false); verify(notificationService, never()).addServerNotification(any()); } diff --git a/src/test/java/com/faforever/client/remote/ServerAccessorTest.java b/src/test/java/com/faforever/client/remote/ServerAccessorTest.java index 756e4f9697..6042c59a66 100644 --- a/src/test/java/com/faforever/client/remote/ServerAccessorTest.java +++ b/src/test/java/com/faforever/client/remote/ServerAccessorTest.java @@ -655,7 +655,7 @@ public void testOnGameLaunch() throws InterruptedException, JsonProcessingExcept .initMode(LobbyMode.AUTO_LOBBY) .get(); - instance.startSearchMatchmaker(); + instance.getGameLaunchMessage(); sendFromServer(gameLaunchMessage); assertTrue(messageReceivedByClientLatch.await(TIMEOUT, TIMEOUT_UNIT)); assertThat(receivedMessage, is(gameLaunchMessage)); diff --git a/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java new file mode 100644 index 0000000000..3236c3f472 --- /dev/null +++ b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java @@ -0,0 +1,67 @@ +package com.faforever.client.tournament.game; + +import com.faforever.client.builders.MapBeanBuilder; +import com.faforever.client.builders.MapVersionBeanBuilder; +import com.faforever.client.builders.TutorialBeanBuilder; +import com.faforever.client.domain.MapVersionBean; +import com.faforever.client.domain.TutorialBean; +import com.faforever.client.fx.JavaFxUtil; +import com.faforever.client.fx.WebViewConfigurer; +import com.faforever.client.i18n.I18n; +import com.faforever.client.map.MapService; +import com.faforever.client.map.MapService.PreviewSize; +import com.faforever.client.test.UITest; +import com.faforever.client.tutorial.TutorialDetailController; +import com.faforever.client.tutorial.TutorialService; +import javafx.scene.image.Image; +import javafx.util.Duration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.testfx.util.WaitForAsyncUtils; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.jupiter.api.Assertions.*; + +class IsReadyForGameControllerTest extends UITest { + @InjectMocks + private IsReadyForGameController instance; + @Mock + private I18n i18n; + + @BeforeEach + public void setUp() throws Exception { + loadFxml("theme/tournaments/is_ready_for_game.fxml", clazz -> instance); + } + + @Test + public void testInitialization(){ + instance.setTimeout(1); + instance.setDismissCallBack(() -> {}); + instance.setReadyCallback(() -> {}); + } + + @Test + public void testTimeOut() { + AtomicBoolean dismissCalled = new AtomicBoolean(false); + instance.setDismissCallBack(() -> dismissCalled.set(true)); + instance.setTimeout(0); + final var time = instance.queuePopTimeUpdater.getKeyFrames().get(1).getTime(); + WaitForAsyncUtils.sleep((long) time.toMillis()+1000, TimeUnit.MILLISECONDS); + assertTrue(dismissCalled.get()); + } + + @Test + public void testClickReady() { + AtomicBoolean readyCallback = new AtomicBoolean(false); + instance.setReadyCallback(() -> readyCallback.set(true)); + instance.isReadyButton.getOnAction().handle(null); + instance.setTimeout(0); + final var time = instance.queuePopTimeUpdater.getKeyFrames().get(1).getTime(); + WaitForAsyncUtils.sleep((long) time.toMillis()+1000, TimeUnit.MILLISECONDS); + assertTrue(readyCallback.get()); + } +} \ No newline at end of file diff --git a/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java new file mode 100644 index 0000000000..e3a75087c0 --- /dev/null +++ b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java @@ -0,0 +1,75 @@ +package com.faforever.client.tournament.game; + +import com.faforever.client.game.GameService; +import com.faforever.client.i18n.I18n; +import com.faforever.client.notification.ImmediateNotification; +import com.faforever.client.notification.NotificationService; +import com.faforever.client.remote.FafServerAccessor; +import com.faforever.client.test.ServiceTest; +import com.faforever.client.theme.UiService; +import com.faforever.client.ui.StageHolder; +import com.faforever.commons.lobby.IsReadyRequest; +import javafx.scene.layout.Region; +import javafx.stage.Stage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.function.Consumer; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class TournamentGameServiceTest extends ServiceTest { + @InjectMocks + private TournamentGameService instance; + @Mock + private FafServerAccessor fafServerAccessor; + @Mock + private I18n i18n; + @Mock + private UiService uiService; + @Mock + private GameService gameService; + @Mock + private IsReadyForGameController isReadyForGameController; + @Mock + private NotificationService notificationService; + @Captor + private ArgumentCaptor> eventListenerCapture; + @Captor + private ArgumentCaptor isReadyCallbackCapture; + + @Test + public void testReceivingIsReadyMessageAndClickingReady() throws Exception { + instance.afterPropertiesSet(); + verify(fafServerAccessor).addEventListener(eq(IsReadyRequest.class), eventListenerCapture.capture()); + + doReturn(isReadyForGameController).when(uiService).loadFxml("theme/tournaments/is_ready_for_game.fxml"); + doReturn(new Region()).when(isReadyForGameController).getRoot(); + + eventListenerCapture.getValue().accept(new IsReadyRequest("name", "faf", 1, "abc")); + + verify(uiService).bringMainStageToFront(); + verify(notificationService).addNotification(any(ImmediateNotification.class)); + verify(isReadyForGameController).setTimeout(1); + verify(isReadyForGameController).setReadyCallback(isReadyCallbackCapture.capture()); + + isReadyCallbackCapture.getValue().run(); + + verify(fafServerAccessor).sendIsReady("abc"); + verify(gameService).startListeningToTournamentGame("faf"); + } +} \ No newline at end of file From 0226c4189e8b1256f82911fe8877f7307546bbe4 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Sep 2022 22:53:05 +0200 Subject: [PATCH 4/9] format --- .../game/IsReadyForGameController.java | 4 +- .../game/TournamentGameService.java | 16 +- .../ui/progress/ProgressCircleIndicator.java | 205 +++++++------- .../ui/progress/RingProgressIndicator.java | 164 +++++------ .../progress/RingProgressIndicatorSkin.java | 256 +++++++++--------- .../game/IsReadyForGameControllerTest.java | 13 - .../game/TournamentGameServiceTest.java | 7 - 7 files changed, 322 insertions(+), 343 deletions(-) diff --git a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java index d7aff4015d..65ead2b361 100644 --- a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java +++ b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java @@ -79,14 +79,14 @@ private void updateQueue(int responseTimeSeconds, OffsetDateTime start) { final var percent = timeGone.toSeconds() / (double) responseTimeSeconds; this.timeLeft = (int) (responseTimeSeconds - timeGone.toSeconds()); progressIndicator.setProgress((int) (percent * 100)); - if(timeLeft <= 0 && queuePopTimeUpdater != null){ + if (timeLeft <= 0 && queuePopTimeUpdater != null) { end(); } } private void end() { queuePopTimeUpdater.stop(); - if(isReadyButton.isDisable()){ + if (isReadyButton.isDisable()) { isReadyButton.setText(i18n.get("isReady.launching")); } else { dismissCallBack.run(); diff --git a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java index d61652d58f..de7b649f95 100644 --- a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java +++ b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java @@ -8,11 +8,9 @@ import com.faforever.client.notification.Severity; import com.faforever.client.remote.FafServerAccessor; import com.faforever.client.theme.UiService; -import com.faforever.client.ui.StageHolder; import com.faforever.commons.lobby.GameLaunchResponse; import com.faforever.commons.lobby.IsReadyRequest; import com.faforever.commons.lobby.MatchmakerMatchCancelledResponse; -import javafx.stage.Stage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -60,7 +58,7 @@ private void onMatchCanceled(MatchmakerMatchCancelledResponse matchmakerMatchCan private void onReadRequest(IsReadyRequest isReadyRequest) { log.info("Tournament game is ready, asking user."); - if(notification != null){ + if (notification != null) { log.warn("Tournament ready request ignored because tournament is already in progress."); respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest); return; @@ -79,16 +77,16 @@ private void safetyCloseMechanism() { timer.schedule(new TimerTask() { @Override public void run() { - if(notification != currentNotification){ + if (notification != currentNotification) { return; } - JavaFxUtil.runLater(()-> dismissNotification()); + JavaFxUtil.runLater(() -> dismissNotification()); } }, SAFETY_CLOSE_NOTIFICATION_SECONDS * 1000); } private void dismissNotification() { - if(notification == null){ + if (notification == null) { return; } notification.dismiss(); @@ -107,16 +105,16 @@ private IsReadyForGameController initializeIsReadyController(IsReadyRequest isRe private void respondToReadyRequest(String requestId, IsReadyRequest isReadyRequest) { matchFuture = gameService.startListeningToTournamentGame(isReadyRequest.getFeaturedMod()); - try{ + try { fafServerAccessor.sendIsReady(requestId); - }catch (Exception e){ + } catch (Exception e) { dismissNotification(); cancelMatch(); notificationService.addImmediateErrorNotification(e, "isReady.readyUpFailed"); } } - private void cancelMatch(){ + private void cancelMatch() { if (matchFuture != null) { matchFuture.cancel(false); } diff --git a/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java index 4974cc8de4..9ba9ec9b04 100644 --- a/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java +++ b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2014, Andrea Vacondio * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,10 +15,6 @@ */ package com.faforever.client.ui.progress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import javafx.beans.property.DoubleProperty; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; @@ -31,124 +27,129 @@ import javafx.css.converter.SizeConverter; import javafx.scene.control.Control; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Base class for the progress indicator controls represented by circualr shapes - * - * @author Andrea Vacondio * + * @author Andrea Vacondio */ abstract class ProgressCircleIndicator extends Control { - private static final int INDETERMINATE_PROGRESS = -1; - - private ReadOnlyIntegerWrapper progress = new ReadOnlyIntegerWrapper(0); - private ReadOnlyBooleanWrapper indeterminate = new ReadOnlyBooleanWrapper(false); - - public ProgressCircleIndicator() { + private static final int INDETERMINATE_PROGRESS = -1; + + private final ReadOnlyIntegerWrapper progress = new ReadOnlyIntegerWrapper(0); + private final ReadOnlyBooleanWrapper indeterminate = new ReadOnlyBooleanWrapper(false); + + public ProgressCircleIndicator() { + } + + public int getProgress() { + return progress.get(); + } + + /** + * Set the value for the progress, it cannot be more then 100 (meaning 100%). A negative value means indeterminate + * progress. + * + * @param progressValue + * @see ProgressCircleIndicator#makeIndeterminate() + */ + public void setProgress(int progressValue) { + progress.set(defaultToHundred(progressValue)); + indeterminate.set(progressValue < 0); + } + + public ReadOnlyIntegerProperty progressProperty() { + return progress.getReadOnlyProperty(); + } + + public boolean isIndeterminate() { + return indeterminate.get(); + } + + public void makeIndeterminate() { + setProgress(INDETERMINATE_PROGRESS); + } + + public ReadOnlyBooleanProperty indeterminateProperty() { + return indeterminate.getReadOnlyProperty(); + } + + private int defaultToHundred(int value) { + if (value > 100) { + return 100; } + return value; + } - public int getProgress() { - return progress.get(); - } + public final void setInnerCircleRadius(int value) { + innerCircleRadiusProperty().set(value); + } - /** - * Set the value for the progress, it cannot be more then 100 (meaning 100%). A negative value means indeterminate progress. - * - * @param progressValue - * @see ProgressCircleIndicator#makeIndeterminate() - */ - public void setProgress(int progressValue) { - progress.set(defaultToHundred(progressValue)); - indeterminate.set(progressValue < 0); - } + public final DoubleProperty innerCircleRadiusProperty() { + return innerCircleRadius; + } - public ReadOnlyIntegerProperty progressProperty() { - return progress.getReadOnlyProperty(); - } - - public boolean isIndeterminate() { - return indeterminate.get(); - } + public final double getInnerCircleRadius() { + return innerCircleRadiusProperty().get(); + } - public void makeIndeterminate() { - setProgress(INDETERMINATE_PROGRESS); - } - - public ReadOnlyBooleanProperty indeterminateProperty() { - return indeterminate.getReadOnlyProperty(); + /** + * radius of the inner circle + */ + private final DoubleProperty innerCircleRadius = new StyleableDoubleProperty(60) { + @Override + public Object getBean() { + return ProgressCircleIndicator.this; } - private int defaultToHundred(int value) { - if (value > 100) { - return 100; - } - return value; + @Override + public String getName() { + return "innerCircleRadius"; } - public final void setInnerCircleRadius(int value) { - innerCircleRadiusProperty().set(value); + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.INNER_CIRCLE_RADIUS; } + }; - public final DoubleProperty innerCircleRadiusProperty() { - return innerCircleRadius; - } + private static class StyleableProperties { + private static final CssMetaData INNER_CIRCLE_RADIUS = new CssMetaData( + "-fx-inner-radius", SizeConverter.getInstance(), 60) { - public final double getInnerCircleRadius() { - return innerCircleRadiusProperty().get(); - } + @Override + public boolean isSettable(ProgressCircleIndicator n) { + return n.innerCircleRadiusProperty() == null || !n.innerCircleRadiusProperty().isBound(); + } - /** - * radius of the inner circle - */ - private DoubleProperty innerCircleRadius = new StyleableDoubleProperty(60) { - @Override - public Object getBean() { - return ProgressCircleIndicator.this; - } - - @Override - public String getName() { - return "innerCircleRadius"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.INNER_CIRCLE_RADIUS; - } + @Override + public StyleableProperty getStyleableProperty(ProgressCircleIndicator n) { + return (StyleableProperty) n.innerCircleRadiusProperty(); + } }; - private static class StyleableProperties { - private static final CssMetaData INNER_CIRCLE_RADIUS = new CssMetaData( - "-fx-inner-radius", SizeConverter.getInstance(), 60) { - - @Override - public boolean isSettable(ProgressCircleIndicator n) { - return n.innerCircleRadiusProperty() == null || !n.innerCircleRadiusProperty().isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(ProgressCircleIndicator n) { - return (StyleableProperty) n.innerCircleRadiusProperty(); - } - }; - - public static final List> STYLEABLES; - static { - final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); - styleables.add(INNER_CIRCLE_RADIUS); - STYLEABLES = Collections.unmodifiableList(styleables); - } - } + public static final List> STYLEABLES; - /** - * @return The CssMetaData associated with this class, which may include the CssMetaData of its super classes. - */ - public static List> getClassCssMetaData() { - return StyleableProperties.STYLEABLES; - } - - @Override - public List> getControlCssMetaData() { - return StyleableProperties.STYLEABLES; + static { + final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); + styleables.add(INNER_CIRCLE_RADIUS); + STYLEABLES = Collections.unmodifiableList(styleables); } + } + + /** + * @return The CssMetaData associated with this class, which may include the CssMetaData of its super classes. + */ + public static List> getClassCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + @Override + public List> getControlCssMetaData() { + return StyleableProperties.STYLEABLES; + } } \ No newline at end of file diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java index eac14f4d0a..57d7d2c915 100644 --- a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2014, Andrea Vacondio * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,10 +15,6 @@ */ package com.faforever.client.ui.progress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; @@ -31,105 +27,109 @@ import javafx.scene.control.Skin; import javafx.util.StringConverter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Progress indicator showing a filling arc. - * - * @author Andrea Vacondio * + * @author Andrea Vacondio */ public class RingProgressIndicator extends ProgressCircleIndicator { - public ObjectProperty> progressLableStringConverter = new SimpleObjectProperty<>(new StringConverter<>() { - @Override - public String toString(Integer object) { - return String.format("%d%%", object); - } - - @Override - public Integer fromString(String string) { - throw new UnsupportedOperationException(); - } - }); - - public RingProgressIndicator() { - this.getStyleClass().add("ringindicator"); + public ObjectProperty> progressLableStringConverter = new SimpleObjectProperty<>(new StringConverter<>() { + @Override + public String toString(Integer object) { + return String.format("%d%%", object); } @Override - protected Skin createDefaultSkin() { - return new RingProgressIndicatorSkin(this); + public Integer fromString(String string) { + throw new UnsupportedOperationException(); } + }); - public final void setRingWidth(int value) { - ringWidthProperty().set(value); - } + public RingProgressIndicator() { + this.getStyleClass().add("ringindicator"); + } - public final DoubleProperty ringWidthProperty() { - return ringWidth; - } + @Override + protected Skin createDefaultSkin() { + return new RingProgressIndicatorSkin(this); + } - public final double getRingWidth() { - return ringWidthProperty().get(); - } + public final void setRingWidth(int value) { + ringWidthProperty().set(value); + } - /** - * thickness of the ring indicator. - */ - private DoubleProperty ringWidth = new StyleableDoubleProperty(22) { - @Override - public Object getBean() { - return RingProgressIndicator.this; - } - - @Override - public String getName() { - return "ringWidth"; - } - - @Override - public CssMetaData getCssMetaData() { - return StyleableProperties.RING_WIDTH; - } - }; + public final DoubleProperty ringWidthProperty() { + return ringWidth; + } - private static class StyleableProperties { - private static final CssMetaData RING_WIDTH = new CssMetaData( - "-fx-ring-width", SizeConverter.getInstance(), 22) { - - @Override - public boolean isSettable(RingProgressIndicator n) { - return n.ringWidth == null || !n.ringWidth.isBound(); - } - - @Override - public StyleableProperty getStyleableProperty(RingProgressIndicator n) { - return (StyleableProperty) n.ringWidth; - } - }; - - public static final List> STYLEABLES; - static { - final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); - styleables.addAll(ProgressCircleIndicator.getClassCssMetaData()); - styleables.add(RING_WIDTH); - STYLEABLES = Collections.unmodifiableList(styleables); - } - } + public final double getRingWidth() { + return ringWidthProperty().get(); + } + /** + * thickness of the ring indicator. + */ + private final DoubleProperty ringWidth = new StyleableDoubleProperty(22) { @Override - public List> getControlCssMetaData() { - return StyleableProperties.STYLEABLES; + public Object getBean() { + return RingProgressIndicator.this; } - public StringConverter getProgressLableStringConverter() { - return progressLableStringConverter.get(); + @Override + public String getName() { + return "ringWidth"; } - public ObjectProperty> progressLableStringConverterProperty() { - return progressLableStringConverter; + @Override + public CssMetaData getCssMetaData() { + return StyleableProperties.RING_WIDTH; } + }; - public void setProgressLableStringConverter(StringConverter progressLableStringConverter) { - this.progressLableStringConverter.set(progressLableStringConverter); + private static class StyleableProperties { + private static final CssMetaData RING_WIDTH = new CssMetaData( + "-fx-ring-width", SizeConverter.getInstance(), 22) { + + @Override + public boolean isSettable(RingProgressIndicator n) { + return n.ringWidth == null || !n.ringWidth.isBound(); + } + + @Override + public StyleableProperty getStyleableProperty(RingProgressIndicator n) { + return (StyleableProperty) n.ringWidth; + } + }; + + public static final List> STYLEABLES; + + static { + final List> styleables = new ArrayList<>(Control.getClassCssMetaData()); + styleables.addAll(ProgressCircleIndicator.getClassCssMetaData()); + styleables.add(RING_WIDTH); + STYLEABLES = Collections.unmodifiableList(styleables); } + } + + @Override + public List> getControlCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + public StringConverter getProgressLableStringConverter() { + return progressLableStringConverter.get(); + } + + public ObjectProperty> progressLableStringConverterProperty() { + return progressLableStringConverter; + } + + public void setProgressLableStringConverter(StringConverter progressLableStringConverter) { + this.progressLableStringConverter.set(progressLableStringConverter); + } } \ No newline at end of file diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java index 41fae77aa5..23922c8197 100644 --- a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2014, Andrea Vacondio * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,138 +28,138 @@ import javafx.util.Duration; /** - * Skin of the ring progress indicator where an arc grows and by the progress value up to 100% where the arc becomes a ring. - * - * @author Andrea Vacondio + * Skin of the ring progress indicator where an arc grows and by the progress value up to 100% where the arc becomes a + * ring. * + * @author Andrea Vacondio */ public class RingProgressIndicatorSkin implements Skin { - private final RingProgressIndicator indicator; - private final Label percentLabel = new Label(); - private final Circle innerCircle = new Circle(); - private final Circle outerCircle = new Circle(); - private final StackPane container = new StackPane(); - private final Arc fillerArc = new Arc(); - private final RotateTransition transition = new RotateTransition(Duration.millis(2000), fillerArc); - - public RingProgressIndicatorSkin(final RingProgressIndicator indicator) { - this.indicator = indicator; - initContainer(indicator); - initFillerArc(); - container.widthProperty().addListener((o, oldVal, newVal) -> { - fillerArc.setCenterX(newVal.intValue() / 2); - }); - container.heightProperty().addListener((o, oldVal, newVal) -> { - fillerArc.setCenterY(newVal.intValue() / 2); - }); - innerCircle.getStyleClass().add("ringindicator-inner-circle"); - outerCircle.getStyleClass().add("ringindicator-outer-circle-secondary"); - updateRadii(); - - this.indicator.indeterminateProperty().addListener((o, oldVal, newVal) -> { - initIndeterminate(newVal); - }); - this.indicator.progressProperty().addListener((o, oldVal, newVal) -> { - if (newVal.intValue() >= 0) { - setProgressLabel(newVal.intValue()); - fillerArc.setLength(newVal.intValue() * -3.6); - } - }); - this.indicator.ringWidthProperty().addListener((o, oldVal, newVal) -> { - updateRadii(); - }); - innerCircle.strokeWidthProperty().addListener((e) -> { - updateRadii(); - }); - innerCircle.radiusProperty().addListener((e) -> { - updateRadii(); - }); - initTransition(); - initIndeterminate(indicator.isIndeterminate()); - initLabel(indicator.getProgress()); - indicator.visibleProperty().addListener((o, oldVal, newVal) -> { - if (newVal && this.indicator.isIndeterminate()) { - transition.play(); - } else { - transition.pause(); - } - }); - container.getChildren().addAll(fillerArc, outerCircle, innerCircle, percentLabel); - } - - private void setProgressLabel(int value) { - if (value >= 0) { - percentLabel.setText(indicator.getProgressLableStringConverter().toString(value)); - } - } - - private void initTransition() { - transition.setAutoReverse(false); - transition.setCycleCount(Animation.INDEFINITE); - transition.setDelay(Duration.ZERO); - transition.setInterpolator(Interpolator.LINEAR); - transition.setByAngle(360); + private final RingProgressIndicator indicator; + private final Label percentLabel = new Label(); + private final Circle innerCircle = new Circle(); + private final Circle outerCircle = new Circle(); + private final StackPane container = new StackPane(); + private final Arc fillerArc = new Arc(); + private final RotateTransition transition = new RotateTransition(Duration.millis(2000), fillerArc); + + public RingProgressIndicatorSkin(final RingProgressIndicator indicator) { + this.indicator = indicator; + initContainer(indicator); + initFillerArc(); + container.widthProperty().addListener((o, oldVal, newVal) -> { + fillerArc.setCenterX(newVal.intValue() / 2); + }); + container.heightProperty().addListener((o, oldVal, newVal) -> { + fillerArc.setCenterY(newVal.intValue() / 2); + }); + innerCircle.getStyleClass().add("ringindicator-inner-circle"); + outerCircle.getStyleClass().add("ringindicator-outer-circle-secondary"); + updateRadii(); + + this.indicator.indeterminateProperty().addListener((o, oldVal, newVal) -> { + initIndeterminate(newVal); + }); + this.indicator.progressProperty().addListener((o, oldVal, newVal) -> { + if (newVal.intValue() >= 0) { + setProgressLabel(newVal.intValue()); + fillerArc.setLength(newVal.intValue() * -3.6); + } + }); + this.indicator.ringWidthProperty().addListener((o, oldVal, newVal) -> { + updateRadii(); + }); + innerCircle.strokeWidthProperty().addListener((e) -> { + updateRadii(); + }); + innerCircle.radiusProperty().addListener((e) -> { + updateRadii(); + }); + initTransition(); + initIndeterminate(indicator.isIndeterminate()); + initLabel(indicator.getProgress()); + indicator.visibleProperty().addListener((o, oldVal, newVal) -> { + if (newVal && this.indicator.isIndeterminate()) { + transition.play(); + } else { + transition.pause(); + } + }); + container.getChildren().addAll(fillerArc, outerCircle, innerCircle, percentLabel); + } + + private void setProgressLabel(int value) { + if (value >= 0) { + percentLabel.setText(indicator.getProgressLableStringConverter().toString(value)); } - - private void initFillerArc() { - fillerArc.setManaged(false); - fillerArc.getStyleClass().add("ringindicator-filler"); - fillerArc.setStartAngle(90); - fillerArc.setLength(indicator.getProgress() * -3.6); - } - - private void initContainer(final RingProgressIndicator indicator) { - container.getStylesheets().addAll(indicator.getStylesheets()); - container.getStyleClass().addAll("circleindicator-container"); - container.setMaxHeight(Region.USE_PREF_SIZE); - container.setMaxWidth(Region.USE_PREF_SIZE); - } - - private void updateRadii() { - double ringWidth = indicator.getRingWidth(); - double innerCircleHalfStrokeWidth = innerCircle.getStrokeWidth() / 2; - double innerCircleRadius = indicator.getInnerCircleRadius(); - outerCircle.setRadius(innerCircleRadius + innerCircleHalfStrokeWidth + ringWidth); - fillerArc.setRadiusY(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); - fillerArc.setRadiusX(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); - fillerArc.setStrokeWidth(ringWidth); - innerCircle.setRadius(innerCircleRadius); - } - - private void initLabel(int value) { - setProgressLabel(value); - percentLabel.getStyleClass().add("circleindicator-label"); - } - - private void initIndeterminate(boolean newVal) { - percentLabel.setVisible(!newVal); - if (newVal) { - fillerArc.setLength(360); - fillerArc.getStyleClass().add("indeterminate"); - if (indicator.isVisible()) { - transition.play(); - } - } else { - fillerArc.getStyleClass().remove("indeterminate"); - fillerArc.setRotate(0); - transition.stop(); - } - } - - @Override - public RingProgressIndicator getSkinnable() { - return indicator; - } - - @Override - public Node getNode() { - return container; - } - - @Override - public void dispose() { - transition.stop(); + } + + private void initTransition() { + transition.setAutoReverse(false); + transition.setCycleCount(Animation.INDEFINITE); + transition.setDelay(Duration.ZERO); + transition.setInterpolator(Interpolator.LINEAR); + transition.setByAngle(360); + } + + private void initFillerArc() { + fillerArc.setManaged(false); + fillerArc.getStyleClass().add("ringindicator-filler"); + fillerArc.setStartAngle(90); + fillerArc.setLength(indicator.getProgress() * -3.6); + } + + private void initContainer(final RingProgressIndicator indicator) { + container.getStylesheets().addAll(indicator.getStylesheets()); + container.getStyleClass().addAll("circleindicator-container"); + container.setMaxHeight(Region.USE_PREF_SIZE); + container.setMaxWidth(Region.USE_PREF_SIZE); + } + + private void updateRadii() { + double ringWidth = indicator.getRingWidth(); + double innerCircleHalfStrokeWidth = innerCircle.getStrokeWidth() / 2; + double innerCircleRadius = indicator.getInnerCircleRadius(); + outerCircle.setRadius(innerCircleRadius + innerCircleHalfStrokeWidth + ringWidth); + fillerArc.setRadiusY(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); + fillerArc.setRadiusX(innerCircleRadius + innerCircleHalfStrokeWidth - 1 + (ringWidth / 2)); + fillerArc.setStrokeWidth(ringWidth); + innerCircle.setRadius(innerCircleRadius); + } + + private void initLabel(int value) { + setProgressLabel(value); + percentLabel.getStyleClass().add("circleindicator-label"); + } + + private void initIndeterminate(boolean newVal) { + percentLabel.setVisible(!newVal); + if (newVal) { + fillerArc.setLength(360); + fillerArc.getStyleClass().add("indeterminate"); + if (indicator.isVisible()) { + transition.play(); + } + } else { + fillerArc.getStyleClass().remove("indeterminate"); + fillerArc.setRotate(0); + transition.stop(); } + } + + @Override + public RingProgressIndicator getSkinnable() { + return indicator; + } + + @Override + public Node getNode() { + return container; + } + + @Override + public void dispose() { + transition.stop(); + } } \ No newline at end of file diff --git a/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java index 3236c3f472..8475cfb1fe 100644 --- a/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java +++ b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java @@ -1,20 +1,7 @@ package com.faforever.client.tournament.game; -import com.faforever.client.builders.MapBeanBuilder; -import com.faforever.client.builders.MapVersionBeanBuilder; -import com.faforever.client.builders.TutorialBeanBuilder; -import com.faforever.client.domain.MapVersionBean; -import com.faforever.client.domain.TutorialBean; -import com.faforever.client.fx.JavaFxUtil; -import com.faforever.client.fx.WebViewConfigurer; import com.faforever.client.i18n.I18n; -import com.faforever.client.map.MapService; -import com.faforever.client.map.MapService.PreviewSize; import com.faforever.client.test.UITest; -import com.faforever.client.tutorial.TutorialDetailController; -import com.faforever.client.tutorial.TutorialService; -import javafx.scene.image.Image; -import javafx.util.Duration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; diff --git a/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java index e3a75087c0..b237924724 100644 --- a/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java +++ b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java @@ -7,10 +7,8 @@ import com.faforever.client.remote.FafServerAccessor; import com.faforever.client.test.ServiceTest; import com.faforever.client.theme.UiService; -import com.faforever.client.ui.StageHolder; import com.faforever.commons.lobby.IsReadyRequest; import javafx.scene.layout.Region; -import javafx.stage.Stage; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -21,15 +19,10 @@ import java.util.function.Consumer; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class TournamentGameServiceTest extends ServiceTest { From 08f5943380fd53dce65722b95551be4c4ad86f53 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Sep 2022 23:36:59 +0200 Subject: [PATCH 5/9] Changes to make rating type null possible --- src/main/java/com/faforever/client/game/GameService.java | 4 ++-- .../com/faforever/client/leaderboard/LeaderboardService.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/faforever/client/game/GameService.java b/src/main/java/com/faforever/client/game/GameService.java index cebb7e383f..5c3c3c839f 100644 --- a/src/main/java/com/faforever/client/game/GameService.java +++ b/src/main/java/com/faforever/client/game/GameService.java @@ -540,7 +540,7 @@ private CompletableFuture listenToServerInitiatedGame(String featuredModTe final var matchFuture = modService.getFeaturedMod(featuredModTechnicalName) .thenAccept(featuredModBean -> updateGameIfNecessary(featuredModBean, Set.of())) .thenCompose(aVoid -> gameLaunchMessageFuture) - .thenCompose((gameLaunchMessage) -> downloadMapIfNecessary(gameLaunchMessage.getMapName()) + .thenCompose(gameLaunchResponse -> downloadMapIfNecessary(gameLaunchResponse.getMapName()) .thenCompose(aVoid -> leaderboardService.getActiveLeagueEntryForPlayer(playerService.getCurrentPlayer(),gameLaunchResponse.getLeaderboard())) .thenApply(leagueEntryOptional -> { GameParameters parameters = gameMapper.map(gameLaunchResponse); @@ -550,7 +550,7 @@ private CompletableFuture listenToServerInitiatedGame(String featuredModTe .orElse(null)); return parameters; }) - .thenCompose(aVoid -> startGame(gameLaunchMessage))); + .thenCompose(this::startGame)); matchFuture.whenComplete((aVoid, throwable) -> { if (throwable != null) { diff --git a/src/main/java/com/faforever/client/leaderboard/LeaderboardService.java b/src/main/java/com/faforever/client/leaderboard/LeaderboardService.java index 0363effb60..d1f63a4b44 100644 --- a/src/main/java/com/faforever/client/leaderboard/LeaderboardService.java +++ b/src/main/java/com/faforever/client/leaderboard/LeaderboardService.java @@ -21,6 +21,7 @@ import com.faforever.commons.api.dto.LeagueSeasonScore; import com.faforever.commons.api.elide.ElideNavigator; import com.faforever.commons.api.elide.ElideNavigatorOnCollection; +import com.google.common.base.Strings; import javafx.scene.image.Image; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; @@ -174,6 +175,9 @@ public CompletableFuture> getHighestActiveLeagueEntryF @Cacheable(value = CacheNames.LEAGUE_ENTRIES, sync = true) public CompletableFuture> getActiveLeagueEntryForPlayer(PlayerBean player, String leaderboardName) { + if (Strings.isNullOrEmpty(leaderboardName)) { + return CompletableFuture.completedFuture(Optional.empty()); + } ElideNavigatorOnCollection navigator = ElideNavigator.of(LeagueSeasonScore.class).collection() .setFilter(qBuilder() .intNum("loginId").eq(player.getId()) From 8550a9091e41c847310cad41a005cca7036fc0cc Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Sep 2022 23:45:56 +0200 Subject: [PATCH 6/9] Compile errors --- src/test/java/com/faforever/client/game/GameServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/faforever/client/game/GameServiceTest.java b/src/test/java/com/faforever/client/game/GameServiceTest.java index ef2df04b92..cee2768ad1 100644 --- a/src/test/java/com/faforever/client/game/GameServiceTest.java +++ b/src/test/java/com/faforever/client/game/GameServiceTest.java @@ -536,7 +536,7 @@ public void testStartSearchLadder1v1() throws Exception { mockStartGameProcess(gameParameters); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.empty())); - when(fafServerAccessor.startSearchMatchmaker()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(),null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -545,7 +545,7 @@ public void testStartSearchLadder1v1() throws Exception { instance.startSearchMatchmaker().join(); - verify(fafServerAccessor).startSearchMatchmaker(); + verify(fafServerAccessor).getGameLaunchMessage(); verify(mapService).download(map); verify(replayServer).start(eq(uid), any()); verify(forgedAllianceService).startGameOnline(gameParameters); From 361953148532831815e95ef7e3d0317f4d85e798 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Sep 2022 23:52:47 +0200 Subject: [PATCH 7/9] Address codacy complains --- src/main/resources/theme/progress.css | 53 ++++++++++--------- .../client/game/GameServiceTest.java | 4 +- .../game/IsReadyForGameControllerTest.java | 7 --- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/main/resources/theme/progress.css b/src/main/resources/theme/progress.css index 685aee0f1a..0c04090b2c 100644 --- a/src/main/resources/theme/progress.css +++ b/src/main/resources/theme/progress.css @@ -1,37 +1,42 @@ -.circleindicator-container { - circleindicator-color: -fx-accent; - -fx-padding: 5.0; - -fx-background-color: -fx-background; +.circleindicator-container { + circleindicator-color: -fx-accent; + -fx-padding: 5.0; + -fx-background-color: -fx-background; } + .circleindicator-container > .circleindicator-label { - -fx-font-weight: bold; - -fx-font-size: 2.5em; - -fx-text-fill: circleindicator-color; - -fx-padding: 5.0; + -fx-font-weight: bold; + -fx-font-size: 2.5em; + -fx-text-fill: circleindicator-color; + -fx-padding: 5.0; } -.ringindicator{ - -fx-ring-width: 22.0; - -fx-inner-radius: 60.0; +.ringindicator { + -fx-ring-width: 22.0; + -fx-inner-radius: 60.0; } + .ringindicator-inner-circle { - -fx-opacity: 0.55; - -fx-stroke: circleindicator-color; - -fx-stroke-width: 8.0px; - -fx-fill: -fx-background; + -fx-opacity: 0.55; + -fx-stroke: circleindicator-color; + -fx-stroke-width: 8.0px; + -fx-fill: -fx-background; } + .ringindicator-filler { - -fx-stroke: circleindicator-color; - -fx-fill: -fx-background; - -fx-stroke-line-cap: butt; + -fx-stroke: circleindicator-color; + -fx-fill: -fx-background; + -fx-stroke-line-cap: butt; } + .ringindicator-outer-circle-secondary { - -fx-opacity: 0.1; - -fx-stroke: circleindicator-color; - -fx-stroke-width: 2.0px; - -fx-fill: -fx-background; + -fx-opacity: 0.1; + -fx-stroke: circleindicator-color; + -fx-stroke-width: 2.0px; + -fx-fill: -fx-background; } + .indeterminate { - -fx-opacity: 0.55; - -fx-stroke: linear-gradient(from 0.0% 0.0% to 70.0% 70.0%, circleindicator-color 70.0%, white 75.0%, white); + -fx-opacity: 0.55; + -fx-stroke: linear-gradient(from 0.0% 0.0% to 70.0% 70.0%, circleindicator-color 70.0%, white 75.0%, white); } \ No newline at end of file diff --git a/src/test/java/com/faforever/client/game/GameServiceTest.java b/src/test/java/com/faforever/client/game/GameServiceTest.java index cee2768ad1..32d342a3b8 100644 --- a/src/test/java/com/faforever/client/game/GameServiceTest.java +++ b/src/test/java/com/faforever/client/game/GameServiceTest.java @@ -799,7 +799,7 @@ public void startSearchMatchmakerThenCancelledWithGame() throws IOException { when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, "global")).thenReturn(completedFuture(Optional.empty())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); CompletableFuture future = instance.startSearchMatchmaker(); when(process.isAlive()).thenReturn(true); future.cancel(false); @@ -821,7 +821,7 @@ public void startSearchMatchmakerThenCancelledNoGame() throws IOException { mockStartGameProcess(gameMapper.map(gameLaunchMessage)); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(CompletableFuture.completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); instance.startSearchMatchmaker().cancel(false); verify(notificationService, never()).addServerNotification(any()); } diff --git a/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java index 8475cfb1fe..8a44a487a0 100644 --- a/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java +++ b/src/test/java/com/faforever/client/tournament/game/IsReadyForGameControllerTest.java @@ -24,13 +24,6 @@ public void setUp() throws Exception { loadFxml("theme/tournaments/is_ready_for_game.fxml", clazz -> instance); } - @Test - public void testInitialization(){ - instance.setTimeout(1); - instance.setDismissCallBack(() -> {}); - instance.setReadyCallback(() -> {}); - } - @Test public void testTimeOut() { AtomicBoolean dismissCalled = new AtomicBoolean(false); From fc66eddfdd44822201aaabfbcb473404def21ff7 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 25 Sep 2022 12:09:57 +0200 Subject: [PATCH 8/9] Address review --- .../com/faforever/client/game/GameService.java | 17 +++++++++-------- .../client/remote/FafServerAccessor.java | 2 +- .../game/IsReadyForGameController.java | 15 +++++++++------ .../tournament/game/TournamentGameService.java | 12 ++++++------ .../ui/progress/ProgressCircleIndicator.java | 4 ++-- .../ui/progress/RingProgressIndicator.java | 14 +++++++------- .../ui/progress/RingProgressIndicatorSkin.java | 2 +- .../faforever/client/game/GameServiceTest.java | 18 +++++++++--------- .../client/remote/ServerAccessorTest.java | 2 +- .../game/TournamentGameServiceTest.java | 2 +- 10 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/faforever/client/game/GameService.java b/src/main/java/com/faforever/client/game/GameService.java index 5c3c3c839f..830e01d03f 100644 --- a/src/main/java/com/faforever/client/game/GameService.java +++ b/src/main/java/com/faforever/client/game/GameService.java @@ -41,6 +41,7 @@ import com.faforever.client.util.ConcurrentUtil; import com.faforever.client.util.MaskPatternLayout; import com.faforever.commons.lobby.GameInfo; +import com.faforever.commons.lobby.GameLaunchResponse; import com.faforever.commons.lobby.GameStatus; import com.faforever.commons.lobby.GameVisibility; import com.google.common.annotations.VisibleForTesting; @@ -514,30 +515,30 @@ public CompletableFuture startSearchMatchmaker() { return matchmakerFuture; } - matchmakerFuture = listenToServerInitiatedGame(FAF.getTechnicalName()); + matchmakerFuture = listenForServerInitiatedGame(FAF.getTechnicalName()); return matchmakerFuture; } - public CompletableFuture startListeningToTournamentGame(String featuredModTechnicalName) { + public CompletableFuture startListeningForTournamentGame(String featuredModTechnicalName) { if (isRunning()) { log.info("Game is running, ignoring tournament search request"); notificationService.addImmediateWarnNotification("game.gameRunning"); return completedFuture(null); } - return listenToServerInitiatedGame(featuredModTechnicalName); + return listenForServerInitiatedGame(featuredModTechnicalName); } - private CompletableFuture listenToServerInitiatedGame(String featuredModTechnicalName) { + private CompletableFuture listenForServerInitiatedGame(String featuredModTechnicalName) { if (!preferencesService.isGamePathValid()) { CompletableFuture gameDirectoryFuture = postGameDirectoryChooseEvent(); return gameDirectoryFuture.thenCompose(path -> startSearchMatchmaker()); } - log.info("Listening to server made game has been started"); + log.info("Started listening for game launch message"); - final var gameLaunchMessageFuture = fafServerAccessor.getGameLaunchMessage(); - final var matchFuture = modService.getFeaturedMod(featuredModTechnicalName) + final CompletableFuture gameLaunchMessageFuture = fafServerAccessor.getGameLaunchMessageFuture(); + final CompletableFuture matchFuture = modService.getFeaturedMod(featuredModTechnicalName) .thenAccept(featuredModBean -> updateGameIfNecessary(featuredModBean, Set.of())) .thenCompose(aVoid -> gameLaunchMessageFuture) .thenCompose(gameLaunchResponse -> downloadMapIfNecessary(gameLaunchResponse.getMapName()) @@ -563,7 +564,7 @@ private CompletableFuture listenToServerInitiatedGame(String featuredModTe process.destroy(); } } else { - log.warn("Server initiated game could not be started", throwable); + log.warn("Game could not be started", throwable); } } else { log.info("Matchmaker queue exited"); diff --git a/src/main/java/com/faforever/client/remote/FafServerAccessor.java b/src/main/java/com/faforever/client/remote/FafServerAccessor.java index aa9d8840c8..1a4120a875 100644 --- a/src/main/java/com/faforever/client/remote/FafServerAccessor.java +++ b/src/main/java/com/faforever/client/remote/FafServerAccessor.java @@ -212,7 +212,7 @@ public void requestMatchmakerInfo() { lobbyClient.requestMatchmakerInfo(); } - public CompletableFuture getGameLaunchMessage() { + public CompletableFuture getGameLaunchMessageFuture() { return lobbyClient.getEvents() .filter(event -> event instanceof GameLaunchResponse) .next() diff --git a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java index 65ead2b361..b920c522c8 100644 --- a/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java +++ b/src/main/java/com/faforever/client/tournament/game/IsReadyForGameController.java @@ -1,6 +1,7 @@ package com.faforever.client.tournament.game; import com.faforever.client.fx.Controller; +import com.faforever.client.fx.JavaFxUtil; import com.faforever.client.i18n.I18n; import com.faforever.client.ui.progress.RingProgressIndicator; import javafx.animation.KeyFrame; @@ -40,11 +41,12 @@ public class IsReadyForGameController implements Controller { private Runnable readyCallback; @Setter private Runnable dismissCallBack; + private boolean clickedReady = false; @Override public void initialize() { - progressIndicator.setProgressLableStringConverter(new StringConverter<>() { + progressIndicator.setProgressLabelStringConverter(new StringConverter<>() { @Override public String toString(Integer object) { return i18n.number(timeLeft); @@ -67,26 +69,26 @@ public void setTimeout(int responseTimeSeconds) { OffsetDateTime start = OffsetDateTime.now(); queuePopTimeUpdater = new Timeline(1, new KeyFrame(javafx.util.Duration.seconds(0), (ActionEvent event) -> { - updateQueue(responseTimeSeconds, start); + updateTimer(responseTimeSeconds, start); }), new KeyFrame(javafx.util.Duration.seconds(1))); queuePopTimeUpdater.setCycleCount(Timeline.INDEFINITE); queuePopTimeUpdater.play(); } - private void updateQueue(int responseTimeSeconds, OffsetDateTime start) { + private void updateTimer(int responseTimeSeconds, OffsetDateTime start) { OffsetDateTime now = OffsetDateTime.now(); Duration timeGone = Duration.between(start, now); final var percent = timeGone.toSeconds() / (double) responseTimeSeconds; this.timeLeft = (int) (responseTimeSeconds - timeGone.toSeconds()); progressIndicator.setProgress((int) (percent * 100)); if (timeLeft <= 0 && queuePopTimeUpdater != null) { - end(); + queuePopTimeUpdater.stop(); + JavaFxUtil.runLater(this::end); } } private void end() { - queuePopTimeUpdater.stop(); - if (isReadyButton.isDisable()) { + if (clickedReady) { isReadyButton.setText(i18n.get("isReady.launching")); } else { dismissCallBack.run(); @@ -96,6 +98,7 @@ private void end() { public void onReady() { readyCallback.run(); isReadyButton.setDisable(true); + clickedReady = true; isReadyButton.setText(i18n.get("isReady.waiting")); } } diff --git a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java index de7b649f95..afb3ec932e 100644 --- a/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java +++ b/src/main/java/com/faforever/client/tournament/game/TournamentGameService.java @@ -60,19 +60,18 @@ private void onReadRequest(IsReadyRequest isReadyRequest) { log.info("Tournament game is ready, asking user."); if (notification != null) { log.warn("Tournament ready request ignored because tournament is already in progress."); - respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest); return; } uiService.bringMainStageToFront(); - final var controller = initializeIsReadyController(isReadyRequest); + final IsReadyForGameController controller = initializeIsReadyController(isReadyRequest); notification = new ImmediateNotification(i18n.get("isReady.title"), i18n.get("isReady.message", isReadyRequest.getGameName()), Severity.INFO, null, List.of(), controller.getRoot(), false); notificationService.addNotification(notification); - safetyCloseMechanism(); + ensureNotificationCloses(); } - private void safetyCloseMechanism() { + private void ensureNotificationCloses() { final var currentNotification = notification; timer.schedule(new TimerTask() { @Override @@ -98,18 +97,19 @@ private IsReadyForGameController initializeIsReadyController(IsReadyRequest isRe IsReadyForGameController controller = uiService.loadFxml("theme/tournaments/is_ready_for_game.fxml"); controller.setTimeout(isReadyRequest.getResponseTimeSeconds()); controller.setReadyCallback(() -> respondToReadyRequest(isReadyRequest.getRequestId(), isReadyRequest)); - controller.setDismissCallBack(() -> JavaFxUtil.runLater(this::dismissNotification)); + controller.setDismissCallBack(this::dismissNotification); return controller; } private void respondToReadyRequest(String requestId, IsReadyRequest isReadyRequest) { - matchFuture = gameService.startListeningToTournamentGame(isReadyRequest.getFeaturedMod()); + matchFuture = gameService.startListeningForTournamentGame(isReadyRequest.getFeaturedMod()); try { fafServerAccessor.sendIsReady(requestId); } catch (Exception e) { dismissNotification(); cancelMatch(); + log.error("Could not send the server that player is ready for the tournament game", e); notificationService.addImmediateErrorNotification(e, "isReady.readyUpFailed"); } } diff --git a/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java index 9ba9ec9b04..3b87534f6b 100644 --- a/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java +++ b/src/main/java/com/faforever/client/ui/progress/ProgressCircleIndicator.java @@ -33,8 +33,8 @@ /** - * Base class for the progress indicator controls represented by circualr shapes - * + * Base class for the progress indicator controls represented by circular shapes + * * * @author Andrea Vacondio */ abstract class ProgressCircleIndicator extends Control { diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java index 57d7d2c915..4a65364806 100644 --- a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicator.java @@ -38,7 +38,7 @@ * @author Andrea Vacondio */ public class RingProgressIndicator extends ProgressCircleIndicator { - public ObjectProperty> progressLableStringConverter = new SimpleObjectProperty<>(new StringConverter<>() { + public ObjectProperty> progressLabelStringConverter = new SimpleObjectProperty<>(new StringConverter<>() { @Override public String toString(Integer object) { return String.format("%d%%", object); @@ -121,15 +121,15 @@ public StyleableProperty getStyleableProperty(RingProgressIndicator n) { return StyleableProperties.STYLEABLES; } - public StringConverter getProgressLableStringConverter() { - return progressLableStringConverter.get(); + public StringConverter getProgressLabelStringConverter() { + return progressLabelStringConverter.get(); } - public ObjectProperty> progressLableStringConverterProperty() { - return progressLableStringConverter; + public ObjectProperty> progressLabelStringConverterProperty() { + return progressLabelStringConverter; } - public void setProgressLableStringConverter(StringConverter progressLableStringConverter) { - this.progressLableStringConverter.set(progressLableStringConverter); + public void setProgressLabelStringConverter(StringConverter progressLabelStringConverter) { + this.progressLabelStringConverter.set(progressLabelStringConverter); } } \ No newline at end of file diff --git a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java index 23922c8197..8a38f3ad73 100644 --- a/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java +++ b/src/main/java/com/faforever/client/ui/progress/RingProgressIndicatorSkin.java @@ -90,7 +90,7 @@ public RingProgressIndicatorSkin(final RingProgressIndicator indicator) { private void setProgressLabel(int value) { if (value >= 0) { - percentLabel.setText(indicator.getProgressLableStringConverter().toString(value)); + percentLabel.setText(indicator.getProgressLabelStringConverter().toString(value)); } } diff --git a/src/test/java/com/faforever/client/game/GameServiceTest.java b/src/test/java/com/faforever/client/game/GameServiceTest.java index 32d342a3b8..0e38c960a3 100644 --- a/src/test/java/com/faforever/client/game/GameServiceTest.java +++ b/src/test/java/com/faforever/client/game/GameServiceTest.java @@ -205,7 +205,7 @@ private void mockMatchmakerChain() { when(modService.getFeaturedMod(FAF.getTechnicalName())) .thenReturn(completedFuture(FeaturedModBeanBuilder.create().defaultValues().get())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(new CompletableFuture<>()); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(new CompletableFuture<>()); } @Test @@ -536,7 +536,7 @@ public void testStartSearchLadder1v1() throws Exception { mockStartGameProcess(gameParameters); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.empty())); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(),null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -545,7 +545,7 @@ public void testStartSearchLadder1v1() throws Exception { instance.startSearchMatchmaker().join(); - verify(fafServerAccessor).getGameLaunchMessage(); + verify(fafServerAccessor).getGameLaunchMessageFuture(); verify(mapService).download(map); verify(replayServer).start(eq(uid), any()); verify(forgedAllianceService).startGameOnline(gameParameters); @@ -573,7 +573,7 @@ public void testStartSearchLadder1v1WithLeagueEntry() throws Exception { mockStartGameProcess(gameParameters); LeagueEntryBean leagueEntry = LeagueEntryBeanBuilder.create().defaultValues().get(); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.of(leagueEntry))); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(),null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -582,7 +582,7 @@ public void testStartSearchLadder1v1WithLeagueEntry() throws Exception { instance.startSearchMatchmaker().join(); - verify(fafServerAccessor).getGameLaunchMessage(); + verify(fafServerAccessor).getGameLaunchMessageFuture(); verify(mapService).download(map); verify(replayServer).start(eq(uid), any()); verify(forgedAllianceService).startGameOnline(gameParameters); @@ -608,7 +608,7 @@ public void testStartSearchLadderTwiceReturnsSameFutureWhenSearching() throws Ex mockStartGameProcess(gameParameters); when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, LADDER_1v1_RATING_TYPE)).thenReturn(completedFuture(Optional.empty())); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); when(gameUpdater.update(featuredMod, Set.of(), null, null)).thenReturn(completedFuture(null)); when(mapService.isInstalled(map)).thenReturn(false); when(mapService.download(map)).thenReturn(completedFuture(null)); @@ -776,7 +776,7 @@ public void startSearchMatchmakerWithGameOptions() throws IOException { when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, "global")).thenReturn(completedFuture(Optional.empty())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); instance.startSearchMatchmaker().join(); verify(forgedAllianceService).startGameOnline(gameParameters); } @@ -799,7 +799,7 @@ public void startSearchMatchmakerThenCancelledWithGame() throws IOException { when(leaderboardService.getActiveLeagueEntryForPlayer(junitPlayer, "global")).thenReturn(completedFuture(Optional.empty())); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); CompletableFuture future = instance.startSearchMatchmaker(); when(process.isAlive()).thenReturn(true); future.cancel(false); @@ -821,7 +821,7 @@ public void startSearchMatchmakerThenCancelledNoGame() throws IOException { mockStartGameProcess(gameMapper.map(gameLaunchMessage)); when(gameUpdater.update(any(), any(), any(), any())).thenReturn(completedFuture(null)); when(mapService.download(gameLaunchMessage.getMapName())).thenReturn(completedFuture(null)); - when(fafServerAccessor.getGameLaunchMessage()).thenReturn(completedFuture(gameLaunchMessage)); + when(fafServerAccessor.getGameLaunchMessageFuture()).thenReturn(completedFuture(gameLaunchMessage)); instance.startSearchMatchmaker().cancel(false); verify(notificationService, never()).addServerNotification(any()); } diff --git a/src/test/java/com/faforever/client/remote/ServerAccessorTest.java b/src/test/java/com/faforever/client/remote/ServerAccessorTest.java index 6042c59a66..054c9e552c 100644 --- a/src/test/java/com/faforever/client/remote/ServerAccessorTest.java +++ b/src/test/java/com/faforever/client/remote/ServerAccessorTest.java @@ -655,7 +655,7 @@ public void testOnGameLaunch() throws InterruptedException, JsonProcessingExcept .initMode(LobbyMode.AUTO_LOBBY) .get(); - instance.getGameLaunchMessage(); + instance.getGameLaunchMessageFuture(); sendFromServer(gameLaunchMessage); assertTrue(messageReceivedByClientLatch.await(TIMEOUT, TIMEOUT_UNIT)); assertThat(receivedMessage, is(gameLaunchMessage)); diff --git a/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java index b237924724..340f9a6c0e 100644 --- a/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java +++ b/src/test/java/com/faforever/client/tournament/game/TournamentGameServiceTest.java @@ -63,6 +63,6 @@ public void testReceivingIsReadyMessageAndClickingReady() throws Exception { isReadyCallbackCapture.getValue().run(); verify(fafServerAccessor).sendIsReady("abc"); - verify(gameService).startListeningToTournamentGame("faf"); + verify(gameService).startListeningForTournamentGame("faf"); } } \ No newline at end of file From 6aa418c70bed5cacbd9fc461fbba5b446ee711c7 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 25 Sep 2022 12:09:57 +0200 Subject: [PATCH 9/9] Address review --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f499379900..0a273ef21a 100644 --- a/build.gradle +++ b/build.gradle @@ -298,7 +298,7 @@ dependencies { implementation("org.springframework:spring-web") implementation("org.springframework:spring-websocket") - def commonsVersion = "b0a374fa17988e0a8249fcf9b6d3a511b476ef8d" + def commonsVersion = "aca27907ccd99917112e02901a6e80de0cc44684" implementation("com.github.FAForever.faf-java-commons:faf-commons-data:${commonsVersion}") { exclude module: 'guava'