Cleanups, added kotlin support, started with auto login support

This commit is contained in:
Dorving 2022-10-24 17:55:58 +02:00
parent ea5227cd3a
commit fe16f85d82
17 changed files with 264 additions and 47 deletions

View File

@ -1,9 +1,12 @@
import org.gradle.internal.os.OperatingSystem import org.gradle.internal.os.OperatingSystem
plugins { plugins {
kotlin("jvm") version "1.6.10"
kotlin("plugin.serialization") version "1.6.10"
id("org.beryx.runtime") version "1.12.5" id("org.beryx.runtime") version "1.12.5"
id("org.openjfx.javafxplugin") version "0.0.11" id("org.openjfx.javafxplugin") version "0.0.11"
`java-library` `java-library`
`maven-publish`
} }
description = "G-Earth" description = "G-Earth"
@ -32,6 +35,7 @@ dependencies {
implementation("org.json:json:20190722") implementation("org.json:json:20190722")
implementation("org.jsoup:jsoup:1.14.2") implementation("org.jsoup:jsoup:1.14.2")
implementation("org.slf4j:slf4j-jdk14:2.0.0-alpha0") implementation("org.slf4j:slf4j-jdk14:2.0.0-alpha0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3")
} }
java { java {
@ -56,7 +60,16 @@ application {
mainClass.set("gearth.GEarthLauncher") mainClass.set("gearth.GEarthLauncher")
applicationName = "G-Earth" applicationName = "G-Earth"
} }
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "dorving"
artifactId = "gearth"
version = "1.5.3"
from(components["java"])
}
}
}
runtime { runtime {
addModules( addModules(
"java.datatransfer", "java.desktop", "java.prefs", "java.datatransfer", "java.desktop", "java.prefs",

View File

@ -2,15 +2,12 @@ package gearth.extensions;
import gearth.misc.HostInfo; import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable; import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.packet_info.PacketInfoManager; import gearth.services.packet_info.PacketInfoManager;
import javafx.application.HostServices; import javafx.application.HostServices;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.stage.Stage; import javafx.stage.Stage;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import java.util.function.Consumer;
/** /**
* Created by Jonas on 22/09/18. * Created by Jonas on 22/09/18.

View File

@ -1,8 +1,10 @@
package gearth.services.extension_handler.extensions; package gearth.services.extension_handler.extensions;
import gearth.extensions.InternalExtensionBuilder;
import gearth.misc.HostInfo; import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable; import gearth.misc.listenerpattern.Observable;
import gearth.misc.listenerpattern.SynchronizedObservable; import gearth.misc.listenerpattern.SynchronizedObservable;
import gearth.services.extension_handler.extensions.implementations.network.NetworkExtension;
import gearth.services.packet_info.PacketInfoManager; import gearth.services.packet_info.PacketInfoManager;
import gearth.protocol.HMessage; import gearth.protocol.HMessage;
import gearth.protocol.HPacket; import gearth.protocol.HPacket;
@ -11,6 +13,13 @@ import gearth.services.extension_handler.extensions.listeners.OmRemoveClickListe
import gearth.services.extension_handler.extensions.listeners.OnClickListener; import gearth.services.extension_handler.extensions.listeners.OnClickListener;
import gearth.services.extension_handler.extensions.listeners.OnDeleteListener; import gearth.services.extension_handler.extensions.listeners.OnDeleteListener;
/**
* Represents a type of extension created with one of the extension APIs.
*
* @see NetworkExtension extensions connecting to G-Earth from a different process.
* @see InternalExtensionBuilder internal extensions (JAR files) that follow
* the same communication protocol as {@link NetworkExtension network extensions}.
*/
public abstract class GEarthExtension { public abstract class GEarthExtension {

View File

@ -76,13 +76,15 @@ public class NetworkExtension extends GEarthExtension {
byte side = message.readByte(); byte side = message.readByte();
int byteLength = message.readInteger(); int byteLength = message.readInteger();
byte[] packetAsByteArray = message.readBytes(byteLength); byte[] packetAsByteArray = message.readBytes(byteLength);
HPacket packet = new HPacket(packetAsByteArray); HPacket packet = new HPacket(packetAsByteArray);
if (!packet.isCorrupted()) { if (!packet.isCorrupted()) {
log("Forwarding incoming packet (packet="+packet+")");
sendMessage( sendMessage(
side == 0 ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, side == 0 ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER,
packet packet
); );
} else {
log("Received corrupted packet (packet="+packet+")");
} }
} }
else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.MANIPULATEDPACKET) { else if (message.headerId() == NetworkExtensionInfo.INCOMING_MESSAGES_IDS.MANIPULATEDPACKET) {

View File

@ -1,5 +1,7 @@
package gearth.services.extension_handler.extensions.implementations.network; package gearth.services.extension_handler.extensions.implementations.network;
import gearth.Configuration;
import gearth.ConfigurationKt;
import gearth.protocol.HPacket; import gearth.protocol.HPacket;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducer; import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerObserver; import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerObserver;
@ -31,6 +33,7 @@ public class NetworkExtensionsProducer implements ExtensionProducer {
port++; port++;
} }
final Configuration configuration = ConfigurationKt.configuration(port);
new Thread(() -> { new Thread(() -> {
try { try {

View File

@ -3,7 +3,6 @@ package gearth.services.internal_extensions.extensionstore;
import gearth.extensions.ExtensionForm; import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo; import gearth.extensions.ExtensionInfo;
import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController; import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByDateOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreFetch; import gearth.services.internal_extensions.extensionstore.repository.StoreFetch;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository; import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import javafx.application.HostServices; import javafx.application.HostServices;
@ -16,7 +15,7 @@ import javafx.application.HostServices;
) )
public class GExtensionStore extends ExtensionForm { public class GExtensionStore extends ExtensionForm {
public static final int PAGESIZE = 20; public static final int MAX_PAGES = 20;
private StoreRepository repository = null; private StoreRepository repository = null;
private GExtensionStoreController extensionStoreController = null; private GExtensionStoreController extensionStoreController = null;

View File

@ -5,7 +5,6 @@ import gearth.services.internal_extensions.extensionstore.application.entities.C
import gearth.services.internal_extensions.extensionstore.application.entities.HOverview; import gearth.services.internal_extensions.extensionstore.application.entities.HOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.categories.CategoryOverview; import gearth.services.internal_extensions.extensionstore.application.entities.categories.CategoryOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.installed.InstalledOverview; import gearth.services.internal_extensions.extensionstore.application.entities.installed.InstalledOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByDateOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByRatingOverview; import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByRatingOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByUpdateOverview; import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.ByUpdateOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.search.SearchOverview; import gearth.services.internal_extensions.extensionstore.application.entities.search.SearchOverview;
@ -55,10 +54,10 @@ public class GExtensionStoreController implements Initializable {
Element seach_link = webView.getEngine().getDocument().getElementById("search_page"); Element seach_link = webView.getEngine().getDocument().getElementById("search_page");
Map<Element, Supplier<HOverview>> hOverviewSupplier = new HashMap<>(); Map<Element, Supplier<HOverview>> hOverviewSupplier = new HashMap<>();
hOverviewSupplier.put(by_update_link, () -> new ByUpdateOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository())); hOverviewSupplier.put(by_update_link, () -> new ByUpdateOverview(null, 0, GExtensionStore.MAX_PAGES, getStoreRepository()));
hOverviewSupplier.put(by_rating_link, () -> new ByRatingOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository())); hOverviewSupplier.put(by_rating_link, () -> new ByRatingOverview(null, 0, GExtensionStore.MAX_PAGES, getStoreRepository()));
hOverviewSupplier.put(by_category_link, () -> new CategoryOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository())); hOverviewSupplier.put(by_category_link, () -> new CategoryOverview(null, 0, GExtensionStore.MAX_PAGES, getStoreRepository()));
hOverviewSupplier.put(installed_link, () -> new InstalledOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository())); hOverviewSupplier.put(installed_link, () -> new InstalledOverview(null, 0, GExtensionStore.MAX_PAGES, getStoreRepository()));
hOverviewSupplier.put(seach_link, () -> new SearchOverview(null, getStoreRepository())); hOverviewSupplier.put(seach_link, () -> new SearchOverview(null, getStoreRepository()));
Arrays.asList(by_update_link, by_rating_link, by_category_link, installed_link, seach_link).forEach(l -> Arrays.asList(by_update_link, by_rating_link, by_category_link, installed_link, seach_link).forEach(l ->
@ -74,18 +73,18 @@ public class GExtensionStoreController implements Initializable {
Map<Element, Supplier<Integer>> newStartIndex = new HashMap<>(); Map<Element, Supplier<Integer>> newStartIndex = new HashMap<>();
newStartIndex.put(first_btn, () -> 0); newStartIndex.put(first_btn, () -> 0);
newStartIndex.put(prev_btn, () -> getCurrentOverview().getStartIndex() - GExtensionStore.PAGESIZE); newStartIndex.put(prev_btn, () -> getCurrentOverview().getStartIndex() - GExtensionStore.MAX_PAGES);
newStartIndex.put(next_btn, () -> getCurrentOverview().getStartIndex() + GExtensionStore.PAGESIZE); newStartIndex.put(next_btn, () -> getCurrentOverview().getStartIndex() + GExtensionStore.MAX_PAGES);
newStartIndex.put(last_btn, () -> { newStartIndex.put(last_btn, () -> {
int lastPageSize = getCurrentOverview().getMaxAmount() % GExtensionStore.PAGESIZE; int lastPageSize = getCurrentOverview().getMaxAmount() % GExtensionStore.MAX_PAGES;
if (lastPageSize == 0) lastPageSize = GExtensionStore.PAGESIZE; if (lastPageSize == 0) lastPageSize = GExtensionStore.MAX_PAGES;
return getCurrentOverview().getMaxAmount() - lastPageSize; return getCurrentOverview().getMaxAmount() - lastPageSize;
}); });
Arrays.asList(first_btn, prev_btn, next_btn, last_btn).forEach(l -> Arrays.asList(first_btn, prev_btn, next_btn, last_btn).forEach(l ->
((EventTarget) l).addEventListener("click", event ->{ ((EventTarget) l).addEventListener("click", event ->{
if (!initialized || l.getAttribute("class").contains("gdisabled")) return; if (!initialized || l.getAttribute("class").contains("gdisabled")) return;
overwriteCurrentOverview(getCurrentOverview().getNewPage(newStartIndex.get(l).get(), GExtensionStore.PAGESIZE)); overwriteCurrentOverview(getCurrentOverview().getNewPage(newStartIndex.get(l).get(), GExtensionStore.MAX_PAGES));
}, true)); }, true));
@ -164,7 +163,7 @@ public class GExtensionStoreController implements Initializable {
WebUtils.removeClass(last_btn, "gdisabled"); WebUtils.removeClass(last_btn, "gdisabled");
boolean isLast = overview.getMaxAmount() <= overview.getAmount() + overview.getStartIndex(); boolean isLast = overview.getMaxAmount() <= overview.getAmount() + overview.getStartIndex();
boolean isFirst = overview.getStartIndex() < GExtensionStore.PAGESIZE; boolean isFirst = overview.getStartIndex() < GExtensionStore.MAX_PAGES;
if (isLast) { if (isLast) {
WebUtils.addClass(next_btn, "gdisabled"); WebUtils.addClass(next_btn, "gdisabled");
WebUtils.addClass(last_btn, "gdisabled"); WebUtils.addClass(last_btn, "gdisabled");
@ -173,8 +172,8 @@ public class GExtensionStoreController implements Initializable {
WebUtils.addClass(first_btn, "gdisabled"); WebUtils.addClass(first_btn, "gdisabled");
WebUtils.addClass(prev_btn, "gdisabled"); WebUtils.addClass(prev_btn, "gdisabled");
} }
int thispage = Math.max(1, 1 + (overview.getStartIndex() / GExtensionStore.PAGESIZE)); int thispage = Math.max(1, 1 + (overview.getStartIndex() / GExtensionStore.MAX_PAGES));
int lastpage = Math.max(1, 1 + ((overview.getMaxAmount() - 1) / GExtensionStore.PAGESIZE)); int lastpage = Math.max(1, 1 + ((overview.getMaxAmount() - 1) / GExtensionStore.MAX_PAGES));
webView.getEngine().executeScript("document.getElementById('paging_lbl').innerHTML = '" + thispage + " / " + lastpage + "';"); webView.getEngine().executeScript("document.getElementById('paging_lbl').innerHTML = '" + thispage + " / " + lastpage + "';");
@ -211,7 +210,7 @@ public class GExtensionStoreController implements Initializable {
private void onFullInitialize() { private void onFullInitialize() {
initialized = true; initialized = true;
setRootOverview(new ByUpdateOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository())); setRootOverview(new ByUpdateOverview(null, 0, GExtensionStore.MAX_PAGES, getStoreRepository()));
} }
public void gExtensionStore(GExtensionStore gExtensionStore) { public void gExtensionStore(GExtensionStore gExtensionStore) {

View File

@ -1,12 +1,9 @@
package gearth.services.internal_extensions.extensionstore.application.entities; package gearth.services.internal_extensions.extensionstore.application.entities;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.internal_extensions.extensionstore.GExtensionStore; import gearth.services.internal_extensions.extensionstore.GExtensionStore;
import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController; import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController;
import gearth.services.internal_extensions.extensionstore.application.WebUtils; import gearth.services.internal_extensions.extensionstore.application.WebUtils;
import gearth.services.internal_extensions.extensionstore.application.entities.extensiondetails.StoreExtensionDetailsOverview; import gearth.services.internal_extensions.extensionstore.application.entities.extensiondetails.StoreExtensionDetailsOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.CategorizedOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository; import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension; import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import netscape.javascript.JSObject; import netscape.javascript.JSObject;
@ -25,7 +22,7 @@ public class StoreExtensionItem implements ContentItem {
new StoreExtensionDetailsOverview( new StoreExtensionDetailsOverview(
gExtensionStore.getController().getCurrentOverview(), gExtensionStore.getController().getCurrentOverview(),
0, 0,
GExtensionStore.PAGESIZE, GExtensionStore.MAX_PAGES,
storeExtension, storeExtension,
gExtensionStore.getRepository() gExtensionStore.getRepository()
) )

View File

@ -10,7 +10,6 @@ import gearth.services.internal_extensions.extensionstore.repository.models.ExtC
import gearth.services.internal_extensions.extensionstore.repository.querying.ExtensionOrdering; import gearth.services.internal_extensions.extensionstore.repository.querying.ExtensionOrdering;
import netscape.javascript.JSObject; import netscape.javascript.JSObject;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
public class CategoryItem implements ContentItem { public class CategoryItem implements ContentItem {
@ -27,7 +26,7 @@ public class CategoryItem implements ContentItem {
new CategorizedOverview( new CategorizedOverview(
gExtensionStore.getController().getCurrentOverview(), gExtensionStore.getController().getCurrentOverview(),
0, 0,
GExtensionStore.PAGESIZE, GExtensionStore.MAX_PAGES,
gExtensionStore.getRepository(), gExtensionStore.getRepository(),
category category
) )

View File

@ -33,7 +33,9 @@ public abstract class QueriedExtensionOverview extends HOverview {
@Override @Override
public List<? extends ContentItem> getContentItems() { public List<? extends ContentItem> getContentItems() {
return query(startIndex, limit).stream().map(StoreExtensionItem::new).collect(Collectors.toList()); final List<StoreExtension> extensions = query(startIndex, limit);
System.out.println("found "+extensions.size()+" extensions");
return extensions.stream().map(StoreExtensionItem::new).collect(Collectors.toList());
} }
@Override @Override

View File

@ -3,7 +3,6 @@ package gearth.services.internal_extensions.extensionstore.application.entities.
import gearth.services.internal_extensions.extensionstore.GExtensionStore; import gearth.services.internal_extensions.extensionstore.GExtensionStore;
import gearth.services.internal_extensions.extensionstore.application.entities.ContentItem; import gearth.services.internal_extensions.extensionstore.application.entities.ContentItem;
import gearth.services.internal_extensions.extensionstore.application.entities.HOverview; import gearth.services.internal_extensions.extensionstore.application.entities.HOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.extensiondetails.StoreExtensionDetailsOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.SearchedQueryOverview; import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.SearchedQueryOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository; import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
@ -51,7 +50,7 @@ public class SearchOverview extends HOverview {
new SearchedQueryOverview( new SearchedQueryOverview(
gExtensionStore.getController().getCurrentOverview(), gExtensionStore.getController().getCurrentOverview(),
0, 0,
GExtensionStore.PAGESIZE, GExtensionStore.MAX_PAGES,
storeRepository, storeRepository,
searchComponent.getSearchKeyword(), searchComponent.getSearchKeyword(),
searchComponent.getOrdering(), searchComponent.getOrdering(),

View File

@ -43,7 +43,14 @@ public class StoreRepository {
String queryLower = queryString.toLowerCase(); String queryLower = queryString.toLowerCase();
Stream<StoreExtension> stream = getExtensions().stream() final List<StoreExtension> extensions = getExtensions();
for (StoreExtension extension : extensions) {
System.out.println(extension.getTitle());
for (String system : extension.getCompatibility().getSystems()) {
System.out.println(system);
}
}
Stream<StoreExtension> stream = extensions.stream()
.filter(ext -> ext.getTitle().toLowerCase().contains(queryLower) || ext.getDescription().toLowerCase().contains(queryLower) .filter(ext -> ext.getTitle().toLowerCase().contains(queryLower) || ext.getDescription().toLowerCase().contains(queryLower)
|| ext.getAuthors().stream().anyMatch(author -> author.getName().toLowerCase().contains(queryLower) || ext.getAuthors().stream().anyMatch(author -> author.getName().toLowerCase().contains(queryLower)
|| author.getUsername() != null && author.getUsername().toLowerCase().contains(queryLower)) || author.getUsername() != null && author.getUsername().toLowerCase().contains(queryLower))

View File

@ -1,12 +1,14 @@
package gearth.ui.subforms.connection; package gearth.ui.subforms.connection;
import gearth.GEarth; import gearth.GEarth;
import gearth.PropertiesKt;
import gearth.misc.Cacher; import gearth.misc.Cacher;
import gearth.protocol.connection.HClient; import gearth.protocol.connection.HClient;
import gearth.protocol.connection.HState; import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory; import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.services.Constants; import gearth.services.Constants;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.control.*; import javafx.scene.control.*;
import gearth.protocol.HConnection; import gearth.protocol.HConnection;
@ -36,6 +38,10 @@ public class ConnectionController extends SubForm {
public TextField txtfield_hotelversion; public TextField txtfield_hotelversion;
private final Object lock = new Object(); private final Object lock = new Object();
public TextField outEmail;
public TextField outPassword;
public Button loginButton;
private volatile int fullyInitialized = 0; private volatile int fullyInitialized = 0;
@ -158,6 +164,13 @@ public class ConnectionController extends SubForm {
inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected()); inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
cbx_autodetect.setDisable(!useFlash()); cbx_autodetect.setDisable(!useFlash());
if (useFlash()) {
final BooleanProperty autoConnectProperty = PropertiesKt.getAutoConnectSelected();
cbx_autodetect.selectedProperty().bindBidirectional(autoConnectProperty);
if (autoConnectProperty.get())
btnConnect_clicked(null);
}
outHost.setDisable(!useFlash()); outHost.setDisable(!useFlash());
outPort.setDisable(!useFlash()); outPort.setDisable(!useFlash());

View File

@ -0,0 +1,25 @@
package gearth
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import java.io.File
@kotlinx.serialization.Serializable
data class Configuration(val port: Int, val email: String, val password: String)
private val json = Json {
prettyPrint = true
}
@ExperimentalSerializationApi
val configurations by lazy {
val file = File("configurations.json")
if (file.exists()) {
json.decodeFromStream<Array<Configuration>>(file.inputStream())
} else
emptyArray()
}
fun configuration(port: Int) = configurations.find { it.port == port }

View File

@ -0,0 +1,14 @@
package gearth
import javafx.beans.property.SimpleBooleanProperty
import java.nio.file.Paths
private val propertiesManager by lazy { PropertiesManager(Paths.get("session.properties")) }
val autoConnectSelected by lazy {
booleanProperty("autoConnectSelected", true)
}
private fun booleanProperty(name: String, default: Boolean) =
SimpleBooleanProperty(default).apply { propertiesManager.bindBoolean(name, this) }

View File

@ -0,0 +1,90 @@
package gearth
import javafx.beans.property.*
import javafx.scene.paint.Color
import javafx.scene.paint.Material
import javafx.scene.paint.PhongMaterial
import org.slf4j.LoggerFactory
import java.nio.file.Path
import java.nio.file.Paths
import java.util.*
class PropertiesManager(private val saveFilePath: Path) {
private val logger = LoggerFactory.getLogger(PropertiesManager::class.java)
private val properties = Properties()
private lateinit var saveThread: Thread
fun loadFromFile(): Boolean {
if (!saveFilePath.toFile().exists())
return false
try {
properties.load(saveFilePath.toFile().reader())
} catch (e: Exception) {
e.printStackTrace()
}
return true
}
fun startSaveThread() {
if (!this::saveThread.isInitialized) {
saveThread = Thread {
saveToFile()
Thread.sleep(2500L)
}
saveThread.start()
}
}
fun saveToFile() {
logger.info("Saving properties to $saveFilePath")
try {
val saveFile = saveFilePath.toFile()
if (!saveFile.parentFile.exists())
saveFile.parentFile.mkdir()
properties.store(saveFile.writer(), "Contains properties for the Qodat application.")
} catch (e: Exception) {
e.printStackTrace()
}
}
fun <T> bind(key: String, property: Property<T>, transformer: (String) -> T) {
val value = properties.getProperty(key)
if (value != null)
property.value = transformer.invoke(value)
property.addListener { _ ->
properties.setProperty(key, property.value.toString())
}
}
/**
* TODO: finish
*/
fun bindMaterial(key: String, property: ObjectProperty<Material>) =
bind(key, property) { PhongMaterial() }
fun bindPath(key: String, property: ObjectProperty<Path>) =
bind(key, property) { Paths.get(it) }
inline fun <reified T : Enum<T>> bindEnum(key: String, property: ObjectProperty<T>) =
bind(key, property) { enumValueOf<T>(it) }
fun bindColor(key: String, property: ObjectProperty<Color>) =
bind(key, property) { Color.valueOf(it) }
fun bindBoolean(key: String, property: BooleanProperty) =
bind(key, property) { java.lang.Boolean.parseBoolean(it) }
fun bindDouble(key: String, property: DoubleProperty) =
bind(key, property) { java.lang.Double.parseDouble(it) }
fun bindInt(key: String, property: IntegerProperty) =
bind(key, property) { Integer.parseInt(it) }
fun bindString(key: String, property: StringProperty) =
bind(key, property) { it }
}

View File

@ -1,11 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.Button?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.CheckBox?>
<?import javafx.scene.text.*?> <?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.subforms.connection.ConnectionController"> <GridPane alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="258.0" prefWidth="650.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gearth.ui.subforms.connection.ConnectionController">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
@ -176,8 +184,9 @@
</GridPane> </GridPane>
<GridPane alignment="CENTER" GridPane.rowIndex="1"> <GridPane alignment="CENTER" GridPane.rowIndex="1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="340.0" minWidth="10.0" prefWidth="208.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="340.0" minWidth="10.0" prefWidth="144.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="380.0" minWidth="10.0" prefWidth="357.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="380.0" minWidth="10.0" prefWidth="251.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="380.0" minWidth="10.0" prefWidth="265.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
@ -185,13 +194,13 @@
<GridPane.margin> <GridPane.margin>
<Insets /> <Insets />
</GridPane.margin> </GridPane.margin>
<GridPane> <GridPane prefHeight="106.0" prefWidth="50.0">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="62.0" minHeight="10.0" prefHeight="53.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="62.0" minHeight="10.0" prefHeight="37.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="107.0" minHeight="10.0" prefHeight="85.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="107.0" minHeight="10.0" prefHeight="69.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<GridPane.margin> <GridPane.margin>
<Insets bottom="14.0" left="20.0" right="20.0" /> <Insets bottom="14.0" left="20.0" right="20.0" />
@ -212,8 +221,8 @@
</GridPane> </GridPane>
<GridPane style="-fx-border-color: #888888; -fx-border-radius: 5px; " GridPane.columnIndex="1"> <GridPane style="-fx-border-color: #888888; -fx-border-radius: 5px; " GridPane.columnIndex="1">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="10.0" prefWidth="103.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="10.0" prefWidth="82.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="191.0" minWidth="10.0" prefWidth="190.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="191.0" minWidth="10.0" prefWidth="149.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
@ -235,7 +244,7 @@
<Insets left="10.0" /> <Insets left="10.0" />
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<TextField fx:id="outHost" editable="false" GridPane.columnIndex="1"> <TextField fx:id="outHost" editable="false" prefHeight="25.0" prefWidth="122.0" GridPane.columnIndex="1">
<opaqueInsets> <opaqueInsets>
<Insets /> <Insets />
</opaqueInsets> </opaqueInsets>
@ -249,5 +258,45 @@
</GridPane.margin> </GridPane.margin>
</TextField> </TextField>
</GridPane> </GridPane>
<GridPane layoutX="170.0" layoutY="22.0" prefHeight="96.0" prefWidth="262.0" style="-fx-border-color: #888888; -fx-border-radius: 5px; " GridPane.columnIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="140.0" minWidth="10.0" prefWidth="56.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="209.0" minWidth="10.0" prefWidth="204.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="7.0" top="7.0" />
</padding>
<children>
<Label text="Email" textFill="#000000cc">
<GridPane.margin>
<Insets left="10.0" />
</GridPane.margin>
</Label>
<Label text="Pass" textFill="#000000cc" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="10.0" />
</GridPane.margin>
</Label>
<TextField fx:id="outEmail" editable="false" prefHeight="25.0" prefWidth="122.0" GridPane.columnIndex="1">
<opaqueInsets>
<Insets />
</opaqueInsets>
<GridPane.margin>
<Insets left="5.0" right="10.0" />
</GridPane.margin>
</TextField>
<TextField fx:id="outPassword" editable="false" GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="5.0" right="10.0" />
</GridPane.margin>
</TextField>
<Button fx:id="loginButton" mnemonicParsing="false" text="Login" GridPane.columnIndex="1" GridPane.rowIndex="2" />
</children>
</GridPane>
</GridPane> </GridPane>
</GridPane> </GridPane>