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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Log4jLevel;
Expand Down Expand Up @@ -79,6 +80,7 @@ public class GameCrashWindow extends Stage {
private final TextFlow reasonTextFlow = new TextFlow(new Text(i18n("game.crash.reason.unknown")));
private final BooleanProperty loading = new SimpleBooleanProperty();
private final TextFlow feedbackTextFlow = new TextFlow();
private final SpinnerPane exportSpinner = new SpinnerPane();

private final ManagedProcess managedProcess;
private final DefaultGameRepository repository;
Expand Down Expand Up @@ -271,6 +273,8 @@ private void showLogWindow() {
}

private void exportGameCrashInfo() {
exportSpinner.showSpinner();

Path logFile = Paths.get("minecraft-exported-crash-info-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".zip").toAbsolutePath();

CompletableFuture.supplyAsync(() ->
Expand Down Expand Up @@ -300,6 +304,7 @@ private void exportGameCrashInfo() {
});
})
.handleAsync((result, exception) -> {
exportSpinner.hideSpinner();
if (exception == null) {
FXUtils.showFileInExplorer(logFile);
var dialog = new MessageDialogPane.Builder(i18n("settings.launcher.launcher_log.export.success", logFile), i18n("message.success"), MessageDialogPane.MessageType.SUCCESS).ok(null).build();
Expand Down Expand Up @@ -444,6 +449,8 @@ private final class View extends VBox {
JFXButton exportGameCrashInfoButton = FXUtils.newRaisedButton(i18n("logwindow.export_game_crash_logs"));
exportGameCrashInfoButton.setOnAction(e -> exportGameCrashInfo());

exportSpinner.setContent(exportGameCrashInfoButton);

JFXButton logButton = FXUtils.newRaisedButton(i18n("logwindow.title"));
logButton.setOnAction(e -> showLogWindow());

Expand All @@ -454,7 +461,7 @@ private final class View extends VBox {
toolBar.setPadding(new Insets(8));
toolBar.setSpacing(8);
toolBar.getStyleClass().add("jfx-tool-bar");
toolBar.getChildren().setAll(exportGameCrashInfoButton, logButton, helpButton);
toolBar.getChildren().setAll(exportSpinner, logButton, helpButton);
}

getChildren().setAll(titlePane, infoPane, moddedPane, gameDirPane, toolBar);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
* 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.construct;

import com.jfoenix.controls.JFXSpinner;
import javafx.animation.FadeTransition;
import javafx.beans.DefaultProperty;
import javafx.beans.InvalidationListener;
import javafx.beans.property.*;
Expand All @@ -31,14 +33,21 @@
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.Motion;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.util.Lang;

@DefaultProperty("content")
public class SpinnerPane extends Control {
private final ObjectProperty<Node> content = new SimpleObjectProperty<>(this, "content");
private final BooleanProperty loading = new SimpleBooleanProperty(this, "loading");
private final StringProperty failedReason = new SimpleStringProperty(this, "failedReason");

public SpinnerPane(Node content) {
this();
setContent(content);
}

public SpinnerPane() {
getStyleClass().add("spinner-pane");
}
Expand Down Expand Up @@ -114,14 +123,22 @@ protected SkinBase<SpinnerPane> createDefaultSkin() {

private static final class Skin extends SkinBase<SpinnerPane> {
private final JFXSpinner spinner = new JFXSpinner();

private final StackPane contentPane = new StackPane();

private final StackPane topPane = new StackPane();
private final TransitionPane root = new TransitionPane();
private final StackPane failedPane = new StackPane();
private final Label failedReasonLabel = new Label();
@SuppressWarnings("FieldCanBeLocal") // prevent from gc.

private final TransitionPane transition = new TransitionPane();

private static final StackPane EMPTY = Lang.apply(new StackPane(), (stackPane) -> stackPane.setMouseTransparent(true));

@SuppressWarnings("FieldCanBeLocal")
private final InvalidationListener observer;

private FadeTransition contentFadeTransition;

Skin(SpinnerPane control) {
super(control);

Expand All @@ -142,20 +159,50 @@ private static final class Skin extends SkinBase<SpinnerPane> {
contentPane.getChildren().setAll(newValue);
}
});
getChildren().setAll(root);

transition.setPickOnBounds(false);
transition.setMouseTransparent(true);

getChildren().setAll(new StackPane(contentPane, transition));

observer = FXUtils.observeWeak(() -> {
if (getSkinnable().getFailedReason() != null) {
root.setContent(failedPane, ContainerAnimations.FADE);
boolean isError = getSkinnable().getFailedReason() != null;
boolean isLoading = getSkinnable().isLoading();
boolean showOverlay = isError || isLoading;

animateContentOpacity(showOverlay ? 0.0 : 1.0);
contentPane.setMouseTransparent(showOverlay);

transition.setMouseTransparent(!showOverlay);

if (isError) {
failedReasonLabel.setText(getSkinnable().getFailedReason());
} else if (getSkinnable().isLoading()) {
root.setContent(topPane, ContainerAnimations.FADE);
transition.setContent(failedPane, ContainerAnimations.FADE);
} else if (isLoading) {
transition.setContent(topPane, ContainerAnimations.FADE);
} else {
root.setContent(contentPane, ContainerAnimations.FADE);
transition.setContent(EMPTY, ContainerAnimations.FADE);
}
}, getSkinnable().loadingProperty(), getSkinnable().failedReasonProperty());
}

private void animateContentOpacity(double targetOpacity) {
if (contentFadeTransition != null) {
contentFadeTransition.stop();
}

if (Math.abs(contentPane.getOpacity() - targetOpacity) < 0.01) {
contentPane.setOpacity(targetOpacity);
return;
}

contentFadeTransition = new FadeTransition(Motion.SHORT4, contentPane);
contentFadeTransition.setFromValue(contentPane.getOpacity());
contentFadeTransition.setToValue(targetOpacity);
contentFadeTransition.play();
}
}

public static final EventType<Event> FAILED_ACTION = new EventType<>(Event.ANY, "FAILED_ACTION");
}

15 changes: 9 additions & 6 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.ComponentSublist;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
import org.jackhuang.hmcl.upgrade.RemoteVersion;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
Expand Down Expand Up @@ -81,6 +78,7 @@ public final class SettingsPage extends ScrollPane {
private final ToggleGroup updateChannelGroup;
@SuppressWarnings("FieldCanBeLocal")
private final InvalidationListener updateListener;
private final SpinnerPane logExportSpinner;

public SettingsPage() {
this.setFitToWidth(true);
Expand Down Expand Up @@ -302,10 +300,11 @@ else if (locale.isSameLanguage(currentLocale))

JFXButton logButton = FXUtils.newBorderButton(i18n("settings.launcher.launcher_log.export"));
logButton.setOnAction(e -> onExportLogs());
logExportSpinner = new SpinnerPane(logButton);

HBox buttonBox = new HBox();
buttonBox.setSpacing(10);
buttonBox.getChildren().addAll(openLogFolderButton, logButton);
buttonBox.getChildren().addAll(openLogFolderButton, logExportSpinner);
BorderPane.setAlignment(buttonBox, Pos.CENTER_RIGHT);
debugPane.setRight(buttonBox);

Expand Down Expand Up @@ -378,6 +377,7 @@ private static boolean exportLogFile(ZipOutputStream output,
}

private void onExportLogs() {
logExportSpinner.showSpinner();
thread(() -> {
String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss"));
List<Path> recentLogFiles = LOG.findRecentLogFiles(5);
Expand Down Expand Up @@ -454,7 +454,10 @@ private void onExportLogs() {
return;
}

Platform.runLater(() -> Controllers.dialog(i18n("settings.launcher.launcher_log.export.success", outputFile)));
Platform.runLater(() -> {
logExportSpinner.hideSpinner();
Controllers.dialog(i18n("settings.launcher.launcher_log.export.success", outputFile));
});
FXUtils.showFileInExplorer(outputFile);
});
}
Expand Down