feat(multiplayer): join request should be cancelled when user operation time out.
This commit is contained in:
@@ -227,7 +227,7 @@ public final class Controllers {
|
||||
}
|
||||
|
||||
public static void dialog(String text, String title, MessageType type, Runnable ok) {
|
||||
dialog(MessageDialogPane.ok(text, title, type, ok));
|
||||
dialog(new MessageDialogPane.Builder(text, title, type).ok(ok).build());
|
||||
}
|
||||
|
||||
public static void confirm(String text, String title, Runnable yes, Runnable no) {
|
||||
@@ -235,15 +235,15 @@ public final class Controllers {
|
||||
}
|
||||
|
||||
public static void confirm(String text, String title, MessageType type, Runnable yes, Runnable no) {
|
||||
dialog(MessageDialogPane.yesOrNo(text, title, type, yes, no));
|
||||
dialog(new MessageDialogPane.Builder(text, title, type).yesOrNo(yes, no).build());
|
||||
}
|
||||
|
||||
public static void confirmAction(String text, String title, MessageType type, ButtonBase actionButton) {
|
||||
dialog(MessageDialogPane.actionOrCancel(text, title, type, actionButton, null));
|
||||
dialog(new MessageDialogPane.Builder(text, title, type).actionOrCancel(actionButton, null).build());
|
||||
}
|
||||
|
||||
public static void confirmAction(String text, String title, MessageType type, ButtonBase actionButton, Runnable cancel) {
|
||||
dialog(MessageDialogPane.actionOrCancel(text, title, type, actionButton, cancel));
|
||||
dialog(new MessageDialogPane.Builder(text, title, type).actionOrCancel(actionButton, cancel).build());
|
||||
}
|
||||
|
||||
public static CompletableFuture<String> prompt(String title, FutureCallback<String> onResult) {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.ui.construct;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ButtonBase;
|
||||
@@ -28,12 +27,16 @@ import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public final class MessageDialogPane extends StackPane {
|
||||
@@ -105,53 +108,89 @@ public final class MessageDialogPane extends StackPane {
|
||||
cancelButton = btn;
|
||||
}
|
||||
|
||||
public static MessageDialogPane ok(String text, String title, MessageType type, Runnable ok) {
|
||||
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
|
||||
|
||||
JFXButton btnOk = new JFXButton(i18n("button.ok"));
|
||||
btnOk.getStyleClass().add("dialog-accept");
|
||||
if (ok != null) {
|
||||
btnOk.setOnAction(e -> ok.run());
|
||||
}
|
||||
dialog.addButton(btnOk);
|
||||
dialog.setCancelButton(btnOk);
|
||||
|
||||
return dialog;
|
||||
public ButtonBase getCancelButton() {
|
||||
return cancelButton;
|
||||
}
|
||||
|
||||
public static MessageDialogPane yesOrNo(String text, String title, MessageType type, Runnable yes, Runnable no) {
|
||||
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
|
||||
public static class Builder {
|
||||
private final MessageDialogPane dialog;
|
||||
|
||||
JFXButton btnYes = new JFXButton(i18n("button.yes"));
|
||||
btnYes.getStyleClass().add("dialog-accept");
|
||||
if (yes != null) {
|
||||
btnYes.setOnAction(e -> yes.run());
|
||||
public Builder(String text, String title, MessageType type) {
|
||||
this.dialog = new MessageDialogPane(text, title, type);
|
||||
}
|
||||
dialog.addButton(btnYes);
|
||||
|
||||
JFXButton btnNo = new JFXButton(i18n("button.no"));
|
||||
btnNo.getStyleClass().add("dialog-cancel");
|
||||
if (no != null) {
|
||||
btnNo.setOnAction(e -> no.run());
|
||||
public Builder ok(Runnable ok) {
|
||||
JFXButton btnOk = new JFXButton(i18n("button.ok"));
|
||||
btnOk.getStyleClass().add("dialog-accept");
|
||||
if (ok != null) {
|
||||
btnOk.setOnAction(e -> ok.run());
|
||||
}
|
||||
dialog.addButton(btnOk);
|
||||
dialog.setCancelButton(btnOk);
|
||||
return this;
|
||||
}
|
||||
dialog.addButton(btnNo);
|
||||
dialog.setCancelButton(btnNo);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
public Builder yesOrNo(Runnable yes, Runnable no) {
|
||||
JFXButton btnYes = new JFXButton(i18n("button.yes"));
|
||||
btnYes.getStyleClass().add("dialog-accept");
|
||||
if (yes != null) {
|
||||
btnYes.setOnAction(e -> yes.run());
|
||||
}
|
||||
dialog.addButton(btnYes);
|
||||
|
||||
public static MessageDialogPane actionOrCancel(String text, String title, MessageType type, ButtonBase actionButton, Runnable cancel) {
|
||||
MessageDialogPane dialog = new MessageDialogPane(text, title, type);
|
||||
dialog.addButton(actionButton);
|
||||
|
||||
JFXButton btnCancel = new JFXButton(i18n("button.cancel"));
|
||||
btnCancel.getStyleClass().add("dialog-cancel");
|
||||
if (cancel != null) {
|
||||
btnCancel.setOnAction(e -> cancel.run());
|
||||
JFXButton btnNo = new JFXButton(i18n("button.no"));
|
||||
btnNo.getStyleClass().add("dialog-cancel");
|
||||
if (no != null) {
|
||||
btnNo.setOnAction(e -> no.run());
|
||||
}
|
||||
dialog.addButton(btnNo);
|
||||
dialog.setCancelButton(btnNo);
|
||||
return this;
|
||||
}
|
||||
dialog.addButton(btnCancel);
|
||||
dialog.setCancelButton(btnCancel);
|
||||
|
||||
return dialog;
|
||||
public Builder actionOrCancel(ButtonBase actionButton, Runnable cancel) {
|
||||
dialog.addButton(actionButton);
|
||||
|
||||
JFXButton btnCancel = new JFXButton(i18n("button.cancel"));
|
||||
btnCancel.getStyleClass().add("dialog-cancel");
|
||||
if (cancel != null) {
|
||||
btnCancel.setOnAction(e -> cancel.run());
|
||||
}
|
||||
dialog.addButton(btnCancel);
|
||||
dialog.setCancelButton(btnCancel);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder cancelOnTimeout(long timeoutMs) {
|
||||
if (dialog.getCancelButton() == null) {
|
||||
throw new IllegalStateException("Call ok/yesOrNo/actionOrCancel before calling cancelOnTimeout");
|
||||
}
|
||||
|
||||
ButtonBase cancelButton = dialog.getCancelButton();
|
||||
String originalText = cancelButton.getText();
|
||||
|
||||
Timer timer = Lang.getTimer();
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
long timeout = timeoutMs;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (timeout < 0) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
timeout -= 1000;
|
||||
long currentTimeout = timeout;
|
||||
runInFX(() -> cancelButton.setText(originalText + " (" + (currentTimeout / 1000) + ")"));
|
||||
}
|
||||
}, 1000, 1000);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MessageDialogPane build() {
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +215,10 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP
|
||||
MultiplayerManager.CatoSession session = MultiplayerManager.createSession(globalConfig().getMultiplayerToken(), result.getServer().getMotd(), gamePort, result.isAllowAllJoinRequests());
|
||||
session.getServer().setOnClientAdding((client, resolveClient, rejectClient) -> {
|
||||
runInFX(() -> {
|
||||
Controllers.confirm(i18n("multiplayer.session.create.join.prompt", client.getUsername()), i18n("multiplayer.session.create.join"), MessageDialogPane.MessageType.INFO,
|
||||
resolveClient, () -> rejectClient.accept(""));
|
||||
Controllers.dialog(new MessageDialogPane.Builder(i18n("multiplayer.session.create.join.prompt", client.getUsername()), i18n("multiplayer.session.create.join"), MessageDialogPane.MessageType.INFO)
|
||||
.yesOrNo(resolveClient, () -> rejectClient.accept(""))
|
||||
.cancelOnTimeout(30 * 1000)
|
||||
.build());
|
||||
});
|
||||
});
|
||||
session.getServer().onClientAdded().register(event -> {
|
||||
|
||||
@@ -359,17 +359,21 @@ public final class Lang {
|
||||
|
||||
private static Timer timer;
|
||||
|
||||
public static synchronized TimerTask setTimeout(Runnable runnable, long delayMs) {
|
||||
public static synchronized Timer getTimer() {
|
||||
if (timer == null) {
|
||||
timer = new Timer();
|
||||
}
|
||||
return timer;
|
||||
}
|
||||
|
||||
public static synchronized TimerTask setTimeout(Runnable runnable, long delayMs) {
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
runnable.run();
|
||||
}
|
||||
};
|
||||
timer.schedule(task, delayMs);
|
||||
getTimer().schedule(task, delayMs);
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user