Merge pull request #425 from yushijinhun/yushijinhun/javafx

修复 UpdateChecker 潜在问题 & 弃用 ImmediateXXXProperty
This commit is contained in:
huanghongxun
2018-08-19 19:47:30 +08:00
committed by GitHub
10 changed files with 81 additions and 237 deletions

View File

@@ -17,23 +17,19 @@
*/ */
package org.jackhuang.hmcl; package org.jackhuang.hmcl;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.Logging.LOG;
import com.jfoenix.concurrency.JFXUtilities; import com.jfoenix.concurrency.JFXUtilities;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.*;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
@@ -42,7 +38,6 @@ import java.nio.file.Paths;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public final class Launcher extends Application { public final class Launcher extends Application {
@@ -58,24 +53,7 @@ public final class Launcher extends Application {
primaryStage.setResizable(false); primaryStage.setResizable(false);
primaryStage.setScene(Controllers.getScene()); primaryStage.setScene(Controllers.getScene());
UpdateChecker.updateChannelProperty().addListener(observable -> { UpdateChecker.init();
thread(() -> {
try {
UpdateChecker.checkUpdate();
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to check for update", e);
}
});
});
UpdateChecker.updateChannelProperty().bind(Bindings.createStringBinding(() -> {
switch (ConfigHolder.config().getUpdateChannel()) {
case DEVELOPMENT:
return UpdateChecker.CHANNEL_DEV;
default:
return UpdateChecker.CHANNEL_STABLE;
}
}, ConfigHolder.config().updateChannelProperty()));
primaryStage.show(); primaryStage.show();
} catch (Throwable e) { } catch (Throwable e) {

View File

@@ -30,6 +30,7 @@ import org.hildan.fxgson.creators.ObservableSetCreator;
import org.hildan.fxgson.factories.JavaFxPropertyTypeAdapterFactory; import org.hildan.fxgson.factories.JavaFxPropertyTypeAdapterFactory;
import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.util.EnumOrdinalDeserializer; import org.jackhuang.hmcl.util.EnumOrdinalDeserializer;
import org.jackhuang.hmcl.util.FileTypeAdapter; import org.jackhuang.hmcl.util.FileTypeAdapter;
import org.jackhuang.hmcl.util.ObservableHelper; import org.jackhuang.hmcl.util.ObservableHelper;
@@ -150,7 +151,7 @@ public final class Config implements Cloneable, Observable {
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList(); private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList();
@SerializedName("updateChannel") @SerializedName("updateChannel")
private ObjectProperty<EnumUpdateChannel> updateChannel = new SimpleObjectProperty<>(EnumUpdateChannel.STABLE); private ObjectProperty<UpdateChannel> updateChannel = new SimpleObjectProperty<>(UpdateChannel.STABLE);
@SerializedName("_version") @SerializedName("_version")
private IntegerProperty configVersion = new SimpleIntegerProperty(0); private IntegerProperty configVersion = new SimpleIntegerProperty(0);
@@ -438,15 +439,15 @@ public final class Config implements Cloneable, Observable {
return authlibInjectorServers; return authlibInjectorServers;
} }
public EnumUpdateChannel getUpdateChannel() { public UpdateChannel getUpdateChannel() {
return updateChannel.get(); return updateChannel.get();
} }
public ObjectProperty<EnumUpdateChannel> updateChannelProperty() { public ObjectProperty<UpdateChannel> updateChannelProperty() {
return updateChannel; return updateChannel;
} }
public void setUpdateChannel(EnumUpdateChannel updateChannel) { public void setUpdateChannel(UpdateChannel updateChannel) {
this.updateChannel.set(updateChannel); this.updateChannel.set(updateChannel);
} }
} }

View File

@@ -46,6 +46,7 @@ import org.jackhuang.hmcl.ui.construct.FontComboBox;
import org.jackhuang.hmcl.ui.construct.MultiFileItem; import org.jackhuang.hmcl.ui.construct.MultiFileItem;
import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.construct.Validator;
import org.jackhuang.hmcl.ui.wizard.DecoratorPage; import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.upgrade.RemoteVersion; import org.jackhuang.hmcl.upgrade.RemoteVersion;
import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.upgrade.UpdateChecker;
import org.jackhuang.hmcl.upgrade.UpdateHandler; import org.jackhuang.hmcl.upgrade.UpdateHandler;
@@ -242,24 +243,24 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
lblUpdateNote.setWrappingWidth(470); lblUpdateNote.setWrappingWidth(470);
ObjectProperty<EnumUpdateChannel> updateChannel = new SimpleObjectProperty<EnumUpdateChannel>() { ObjectProperty<UpdateChannel> updateChannel = new SimpleObjectProperty<UpdateChannel>() {
@Override @Override
protected void invalidated() { protected void invalidated() {
EnumUpdateChannel updateChannel = Objects.requireNonNull(get()); UpdateChannel updateChannel = Objects.requireNonNull(get());
chkUpdateDev.setSelected(updateChannel == EnumUpdateChannel.DEVELOPMENT); chkUpdateDev.setSelected(updateChannel == UpdateChannel.DEVELOPMENT);
chkUpdateStable.setSelected(updateChannel == EnumUpdateChannel.STABLE); chkUpdateStable.setSelected(updateChannel == UpdateChannel.STABLE);
} }
}; };
ToggleGroup updateChannelGroup = new ToggleGroup(); ToggleGroup updateChannelGroup = new ToggleGroup();
chkUpdateDev.setToggleGroup(updateChannelGroup); chkUpdateDev.setToggleGroup(updateChannelGroup);
chkUpdateDev.setUserData(EnumUpdateChannel.DEVELOPMENT); chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
chkUpdateStable.setToggleGroup(updateChannelGroup); chkUpdateStable.setToggleGroup(updateChannelGroup);
chkUpdateStable.setUserData(EnumUpdateChannel.STABLE); chkUpdateStable.setUserData(UpdateChannel.STABLE);
updateChannelGroup.getToggles().forEach( updateChannelGroup.getToggles().forEach(
toggle -> toggle.selectedProperty().addListener((observable, oldValue, newValue) -> { toggle -> toggle.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) { if (newValue) {
updateChannel.set((EnumUpdateChannel) toggle.getUserData()); updateChannel.set((UpdateChannel) toggle.getUserData());
} }
})); }));
updateChannel.bindBidirectional(ConfigHolder.config().updateChannelProperty()); updateChannel.bindBidirectional(ConfigHolder.config().updateChannelProperty());

View File

@@ -1,6 +1,6 @@
/* /*
* Hello Minecraft! Launcher. * Hello Minecraft! Launcher.
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com> * Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -15,9 +15,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}. * along with this program. If not, see {http://www.gnu.org/licenses/}.
*/ */
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.upgrade;
public enum EnumUpdateChannel { public enum UpdateChannel {
STABLE, STABLE("stable"),
DEVELOPMENT DEVELOPMENT("dev");
public final String channelName;
UpdateChannel(String channelName) {
this.channelName = channelName;
}
} }

View File

@@ -17,16 +17,20 @@
*/ */
package org.jackhuang.hmcl.upgrade; package org.jackhuang.hmcl.upgrade;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.VersionNumber.asVersion; import static org.jackhuang.hmcl.util.VersionNumber.asVersion;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Level;
import com.jfoenix.concurrency.JFXUtilities;
import javafx.beans.property.*; import javafx.beans.property.*;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.util.ImmediateStringProperty; import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.util.NetworkUtils; import org.jackhuang.hmcl.util.NetworkUtils;
import javafx.application.Platform; import javafx.application.Platform;
@@ -37,11 +41,6 @@ import javafx.beans.value.ObservableBooleanValue;
public final class UpdateChecker { public final class UpdateChecker {
private UpdateChecker() {} private UpdateChecker() {}
public static final String CHANNEL_STABLE = "stable";
public static final String CHANNEL_DEV = "dev";
private static StringProperty updateChannel = new ImmediateStringProperty(null, "updateChannel", CHANNEL_STABLE);
private static ObjectProperty<RemoteVersion> latestVersion = new SimpleObjectProperty<>(); private static ObjectProperty<RemoteVersion> latestVersion = new SimpleObjectProperty<>();
private static BooleanBinding outdated = Bindings.createBooleanBinding( private static BooleanBinding outdated = Bindings.createBooleanBinding(
() -> { () -> {
@@ -55,16 +54,9 @@ public final class UpdateChecker {
latestVersion); latestVersion);
private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false); private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
public static String getUpdateChannel() { public static void init() {
return updateChannel.get(); ConfigHolder.config().updateChannelProperty().addListener(onInvalidating(UpdateChecker::requestCheckUpdate));
} requestCheckUpdate();
public static void setUpdateChannel(String updateChannel) {
UpdateChecker.updateChannel.set(updateChannel);
}
public static StringProperty updateChannelProperty() {
return updateChannel;
} }
public static RemoteVersion getLatestVersion() { public static RemoteVersion getLatestVersion() {
@@ -91,35 +83,53 @@ public final class UpdateChecker {
return checkingUpdate.getReadOnlyProperty(); return checkingUpdate.getReadOnlyProperty();
} }
public static void checkUpdate() throws IOException { private static RemoteVersion checkUpdate(UpdateChannel channel) throws IOException {
if (!IntegrityChecker.isSelfVerified()) { if (!IntegrityChecker.isSelfVerified()) {
return; throw new IOException("Self verification failed");
} }
JFXUtilities.runInFXAndWait(() -> { String url = NetworkUtils.withQuery(Metadata.UPDATE_URL, mapOf(
checkingUpdate.set(true); pair("version", Metadata.VERSION),
}); pair("channel", channel.channelName)));
try { return RemoteVersion.fetch(url);
String channel = getUpdateChannel();
String url = NetworkUtils.withQuery(Metadata.UPDATE_URL, mapOf(
pair("version", Metadata.VERSION),
pair("channel", channel)));
RemoteVersion fetched = RemoteVersion.fetch(url);
Platform.runLater(() -> {
if (channel.equals(getUpdateChannel())) {
latestVersion.set(fetched);
}
});
} finally {
Platform.runLater(() -> checkingUpdate.set(false));
}
} }
private static boolean isDevelopmentVersion(String version) { private static boolean isDevelopmentVersion(String version) {
return version.contains("@") || // eg. @develop@ return version.contains("@") || // eg. @develop@
version.contains("SNAPSHOT"); // eg. 3.1.SNAPSHOT version.contains("SNAPSHOT"); // eg. 3.1.SNAPSHOT
} }
public static void requestCheckUpdate() {
Platform.runLater(() -> {
if (isCheckingUpdate())
return;
checkingUpdate.set(true);
UpdateChannel channel = config().getUpdateChannel();
thread(() -> {
RemoteVersion result = null;
try {
result = checkUpdate(channel);
LOG.info("Latest version (" + channel + ") is " + result);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to check for update", e);
}
RemoteVersion finalResult = result;
Platform.runLater(() -> {
checkingUpdate.set(false);
if (finalResult != null) {
if (channel.equals(config().getUpdateChannel())) {
latestVersion.set(finalResult);
} else {
// the channel has been changed during the period
// check update again
requestCheckUpdate();
}
}
});
});
});
}
} }

View File

@@ -21,13 +21,11 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.Objects;
import java.util.function.Consumer;
/** /**
*
* @author huangyuhui * @author huangyuhui
* @deprecated Use SimpleBooleanProperty instead
*/ */
@Deprecated
public class ImmediateBooleanProperty extends SimpleBooleanProperty { public class ImmediateBooleanProperty extends SimpleBooleanProperty {
@Override @Override
@@ -48,31 +46,9 @@ public class ImmediateBooleanProperty extends SimpleBooleanProperty {
super.unbind(); super.unbind();
} }
private Consumer<Boolean> consumer = null;
private ChangeListener<Boolean> listener = null;
public void setChangedListener(Consumer<Boolean> consumer) {
this.consumer = Objects.requireNonNull(consumer);
this.listener = null;
}
public void setChangedListener(ChangeListener<Boolean> listener) {
this.consumer = null;
this.listener = Objects.requireNonNull(listener);
}
public void setChangedListenerAndOperate(Consumer<Boolean> listener) {
setChangedListener(listener);
listener.accept(get());
}
public ImmediateBooleanProperty(Object bean, String name, boolean initialValue) { public ImmediateBooleanProperty(Object bean, String name, boolean initialValue) {
super(bean, name, initialValue); super(bean, name, initialValue);
ChangeListener<Boolean> changeListener = (a, b, newValue) -> { ChangeListener<Boolean> changeListener = (a, b, newValue) -> {
if (consumer != null)
consumer.accept(newValue);
if (listener != null)
listener.changed(a, b, newValue);
}; };
addListener(changeListener); addListener(changeListener);
} }

View File

@@ -1,81 +0,0 @@
/*
* Hello Minecraft! Launcher.
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
*
* 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 {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hmcl.util;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import java.util.Objects;
import java.util.function.Consumer;
/**
*
* @author huangyuhui
*/
public class ImmediateDoubleProperty extends SimpleDoubleProperty {
@Override
public void set(double newValue) {
super.get();
super.set(newValue);
}
@Override
public void bind(ObservableValue<? extends Number> newObservable) {
super.get();
super.bind(newObservable);
}
@Override
public void unbind() {
super.get();
super.unbind();
}
private Consumer<Double> consumer = null;
private ChangeListener<Number> listener = null;
public void setChangedListener(Consumer<Double> consumer) {
this.consumer = Objects.requireNonNull(consumer);
this.listener = null;
}
public void setChangedListener(ChangeListener<Number> listener) {
this.consumer = null;
this.listener = Objects.requireNonNull(listener);
}
public void setChangedListenerAndOperate(Consumer<Double> listener) {
setChangedListener(listener);
listener.accept(get());
}
public ImmediateDoubleProperty(Object bean, String name, double initialValue) {
super(bean, name, initialValue);
ChangeListener<Number> changeListener = (a, b, newValue) -> {
if (consumer != null)
consumer.accept(newValue.doubleValue());
if (listener != null)
listener.changed(a, b, newValue);
};
addListener(changeListener);
}
}

View File

@@ -21,13 +21,11 @@ import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.Objects;
import java.util.function.Consumer;
/** /**
*
* @author huangyuhui * @author huangyuhui
* @deprecated Use SimpleIntegerProperty instead
*/ */
@Deprecated
public class ImmediateIntegerProperty extends SimpleIntegerProperty { public class ImmediateIntegerProperty extends SimpleIntegerProperty {
@Override @Override
@@ -48,31 +46,9 @@ public class ImmediateIntegerProperty extends SimpleIntegerProperty {
super.unbind(); super.unbind();
} }
private Consumer<Integer> consumer = null;
private ChangeListener<Number> listener = null;
public void setChangedListener(Consumer<Integer> consumer) {
this.consumer = Objects.requireNonNull(consumer);
this.listener = null;
}
public void setChangedListener(ChangeListener<Number> listener) {
this.consumer = null;
this.listener = Objects.requireNonNull(listener);
}
public void setChangedListenerAndOperate(Consumer<Integer> listener) {
setChangedListener(listener);
listener.accept(get());
}
public ImmediateIntegerProperty(Object bean, String name, int initialValue) { public ImmediateIntegerProperty(Object bean, String name, int initialValue) {
super(bean, name, initialValue); super(bean, name, initialValue);
ChangeListener<Number> changeListener = (a, b, newValue) -> { ChangeListener<Number> changeListener = (a, b, newValue) -> {
if (consumer != null)
consumer.accept(newValue.intValue());
if (listener != null)
listener.changed(a, b, newValue);
}; };
addListener(changeListener); addListener(changeListener);
} }

View File

@@ -21,13 +21,11 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.Objects;
import java.util.function.Consumer;
/** /**
*
* @author huangyuhui * @author huangyuhui
* @deprecated Use SimpleObjectProperty instead
*/ */
@Deprecated
public class ImmediateObjectProperty<T> extends SimpleObjectProperty<T> { public class ImmediateObjectProperty<T> extends SimpleObjectProperty<T> {
@Override @Override
@@ -48,31 +46,9 @@ public class ImmediateObjectProperty<T> extends SimpleObjectProperty<T> {
super.unbind(); super.unbind();
} }
private Consumer<T> consumer = null;
private ChangeListener<T> listener = null;
public void setChangedListener(Consumer<T> consumer) {
this.consumer = Objects.requireNonNull(consumer);
this.listener = null;
}
public void setChangedListener(ChangeListener<T> listener) {
this.consumer = null;
this.listener = Objects.requireNonNull(listener);
}
public void setChangedListenerAndOperate(Consumer<T> listener) {
setChangedListener(listener);
listener.accept(get());
}
public ImmediateObjectProperty(Object bean, String name, T initialValue) { public ImmediateObjectProperty(Object bean, String name, T initialValue) {
super(bean, name, initialValue); super(bean, name, initialValue);
ChangeListener<T> changeListener = (a, b, newValue) -> { ChangeListener<T> changeListener = (a, b, newValue) -> {
if (consumer != null)
consumer.accept(newValue);
if (listener != null)
listener.changed(a, b, newValue);
}; };
addListener(changeListener); addListener(changeListener);
} }

View File

@@ -25,9 +25,10 @@ import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
*
* @author huangyuhui * @author huangyuhui
* @deprecated Use SimpleStringProperty instead
*/ */
@Deprecated
public class ImmediateStringProperty extends SimpleStringProperty { public class ImmediateStringProperty extends SimpleStringProperty {
@Override @Override