mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-02-05 16:44:47 +08:00
refactor: WizardDisplayer
This commit is contained in:
parent
bd18355a1a
commit
dc03f28d56
@ -19,16 +19,28 @@ package org.jackhuang.hmcl.ui.decorator;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.SkinBase;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.ui.construct.Navigator;
|
||||
import org.jackhuang.hmcl.ui.construct.PageCloseEvent;
|
||||
import org.jackhuang.hmcl.ui.wizard.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements TaskExecutorDialogWizardDisplayer {
|
||||
public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements WizardDisplayer {
|
||||
private final WizardController wizardController = new WizardController(this);
|
||||
private final Queue<Object> cancelQueue = new ConcurrentLinkedQueue<>();
|
||||
private final WizardDisplayer displayer = new TaskExecutorDialogWizardDisplayer(new ConcurrentLinkedQueue<>()) {
|
||||
@Override
|
||||
public void onEnd() {
|
||||
super.onEnd();
|
||||
fireEvent(new PageCloseEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateTo(Node page, Navigation.NavigationDirection nav) {
|
||||
}
|
||||
};
|
||||
|
||||
private final String category;
|
||||
|
||||
@ -45,28 +57,24 @@ public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements
|
||||
addEventHandler(Navigator.NavigationEvent.NAVIGATED, this::onDecoratorPageNavigating);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WizardController getWizardController() {
|
||||
return wizardController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<Object> getCancelQueue() {
|
||||
return cancelQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
displayer.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
displayer.onCancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
fireEvent(new PageCloseEvent());
|
||||
displayer.onEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateTo(Node page, Navigation.NavigationDirection nav) {
|
||||
displayer.navigateTo(page, nav);
|
||||
navigate(page, nav.getAnimation().getAnimationProducer());
|
||||
|
||||
String prefix = category == null ? "" : category + " - ";
|
||||
@ -86,6 +94,11 @@ public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTask(Map<String, Object> settings, Task<?> task) {
|
||||
displayer.handleTask(settings, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPageCloseable() {
|
||||
return true;
|
||||
|
@ -101,7 +101,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
|
||||
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
|
||||
selectedFile = chooser.showOpenDialog(Controllers.getStage());
|
||||
if (selectedFile == null) {
|
||||
Platform.runLater(controller::onEnd);
|
||||
controller.onEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -26,32 +26,34 @@ import org.jackhuang.hmcl.ui.construct.TaskListPane;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
public interface AbstractWizardDisplayer extends WizardDisplayer {
|
||||
WizardController getWizardController();
|
||||
public abstract class AbstractWizardDisplayer implements WizardDisplayer {
|
||||
private final Queue<Object> cancelQueue;
|
||||
|
||||
Queue<Object> getCancelQueue();
|
||||
public AbstractWizardDisplayer(Queue<Object> cancelQueue) {
|
||||
this.cancelQueue = cancelQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
default void handleTask(Map<String, Object> settings, Task<?> task) {
|
||||
public void handleTask(Map<String, Object> settings, Task<?> task) {
|
||||
TaskExecutor executor = task.withRunAsync(Schedulers.javafx(), this::navigateToSuccess).executor();
|
||||
TaskListPane pane = new TaskListPane();
|
||||
pane.setExecutor(executor);
|
||||
navigateTo(pane, Navigation.NavigationDirection.FINISH);
|
||||
getCancelQueue().add(executor);
|
||||
cancelQueue.add(executor);
|
||||
executor.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void onCancel() {
|
||||
while (!getCancelQueue().isEmpty()) {
|
||||
Object x = getCancelQueue().poll();
|
||||
public void onCancel() {
|
||||
while (!cancelQueue.isEmpty()) {
|
||||
Object x = cancelQueue.poll();
|
||||
if (x instanceof TaskExecutor) ((TaskExecutor) x).cancel();
|
||||
else if (x instanceof Thread) ((Thread) x).interrupt();
|
||||
else throw new IllegalStateException("Unrecognized cancel queue element: " + x);
|
||||
}
|
||||
}
|
||||
|
||||
default void navigateToSuccess() {
|
||||
void navigateToSuccess() {
|
||||
navigateTo(new Label("Successful"), Navigation.NavigationDirection.FINISH);
|
||||
}
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.wizard;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXToolbar;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class DefaultWizardDisplayer extends StackPane implements AbstractWizardDisplayer {
|
||||
|
||||
private final String prefix;
|
||||
private final WizardController wizardController;
|
||||
private final Queue<Object> cancelQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private Node nowPage;
|
||||
|
||||
@FXML
|
||||
private TransitionPane root;
|
||||
@FXML
|
||||
private JFXButton backButton;
|
||||
@FXML
|
||||
private JFXToolbar toolbar;
|
||||
@FXML
|
||||
private JFXButton refreshButton;
|
||||
@FXML
|
||||
private Label titleLabel;
|
||||
|
||||
public DefaultWizardDisplayer(String prefix, WizardProvider wizardProvider) {
|
||||
this.prefix = prefix;
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/wizard.fxml");
|
||||
toolbar.setEffect(null);
|
||||
|
||||
wizardController = new WizardController(this);
|
||||
wizardController.setProvider(wizardProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WizardController getWizardController() {
|
||||
return wizardController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<Object> getCancelQueue() {
|
||||
return cancelQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateTo(Node page, Navigation.NavigationDirection nav) {
|
||||
backButton.setDisable(!wizardController.canPrev());
|
||||
root.setContent(page, nav.getAnimation().getAnimationProducer());
|
||||
String title = StringUtils.isBlank(prefix) ? "" : prefix + " - ";
|
||||
if (page instanceof WizardPage)
|
||||
titleLabel.setText(title + ((WizardPage) page).getTitle());
|
||||
refreshButton.setVisible(page instanceof Refreshable);
|
||||
nowPage = page;
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void initialize() {
|
||||
wizardController.onStart();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void back() {
|
||||
wizardController.onPrev(true);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void close() {
|
||||
wizardController.onCancel();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void refresh() {
|
||||
((Refreshable) nowPage).refresh();
|
||||
}
|
||||
}
|
@ -28,14 +28,19 @@ import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplayer {
|
||||
public abstract class TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplayer {
|
||||
|
||||
public TaskExecutorDialogWizardDisplayer(Queue<Object> cancelQueue) {
|
||||
super(cancelQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void handleTask(Map<String, Object> settings, Task<?> task) {
|
||||
public void handleTask(Map<String, Object> settings, Task<?> task) {
|
||||
TaskExecutorDialogPane pane = new TaskExecutorDialogPane(it -> {
|
||||
it.fireEvent(new DialogCloseEvent());
|
||||
onEnd();
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.wizard;
|
||||
|
||||
import javafx.scene.Node;
|
||||
|
||||
public final class Wizard {
|
||||
|
||||
public static Node createWizard(WizardProvider provider) {
|
||||
return createWizard("", provider);
|
||||
}
|
||||
|
||||
public static Node createWizard(String namespace, WizardProvider provider) {
|
||||
return new DefaultWizardDisplayer(namespace, provider);
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ public class WizardController implements Navigation {
|
||||
private WizardProvider provider = null;
|
||||
private final Map<String, Object> settings = new HashMap<>();
|
||||
private final Stack<Node> pages = new Stack<>();
|
||||
private boolean stopped = false;
|
||||
|
||||
public WizardController(WizardDisplayer displayer) {
|
||||
this.displayer = displayer;
|
||||
@ -60,6 +61,10 @@ public class WizardController implements Navigation {
|
||||
Node page = navigatingTo(0);
|
||||
pages.push(page);
|
||||
|
||||
if (stopped) { // navigatingTo may stop this wizard.
|
||||
return;
|
||||
}
|
||||
|
||||
if (page instanceof WizardPage)
|
||||
((WizardPage) page).onNavigate(settings);
|
||||
|
||||
@ -77,6 +82,10 @@ public class WizardController implements Navigation {
|
||||
public void onNext(Node page) {
|
||||
pages.push(page);
|
||||
|
||||
if (stopped) { // navigatingTo may stop this wizard.
|
||||
return;
|
||||
}
|
||||
|
||||
if (page instanceof WizardPage)
|
||||
((WizardPage) page).onNavigate(settings);
|
||||
|
||||
@ -122,6 +131,7 @@ public class WizardController implements Navigation {
|
||||
|
||||
@Override
|
||||
public void onEnd() {
|
||||
stopped = true;
|
||||
settings.clear();
|
||||
pages.clear();
|
||||
displayer.onEnd();
|
||||
|
@ -23,9 +23,16 @@ import org.jackhuang.hmcl.task.Task;
|
||||
import java.util.Map;
|
||||
|
||||
public interface WizardDisplayer {
|
||||
void onStart();
|
||||
void onEnd();
|
||||
void onCancel();
|
||||
default void onStart() {
|
||||
}
|
||||
|
||||
default void onEnd() {
|
||||
}
|
||||
|
||||
default void onCancel() {
|
||||
}
|
||||
|
||||
void navigateTo(Node page, Navigation.NavigationDirection nav);
|
||||
|
||||
void handleTask(Map<String, Object> settings, Task<?> task);
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXButton?>
|
||||
<?import com.jfoenix.controls.JFXToolbar?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.jackhuang.hmcl.ui.animation.TransitionPane?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
type="StackPane"
|
||||
style="-fx-background-color: gray;"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
<VBox>
|
||||
<JFXToolbar fx:id="toolbar" styleClass="jfx-tool-bar">
|
||||
<leftItems>
|
||||
<JFXButton maxHeight="20" styleClass="toggle-icon3"
|
||||
StackPane.alignment="CENTER_RIGHT" onMouseClicked="#close">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/close.fxml"/>
|
||||
</graphic>
|
||||
<StackPane.margin>
|
||||
<Insets left="20"/>
|
||||
</StackPane.margin>
|
||||
</JFXButton>
|
||||
<JFXButton fx:id="backButton" maxHeight="20" styleClass="toggle-icon3"
|
||||
StackPane.alignment="CENTER_LEFT" onMouseClicked="#back">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/arrow-left.fxml"/>
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<Label fx:id="titleLabel" style="-fx-text-fill:WHITE; -fx-font-size: 15;"
|
||||
StackPane.alignment="CENTER_LEFT"/>
|
||||
</leftItems>
|
||||
<rightItems>
|
||||
<JFXButton fx:id="refreshButton" maxHeight="20" styleClass="toggle-icon3" disable="true"
|
||||
StackPane.alignment="CENTER_RIGHT" onMouseClicked="#refrseh">
|
||||
<graphic>
|
||||
<fx:include source="/assets/svg/refresh.fxml"/>
|
||||
</graphic>
|
||||
<StackPane.margin>
|
||||
<Insets left="20"/>
|
||||
</StackPane.margin>
|
||||
</JFXButton>
|
||||
</rightItems>
|
||||
</JFXToolbar>
|
||||
|
||||
<TransitionPane fx:id="root"/>
|
||||
</VBox>
|
||||
</fx:root>
|
@ -17,8 +17,10 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.download.game;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.gson.Validation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -28,7 +30,7 @@ import java.util.List;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class GameRemoteVersions {
|
||||
public final class GameRemoteVersions implements Validation {
|
||||
|
||||
@SerializedName("versions")
|
||||
private final List<GameRemoteVersionInfo> versions;
|
||||
@ -57,4 +59,9 @@ public final class GameRemoteVersions {
|
||||
return versions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws JsonParseException {
|
||||
if (versions == null)
|
||||
throw new JsonParseException("GameRemoteVersions.versions cannot be null");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user