mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-07-01 04:21:11 +12:00
Bug fixes [release]
This commit is contained in:
parent
eecafd3cf9
commit
9e3637a97b
|
@ -7,8 +7,10 @@ import io.xpipe.app.fxcomps.SimpleComp;
|
||||||
import io.xpipe.app.fxcomps.impl.PrettyImageComp;
|
import io.xpipe.app.fxcomps.impl.PrettyImageComp;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
import io.xpipe.app.util.BusyProperty;
|
||||||
import io.xpipe.core.store.FileSystem;
|
import io.xpipe.core.store.FileSystem;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
@ -94,8 +96,15 @@ public class FileBrowserComp extends SimpleComp {
|
||||||
});
|
});
|
||||||
tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(model.getSelected().getValue()));
|
tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(model.getSelected().getValue()));
|
||||||
|
|
||||||
|
// Used for ignoring changes by the tabpane when new tabs are added. We want to perform the selections manually!
|
||||||
|
var modifying = new SimpleBooleanProperty();
|
||||||
|
|
||||||
// Handle selection from platform
|
// Handle selection from platform
|
||||||
tabs.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
|
tabs.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (modifying.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (newValue.intValue() == -1) {
|
if (newValue.intValue() == -1) {
|
||||||
model.getSelected().setValue(null);
|
model.getSelected().setValue(null);
|
||||||
return;
|
return;
|
||||||
|
@ -104,31 +113,36 @@ public class FileBrowserComp extends SimpleComp {
|
||||||
model.getSelected().setValue(model.getOpenFileSystems().get(newValue.intValue()));
|
model.getSelected().setValue(model.getOpenFileSystems().get(newValue.intValue()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle selection from model
|
||||||
|
model.getSelected().addListener((observable, oldValue, newValue) -> {
|
||||||
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
|
tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(newValue));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
model.getOpenFileSystems().addListener((ListChangeListener<? super OpenFileSystemModel>) c -> {
|
model.getOpenFileSystems().addListener((ListChangeListener<? super OpenFileSystemModel>) c -> {
|
||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
for (var r : c.getRemoved()) {
|
for (var r : c.getRemoved()) {
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
|
try (var b = new BusyProperty(modifying)) {
|
||||||
var t = map.remove(r);
|
var t = map.remove(r);
|
||||||
tabs.getTabs().remove(t);
|
tabs.getTabs().remove(t);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var a : c.getAddedSubList()) {
|
for (var a : c.getAddedSubList()) {
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
PlatformThread.runLaterIfNeeded(() -> {
|
||||||
|
try (var b = new BusyProperty(modifying)) {
|
||||||
var t = createTab(tabs, a);
|
var t = createTab(tabs, a);
|
||||||
map.put(a, t);
|
map.put(a, t);
|
||||||
tabs.getTabs().add(t);
|
tabs.getTabs().add(t);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
model.getSelected().addListener((observable, oldValue, newValue) -> {
|
|
||||||
PlatformThread.runLaterIfNeeded(() -> {
|
|
||||||
tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(newValue));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tabs.getTabs().addListener((ListChangeListener<? super Tab>) c -> {
|
tabs.getTabs().addListener((ListChangeListener<? super Tab>) c -> {
|
||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
for (var r : c.getRemoved()) {
|
for (var r : c.getRemoved()) {
|
||||||
|
@ -198,7 +212,7 @@ public class FileBrowserComp extends SimpleComp {
|
||||||
.getDisplayIconFileName()
|
.getDisplayIconFileName()
|
||||||
: null;
|
: null;
|
||||||
},
|
},
|
||||||
PlatformThread.sync(model.getStore()));
|
model.getStore());
|
||||||
var logo = new PrettyImageComp(image, 20, 20).createRegion();
|
var logo = new PrettyImageComp(image, 20, 20).createRegion();
|
||||||
|
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
|
|
|
@ -83,13 +83,14 @@ public class FileBrowserModel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var found = openFileSystems.stream()
|
// Duplication protection (Not needed for now)
|
||||||
.filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store))
|
// var found = openFileSystems.stream()
|
||||||
.findFirst();
|
// .filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store))
|
||||||
if (found.isPresent()) {
|
// .findFirst();
|
||||||
selected.setValue(found.get());
|
// if (found.isPresent()) {
|
||||||
return;
|
// selected.setValue(found.get());
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
var model = new OpenFileSystemModel(this);
|
var model = new OpenFileSystemModel(this);
|
||||||
openFileSystems.add(model);
|
openFileSystems.add(model);
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class ThirdPartyDependencyListComp extends Comp<CompStructure<?>> {
|
||||||
tp.setPadding(Insets.EMPTY);
|
tp.setPadding(Insets.EMPTY);
|
||||||
tp.setGraphic(link);
|
tp.setGraphic(link);
|
||||||
tp.setAlignment(Pos.CENTER_LEFT);
|
tp.setAlignment(Pos.CENTER_LEFT);
|
||||||
AppFont.medium(tp);
|
AppFont.small(tp);
|
||||||
|
|
||||||
var licenseName = new Label("(" + t.licenseName() + ")");
|
var licenseName = new Label("(" + t.licenseName() + ")");
|
||||||
var sp = new StackPane(link, licenseName);
|
var sp = new StackPane(link, licenseName);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.xpipe.app.comp.source.store;
|
package io.xpipe.app.comp.source.store;
|
||||||
|
|
||||||
import io.xpipe.app.comp.base.InstallExtensionComp;
|
import io.xpipe.app.comp.base.InstallExtensionComp;
|
||||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
|
||||||
import io.xpipe.app.comp.base.MessageComp;
|
import io.xpipe.app.comp.base.MessageComp;
|
||||||
import io.xpipe.app.comp.base.MultiStepComp;
|
import io.xpipe.app.comp.base.MultiStepComp;
|
||||||
import io.xpipe.app.core.AppExtensionManager;
|
import io.xpipe.app.core.AppExtensionManager;
|
||||||
|
@ -125,6 +124,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
Consumer<DataStoreEntry> con) {
|
Consumer<DataStoreEntry> con) {
|
||||||
var prop = new SimpleObjectProperty<DataStoreProvider>(provider);
|
var prop = new SimpleObjectProperty<DataStoreProvider>(provider);
|
||||||
var store = new SimpleObjectProperty<DataStore>(s);
|
var store = new SimpleObjectProperty<DataStore>(s);
|
||||||
|
var loading = new SimpleBooleanProperty();
|
||||||
var name = "addConnection";
|
var name = "addConnection";
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
var stage = AppWindowHelper.sideWindow(
|
var stage = AppWindowHelper.sideWindow(
|
||||||
|
@ -137,6 +137,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Entry> setup() {
|
protected List<Entry> setup() {
|
||||||
|
loading.bind(creator.busy);
|
||||||
return List.of(new Entry(AppI18n.observable("a"), creator));
|
return List.of(new Entry(AppI18n.observable("a"), creator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
null);
|
loading);
|
||||||
stage.show();
|
stage.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -226,7 +227,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
top.getStyleClass().add("top");
|
top.getStyleClass().add("top");
|
||||||
layout.setTop(top);
|
layout.setTop(top);
|
||||||
// layout.getStyleClass().add("data-input-creation-step");
|
// layout.getStyleClass().add("data-input-creation-step");
|
||||||
return new LoadingOverlayComp(Comp.of(() -> layout), busy).createStructure();
|
return Comp.of(() -> layout).createStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -281,8 +282,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
||||||
|
|
||||||
ThreadHelper.runAsync(() -> {
|
ThreadHelper.runAsync(() -> {
|
||||||
try (var b = new BusyProperty(busy)) {
|
try (var b = new BusyProperty(busy)) {
|
||||||
entry.getValue().setStore(input.getValue());
|
var e = DataStoreEntry.createNew(UUID.randomUUID(), entry.getValue().getName(), input.getValue());
|
||||||
entry.getValue().refresh(true);
|
e.refresh(true);
|
||||||
finished.setValue(true);
|
finished.setValue(true);
|
||||||
PlatformThread.runLaterIfNeeded(parent::next);
|
PlatformThread.runLaterIfNeeded(parent::next);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
30
app/src/main/java/io/xpipe/app/core/AppSplashScreen.java
Normal file
30
app/src/main/java/io/xpipe/app/core/AppSplashScreen.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package io.xpipe.app.core;
|
||||||
|
|
||||||
|
import io.xpipe.app.Main;
|
||||||
|
import javafx.application.ConditionalFeature;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.SceneAntialiasing;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.StageStyle;
|
||||||
|
|
||||||
|
public class AppSplashScreen {
|
||||||
|
|
||||||
|
public static void show() {
|
||||||
|
var stage = new Stage();
|
||||||
|
stage.setWidth(500);
|
||||||
|
stage.setHeight(500);
|
||||||
|
stage.setResizable(false);
|
||||||
|
stage.initStyle(StageStyle.TRANSPARENT);
|
||||||
|
|
||||||
|
var content = new ImageView(Main.class.getResource("resources/img/loading.gif").toString());
|
||||||
|
var aa = Platform.isSupported(ConditionalFeature.SCENE3D)
|
||||||
|
? SceneAntialiasing.BALANCED
|
||||||
|
: SceneAntialiasing.DISABLED;
|
||||||
|
var scene = new Scene(new Pane(content), -1, -1, false, aa);
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ public class EditStoreExchangeImpl extends EditStoreExchange
|
||||||
var s = getStoreEntryByName(msg.getName(), false);
|
var s = getStoreEntryByName(msg.getName(), false);
|
||||||
var dialog = s.getProvider().dialogForStore(s.getStore());
|
var dialog = s.getProvider().dialogForStore(s.getStore());
|
||||||
var reference = DialogExchangeImpl.add(dialog, (DataStore newStore) -> {
|
var reference = DialogExchangeImpl.add(dialog, (DataStore newStore) -> {
|
||||||
s.setStore(newStore);
|
// s.setStore(newStore);
|
||||||
});
|
});
|
||||||
return Response.builder().dialog(reference).build();
|
return Response.builder().dialog(reference).build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class PlatformThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ObservableValue<T> sync(ObservableValue<T> ov) {
|
public static <T> ObservableValue<T> sync(ObservableValue<T> ov) {
|
||||||
return new ObservableValue<>() {
|
ObservableValue<T> obs = new ObservableValue<>() {
|
||||||
|
|
||||||
private final Map<ChangeListener<? super T>, ChangeListener<? super T>> changeListenerMap =
|
private final Map<ChangeListener<? super T>, ChangeListener<? super T>> changeListenerMap =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
@ -79,10 +79,12 @@ public class PlatformThread {
|
||||||
ov.removeListener(invListenerMap.getOrDefault(listener, listener));
|
ov.removeListener(invListenerMap.getOrDefault(listener, listener));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
BindingsHelper.linkPersistently(obs, ov);
|
||||||
|
return obs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ObservableList<T> sync(ObservableList<T> ol) {
|
public static <T> ObservableList<T> sync(ObservableList<T> ol) {
|
||||||
return new ObservableList<>() {
|
ObservableList<T> obs = new ObservableList<>() {
|
||||||
|
|
||||||
private final Map<ListChangeListener<? super T>, ListChangeListener<? super T>> listChangeListenerMap =
|
private final Map<ListChangeListener<? super T>, ListChangeListener<? super T>> listChangeListenerMap =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
@ -263,6 +265,8 @@ public class PlatformThread {
|
||||||
ol.removeListener(invListenerMap.getOrDefault(listener, listener));
|
ol.removeListener(invListenerMap.getOrDefault(listener, listener));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
BindingsHelper.linkPersistently(obs, ol);
|
||||||
|
return obs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runLaterIfNeeded(Runnable r) {
|
public static void runLaterIfNeeded(Runnable r) {
|
||||||
|
|
|
@ -58,15 +58,15 @@ public class DataStorageParser {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var storeNode = entry.get().getResolvedNode();
|
var testNode = entry.get().getResolvedNode();
|
||||||
if (storeNode == null) {
|
if (testNode == null) {
|
||||||
TrackEvent.withWarn("storage", "Encountered disabled store").tag("id", id);
|
TrackEvent.withWarn("storage", "Encountered disabled store").tag("id", id);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var newSeenIds = new HashSet<>(seenIds);
|
var newSeenIds = new HashSet<>(seenIds);
|
||||||
newSeenIds.add(id);
|
newSeenIds.add(id);
|
||||||
return Optional.of(replaceReferenceIds(storeNode, newSeenIds));
|
return Optional.of(replaceReferenceIds(entry.get().getStoreNode(), newSeenIds));
|
||||||
});
|
});
|
||||||
|
|
||||||
node = replaceReferenceIdsForType(node, "sourceId", id -> {
|
node = replaceReferenceIdsForType(node, "sourceId", id -> {
|
||||||
|
@ -86,6 +86,10 @@ public class DataStorageParser {
|
||||||
var value = getReferenceIdFromNode(node, replacementKeyName).orElse(null);
|
var value = getReferenceIdFromNode(node, replacementKeyName).orElse(null);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
var found = function.apply(value);
|
var found = function.apply(value);
|
||||||
|
if (found.isEmpty() || found.get().isNull()) {
|
||||||
|
TrackEvent.withWarn("storage", "Encountered unknown reference").tag("id", value);
|
||||||
|
}
|
||||||
|
|
||||||
return found.orElseGet(NullNode::getInstance);
|
return found.orElseGet(NullNode::getInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,12 +152,6 @@ public class DataStoreEntry extends StorageElement {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStore(DataStore store) {
|
|
||||||
var node = DataStorageWriter.storeToNode(store);
|
|
||||||
this.storeNode = node;
|
|
||||||
simpleRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches(String filter) {
|
public boolean matches(String filter) {
|
||||||
return getName().toLowerCase().contains(filter.toLowerCase())
|
return getName().toLowerCase().contains(filter.toLowerCase())
|
||||||
|| (!isDisabled()
|
|| (!isDisabled()
|
||||||
|
@ -204,7 +198,13 @@ public class DataStoreEntry extends StorageElement {
|
||||||
dirty = dirty || oldStore != null;
|
dirty = dirty || oldStore != null;
|
||||||
listeners.forEach(l -> l.onUpdate());
|
listeners.forEach(l -> l.onUpdate());
|
||||||
} else {
|
} else {
|
||||||
dirty = dirty || !Objects.equals(store, newStore);
|
var newNode = DataStorageWriter.storeToNode(newStore);
|
||||||
|
var nodesEqual = Objects.equals(storeNode, newNode);
|
||||||
|
if (!nodesEqual) {
|
||||||
|
storeNode = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
dirty = dirty || !nodesEqual;
|
||||||
store = newStore;
|
store = newStore;
|
||||||
var complete = newStore.isComplete();
|
var complete = newStore.isComplete();
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ public class AppUpdater {
|
||||||
event("Was updated is " + hasUpdated);
|
event("Was updated is " + hasUpdated);
|
||||||
if (hasUpdated) {
|
if (hasUpdated) {
|
||||||
AppCache.clear("performedUpdate");
|
AppCache.clear("performedUpdate");
|
||||||
|
AppCache.clear("lastUpdateCheckResult");
|
||||||
|
AppCache.clear("downloadedUpdate");
|
||||||
event("Found information about recent update");
|
event("Found information about recent update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,9 +219,6 @@ public class AppUpdater {
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
AppCache.clear("lastUpdateCheckResult");
|
|
||||||
AppCache.clear("downloadedUpdate");
|
|
||||||
|
|
||||||
var performedUpdate = new PerformedUpdate(
|
var performedUpdate = new PerformedUpdate(
|
||||||
downloadedUpdate.getValue().getVersion(),
|
downloadedUpdate.getValue().getVersion(),
|
||||||
downloadedUpdate.getValue().getBody(),
|
downloadedUpdate.getValue().getBody(),
|
||||||
|
|
|
@ -17,9 +17,9 @@ public class UpdateAvailableAlert {
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = AppWindowHelper.showBlockingAlert(alert -> {
|
var update = AppWindowHelper.showBlockingAlert(alert -> {
|
||||||
alert.setTitle(AppI18n.get("updateReadyTitle"));
|
alert.setTitle(AppI18n.get("updateReadyAlertTitle"));
|
||||||
alert.setHeaderText(AppI18n.get("updateReadyHeader"));
|
alert.setHeaderText(AppI18n.get("updateReadyAlertHeader"));
|
||||||
alert.setContentText(AppI18n.get("updateReadyContent"));
|
alert.setContentText(AppI18n.get("updateReadyAlertContent"));
|
||||||
alert.setAlertType(Alert.AlertType.INFORMATION);
|
alert.setAlertType(Alert.AlertType.INFORMATION);
|
||||||
})
|
})
|
||||||
.map(buttonType -> buttonType.getButtonData().isDefaultButton())
|
.map(buttonType -> buttonType.getButtonData().isDefaultButton())
|
||||||
|
|
BIN
app/src/main/resources/io/xpipe/app/resources/img/loading.gif
Normal file
BIN
app/src/main/resources/io/xpipe/app/resources/img/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 201 KiB |
|
@ -48,9 +48,9 @@ target=Target
|
||||||
data=Data
|
data=Data
|
||||||
more=More
|
more=More
|
||||||
pipeDataSource=Pipe Data Source
|
pipeDataSource=Pipe Data Source
|
||||||
updateReadyTitle=Update Ready
|
updateReadyAlertTitle=Update Ready
|
||||||
updateReadyHeader=An update is ready to be installed
|
updateReadyAlertHeader=An update to version $VERSION$ is ready to be installed
|
||||||
updateReadyContent=This will install the new version.
|
updateReadyAlertContent=This will install the new version and restart X-Pipe once the installation finished.
|
||||||
errorNoDetail=No error details are available
|
errorNoDetail=No error details are available
|
||||||
updateAvailableTitle=Update Available
|
updateAvailableTitle=Update Available
|
||||||
updateAvailableHeader=An X-Pipe update is available to install
|
updateAvailableHeader=An X-Pipe update is available to install
|
||||||
|
|
Loading…
Reference in a new issue