mirror of
https://github.com/xpipe-io/xpipe.git
synced 2025-04-15 08:43:35 +00:00
Various bug fixes for updater, exit behaviour, error handling
This commit is contained in:
parent
b507ed8a11
commit
a37821e22c
21 changed files with 159 additions and 86 deletions
|
@ -74,14 +74,8 @@ public class StoreSection {
|
|||
private static ObservableList<StoreSection> sorted(
|
||||
ObservableList<StoreSection> list, ObservableValue<StoreCategoryWrapper> category) {
|
||||
var c = Comparator.<StoreSection>comparingInt(
|
||||
value -> value.getWrapper().getEntry().getValidity().isUsable() ? 1 : -1);
|
||||
category.getValue().getSortMode().addListener((observable, oldValue, newValue) -> {
|
||||
int a = 0;
|
||||
});
|
||||
value -> value.getWrapper().getEntry().getValidity().isUsable() ? -1 : 1);
|
||||
var mapped = BindingsHelper.mappedBinding(category, storeCategoryWrapper -> storeCategoryWrapper.getSortMode());
|
||||
mapped.addListener((observable, oldValue, newValue) -> {
|
||||
int a = 0;
|
||||
});
|
||||
return BindingsHelper.orderedContentBinding(
|
||||
list,
|
||||
(o1, o2) -> {
|
||||
|
|
|
@ -117,13 +117,24 @@ public class StoreViewState {
|
|||
}
|
||||
|
||||
public static void init() {
|
||||
if (INSTANCE != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
new StoreViewState();
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
AppCache.update(
|
||||
"selectedCategory",
|
||||
INSTANCE.activeCategory.getValue().getCategory().getUuid());
|
||||
if (INSTANCE == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var active = INSTANCE.activeCategory.getValue().getCategory();
|
||||
if (active == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppCache.update("selectedCategory", active.getUuid());
|
||||
INSTANCE = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ package io.xpipe.app.core.mode;
|
|||
import io.xpipe.app.core.App;
|
||||
import io.xpipe.app.core.AppGreetings;
|
||||
import io.xpipe.app.core.AppMainWindow;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.issue.*;
|
||||
import io.xpipe.app.update.CommercializationAlert;
|
||||
import io.xpipe.app.update.UpdateChangelogAlert;
|
||||
import io.xpipe.app.util.PlatformState;
|
||||
import io.xpipe.app.util.UnlockAlert;
|
||||
import javafx.application.Platform;
|
||||
|
||||
|
@ -21,7 +21,7 @@ public class GuiMode extends PlatformMode {
|
|||
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
super.platformSetup();
|
||||
super.onSwitchTo();
|
||||
|
||||
UnlockAlert.showIfNeeded();
|
||||
UpdateChangelogAlert.showIfNeeded();
|
||||
|
@ -53,11 +53,11 @@ public class GuiMode extends PlatformMode {
|
|||
|
||||
@Override
|
||||
public void onSwitchFrom() {
|
||||
if (PlatformState.getCurrent() == PlatformState.RUNNING) {
|
||||
super.onSwitchFrom();
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
TrackEvent.info("mode", "Closing window");
|
||||
App.getApp().close();
|
||||
waitForPlatform();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.xpipe.core.util.FailableRunnable;
|
|||
import io.xpipe.core.util.XPipeDaemonMode;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
import io.xpipe.core.util.XPipeSystemId;
|
||||
import javafx.application.Platform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -72,6 +73,7 @@ public abstract class OperationMode {
|
|||
try {
|
||||
// Only for handling SIGTERM
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
TrackEvent.info("Received SIGTERM externally");
|
||||
OperationMode.shutdown(true, false);
|
||||
}));
|
||||
|
||||
|
@ -178,8 +180,7 @@ public abstract class OperationMode {
|
|||
}
|
||||
|
||||
public static void executeAfterShutdown(FailableRunnable<Exception> r) {
|
||||
// Creates separate non daemon thread to force execution after shutdown even if current thread is a daemon
|
||||
var t = new Thread(() -> {
|
||||
Runnable exec = () -> {
|
||||
if (inShutdown) {
|
||||
return;
|
||||
}
|
||||
|
@ -198,12 +199,19 @@ public abstract class OperationMode {
|
|||
}
|
||||
|
||||
OperationMode.halt(0);
|
||||
});
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException ignored) {
|
||||
};
|
||||
|
||||
if (Platform.isFxApplicationThread() || !Thread.currentThread().isDaemon()) {
|
||||
exec.run();
|
||||
} else {
|
||||
// Creates separate non daemon thread to force execution after shutdown even if current thread is a daemon
|
||||
var t = new Thread(exec);
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,6 @@ import io.xpipe.app.update.UpdateAvailableAlert;
|
|||
import io.xpipe.app.util.PlatformState;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class PlatformMode extends OperationMode {
|
||||
|
||||
|
@ -21,7 +17,8 @@ public abstract class PlatformMode extends OperationMode {
|
|||
return PlatformState.getCurrent() == PlatformState.RUNNING;
|
||||
}
|
||||
|
||||
protected void platformSetup() throws Throwable {
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
if (App.getApp() != null) {
|
||||
return;
|
||||
}
|
||||
|
@ -60,25 +57,9 @@ public abstract class PlatformMode extends OperationMode {
|
|||
StoreViewState.init();
|
||||
}
|
||||
|
||||
protected void waitForPlatform() {
|
||||
// The platform thread waits for the shutdown hook to finish in case SIGTERM is sent.
|
||||
// Therefore, we do not wait for the platform when being in a shutdown hook.
|
||||
if (PlatformState.getCurrent() == PlatformState.RUNNING
|
||||
&& !Platform.isFxApplicationThread()
|
||||
&& !OperationMode.isInShutdownHook()) {
|
||||
TrackEvent.info("mode", "Waiting for platform thread ...");
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Platform.runLater(latch::countDown);
|
||||
try {
|
||||
if (!latch.await(5, TimeUnit.SECONDS)) {
|
||||
TrackEvent.info("mode", "Platform wait timed out");
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
TrackEvent.info("mode", "Synced with platform thread");
|
||||
} else {
|
||||
TrackEvent.info("mode", "Not waiting for platform thread");
|
||||
}
|
||||
@Override
|
||||
public void onSwitchFrom() {
|
||||
StoreViewState.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.xpipe.app.core.mode;
|
|||
|
||||
import com.dustinredmond.fxtrayicon.FXTrayIcon;
|
||||
import io.xpipe.app.core.AppTray;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.issue.*;
|
||||
|
||||
public class TrayMode extends PlatformMode {
|
||||
|
@ -18,24 +19,24 @@ public class TrayMode extends PlatformMode {
|
|||
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
super.platformSetup();
|
||||
super.onSwitchTo();
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
if (AppTray.get() == null) {
|
||||
TrackEvent.info("mode", "Initializing tray");
|
||||
AppTray.init();
|
||||
}
|
||||
|
||||
if (AppTray.get() == null) {
|
||||
TrackEvent.info("mode", "Initializing tray");
|
||||
AppTray.init();
|
||||
}
|
||||
|
||||
AppTray.get().show();
|
||||
waitForPlatform();
|
||||
TrackEvent.info("mode", "Finished tray initialization");
|
||||
AppTray.get().show();
|
||||
TrackEvent.info("mode", "Finished tray initialization");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwitchFrom() {
|
||||
super.onSwitchFrom();
|
||||
if (AppTray.get() != null) {
|
||||
TrackEvent.info("mode", "Closing tray");
|
||||
AppTray.get().hide();
|
||||
waitForPlatform();
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> AppTray.get().hide());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package io.xpipe.app.fxcomps.util;
|
||||
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.PlatformState;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
|
@ -274,7 +276,24 @@ public class PlatformThread {
|
|||
return obs;
|
||||
}
|
||||
|
||||
private static boolean canRunPlatform() {
|
||||
if (PlatformState.getCurrent() != PlatformState.RUNNING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Once the shutdown hooks are run, the toolkit is shutdown, causing it to no longer perform runLater operations
|
||||
if (OperationMode.isInShutdownHook()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void runLaterIfNeeded(Runnable r) {
|
||||
if (!canRunPlatform()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable catcher = () -> {
|
||||
try {
|
||||
r.run();
|
||||
|
@ -291,6 +310,10 @@ public class PlatformThread {
|
|||
}
|
||||
|
||||
public static void runLaterIfNeededBlocking(Runnable r) {
|
||||
if (!canRunPlatform()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable catcher = () -> {
|
||||
try {
|
||||
r.run();
|
||||
|
|
|
@ -26,6 +26,7 @@ import javafx.beans.binding.Bindings;
|
|||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableBooleanValue;
|
||||
import javafx.beans.value.ObservableDoubleValue;
|
||||
import javafx.beans.value.ObservableStringValue;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.geometry.Insets;
|
||||
|
@ -166,6 +167,17 @@ public class AppPrefs {
|
|||
startupBehaviourList, startupBehaviour)
|
||||
.render(() -> new TranslatableComboBoxControl<>());
|
||||
|
||||
// Git storage
|
||||
// ===========
|
||||
public final BooleanProperty enableGitStorage = typed(new SimpleBooleanProperty(false), Boolean.class);
|
||||
public ObservableBooleanValue enableGitStorage() {
|
||||
return enableGitStorage;
|
||||
}
|
||||
final StringProperty storageGitRemote = typed(new SimpleStringProperty(""), String.class);
|
||||
public ObservableStringValue storageGitRemote() {
|
||||
return storageGitRemote;
|
||||
}
|
||||
|
||||
// Close behaviour
|
||||
// ===============
|
||||
private final ObjectProperty<CloseBehaviour> closeBehaviour =
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.app.prefs;
|
|||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppWindowHelper;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.ext.PrefsChoiceValue;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
@ -14,6 +15,10 @@ import javafx.scene.layout.VBox;
|
|||
public class CloseBehaviourAlert {
|
||||
|
||||
public static boolean showIfNeeded() {
|
||||
if (OperationMode.isInShutdown()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean set = AppCache.get("closeBehaviourSet", Boolean.class, () -> false);
|
||||
if (set) {
|
||||
return true;
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.dlsc.preferencesfx.util.PreferencesFxUtils;
|
|||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
@ -71,14 +72,15 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
// add to GridPane
|
||||
Element element = elements.get(i);
|
||||
if (element instanceof Field f) {
|
||||
var label = f.getLabel();
|
||||
var descriptionKey = label != null ? label + "Description" : null;
|
||||
|
||||
SimpleControl c = (SimpleControl) ((Field) element).getRenderer();
|
||||
c.setField((Field) element);
|
||||
SimpleControl c = (SimpleControl) f.getRenderer();
|
||||
c.setField(f);
|
||||
AppFont.normal(c.getFieldLabel());
|
||||
c.getFieldLabel().setPrefHeight(AppFont.getPixelSize(1));
|
||||
c.getFieldLabel().setMaxHeight(AppFont.getPixelSize(1));
|
||||
c.getFieldLabel().textProperty().unbind();
|
||||
c.getFieldLabel().textProperty().bind(Bindings.createStringBinding(() -> {
|
||||
return f.labelProperty().get() + (f.isEditable() ? "" : " (Pro)");
|
||||
}, f.labelProperty()));
|
||||
grid.add(c.getFieldLabel(), 0, i + rowAmount);
|
||||
|
||||
var canFocus = BindingsHelper.persist(
|
||||
|
@ -101,6 +103,8 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
descriptionLabel
|
||||
.visibleProperty()
|
||||
.bind(c.getFieldLabel().visibleProperty());
|
||||
|
||||
var descriptionKey = f.getLabel() != null ? f.getLabel() + "Description" : null;
|
||||
if (AppI18n.getInstance().containsKey(descriptionKey)) {
|
||||
rowAmount++;
|
||||
descriptionLabel.textProperty().bind(AppI18n.observable(descriptionKey));
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package io.xpipe.app.prefs;
|
||||
|
||||
import com.dlsc.formsfx.model.structure.BooleanField;
|
||||
import com.dlsc.formsfx.model.structure.StringField;
|
||||
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleControl;
|
||||
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleTextControl;
|
||||
import com.dlsc.preferencesfx.model.Category;
|
||||
import com.dlsc.preferencesfx.model.Group;
|
||||
import com.dlsc.preferencesfx.model.Setting;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.LicenseProvider;
|
||||
import io.xpipe.app.util.LicenseType;
|
||||
import io.xpipe.app.util.LockChangeAlert;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
import javafx.beans.binding.Bindings;
|
||||
|
@ -53,13 +57,39 @@ public class VaultCategory extends AppPrefsCategory {
|
|||
|
||||
@SneakyThrows
|
||||
public Category create() {
|
||||
var pro = LicenseType.isAtLeast(
|
||||
LicenseProvider.get().getLicenseType(), LicenseType.PROFESSIONAL);
|
||||
BooleanField enable = BooleanField.ofBooleanType(prefs.enableGitStorage)
|
||||
.editable(pro)
|
||||
.render(() -> {
|
||||
var c = new CustomToggleControl();
|
||||
return c;
|
||||
});
|
||||
StringField remote = StringField.ofStringType(prefs.storageGitRemote)
|
||||
.editable(pro)
|
||||
.render(() -> {
|
||||
var c = new SimpleTextControl();
|
||||
c.setPrefWidth(1000);
|
||||
return c;
|
||||
});
|
||||
return Category.of(
|
||||
"vault",
|
||||
group(
|
||||
"sharing",
|
||||
Setting.of(
|
||||
"enableGitStorage",
|
||||
enable,
|
||||
prefs.enableGitStorage),
|
||||
Setting.of(
|
||||
"storageGitRemote",
|
||||
remote,
|
||||
prefs.storageGitRemote)),
|
||||
group(
|
||||
"storage",
|
||||
STORAGE_DIR_FIXED
|
||||
? null
|
||||
: Setting.of("storageDirectory", prefs.storageDirectoryControl, prefs.storageDirectory)),
|
||||
: Setting.of(
|
||||
"storageDirectory", prefs.storageDirectoryControl, prefs.storageDirectory)),
|
||||
Group.of("security", Setting.of("workspaceLock", lockCryptControl, prefs.getLockCrypt())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.app.update;
|
|||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.util.XPipeSession;
|
||||
import io.xpipe.core.store.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
|
@ -58,6 +59,7 @@ public enum XPipeDistributionType {
|
|||
|
||||
type = det;
|
||||
AppCache.update("dist", type.getId());
|
||||
TrackEvent.withInfo("Determined distribution type").tag("type",type.getId()).handle();
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Value
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class LicenseRequiredException extends RuntimeException {
|
||||
|
||||
String featureName;
|
||||
|
|
|
@ -25,6 +25,8 @@ public interface ShellControl extends ProcessControl {
|
|||
|
||||
ShellControl getMachineRootSession();
|
||||
|
||||
ShellControl withoutLicenseCheck();
|
||||
|
||||
String getOsName();
|
||||
|
||||
UUID getSystemId();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import io.xpipe.core.util.DataStateProvider;
|
||||
|
||||
/**
|
||||
* A data store represents some form of a location where data is stored, e.g. a file or a database.
|
||||
|
@ -10,6 +11,10 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public interface DataStore {
|
||||
|
||||
default boolean isInStorage() {
|
||||
return DataStateProvider.get().isInStorage(this);
|
||||
}
|
||||
|
||||
default boolean isComplete() {
|
||||
try {
|
||||
checkComplete();
|
||||
|
|
|
@ -6,10 +6,6 @@ import java.util.function.Supplier;
|
|||
|
||||
public interface InternalCacheDataStore extends DataStore {
|
||||
|
||||
default boolean isInStorage() {
|
||||
return DataStateProvider.get().isInStorage(this);
|
||||
}
|
||||
|
||||
default <T> T getCache(String key, Class<T> c, T def) {
|
||||
return DataStateProvider.get().getCache(this, key, c, () -> def);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,12 @@ public interface ShellStore extends DataStore, InternalCacheDataStore, Launchabl
|
|||
|
||||
@Override
|
||||
default void validate() throws Exception {
|
||||
try (ShellControl pc = control().start()) {}
|
||||
var c = control();
|
||||
if (!isInStorage()) {
|
||||
c.withoutLicenseCheck();
|
||||
}
|
||||
|
||||
try (ShellControl pc = c.start()) {}
|
||||
}
|
||||
|
||||
default String queryMachineName() throws Exception {
|
||||
|
|
8
dist/build.gradle
vendored
8
dist/build.gradle
vendored
|
@ -14,14 +14,6 @@ repositories {
|
|||
|
||||
task dist(type: DefaultTask) {}
|
||||
|
||||
clean {
|
||||
setDelete(Set.of())
|
||||
doLast {
|
||||
fileTree(dir: project.buildDir).exclude("jreleaser/**").visit { FileVisitDetails details ->
|
||||
delete details.file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
distTar {
|
||||
enabled = false;
|
||||
|
|
6
dist/changelogs/1.7.0.md
vendored
6
dist/changelogs/1.7.0.md
vendored
|
@ -18,8 +18,8 @@ You will definitely notice this change when you connect to a system.
|
|||
|
||||
### Colors
|
||||
|
||||
For organization purposes when many connections are opened in the file base and terminals at the same time, you can now assign colors to connections.
|
||||
These colors will be shown to identify tabs both within and outside XPipe for example in terminals.
|
||||
You can now assign colors to connections for organizational purposes to help in situations when many connections are opened in the file browser and terminals at the same time.
|
||||
These colors will be shown to identify tabs everywhere within XPipe and also outside of XPipe, for example in terminals.
|
||||
|
||||
### Other changes
|
||||
|
||||
|
@ -29,4 +29,6 @@ These colors will be shown to identify tabs both within and outside XPipe for ex
|
|||
- Save configuration data more frequently to avoid any data loss
|
||||
- Fix shutdown error caused by clipboard being inaccessible
|
||||
- Fix some environment scripts not being sourced correctly
|
||||
- Fix autoupdater not working properly
|
||||
- Fix application not exiting properly on SIGTERM
|
||||
- Many other small miscellaneous fixes and improvements
|
1
dist/debug/windows/xpiped_debug.bat
vendored
1
dist/debug/windows/xpiped_debug.bat
vendored
|
@ -2,3 +2,4 @@
|
|||
set CDS_JVM_OPTS=JVM-ARGS
|
||||
chcp 65001 > NUL
|
||||
CALL "%~dp0\..\runtime\bin\xpiped.bat" %*
|
||||
pause
|
||||
|
|
|
@ -7,9 +7,9 @@ dependencies {
|
|||
testImplementation project(':core')
|
||||
testImplementation project(':app')
|
||||
|
||||
testImplementation "org.openjfx:javafx-base:20.0.1:win"
|
||||
testImplementation "org.openjfx:javafx-controls:20.0.1:win"
|
||||
testImplementation "org.openjfx:javafx-graphics:20.0.1:win"
|
||||
testImplementation "org.openjfx:javafx-base:21:win"
|
||||
testImplementation "org.openjfx:javafx-controls:21:win"
|
||||
testImplementation "org.openjfx:javafx-graphics:21:win"
|
||||
}
|
||||
|
||||
def attachDebugger = System.getProperty('idea.debugger.dispatch.addr') != null
|
||||
|
|
Loading…
Add table
Reference in a new issue