Work on porting stuff to javafx properties

This commit is contained in:
dorving 2023-03-29 19:16:21 +02:00
parent 6a9b1201ac
commit 850e89eb5e
29 changed files with 662 additions and 453 deletions

View File

@ -299,6 +299,12 @@
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>com.dustinredmond.fxtrayicon</groupId>
<artifactId>FXTrayIcon</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
<repositories>

View File

@ -1,41 +1,33 @@
package gearth;
import gearth.misc.AdminValidator;
import gearth.misc.Cacher;
import gearth.misc.UpdateChecker;
import gearth.misc.listenerpattern.ObservableObject;
import gearth.ui.GEarthController;
import gearth.ui.GEarthProperties;
import gearth.ui.themes.Theme;
import gearth.ui.themes.ThemeFactory;
import gearth.ui.titlebar.TitleBarConfig;
import gearth.ui.titlebar.TitleBarController;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import java.io.IOException;
public class GEarth extends Application {
public static GEarth main;
public static String version = "1.5.3";
public static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest";
public static ObservableObject<Theme> observableTheme;
private Stage stage;
private GEarthController controller;
static {
observableTheme = new ObservableObject<>(
Cacher.getCacheContents().has("theme") ?
ThemeFactory.themeForTitle(Cacher.getCacheContents().getString("theme")) :
ThemeFactory.getDefaultTheme()
);
}
@Override
public void start(Stage primaryStage) throws Exception{
@ -52,9 +44,28 @@ public class GEarth extends Application {
}
controller = loader.getController();
controller.setStage(primaryStage);
stage.initStyle(StageStyle.TRANSPARENT);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(new Scene(root));
primaryStage.setAlwaysOnTop(GEarthProperties.isAlwaysOnTop());
GEarthProperties.alwaysOnTopProperty
.addListener((observable, oldValue, newValue) -> primaryStage.setAlwaysOnTop(newValue));
initTitleBar(primaryStage);
initTheme();
primaryStage.setResizable(false);
primaryStage.sizeToScene();
primaryStage.show();
primaryStage.setOnCloseRequest(event -> closeGEarth());
AdminValidator.validate();
UpdateChecker.checkForUpdates();
}
private void initTitleBar(Stage primaryStage) throws IOException {
TitleBarController.create(primaryStage, new TitleBarConfig() {
@Override
public boolean displayThemePicker() {
@ -66,11 +77,6 @@ public class GEarth extends Application {
return true;
}
// @Override
// public boolean allowResizing() {
// return false;
// }
@Override
public void onCloseClicked() {
closeGEarth();
@ -83,25 +89,20 @@ public class GEarth extends Application {
@Override
public void setTheme(Theme theme) {
setGearthTheme(theme);
GEarthProperties.themeProperty.set(theme);
}
@Override
public Theme getCurrentTheme() {
return observableTheme.getObject();
return GEarthProperties.getTheme();
}
});
primaryStage.setResizable(false);
primaryStage.sizeToScene();
setGearthTheme(observableTheme.getObject());
primaryStage.show();
primaryStage.setOnCloseRequest(event -> closeGEarth());
AdminValidator.validate();
UpdateChecker.checkForUpdates();
}
private void initTheme() {
stage.titleProperty().bind(GEarthProperties.themeTitleBinding);
Bindings.bindContent(stage.getScene().getStylesheets(), GEarthProperties.styleSheets);
Bindings.bindContent(stage.getIcons(), GEarthProperties.icons);
}
private void closeGEarth() {
@ -110,30 +111,6 @@ public class GEarth extends Application {
System.exit(0);
}
private void setGearthTheme(Theme theme) {
Cacher.put("theme", theme.title());
observableTheme.setObject(theme);
Theme defaultTheme = ThemeFactory.getDefaultTheme();
// Platform.runLater(() -> {
stage.getScene().getStylesheets().clear();
stage.getScene().getStylesheets().add(GEarth.class.getResource(String.format("/gearth/ui/themes/%s/styling.css", theme.internalName())).toExternalForm());
stage.getIcons().clear();
stage.getIcons().add(new Image(GEarth.class.getResourceAsStream(String.format("/gearth/ui/themes/%s/logoSmall.png", theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName()))));
stage.setTitle((theme.overridesTitle() ? theme.title() : defaultTheme.title()) + " " + GEarth.version);
controller.infoController.img_logo.setImage(new Image(GEarth.class.getResourceAsStream(
String.format(
"/gearth/ui/themes/%s/logo.png",
theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName()
)
)));
controller.infoController.version.setText(stage.getTitle());
// });
}
public static String[] args;
public static void main(String[] args) {
@ -161,14 +138,6 @@ public class GEarth extends Application {
return null;
}
public static ObservableObject<Theme> getThemeObservable() {
return observableTheme;
}
public static Theme getTheme() {
return observableTheme.getObject();
}
public static void setAlertOwner(Alert alert) {
alert.initOwner(main.stage);
}

View File

@ -2,19 +2,14 @@ package gearth.extensions;
import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
import gearth.misc.listenerpattern.ObservableObject;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import javafx.beans.property.ObjectProperty;
import org.reactfx.util.Lists;
import javafx.beans.property.SimpleObjectProperty;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
public abstract class ExtensionBase extends IExtension {
@ -33,10 +28,11 @@ public abstract class ExtensionBase extends IExtension {
volatile PacketInfoManager packetInfoManager = PacketInfoManager.EMPTY;
ObservableObject<HostInfo> observableHostInfo = new ObservableObject<>(null);
ObjectProperty<HostInfo> hostInfoProperty = new SimpleObjectProperty<>();
void updateHostInfo(HostInfo hostInfo) {
observableHostInfo.setObject(hostInfo);
hostInfoProperty.set(hostInfo);
}
/**
@ -67,7 +63,7 @@ public abstract class ExtensionBase extends IExtension {
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, String hashOrName, MessageListener messageListener) {
Map<String, List<MessageListener>> listeners =
final Map<String, List<MessageListener>> listeners =
direction == HMessage.Direction.TOCLIENT ?
hashOrNameIncomingListeners :
hashOrNameOutgoingListeners;
@ -197,6 +193,6 @@ public abstract class ExtensionBase extends IExtension {
}
public HostInfo getHostInfo() {
return observableHostInfo.getObject();
return hostInfoProperty.get();
}
}

View File

@ -1,17 +1,17 @@
package gearth.extensions;
import com.sun.org.apache.xpath.internal.operations.Bool;
import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
import gearth.services.packet_info.PacketInfoManager;
import javafx.application.HostServices;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.stage.Stage;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.util.function.Consumer;
/**
* Created by Jonas on 22/09/18.
*/
@ -99,8 +99,17 @@ public abstract class ExtensionForm extends ExtensionBase {
}
public HostInfo getHostInfo() {
return extension.observableHostInfo.getObject();
return extension.hostInfoProperty.get();
}
private final BooleanProperty fieldsInitializedProperty = new SimpleBooleanProperty(false);
public void setFieldsInitialised(boolean value) {
fieldsInitializedProperty.set(value);
}
public BooleanProperty fieldsInitialisedProperty() {
return fieldsInitializedProperty;
}
Observable<Runnable> fieldsInitialized = new Observable<>(Runnable::run);
}

View File

@ -60,7 +60,8 @@ public class ExtensionFormLauncher extends Application {
extensionForm.extension = extension;
extensionForm.primaryStage = primaryStage;
extensionForm.fieldsInitialized.fireEvent();
extensionForm.setFieldsInitialised(true);
Thread t = new Thread(() -> {
extension.run();
//when the extension has ended, close this process

View File

@ -55,7 +55,7 @@ public class InternalExtensionFormLauncher<L extends InternalExtensionFormCreato
extensionForm.extension = internalExtension;
extensionForm.primaryStage = stage;
extensionForm.fieldsInitialized.fireEvent();
extensionForm.setFieldsInitialised(true);
GEarthExtension gEarthExtension = new InternalExtensionBuilder(internalExtension);
observer.onExtensionProduced(gEarthExtension);

View File

@ -18,8 +18,8 @@ public abstract class ThemedExtensionFormCreator extends ExtensionFormCreator {
@Override
protected ExtensionForm createForm(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getFormResource());
Parent root = loader.load();
final FXMLLoader loader = new FXMLLoader(getFormResource());
final Parent root = loader.load();
primaryStage.setTitle(getTitle());
primaryStage.setScene(new Scene(root));
@ -27,31 +27,38 @@ public abstract class ThemedExtensionFormCreator extends ExtensionFormCreator {
primaryStage.setResizable(false);
primaryStage.sizeToScene();
Theme defaultTheme = ThemeFactory.getDefaultTheme();
DefaultTitleBarConfig config = new DefaultTitleBarConfig(primaryStage, defaultTheme) {
final Theme defaultTheme = ThemeFactory.getDefaultTheme();
final DefaultTitleBarConfig config = new DefaultTitleBarConfig(primaryStage, defaultTheme) {
@Override
public boolean displayThemePicker() {
return false;
}
};
TitleBarController.create(primaryStage, config);
Platform.runLater(() -> {
primaryStage.getScene().getRoot().getStyleClass().add(defaultTheme.title().replace(" ", "-").toLowerCase());
primaryStage.getScene().getRoot().getStyleClass().add(defaultTheme.isDark() ? "g-dark" : "g-light");
});
Platform.runLater(() -> primaryStage.getScene().getRoot().getStyleClass().addAll(
defaultTheme.title().replace(" ", "-").toLowerCase(),
defaultTheme.isDark() ? "g-dark" : "g-light"
));
ExtensionForm extensionForm = loader.getController();
extensionForm.fieldsInitialized.addListener(() -> extensionForm.extension.observableHostInfo.addListener(hostInfo -> {
if (hostInfo.getAttributes().containsKey("theme")) {
String themeTitle = hostInfo.getAttributes().get("theme");
Theme theme = ThemeFactory.themeForTitle(themeTitle);
final ExtensionForm extensionForm = loader.getController();
extensionForm
.fieldsInitialisedProperty()
.addListener(observable -> listenForThemeChange(primaryStage, config, extensionForm));
return extensionForm;
}
private static void listenForThemeChange(Stage primaryStage, DefaultTitleBarConfig config, ExtensionForm extensionForm) {
extensionForm.extension.hostInfoProperty.addListener((observable, oldValue, newValue) -> {
final String themeTitle = newValue.getAttributes().get("theme");
if (themeTitle != null) {
final Theme theme = ThemeFactory.themeForTitle(themeTitle);
if (config.getCurrentTheme() != theme) {
String styleClassOld = config.getCurrentTheme().title().replace(" ", "-").toLowerCase();
String lightClassOld = config.getCurrentTheme().isDark() ? "g-dark" : "g-light";
String styleClassNew = theme.title().replace(" ", "-").toLowerCase();
String lightClassNew = theme.isDark() ? "g-dark" : "g-light";
final String styleClassOld = config.getCurrentTheme().title().replace(" ", "-").toLowerCase();
final String lightClassOld = config.getCurrentTheme().isDark() ? "g-dark" : "g-light";
final String styleClassNew = theme.title().replace(" ", "-").toLowerCase();
final String lightClassNew = theme.isDark() ? "g-dark" : "g-light";
config.setTheme(theme);
Parent currentRoot = primaryStage.getScene().getRoot();
final Parent currentRoot = primaryStage.getScene().getRoot();
Platform.runLater(() -> {
currentRoot.getStyleClass().remove(styleClassOld);
currentRoot.getStyleClass().add(styleClassNew);
@ -62,13 +69,11 @@ public abstract class ThemedExtensionFormCreator extends ExtensionFormCreator {
});
}
}
}));
return extensionForm;
});
}
protected abstract String getTitle();
protected abstract URL getFormResource();
// can be overridden for more settings

View File

@ -0,0 +1,62 @@
package gearth.misc;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
/**
* Provides utility methods for bindings.
*
* @author Dorving
*/
public final class BindingsUtil {
/**
* Ensures the list always contains the value of the binding.
*/
public static <T> void addAndBindContent(ObservableList<T> list, ObjectBinding<T> binding) {
binding.addListener((observable, oldValue, newValue) -> {
list.remove(oldValue);
list.add(newValue);
});
list.add(binding.get());
}
/**
* Sets the value of a property and binds it bidirectionally to another property.
*/
public static<T> void setAndBindBiDirectional(Property<T> a, Property<T> b) {
a.setValue(b.getValue());
a.bindBidirectional(b);
}
/**
* Sets the value of a string property and binds it bidirectionally to another property using a converter.
*/
public static<T> void setAndBindBiDirectional(StringProperty a, Property<T> b, StringConverter<T> converter) {
a.setValue(converter.toString(b.getValue()));
a.bindBidirectional(b, converter);
}
/**
* Sets the value of a string property and binds it bidirectionally to an integer property.
*/
public static<T> void setAndBindBiDirectional(StringProperty a, IntegerProperty b) {
setAndBindBiDirectional(a, b, STRING_INT_CONVERTER);
}
private static final StringConverter<Number> STRING_INT_CONVERTER = new StringConverter<Number>() {
@Override
public String toString(Number object) {
return Integer.toString(object.intValue());
}
@Override
public Number fromString(String string) {
return Integer.parseInt(string);
}
};
}

View File

@ -1,6 +1,10 @@
package gearth.misc;
import gearth.GEarth;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.StringProperty;
import org.json.JSONArray;
import org.json.JSONObject;
@ -10,6 +14,8 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Created by Jonas on 28/09/18.
@ -130,4 +136,36 @@ public class Cacher {
public static void clear() {
clear(DEFAULT_CACHE_FILENAME);
}
public static <E extends Enum<E>> void ifEnumPresent(String key, Class<E> enumClass, Consumer<E> consumer) {
if (getCacheContents().has(key)) {
final E value = getCacheContents().getEnum(enumClass, key);
consumer.accept(value);
}
}
public static <E extends Enum<E>> void bindEnum(String key, Class<E> enumClass, ObjectProperty<E> valueProperty) {
if (getCacheContents().has(key)) {
final E value = getCacheContents().getEnum(enumClass, key);
valueProperty.set(value);
}
valueProperty.addListener((observable, oldValue, newValue) -> put(key, newValue));
}
public static void bindString(String key, StringProperty valueProperty) {
bind(key, valueProperty, getCacheContents()::getString);
}
public static void bindNumber(String key, Property<Number> valueProperty) {
bind(key, valueProperty, getCacheContents()::getNumber);
}
public static void bindBoolean(String key, BooleanProperty valueProperty) {
bind(key, valueProperty, getCacheContents()::getBoolean);
}
public static void bindJSONObject(String key, ObjectProperty<JSONObject> valueProperty) {
bind(key, valueProperty, getCacheContents()::getJSONObject);
}
private static <T> void bind(String key, Property<T> valueProperty, Function<String, T> reader) {
if (getCacheContents().has(key))
valueProperty.setValue(reader.apply(key));
valueProperty.addListener((observable, oldValue, newValue) -> put(key, newValue));
}
}

View File

@ -1,22 +0,0 @@
package gearth.misc.listenerpattern;
import java.util.function.Consumer;
public class ObservableObject<T> extends Observable<Consumer<T>> {
private T object;
public ObservableObject(T object) {
super();
this.object = object;
}
public void setObject(T object) {
this.object = object;
fireEvent(c -> c.accept(object));
}
public T getObject() {
return object;
}
}

View File

@ -13,29 +13,29 @@ import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import gearth.protocol.connection.proxy.unity.UnityProxyProvider;
import gearth.services.extension_handler.ExtensionHandler;
import gearth.ui.GEarthProperties;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.io.IOException;
import java.util.function.Consumer;
public class HConnection {
public static volatile boolean DECRYPTPACKETS = true;
public static volatile boolean DEBUG = false;
private volatile ExtensionHandler extensionHandler = null;
private volatile Object[] trafficObservables = {new Observable<TrafficListener>(), new Observable<TrafficListener>(), new Observable<TrafficListener>()};
private volatile Observable<StateChangeListener> stateObservable = new Observable<>();
private volatile Observable<Consumer<Boolean>> developerModeChangeObservable = new Observable<>();
private volatile HState state = HState.NOT_CONNECTED;
@Deprecated
private volatile Observable<StateChangeListener> stateObservable = new Observable<>();
private final ObjectProperty<HState> stateProperty = new SimpleObjectProperty<>(HState.NOT_CONNECTED);
private volatile HProxy proxy = null;
private ProxyProviderFactory proxyProviderFactory;
private ProxyProvider proxyProvider = null;
private volatile boolean developerMode = false;
public HConnection() {
HConnection selff = this;
proxyProviderFactory = new ProxyProviderFactory(
@ -47,16 +47,16 @@ public class HConnection {
PacketSafetyManager.PACKET_SAFETY_MANAGER.initialize(this);
}
public ObjectProperty<HState> stateProperty() {
return stateProperty;
}
public HState getState() {
return state;
return stateProperty.get();
}
private void setState(HState state) {
if (state != this.state) {
HState buffer = this.state;
this.state = state;
stateObservable.fireEvent(l -> l.stateChanged(buffer, state));
}
stateProperty.set(state);
}
// autodetect mode
@ -107,6 +107,7 @@ public class HConnection {
}
}
@Deprecated
public Observable<StateChangeListener> getStateObservable() {
return stateObservable;
}
@ -165,11 +166,12 @@ public class HConnection {
}
public boolean canSendPacket(HMessage.Direction direction, HPacket packet) {
return isPacketSendingAllowed(direction, packet) && (developerMode || isPacketSendingSafe(direction, packet));
return isPacketSendingAllowed(direction, packet)
&& (GEarthProperties.isDeveloperModeEnabled() || isPacketSendingSafe(direction, packet));
}
public boolean isPacketSendingAllowed(HMessage.Direction direction, HPacket packet) {
if (state != HState.CONNECTED) return false;
if (getState() != HState.CONNECTED) return false;
HProxy proxy = this.proxy;
if (proxy == null) return false;
@ -196,14 +198,6 @@ public class HConnection {
return packetsContainer.isPacketSafe(packet.headerId(), direction);
}
public void setDeveloperMode(boolean developerMode) {
this.developerMode = developerMode;
developerModeChangeObservable.fireEvent(listener -> listener.accept(developerMode));
}
public void onDeveloperModeChange(Consumer<Boolean> onChange) {
developerModeChangeObservable.addListener(onChange);
}
public String getClientHost() {
if (proxy == null) {

View File

@ -10,15 +10,14 @@ import gearth.protocol.memory.Rc4Obtainer;
import gearth.protocol.packethandler.flash.IncomingFlashPacketHandler;
import gearth.protocol.packethandler.flash.OutgoingFlashPacketHandler;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.Socket;
@ -47,7 +46,7 @@ public abstract class FlashProxyProvider implements ProxyProvider {
client.setSoTimeout(0);
server.setSoTimeout(0);
if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
if (GEarthProperties.isDebugModeEnabled()) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
OutgoingFlashPacketHandler outgoingHandler = new OutgoingFlashPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
@ -73,7 +72,7 @@ public abstract class FlashProxyProvider implements ProxyProvider {
try {
if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close();
if (HConnection.DEBUG) System.out.println("STOP");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("STOP");
if (datastream[0]) {
onConnectEnd();
};

View File

@ -1,6 +1,5 @@
package gearth.protocol.connection.proxy.flash;
import gearth.GEarth;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.connection.*;
@ -10,12 +9,11 @@ import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
import gearth.protocol.hostreplacer.hostsfile.HostReplacerFactory;
import gearth.protocol.portchecker.PortChecker;
import gearth.protocol.portchecker.PortCheckerFactory;
import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.*;
@ -128,7 +126,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
Socket client = proxy_server.accept();
proxy = potentialProxy;
closeAllProxies(proxy);
if (HConnection.DEBUG) System.out.println("accepted a proxy");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("accepted a proxy");
new Thread(() -> {
try {
@ -173,7 +171,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
}
if (HConnection.DEBUG) System.out.println("done waiting for clients with: " + hConnection.getState() );
if (GEarthProperties.isDebugModeEnabled()) System.out.println("done waiting for clients with: " + hConnection.getState() );
}

View File

@ -7,6 +7,7 @@ import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
import gearth.ui.GEarthProperties;
import java.io.IOException;
import java.net.*;
@ -54,7 +55,7 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
maybeAddMapping();
if (HConnection.DEBUG) System.out.println("Added mapping for raw IP");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("Added mapping for raw IP");
ServerSocket proxy_server = new ServerSocket(proxy.getIntercept_port(), 10, InetAddress.getByName(proxy.getIntercept_host()));
proxy.initProxy(proxy_server);
@ -62,10 +63,10 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
stateSetter.setState(HState.WAITING_FOR_CLIENT);
while ((hConnection.getState() == HState.WAITING_FOR_CLIENT) && !proxy_server.isClosed()) {
try {
if (HConnection.DEBUG) System.out.println("try accept proxy");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("try accept proxy");
Socket client = proxy_server.accept();
if (HConnection.DEBUG) System.out.println("accepted a proxy");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("accepted a proxy");
new Thread(() -> {
try {
@ -151,7 +152,7 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
createSocksProxyThread(client);
}
else if (preConnectedServerConnections.isEmpty()) {
if (HConnection.DEBUG) System.out.println("pre-made server connections ran out of stock");
if (GEarthProperties.isDebugModeEnabled()) System.out.println("pre-made server connections ran out of stock");
}
else {
startProxyThread(client, preConnectedServerConnections.poll(), proxy);

View File

@ -9,6 +9,8 @@ import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.proxy.nitro.http.NitroHttpProxy;
import gearth.protocol.connection.proxy.nitro.http.NitroHttpProxyServerCallback;
import gearth.protocol.connection.proxy.nitro.websocket.NitroWebsocketProxy;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -16,7 +18,7 @@ import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicBoolean;
public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCallback, StateChangeListener {
public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCallback, ChangeListener<HState> {
private static final Logger logger = LoggerFactory.getLogger(NitroProxyProvider.class);
@ -53,7 +55,7 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
originalWebsocketUrl = null;
originalCookies = null;
connection.getStateObservable().addListener(this);
connection.stateProperty().addListener(this);
logger.info("Starting http proxy");
@ -112,7 +114,7 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
stateSetter.setState(HState.NOT_CONNECTED);
connection.getStateObservable().removeListener(this);
connection.stateProperty().removeListener(this);
logger.info("Nitro proxy stopped");
}).start();
@ -131,16 +133,15 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
}
@Override
public void stateChanged(HState oldState, HState newState) {
if (oldState == HState.WAITING_FOR_CLIENT && newState == HState.CONNECTED) {
public void changed(ObservableValue<? extends HState> observable, HState oldValue, HState newValue) {
if (oldValue == HState.WAITING_FOR_CLIENT && newValue == HState.CONNECTED) {
// Unregister but do not stop http proxy.
// We are not stopping the http proxy because some requests might still require it to be running.
nitroHttpProxy.pause();
}
// Catch setState ABORTING inside NitroWebsocketClient.
if (newState == HState.ABORTING) {
if (newValue == HState.ABORTING)
abort();
}
}
}

View File

@ -1,18 +1,21 @@
package gearth.protocol.connection.proxy.unity;
import gearth.protocol.HConnection;
import gearth.protocol.StateChangeListener;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.services.unity_tools.GUnityFileServer;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
@ -22,6 +25,9 @@ import static gearth.services.unity_tools.GUnityFileServer.FILESERVER_PORT;
public class UnityProxyProvider implements ProxyProvider {
private final static Logger LOGGER = LoggerFactory.getLogger(UnityProxyProvider.class);
public static final int PORT_REQUESTER_SERVER_PORT = 9039;
private final HProxySetter proxySetter;
private final HStateSetter stateSetter;
private final HConnection hConnection;
@ -34,7 +40,6 @@ public class UnityProxyProvider implements ProxyProvider {
this.hConnection = hConnection;
}
@Override
public void start() throws IOException {
// https://happyhyppo.ro/2016/03/21/minimal-websockets-communication-with-javajetty-and-angularjs/
@ -45,13 +50,13 @@ public class UnityProxyProvider implements ProxyProvider {
while (fail && port < 9100) {
try {
packetHandlerServer = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
HandlerList handlers = new HandlerList();
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
final ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(UnityCommunicator.class, "/packethandler") // the endpoint url
.configurator(new UnityCommunicatorConfig(proxySetter, stateSetter, hConnection, this))
@ -65,10 +70,8 @@ public class UnityProxyProvider implements ProxyProvider {
}
}
if (fail) {
if (fail)
throw new Exception();
}
startPortRequestServer(port);
startUnityFileServer();
@ -79,17 +82,16 @@ public class UnityProxyProvider implements ProxyProvider {
try {
packetHandlerServer.stop();
} catch (Exception ex) {
ex.printStackTrace();
LOGGER.error("Failed to close packet handler server", ex);
}
e.printStackTrace();
LOGGER.error("Failed to connect to unity proxy", e);
}
}
@Override
public synchronized void abort() {
if (packetHandlerServer == null) {
if (packetHandlerServer == null)
return;
}
final Server abortThis = packetHandlerServer;
stateSetter.setState(HState.ABORTING);
@ -97,7 +99,7 @@ public class UnityProxyProvider implements ProxyProvider {
try {
abortThis.stop();
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Failed to abort", e);
} finally {
stateSetter.setState(HState.NOT_CONNECTED);
}
@ -106,43 +108,30 @@ public class UnityProxyProvider implements ProxyProvider {
}
private void startUnityFileServer() throws Exception {
Server server = new Server(FILESERVER_PORT);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
final Server server = new Server(FILESERVER_PORT);
final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new GUnityFileServer()), "/*");
HandlerList handlers = new HandlerList();
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
server.setHandler(handlers);
server.start();
StateChangeListener fileServerCloser = new StateChangeListener() {
@Override
public void stateChanged(HState oldState, HState newState) {
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
hConnection.getStateObservable().removeListener(this);
try {
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
hConnection.getStateObservable().addListener(fileServerCloser);
stopServerOnDisconnect(server);
}
private void startPortRequestServer(int packetHandlerPort) throws Exception {
Server portRequestServer = new Server(9039);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
final Server portRequestServer = new Server(PORT_REQUESTER_SERVER_PORT);
final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
HandlerList handlers = new HandlerList();
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
portRequestServer.setHandler(handlers);
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
final ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(PortRequester.class, "/portrequest") // the endpoint url
.configurator(new PortRequesterConfig(packetHandlerPort))
@ -150,19 +139,22 @@ public class UnityProxyProvider implements ProxyProvider {
portRequestServer.start();
StateChangeListener portRequesterCloser = new StateChangeListener() {
stopServerOnDisconnect(portRequestServer);
}
private void stopServerOnDisconnect(Server server) {
hConnection.stateProperty().addListener(new ChangeListener<HState>() {
@Override
public void stateChanged(HState oldState, HState newState) {
if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
hConnection.getStateObservable().removeListener(this);
public void changed(ObservableValue<? extends HState> observable, HState oldValue, HState newValue) {
if (oldValue == HState.WAITING_FOR_CLIENT || newValue == HState.NOT_CONNECTED) {
hConnection.stateProperty().removeListener(this);
try {
portRequestServer.stop();
server.stop();
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Failed to stop server {}", server, e);
}
}
}
};
hConnection.getStateObservable().addListener(portRequesterCloser);
});
}
}

View File

@ -7,11 +7,13 @@ import gearth.protocol.crypto.RC4;
import gearth.protocol.memory.habboclient.HabboClient;
import gearth.protocol.memory.habboclient.HabboClientFactory;
import gearth.protocol.packethandler.PayloadBuffer;
import gearth.protocol.packethandler.flash.BufferChangeListener;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
@ -37,21 +39,22 @@ public class Rc4Obtainer {
public void setFlashPacketHandlers(FlashPacketHandler... flashPacketHandlers) {
this.flashPacketHandlers = Arrays.asList(flashPacketHandlers);
for (FlashPacketHandler handler : flashPacketHandlers) {
BufferChangeListener bufferChangeListener = new BufferChangeListener() {
final InvalidationListener bufferChangeListener = new InvalidationListener() {
@Override
public void act() {
public void invalidated(Observable observable) {
if (handler.isEncryptedStream()) {
onSendFirstEncryptedMessage(handler);
handler.getBufferChangeObservable().removeListener(this);
Rc4Obtainer.this.onSendFirstEncryptedMessage(handler);
handler.incomingBufferProperty().removeListener(this);
}
}
};
handler.getBufferChangeObservable().addListener(bufferChangeListener);
handler.incomingBufferProperty().addListener(bufferChangeListener);
}
}
private void onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler) {
if (!HConnection.DECRYPTPACKETS) return;
if (GEarthProperties.isPacketDecryptionDisabled())
return;
flashPacketHandlers.forEach(FlashPacketHandler::block);

View File

@ -1,8 +0,0 @@
package gearth.protocol.packethandler.flash;
public interface BufferChangeListener {
void act();
}

View File

@ -1,13 +1,14 @@
package gearth.protocol.packethandler.flash;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.crypto.RC4;
import gearth.protocol.packethandler.PacketHandler;
import gearth.protocol.packethandler.PayloadBuffer;
import gearth.services.extension_handler.ExtensionHandler;
import gearth.ui.GEarthProperties;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.io.IOException;
import java.io.OutputStream;
@ -18,7 +19,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
protected static final boolean DEBUG = false;
private volatile OutputStream out;
private final OutputStream out;
private volatile boolean isTempBlocked = false;
volatile boolean isDataStream = false;
@ -36,7 +37,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
FlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
super(extensionHandler, trafficObservables);
out = outputStream;
this.payloadBuffer = new PayloadBuffer();
payloadBuffer = new PayloadBuffer();
}
public boolean isDataStream() {return isDataStream;}
@ -49,6 +50,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
}
public void act(byte[] buffer) throws IOException {
if (!isDataStream) {
synchronized (sendLock) {
out.write(buffer);
@ -56,20 +58,19 @@ public abstract class FlashPacketHandler extends PacketHandler {
return;
}
bufferChangeObservable.fireEvent();
incomingBufferProperty.set(buffer);
if (!isEncryptedStream) {
payloadBuffer.push(buffer);
}
else if (!HConnection.DECRYPTPACKETS) {
else if (GEarthProperties.isPacketDecryptionDisabled()) {
synchronized (sendLock) {
out.write(buffer);
}
}
else if (decryptcipher == null) {
for (int i = 0; i < buffer.length; i++) {
tempEncryptedBuffer.add(buffer[i]);
}
for (byte b : buffer)
tempEncryptedBuffer.add(b);
}
else {
byte[] tm = decryptcipher.rc4(buffer);
@ -162,9 +163,10 @@ public abstract class FlashPacketHandler extends PacketHandler {
protected abstract void printForDebugging(byte[] bytes);
private Observable<BufferChangeListener> bufferChangeObservable = new Observable<>(BufferChangeListener::act);
public Observable<BufferChangeListener> getBufferChangeObservable() {
return bufferChangeObservable;
private final ObjectProperty<byte[]> incomingBufferProperty = new SimpleObjectProperty<>();
public ObjectProperty<byte[]> incomingBufferProperty() {
return incomingBufferProperty;
}
public int getCurrentIndex() {

View File

@ -1,7 +1,6 @@
package gearth.services.extension_handler;
import gearth.GEarth;
import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
@ -12,14 +11,15 @@ import gearth.services.extension_handler.extensions.GEarthExtension;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerFactory;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerObserver;
import gearth.ui.themes.Theme;
import gearth.ui.GEarthProperties;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.util.Pair;
import java.io.IOException;
import java.util.*;
import java.util.function.Consumer;
public class ExtensionHandler {
public class ExtensionHandler implements ChangeListener<HState> {
private final List<GEarthExtension> gEarthExtensions = new ArrayList<>();
private final HConnection hConnection;
@ -47,38 +47,13 @@ public class ExtensionHandler {
}
private void initialize() {
GEarth.getThemeObservable().addListener(theme -> {
GEarthProperties.hostInfoBinding.addListener(((observable1, oldValue, newValue) -> {
synchronized (gEarthExtensions) {
for (GEarthExtension extension : gEarthExtensions) {
extension.updateHostInfo(getHostInfo());
}
gEarthExtensions.forEach(extension -> extension.updateHostInfo(newValue));
}
});
hConnection.getStateObservable().addListener((oldState, newState) -> {
if (newState == HState.CONNECTED) {
synchronized (gEarthExtensions) {
for (GEarthExtension extension : gEarthExtensions) {
extension.connectionStart(
hConnection.getDomain(),
hConnection.getServerPort(),
hConnection.getHotelVersion(),
hConnection.getClientIdentifier(),
hConnection.getClientType(),
hConnection.getPacketInfoManager()
);
}
}
}
if (oldState == HState.CONNECTED) {
synchronized (gEarthExtensions) {
for (GEarthExtension extension : gEarthExtensions) {
extension.connectionEnd();
}
}
}
});
}));
hConnection.stateProperty().addListener(this);
extensionProducers = ExtensionProducerFactory.getAll();
extensionProducers.forEach(extensionProducer -> extensionProducer.startProducing(createExtensionProducerObserver()));
}
@ -259,7 +234,7 @@ public class ExtensionHandler {
extension.getClickedObservable().addListener(extension::doubleclick);
observable.fireEvent(l -> l.onExtensionConnect(extension));
extension.init(hConnection.getState() == HState.CONNECTED, getHostInfo());
extension.init(hConnection.getState() == HState.CONNECTED, GEarthProperties.getHostInfo());
if (hConnection.getState() == HState.CONNECTED) {
extension.connectionStart(
hConnection.getDomain(),
@ -274,16 +249,6 @@ public class ExtensionHandler {
};
}
private HostInfo getHostInfo() {
HashMap<String, String> attributes = new HashMap<>();
attributes.put("theme", GEarth.getTheme().title());
return new HostInfo(
"G-Earth",
GEarth.version,
attributes
);
}
public List<ExtensionProducer> getExtensionProducers() {
return extensionProducers;
}
@ -296,5 +261,26 @@ public class ExtensionHandler {
extensionProducers.add(producer);
}
@Override
public void changed(ObservableValue<? extends HState> observable, HState oldValue, HState newValue) {
if (newValue == HState.CONNECTED) {
synchronized (gEarthExtensions) {
for (GEarthExtension extension : gEarthExtensions) {
extension.connectionStart(
hConnection.getDomain(),
hConnection.getServerPort(),
hConnection.getHotelVersion(),
hConnection.getClientIdentifier(),
hConnection.getClientType(),
hConnection.getPacketInfoManager()
);
}
}
}
if (oldValue == HState.CONNECTED) {
synchronized (gEarthExtensions) {
gEarthExtensions.forEach(GEarthExtension::connectionEnd);
}
}
}
}

View File

@ -0,0 +1,228 @@
package gearth.ui;
import gearth.GEarth;
import gearth.misc.BindingsUtil;
import gearth.misc.Cacher;
import gearth.misc.HostInfo;
import gearth.protocol.connection.HClient;
import gearth.ui.themes.Theme;
import gearth.ui.themes.ThemeFactory;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Objects;
/**
* Handles G-Earth's observable properties.
*
* @author Dorving
*/
public final class GEarthProperties {
private static final Logger LOGGER = LoggerFactory.getLogger(GEarthProperties.class);
public static final ObjectProperty<Theme> themeProperty = new SimpleObjectProperty<>();
public static final StringBinding themeTitleBinding;
public static final ObjectBinding<HostInfo> hostInfoBinding;
public static final ObjectBinding<Image> logoImageBinding;
public static final ObjectBinding<Image> logoSmallImageBinding;
public static final ObservableList<Image> icons = FXCollections.observableArrayList();
public static final ObjectBinding<String> styleSheetBinding;
public static final ObservableList<String> styleSheets = FXCollections.observableArrayList();
public static final ObjectProperty<HClient> clientTypeProperty = new SimpleObjectProperty<>();
public static final BooleanProperty autoDetectProperty = new SimpleBooleanProperty(false);
public static final StringProperty hostProperty = new SimpleStringProperty();
public static final IntegerProperty portProperty = new SimpleIntegerProperty();
public static final BooleanProperty alwaysOnTopProperty = new SimpleBooleanProperty(false);
public static final BooleanProperty enableDeveloperModeProperty = new SimpleBooleanProperty(false);
public static final BooleanProperty enableDebugProperty = new SimpleBooleanProperty(false);
public static final BooleanProperty disablePacketDecryptionProperty = new SimpleBooleanProperty(false);
public static final BooleanProperty enableSocksProperty = new SimpleBooleanProperty(false);
public static final StringProperty socksHostProperty = new SimpleStringProperty();
public static final IntegerProperty socksPortProperty = new SimpleIntegerProperty();
public static final BooleanProperty enableGPythonProperty = new SimpleBooleanProperty(false);
public static final BooleanProperty alwaysAdminProperty = new SimpleBooleanProperty(false);
public static final StringProperty notesProperty = new SimpleStringProperty();
static {
themeProperty.addListener((observable, oldValue, newValue) -> Cacher.put("theme", newValue.title()));
final Theme value = Cacher.getCacheContents().has("theme") ?
ThemeFactory.themeForTitle(Cacher.getCacheContents().getString("theme")) :
ThemeFactory.getDefaultTheme();
LOGGER.debug("Loading theme {}", value);
themeProperty.set(Objects.requireNonNull(value, "Unable to load theme"));
styleSheetBinding = createThemeStylesheetBinding();
logoSmallImageBinding = createThemeImageBinding("logoSmall.png");
logoImageBinding = createThemeImageBinding("logo.png");
hostInfoBinding = createThemeHostInfoBinding();
themeTitleBinding = createThemeTitleBinding();
BindingsUtil.addAndBindContent(icons, logoSmallImageBinding);
BindingsUtil.addAndBindContent(styleSheets, styleSheetBinding);
Cacher.bindEnum("last_client_mode", HClient.class, clientTypeProperty);
Cacher.bindBoolean("auto_detect", autoDetectProperty);
Cacher.bindString("host", hostProperty);
Cacher.bindNumber("port", portProperty);
convertOldConnectionSettingsIfPresent();
Cacher.bindBoolean("always_on_top", alwaysOnTopProperty);
Cacher.bindBoolean("always_admin", alwaysAdminProperty);
Cacher.bindBoolean("develop_mode", enableDeveloperModeProperty);
Cacher.bindBoolean("debug_mode_enabled", enableDebugProperty);
Cacher.bindBoolean("packet_decryption_disabled", disablePacketDecryptionProperty);
Cacher.bindBoolean("socks_enabled", enableSocksProperty);
Cacher.bindString("socks_host", socksHostProperty);
Cacher.bindNumber("socks_port", socksPortProperty);
Cacher.bindBoolean("use_gpython", enableGPythonProperty);
Cacher.bindString("notepad_text", notesProperty);
}
public static Theme getTheme() {
return themeProperty.get();
}
public static String getThemeTitle() {
return themeTitleBinding.get();
}
public static HostInfo getHostInfo() {
return hostInfoBinding.get();
}
public static Image getLogoImage() {
return logoImageBinding.get();
}
public static Image getLogoSmallImage() {
return logoSmallImageBinding.get();
}
public static String getStyleSheet() {
return styleSheetBinding.get();
}
public static HClient getClientType() {
return clientTypeProperty.get();
}
public static boolean isPacketDecryptionDisabled() {
return disablePacketDecryptionProperty.get();
}
public static boolean isDebugModeEnabled() {
return enableDebugProperty.get();
}
public static boolean isDeveloperModeEnabled() {
return enableDeveloperModeProperty.get();
}
public static boolean isAlwaysOnTop() {
return alwaysOnTopProperty.get();
}
public static String getSocksHost() {
return socksHostProperty.get();
}
public static int getSocksPort() {
return socksPortProperty.get();
}
private static StringBinding createThemeTitleBinding() {
return Bindings.createStringBinding(() -> {
final Theme theme = getTheme();
return theme.overridesTitle() ? theme.title() : ThemeFactory.getDefaultTheme().title();
}, themeProperty);
}
private static ObjectBinding<HostInfo> createThemeHostInfoBinding() {
return Bindings.createObjectBinding(() -> new HostInfo(
"G-Earth",
GEarth.version,
new HashMap<>(Collections.singletonMap("theme", getTheme().title()))
), themeProperty);
}
private static ObjectBinding<String> createThemeStylesheetBinding() {
return Bindings.createObjectBinding(() -> {
final String pathToStyleSheet = getThemeRelativePath("styling.css");
final URL styleSheetInput = GEarth.class.getResource(pathToStyleSheet);
if (styleSheetInput == null) {
LOGGER.error("Could not load style sheet `{}`, input-stream is null for {}", "styling.css", pathToStyleSheet);
return null;
}
return styleSheetInput.toExternalForm();
}, themeProperty);
}
private static ObjectBinding<Image> createThemeImageBinding(String imageName) {
return Bindings.createObjectBinding(() -> {
final Theme theme = getTheme();
final String pathToLogo = getThemeRelativePath(theme.overridesLogo()
? theme
: ThemeFactory.getDefaultTheme(), imageName);
try (final InputStream imageInput = GEarth.class.getResourceAsStream(pathToLogo)) {
if (imageInput == null) {
LOGGER.error("Could not load image `{}`, input-stream is null for {}", imageName, pathToLogo);
return null;
}
return new Image(imageInput);
} catch (Exception e) {
LOGGER.error("Failed to load image `{}", imageName, e);
return null;
}
}, themeProperty);
}
private static String getThemeRelativePath(String fileName) {
return getThemeRelativePath(getTheme(), fileName);
}
private static String getThemeRelativePath(Theme theme, String fileName) {
return String.format("/gearth/ui/themes/%s/" + fileName, theme.internalName());
}
private static final String KEY_LAST_CONNECTION_SETTINGS = "last_connection_settings";
private static final String KEY_AUTODETECT = "auto_detect";
private static final String KEY_HOST = "host";
private static final String KEY_PORT = "port";
private static void convertOldConnectionSettingsIfPresent() {
/*
BACKWARDS COMPATABILITY
*/
if (Cacher.getCacheContents().has(KEY_LAST_CONNECTION_SETTINGS)) {
final JSONObject jsonObject = Cacher.getCacheContents().getJSONObject(KEY_LAST_CONNECTION_SETTINGS);
if (jsonObject != null) {
autoDetectProperty.set(jsonObject.getBoolean(KEY_AUTODETECT));
hostProperty.set(jsonObject.getString(KEY_HOST));
portProperty.set(jsonObject.getInt(KEY_PORT));
Cacher.getCacheContents().remove(KEY_LAST_CONNECTION_SETTINGS);
}
}
}
}

View File

@ -1,19 +1,19 @@
package gearth.ui.subforms.connection;
import gearth.GEarth;
import gearth.misc.Cacher;
import gearth.misc.BindingsUtil;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HClient;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.services.Constants;
import gearth.ui.GEarthProperties;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import gearth.protocol.HConnection;
import gearth.ui.SubForm;
import javafx.scene.layout.GridPane;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
@ -22,11 +22,6 @@ import java.util.Set;
public class ConnectionController extends SubForm {
private final String CONNECTION_INFO_CACHE_KEY = "last_connection_settings";
private final String AUTODETECT_CACHE = "auto_detect";
private final String HOST_CACHE = "host";
private final String PORT_CACHE = "port";
public ComboBox<String> inpPort;
public ComboBox<String> inpHost;
public Button btnConnect;
@ -40,7 +35,6 @@ public class ConnectionController extends SubForm {
private volatile int fullyInitialized = 0;
public static final String CLIENT_CACHE_KEY = "last_client_mode";
public ToggleGroup tgl_clientMode;
public RadioButton rd_unity;
public RadioButton rd_flash;
@ -59,38 +53,16 @@ public class ConnectionController extends SubForm {
Constants.UNITY_PACKETS = rd_unity.isSelected();
});
if (Cacher.getCacheContents().has(CLIENT_CACHE_KEY)) {
switch (Cacher.getCacheContents().getEnum(HClient.class, CLIENT_CACHE_KEY)) {
case FLASH:
rd_flash.setSelected(true);
break;
case UNITY:
rd_unity.setSelected(true);
break;
case NITRO:
rd_nitro.setSelected(true);
break;
}
}
GEarthProperties.clientTypeProperty
.addListener((observable, oldValue, newValue) -> selectClientType(newValue));
selectClientType(GEarthProperties.clientTypeProperty.getValue());
cbx_autodetect.selectedProperty().addListener(observable -> updateInputUI());
inpPort.getEditor().textProperty().addListener(observable -> updateInputUI());
Object object;
String hostRemember = null;
String portRemember = null;
if ((object = Cacher.get(CONNECTION_INFO_CACHE_KEY)) != null) {
JSONObject connectionSettings = (JSONObject) object;
boolean autoDetect = connectionSettings.getBoolean(AUTODETECT_CACHE);
hostRemember = connectionSettings.getString(HOST_CACHE);
portRemember = connectionSettings.getInt(PORT_CACHE) + "";
cbx_autodetect.setSelected(autoDetect);
}
inpPort.getEditor().textProperty().addListener(observable -> {
updateInputUI();
});
cbx_autodetect.selectedProperty().addListener(observable -> {
updateInputUI();
});
BindingsUtil.setAndBindBiDirectional(cbx_autodetect.selectedProperty(), GEarthProperties.autoDetectProperty);
BindingsUtil.setAndBindBiDirectional(outHost.textProperty(), GEarthProperties.hostProperty);
BindingsUtil.setAndBindBiDirectional(outPort.textProperty(), GEarthProperties.portProperty);
List<String> knownHosts = ProxyProviderFactory.autoDetectHosts;
Set<String> hosts = new HashSet<>();
@ -110,6 +82,8 @@ public class ConnectionController extends SubForm {
int hostSelectIndex = 0;
int portSelectIndex = 0;
final String hostRemember = GEarthProperties.hostProperty.get();
final String portRemember = Integer.toString(GEarthProperties.portProperty.get());
if (hostRemember != null) {
hostSelectIndex = hostsSorted.indexOf(hostRemember);
portSelectIndex = portsSorted.indexOf(portRemember);
@ -138,15 +112,31 @@ public class ConnectionController extends SubForm {
initLanguageBinding();
}
private void selectClientType(HClient newValue) {
switch (newValue) {
case FLASH:
rd_flash.setSelected(true);
break;
case UNITY:
rd_unity.setSelected(true);
break;
case NITRO:
rd_nitro.setSelected(true);
break;
}
}
private void updateInputUI() {
if (parentController == null) return;
grd_clientSelection.setDisable(getHConnection().getState() != HState.NOT_CONNECTED);
txtfield_hotelversion.setText(getHConnection().getHotelVersion());
final HConnection hConnection = getHConnection();
final HState hConnectionState = hConnection.getState();
btnConnect.setDisable(getHConnection().getState() == HState.PREPARING || getHConnection().getState() == HState.ABORTING);
grd_clientSelection.setDisable(hConnectionState != HState.NOT_CONNECTED);
txtfield_hotelversion.setText(hConnection.getHotelVersion());
btnConnect.setDisable(hConnectionState == HState.PREPARING || hConnectionState == HState.ABORTING);
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable() && useFlash()) {
@ -159,15 +149,15 @@ public class ConnectionController extends SubForm {
}
}
inpHost.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpHost.setDisable(hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
cbx_autodetect.setDisable(!useFlash());
outHost.setDisable(!useFlash());
outPort.setDisable(!useFlash());
inpHost.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpHost.setDisable(!useFlash() || hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
inpPort.setDisable(!useFlash() || hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
}
public void onParentSet(){
@ -178,37 +168,28 @@ public class ConnectionController extends SubForm {
}
}
getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(() -> {
getHConnection().stateProperty().addListener((observable, oldValue, newValue) -> Platform.runLater(() -> {
updateInputUI();
if (newState == HState.NOT_CONNECTED) {
if (newValue == HState.NOT_CONNECTED) {
state.setKey(0, "tab.connection.state.notconnected");
connect.setKey(0, "tab.connection.button.connect");
outHost.setText("");
outPort.setText("");
}
else if (oldState == HState.NOT_CONNECTED) {
else if (oldValue == HState.NOT_CONNECTED)
connect.setKey(0, "tab.connection.button.abort");
}
if (newState == HState.CONNECTED) {
if (newValue == HState.CONNECTED)
state.setKey(0, "tab.connection.state.connected");
}
if (newState == HState.WAITING_FOR_CLIENT) {
if (newValue == HState.WAITING_FOR_CLIENT)
state.setKey(0, "tab.connection.state.waiting");
if (newValue == HState.CONNECTED && useFlash()) {
final String host = getHConnection().getDomain();
final int port = getHConnection().getServerPort();
outHost.setText(host);
outPort.setText(Integer.toString(port));
GEarthProperties.hostProperty.set(host);
GEarthProperties.portProperty.set(port);
}
if (newState == HState.CONNECTED && useFlash()) {
outHost.setText(getHConnection().getDomain());
outPort.setText(getHConnection().getServerPort()+"");
JSONObject connectionSettings = new JSONObject();
connectionSettings.put(AUTODETECT_CACHE, cbx_autodetect.isSelected());
connectionSettings.put(HOST_CACHE, inpHost.getEditor().getText());
connectionSettings.put(PORT_CACHE, Integer.parseInt(inpPort.getEditor().getText()));
Cacher.put(CONNECTION_INFO_CACHE_KEY, connectionSettings);
}
}));
Platform.runLater(this::updateInputUI);
@ -234,9 +215,11 @@ public class ConnectionController extends SubForm {
String port = GEarth.getArgument("--port");
if (host != null && port != null) {
Platform.runLater(() -> {
if (!inpHost.getItems().contains(host)) inpHost.getItems().add(host);
if (!inpHost.getItems().contains(host))
inpHost.getItems().add(host);
inpHost.getSelectionModel().select(host);
if (!inpPort.getItems().contains(port)) inpPort.getItems().add(port);
if (!inpPort.getItems().contains(port))
inpPort.getItems().add(port);
inpPort.getSelectionModel().select(port);
cbx_autodetect.setSelected(false);
});
@ -275,12 +258,9 @@ public class ConnectionController extends SubForm {
} else if (isClientMode(HClient.NITRO)) {
getHConnection().startNitro();
}
if (HConnection.DEBUG) System.out.println("connecting");
if (GEarthProperties.isDebugModeEnabled())
System.out.println("connecting");
}).start();
}
else {
getHConnection().abort();
@ -289,13 +269,10 @@ public class ConnectionController extends SubForm {
@Override
protected void onExit() {
if (rd_flash.isSelected()) {
Cacher.put(CLIENT_CACHE_KEY, HClient.FLASH);
} else if (rd_unity.isSelected()) {
Cacher.put(CLIENT_CACHE_KEY, HClient.UNITY);
} else if (rd_nitro.isSelected()) {
Cacher.put(CLIENT_CACHE_KEY, HClient.NITRO);
}
GEarthProperties.clientTypeProperty.set(
rd_flash.isSelected() ? HClient.FLASH
: rd_unity.isSelected() ? HClient.UNITY
: HClient.NITRO);
getHConnection().abort();
}

View File

@ -8,6 +8,7 @@ import gearth.services.extension_handler.extensions.implementations.network.exec
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunner;
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunnerFactory;
import gearth.services.g_python.GPythonShell;
import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.subforms.extensions.logger.ExtensionLogger;
import gearth.ui.translations.LanguageBundle;
@ -48,6 +49,8 @@ public class ExtensionsController extends SubForm {
scroller.widthProperty().addListener(observable -> header_ext.setPrefWidth(scroller.getWidth()));
extensionLogger = new ExtensionLogger();
btn_install.disableProperty().bind(GEarthProperties.enableDeveloperModeProperty.not());
initLanguageBinding();
}
@ -79,8 +82,6 @@ public class ExtensionsController extends SubForm {
extensionLogger.log(text);
}
}));
getHConnection().onDeveloperModeChange(this::setLocalInstallingEnabled);
}

View File

@ -1,25 +1,25 @@
package gearth.ui.subforms.extra;
import gearth.GEarth;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.misc.BindingsUtil;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.services.always_admin.AdminService;
import gearth.services.g_python.GPythonVersionUtils;
import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.subforms.info.InfoController;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Optional;
@ -31,16 +31,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
public static final String INFO_URL_GPYTHON = "https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole";
public static final String NOTEPAD_CACHE_KEY = "notepad_text";
public static final String DEVELOP_CACHE_KEY = "develop_mode";
public static final String ALWAYS_ADMIN_KEY = "always_admin";
public static final String SOCKS_CACHE_KEY = "socks_config";
public static final String GPYTHON_CACHE_KEY = "use_gpython";
public static final String SOCKS_IP = "ip";
public static final String SOCKS_PORT = "port";
// public static final String IGNORE_ONCE = "ignore_once";
public TextArea txtarea_notepad;
@ -69,32 +59,23 @@ public class ExtraController extends SubForm implements SocksConfiguration {
url_troubleshooting.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting"));
InfoController.activateHyperlink(url_troubleshooting);
String notepadInitValue = (String)Cacher.get(NOTEPAD_CACHE_KEY);
if (notepadInitValue != null) {
txtarea_notepad.setText(notepadInitValue);
}
BindingsUtil.setAndBindBiDirectional(txtarea_notepad.textProperty(), GEarthProperties.notesProperty);
if (Cacher.getCacheContents().has(SOCKS_CACHE_KEY)) {
JSONObject socksInitValue = Cacher.getCacheContents().getJSONObject(SOCKS_CACHE_KEY);
txt_socksIp.setText(socksInitValue.getString(SOCKS_IP) + ":" + socksInitValue.getInt(SOCKS_PORT));
// cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
}
if (Cacher.getCacheContents().has(GPYTHON_CACHE_KEY)) {
cbx_gpython.setSelected(Cacher.getCacheContents().getBoolean(GPYTHON_CACHE_KEY));
}
if (Cacher.getCacheContents().has(ALWAYS_ADMIN_KEY)) {
cbx_admin.setSelected(Cacher.getCacheContents().getBoolean(ALWAYS_ADMIN_KEY));
}
cbx_debug.selectedProperty().addListener(observable -> HConnection.DEBUG = cbx_debug.isSelected());
cbx_disableDecryption.selectedProperty().addListener(observable -> HConnection.DECRYPTPACKETS = !cbx_disableDecryption.isSelected());
cbx_useSocks.selectedProperty().addListener(observable -> grd_socksInfo.setDisable(!cbx_useSocks.isSelected()));
txt_socksIp.textProperty().set(GEarthProperties.getSocksHost()+":"+GEarthProperties.getSocksPort());
GEarthProperties.socksHostProperty.bind(Bindings.createStringBinding(this::getSocksHost, txt_socksIp.textProperty()));
GEarthProperties.socksPortProperty.bind(Bindings.createIntegerBinding(this::getSocksPort, txt_socksIp.textProperty()));
grd_socksInfo.disableProperty().bind(GEarthProperties.enableSocksProperty.not());
BindingsUtil.setAndBindBiDirectional(cbx_useSocks.selectedProperty(), GEarthProperties.enableSocksProperty);
ProxyProviderFactory.setSocksConfig(this);
BindingsUtil.setAndBindBiDirectional(cbx_debug.selectedProperty(), GEarthProperties.enableDebugProperty);
BindingsUtil.setAndBindBiDirectional(cbx_disableDecryption.selectedProperty(), GEarthProperties.disablePacketDecryptionProperty);
BindingsUtil.setAndBindBiDirectional(cbx_alwaysOnTop.selectedProperty(), GEarthProperties.alwaysOnTopProperty);
BindingsUtil.setAndBindBiDirectional(cbx_develop.selectedProperty(), GEarthProperties.enableDeveloperModeProperty);
BindingsUtil.setAndBindBiDirectional(cbx_admin.selectedProperty(), GEarthProperties.alwaysAdminProperty);
BindingsUtil.setAndBindBiDirectional(cbx_gpython.selectedProperty(), GEarthProperties.enableGPythonProperty);
initLanguageBinding();
}
@ -102,47 +83,16 @@ public class ExtraController extends SubForm implements SocksConfiguration {
protected void onParentSet() {
adminService = new AdminService(cbx_admin.isSelected(), getHConnection());
getHConnection().addTrafficListener(1, message -> adminService.onMessage(message));
getHConnection().getStateObservable().addListener((oldState, newState) -> {if (newState == HState.CONNECTED) adminService.onConnect();});
parentController.getStage().setAlwaysOnTop(cbx_alwaysOnTop.isSelected());
cbx_alwaysOnTop.selectedProperty().addListener(observable -> parentController.getStage().setAlwaysOnTop(cbx_alwaysOnTop.isSelected()));
cbx_advanced.selectedProperty().addListener(observable -> updateAdvancedUI());
getHConnection().getStateObservable().addListener((oldState, newState) -> {
if (oldState == HState.NOT_CONNECTED || newState == HState.NOT_CONNECTED) {
getHConnection().stateProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == HState.CONNECTED)
adminService.onConnect();
if (oldValue == HState.NOT_CONNECTED || newValue == HState.NOT_CONNECTED)
updateAdvancedUI();
}
});
if (Cacher.getCacheContents().has(DEVELOP_CACHE_KEY)) {
boolean inDevelopMode = Cacher.getCacheContents().getBoolean(DEVELOP_CACHE_KEY);
setDevelopMode(inDevelopMode);
}
cbx_advanced.selectedProperty().addListener(observable -> updateAdvancedUI());
updateAdvancedUI();
}
@Override
protected void onExit() {
Cacher.put(NOTEPAD_CACHE_KEY, txtarea_notepad.getText());
Cacher.put(GPYTHON_CACHE_KEY, cbx_gpython.isSelected());
Cacher.put(ALWAYS_ADMIN_KEY, cbx_admin.isSelected());
Cacher.put(DEVELOP_CACHE_KEY, cbx_develop.isSelected());
saveSocksConfig();
}
private void saveSocksConfig() {
if (txt_socksIp.getText().contains(":")) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(SOCKS_IP, getSocksHost());
jsonObject.put(SOCKS_PORT, getSocksPort());
Cacher.put(SOCKS_CACHE_KEY, jsonObject);
}
else {
Cacher.remove(SOCKS_CACHE_KEY);
}
}
private void updateAdvancedUI() {
if (!cbx_advanced.isSelected()) {
cbx_debug.setSelected(false);
@ -158,7 +108,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
@Override
public boolean useSocks() {
saveSocksConfig();
return cbx_useSocks.isSelected();
}
@ -265,7 +214,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
private void setDevelopMode(boolean enabled) {
cbx_develop.setSelected(enabled);
getHConnection().setDeveloperMode(enabled);
}
public void adminCbxClick(ActionEvent actionEvent) {

View File

@ -1,23 +1,26 @@
package gearth.ui.subforms.info;
import gearth.GEarth;
import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import gearth.ui.SubForm;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by Jonas on 06/04/18.
*/
public class InfoController extends SubForm {
public class InfoController extends SubForm implements Initializable {
public ImageView img_logo;
public Hyperlink link_darkbox;
public Hyperlink link_g_gearth;
@ -38,7 +41,12 @@ public class InfoController extends SubForm {
});
}
public void initialize() {
@Override
public void initialize(URL location, ResourceBundle resources) {
img_logo.imageProperty().bind(GEarthProperties.logoImageBinding);
version.textProperty().bind(GEarthProperties.themeTitleBinding);
link_darkbox.setTooltip(new Tooltip("https://darkbox.nl"));
link_d_gearth.setTooltip(new Tooltip("https://discord.gg/AVkcF8y"));
link_g_gearth.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth"));
@ -87,4 +95,5 @@ public class InfoController extends SubForm {
btn_donate.textProperty().bind(new TranslatableString("%s", "tab.info.donate"));
}
}

View File

@ -4,10 +4,14 @@ import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
@ -38,10 +42,10 @@ public class InjectionController extends SubForm {
private TranslatableString corruption, pcktInfo;
protected void onParentSet() {
getHConnection().onDeveloperModeChange(developMode -> updateUI());
getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(this::updateUI));
inputPacket.textProperty().addListener(event -> Platform.runLater(this::updateUI));
final InvalidationListener updateUI = observable -> Platform.runLater(this::updateUI);
GEarthProperties.enableDeveloperModeProperty.addListener(updateUI);
getHConnection().stateProperty().addListener(updateUI);
inputPacket.textProperty().addListener(updateUI);
}
public void initialize() {

View File

@ -9,6 +9,15 @@ import gearth.services.scheduler.listeners.OnBeingUpdatedListener;
import gearth.services.scheduler.listeners.OnDeleteListener;
import gearth.services.scheduler.listeners.OnEditListener;
import gearth.services.scheduler.listeners.OnUpdatedListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
public class InteractableScheduleItem extends ScheduleItem implements StringifyAble {

View File

@ -7,9 +7,12 @@ import gearth.protocol.StateChangeListener;
import gearth.protocol.connection.HState;
import gearth.services.scheduler.Interval;
import gearth.services.scheduler.Scheduler;
import gearth.ui.GEarthProperties;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
@ -88,8 +91,9 @@ public class SchedulerController extends SubForm {
@Override
protected void onParentSet() {
scheduler = new Scheduler<>(getHConnection());
getHConnection().onDeveloperModeChange(developMode -> updateUI());
getHConnection().getStateObservable().addListener((oldState, newState) -> updateUI());
final InvalidationListener updateUI = observable -> Platform.runLater(this::updateUI);
GEarthProperties.enableDeveloperModeProperty.addListener(updateUI);
getHConnection().stateProperty().addListener(updateUI);
updateUI();
}

View File

@ -1,16 +1,13 @@
package gearth.ui.titlebar;
import gearth.GEarth;
import gearth.ui.themes.Theme;
import gearth.ui.GEarthProperties;
import javafx.stage.Stage;
import java.util.function.Consumer;
public class GEarthThemedTitleBarConfig extends DefaultTitleBarConfig {
public GEarthThemedTitleBarConfig(Stage stage) {
super(stage, GEarth.getTheme());
GEarth.getThemeObservable().addListener(this::setTheme);
super(stage, GEarthProperties.getTheme());
GEarthProperties.themeProperty.addListener((observable, oldValue, newValue) -> setTheme(newValue));
}
@Override