Try to fix #462.

This commit is contained in:
huanghongxun
2018-10-05 22:27:19 +08:00
parent 1b1f22b9fa
commit 6b3152c4b5
6 changed files with 65 additions and 99 deletions

View File

@@ -19,10 +19,8 @@ package org.jackhuang.hmcl.setting;
import com.jfoenix.concurrency.JFXUtilities; import com.jfoenix.concurrency.JFXUtilities;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.EventBus;
@@ -30,9 +28,11 @@ import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
import java.io.File; import java.io.File;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static javafx.collections.FXCollections.observableArrayList; import static javafx.collections.FXCollections.observableArrayList;
import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
@@ -43,8 +43,6 @@ public final class Profiles {
public static final String DEFAULT_PROFILE = "Default"; public static final String DEFAULT_PROFILE = "Default";
public static final String HOME_PROFILE = "Home"; public static final String HOME_PROFILE = "Home";
private static InvalidationListener listener = o -> loadVersion();
private Profiles() { private Profiles() {
} }
@@ -65,16 +63,14 @@ public final class Profiles {
private static ObjectProperty<Profile> selectedProfile = new SimpleObjectProperty<Profile>() { private static ObjectProperty<Profile> selectedProfile = new SimpleObjectProperty<Profile>() {
{ {
profiles.addListener(onInvalidating(this::invalidated)); profiles.addListener(onInvalidating(this::invalidated));
this.addListener(this::change);
} }
@Override @Override
protected void invalidated() { protected void invalidated() {
Profile profile = get(); if (!initialized)
return;
if (get() != null) Profile profile = get();
get().removeListener(listener);
if (profiles.isEmpty()) { if (profiles.isEmpty()) {
if (profile != null) { if (profile != null) {
@@ -88,18 +84,20 @@ public final class Profiles {
} }
} }
if (!initialized)
return;
config().setSelectedProfile(profile == null ? "" : profile.getName()); config().setSelectedProfile(profile == null ? "" : profile.getName());
loadVersion(); if (profile != null) {
} if (profile.getRepository().isLoaded())
selectedVersion.bind(profile.selectedVersionProperty());
private void change(ObservableValue<? extends Profile> observableValue, Profile oldProfile, Profile newProfile) { else {
if (oldProfile != null) selectedVersion.unbind();
oldProfile.selectedVersionProperty().removeListener(listener); selectedVersion.set(null);
if (newProfile != null) // bind when repository was reloaded.
newProfile.selectedVersionProperty().addListener(listener); profile.getRepository().refreshVersionsAsync().start();
}
} else {
selectedVersion.unbind();
selectedVersion.set(null);
}
} }
}; };
@@ -154,19 +152,23 @@ public final class Profiles {
// Platform.runLater is necessary or profiles will be empty // Platform.runLater is necessary or profiles will be empty
// since checkProfiles adds 2 base profile later. // since checkProfiles adds 2 base profile later.
Platform.runLater(() -> { Platform.runLater(() -> {
initialized = true;
selectedProfile.set( selectedProfile.set(
profiles.stream() profiles.stream()
.filter(it -> it.getName().equals(config().getSelectedProfile())) .filter(it -> it.getName().equals(config().getSelectedProfile()))
.findFirst() .findFirst()
.orElse(profiles.get(0))); .orElse(profiles.get(0)));
initialized = true;
}); });
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> { EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> {
JFXUtilities.runInFX(() -> { JFXUtilities.runInFX(() -> {
if (selectedProfile.get() != null && selectedProfile.get().getRepository() == event.getSource()) Profile profile = selectedProfile.get();
loadVersion(); if (profile != null && profile.getRepository() == event.getSource()) {
selectedVersion.bind(profile.selectedVersionProperty());
for (Consumer<Profile> listener : versionsListeners)
listener.accept(profile);
}
}); });
}); });
} }
@@ -197,14 +199,17 @@ public final class Profiles {
return selectedVersion.getReadOnlyProperty(); return selectedVersion.getReadOnlyProperty();
} }
// Guaranteed that the repository is loaded.
public static String getSelectedVersion() { public static String getSelectedVersion() {
return selectedVersion.get(); return selectedVersion.get();
} }
private static void loadVersion() { private static final List<Consumer<Profile>> versionsListeners = new LinkedList<>();
Profile profile = selectedProfile.get();
if (profile == null || !profile.getRepository().isLoaded()) return; public static void registerVersionsListener(Consumer<Profile> listener) {
JFXUtilities.runInFX(() -> Profile profile = getSelectedProfile();
selectedVersion.set(profile.getSelectedVersion())); if (profile != null && profile.getRepository().isLoaded())
listener.accept(profile);
versionsListeners.add(listener);
} }
} }

View File

@@ -90,13 +90,13 @@ public final class FXUtils {
} }
public static <T> void onChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) { public static <T> void onChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) {
onChange(value, consumer);
consumer.accept(value.getValue()); consumer.accept(value.getValue());
onChange(value, consumer);
} }
public static <T> void onWeakChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) { public static <T> void onWeakChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) {
onWeakChange(value, consumer);
consumer.accept(value.getValue()); consumer.accept(value.getValue());
onWeakChange(value, consumer);
} }
public static void runLaterIf(BooleanSupplier condition, Runnable runnable) { public static void runLaterIf(BooleanSupplier condition, Runnable runnable) {

View File

@@ -33,8 +33,6 @@ import javafx.scene.control.Label;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle; import javafx.scene.shape.Rectangle;
import javafx.util.Duration; import javafx.util.Duration;
import org.jackhuang.hmcl.event.EventBus;
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
import org.jackhuang.hmcl.game.HMCLGameRepository; import org.jackhuang.hmcl.game.HMCLGameRepository;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Profiles;
@@ -81,7 +79,6 @@ public final class MainPage extends StackPane implements DecoratorPage {
@FXML @FXML
private Rectangle separator; private Rectangle separator;
private Profile profile;
{ {
FXUtils.loadFXML(this, "/assets/fxml/main.fxml"); FXUtils.loadFXML(this, "/assets/fxml/main.fxml");
@@ -126,41 +123,30 @@ public final class MainPage extends StackPane implements DecoratorPage {
} }
}); });
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> { Profiles.registerVersionsListener(this::loadVersions);
if (event.getSource() == profile.getRepository())
loadVersions((HMCLGameRepository) event.getSource());
});
Profiles.selectedProfileProperty().addListener((a, b, newValue) -> profile = newValue);
profile = Profiles.getSelectedProfile();
if (profile != null) {
if (profile.getRepository().isLoaded())
loadVersions(profile.getRepository());
else
profile.getRepository().refreshVersionsAsync().start();
}
} }
private void loadVersions(HMCLGameRepository repository) { private void loadVersions(Profile profile) {
HMCLGameRepository repository = profile.getRepository();
List<Node> children = repository.getVersions().parallelStream() List<Node> children = repository.getVersions().parallelStream()
.filter(version -> !version.isHidden()) .filter(version -> !version.isHidden())
.sorted((a, b) -> VersionNumber.COMPARATOR.compare(VersionNumber.asVersion(a.getId()), VersionNumber.asVersion(b.getId()))) .sorted((a, b) -> VersionNumber.COMPARATOR.compare(VersionNumber.asVersion(a.getId()), VersionNumber.asVersion(b.getId())))
.map(version -> { .map(version -> {
StackPane pane = new StackPane(); StackPane pane = new StackPane();
GameItem item = new GameItem(repository.getProfile(), version.getId()); GameItem item = new GameItem(profile, version.getId());
pane.getChildren().setAll(item); pane.getChildren().setAll(item);
pane.getStyleClass().setAll("menu-container"); pane.getStyleClass().setAll("menu-container");
item.setMouseTransparent(true); item.setMouseTransparent(true);
RipplerContainer container = new RipplerContainer(pane); RipplerContainer container = new RipplerContainer(pane);
container.setOnMouseClicked(e -> { container.setOnMouseClicked(e -> {
repository.getProfile().setSelectedVersion(version.getId()); profile.setSelectedVersion(version.getId());
popup.hide(); popup.hide();
}); });
return container; return container;
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
JFXUtilities.runInFX(() -> { JFXUtilities.runInFX(() -> {
if (profile == repository.getProfile()) if (profile == Profiles.getSelectedProfile())
menu.getContent().setAll(children); menu.getContent().setAll(children);
}); });
} }

View File

@@ -24,6 +24,7 @@ import javafx.animation.KeyValue;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -78,7 +79,6 @@ class ComponentListCell extends StackPane {
content.getStyleClass().add("options-sublist"); content.getStyleClass().add("options-sublist");
BorderPane groupNode = new BorderPane(); BorderPane groupNode = new BorderPane();
groupNode.getStyleClass().add("options-list-item-header");
Node expandIcon = SVG.expand(Theme.blackFillBinding(), 10, 10); Node expandIcon = SVG.expand(Theme.blackFillBinding(), 10, 10);
JFXButton expandButton = new JFXButton(); JFXButton expandButton = new JFXButton();
@@ -86,6 +86,7 @@ class ComponentListCell extends StackPane {
expandButton.getStyleClass().add("options-list-item-expand-button"); expandButton.getStyleClass().add("options-list-item-expand-button");
VBox labelVBox = new VBox(); VBox labelVBox = new VBox();
labelVBox.setAlignment(Pos.CENTER_LEFT);
if (list instanceof ComponentSublist) { if (list instanceof ComponentSublist) {
Node leftNode = ((ComponentSublist) list).getHeaderLeft(); Node leftNode = ((ComponentSublist) list).getHeaderLeft();
@@ -94,13 +95,11 @@ class ComponentListCell extends StackPane {
} else { } else {
Label label = new Label(); Label label = new Label();
label.textProperty().bind(list.titleProperty()); label.textProperty().bind(list.titleProperty());
label.setMouseTransparent(true);
labelVBox.getChildren().add(label); labelVBox.getChildren().add(label);
if (list.isHasSubtitle()) { if (list.isHasSubtitle()) {
Label subtitleLabel = new Label(); Label subtitleLabel = new Label();
subtitleLabel.textProperty().bind(list.subtitleProperty()); subtitleLabel.textProperty().bind(list.subtitleProperty());
subtitleLabel.setMouseTransparent(true);
subtitleLabel.getStyleClass().add("subtitle-label"); subtitleLabel.getStyleClass().add("subtitle-label");
labelVBox.getChildren().add(subtitleLabel); labelVBox.getChildren().add(subtitleLabel);
} }
@@ -109,6 +108,7 @@ class ComponentListCell extends StackPane {
groupNode.setLeft(labelVBox); groupNode.setLeft(labelVBox);
HBox right = new HBox(); HBox right = new HBox();
right.setAlignment(Pos.CENTER_RIGHT);
if (list instanceof ComponentSublist) { if (list instanceof ComponentSublist) {
Node rightNode = ((ComponentSublist) list).getHeaderRight(); Node rightNode = ((ComponentSublist) list).getHeaderRight();
if (rightNode != null) if (rightNode != null)
@@ -116,18 +116,13 @@ class ComponentListCell extends StackPane {
} }
right.getChildren().add(expandButton); right.getChildren().add(expandButton);
groupNode.setRight(right); groupNode.setRight(right);
labelVBox.setAlignment(Pos.CENTER_LEFT);
right.setAlignment(Pos.CENTER_RIGHT);
VBox container = new VBox(); VBox container = new VBox();
container.setStyle("-fx-padding: 8 0 0 0;"); container.setPadding(new Insets(8, 0, 0, 0));
FXUtils.setLimitHeight(container, 0); FXUtils.setLimitHeight(container, 0);
FXUtils.setOverflowHidden(container, true); FXUtils.setOverflowHidden(container, true);
container.getChildren().setAll(content); container.getChildren().setAll(content);
groupNode.setBottom(container);
VBox holder = new VBox();
holder.getChildren().setAll(groupNode, container);
holder.getStyleClass().add("options-list-item-container");
expandButton.setOnMouseClicked(e -> { expandButton.setOnMouseClicked(e -> {
if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) { if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) {
@@ -159,7 +154,7 @@ class ComponentListCell extends StackPane {
expandedProperty().addListener((a, b, newValue) -> expandedProperty().addListener((a, b, newValue) ->
expandIcon.setRotate(newValue ? 180 : 0)); expandIcon.setRotate(newValue ? 180 : 0));
getChildren().setAll(holder); getChildren().setAll(groupNode);
} else } else
getChildren().setAll(content); getChildren().setAll(content);
} }

View File

@@ -17,39 +17,28 @@
*/ */
package org.jackhuang.hmcl.ui.versions; package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.concurrency.JFXUtilities;
import javafx.beans.InvalidationListener;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import org.jackhuang.hmcl.event.EventBus;
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.WeakListenerHolder;
import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
import java.io.File;
import java.util.Objects;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class GameAdvancedListItem extends AdvancedListItem { public class GameAdvancedListItem extends AdvancedListItem {
public GameAdvancedListItem() { public GameAdvancedListItem() {
FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), version -> { FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), version -> {
FXUtils.runLaterIf(() -> !Objects.nonNull(Profiles.getSelectedProfile()), () -> { if (version != null) {
imageProperty().set(Profiles.getSelectedProfile().getRepository().getVersionIconImage(version)); setTitle(version);
setSubtitle(null);
if (version != null) { setImage(Profiles.getSelectedProfile().getRepository().getVersionIconImage(version));
setTitle(version); } else {
setSubtitle(null); setTitle(i18n("version.empty"));
} else { setSubtitle(i18n("version.empty.add"));
setTitle(i18n("version.empty")); setImage(new Image("/assets/img/grass.png"));
setSubtitle(i18n("version.empty.add")); }
}
});
}); });
setRightGraphic(SVG.gear(Theme.blackFillBinding(), -1, -1)); setRightGraphic(SVG.gear(Theme.blackFillBinding(), -1, -1));

View File

@@ -47,28 +47,19 @@ public class GameList extends Control implements DecoratorPage {
private final BooleanProperty loading = new SimpleBooleanProperty(true); private final BooleanProperty loading = new SimpleBooleanProperty(true);
private final ListProperty<GameListItem> items = new SimpleListProperty<>(FXCollections.observableArrayList()); private final ListProperty<GameListItem> items = new SimpleListProperty<>(FXCollections.observableArrayList());
private Profile profile;
private ToggleGroup toggleGroup; private ToggleGroup toggleGroup;
public GameList() { public GameList() {
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> {
if (event.getSource() == profile.getRepository())
loadVersions((HMCLGameRepository) event.getSource());
});
EventBus.EVENT_BUS.channel(RefreshingVersionsEvent.class).register(event -> { EventBus.EVENT_BUS.channel(RefreshingVersionsEvent.class).register(event -> {
if (event.getSource() == profile.getRepository()) if (event.getSource() == Profiles.getSelectedProfile().getRepository())
JFXUtilities.runInFX(() -> loading.set(true)); JFXUtilities.runInFX(() -> loading.set(true));
}); });
Profiles.selectedProfileProperty().addListener((a, b, newValue) -> profile = newValue);
profile = Profiles.getSelectedProfile(); Profiles.registerVersionsListener(this::loadVersions);
if (profile.getRepository().isLoaded())
loadVersions(profile.getRepository());
else
profile.getRepository().refreshVersionsAsync().start();
} }
private void loadVersions(HMCLGameRepository repository) { private void loadVersions(Profile profile) {
HMCLGameRepository repository = profile.getRepository();
toggleGroup = new ToggleGroup(); toggleGroup = new ToggleGroup();
WeakListenerHolder listenerHolder = new WeakListenerHolder(); WeakListenerHolder listenerHolder = new WeakListenerHolder();
toggleGroup.getProperties().put("ReferenceHolder", listenerHolder); toggleGroup.getProperties().put("ReferenceHolder", listenerHolder);
@@ -78,7 +69,7 @@ public class GameList extends Control implements DecoratorPage {
.map(version -> new GameListItem(toggleGroup, profile, version.getId())) .map(version -> new GameListItem(toggleGroup, profile, version.getId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
JFXUtilities.runInFX(() -> { JFXUtilities.runInFX(() -> {
if (profile == repository.getProfile()) { if (profile == Profiles.getSelectedProfile()) {
loading.set(false); loading.set(false);
items.setAll(children); items.setAll(children);
children.forEach(GameListItem::checkSelection); children.forEach(GameListItem::checkSelection);
@@ -115,11 +106,11 @@ public class GameList extends Control implements DecoratorPage {
} }
public void refresh() { public void refresh() {
profile.getRepository().refreshVersionsAsync().start(); Profiles.getSelectedProfile().getRepository().refreshVersionsAsync().start();
} }
public void modifyGlobalGameSettings() { public void modifyGlobalGameSettings() {
Versions.modifyGlobalSettings(profile); Versions.modifyGlobalSettings(Profiles.getSelectedProfile());
} }
@Override @Override