mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-06-24 17:10:19 +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.util.PlatformThread;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.util.BusyProperty;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
|
@ -94,8 +96,15 @@ public class FileBrowserComp extends SimpleComp {
|
|||
});
|
||||
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
|
||||
tabs.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (modifying.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue.intValue() == -1) {
|
||||
model.getSelected().setValue(null);
|
||||
return;
|
||||
|
@ -104,31 +113,36 @@ public class FileBrowserComp extends SimpleComp {
|
|||
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 -> {
|
||||
while (c.next()) {
|
||||
for (var r : c.getRemoved()) {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
var t = map.remove(r);
|
||||
tabs.getTabs().remove(t);
|
||||
try (var b = new BusyProperty(modifying)) {
|
||||
var t = map.remove(r);
|
||||
tabs.getTabs().remove(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (var a : c.getAddedSubList()) {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
var t = createTab(tabs, a);
|
||||
map.put(a, t);
|
||||
tabs.getTabs().add(t);
|
||||
try (var b = new BusyProperty(modifying)) {
|
||||
var t = createTab(tabs, a);
|
||||
map.put(a, 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 -> {
|
||||
while (c.next()) {
|
||||
for (var r : c.getRemoved()) {
|
||||
|
@ -198,7 +212,7 @@ public class FileBrowserComp extends SimpleComp {
|
|||
.getDisplayIconFileName()
|
||||
: null;
|
||||
},
|
||||
PlatformThread.sync(model.getStore()));
|
||||
model.getStore());
|
||||
var logo = new PrettyImageComp(image, 20, 20).createRegion();
|
||||
|
||||
var label = new Label();
|
||||
|
|
|
@ -83,13 +83,14 @@ public class FileBrowserModel {
|
|||
return;
|
||||
}
|
||||
|
||||
var found = openFileSystems.stream()
|
||||
.filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store))
|
||||
.findFirst();
|
||||
if (found.isPresent()) {
|
||||
selected.setValue(found.get());
|
||||
return;
|
||||
}
|
||||
// Duplication protection (Not needed for now)
|
||||
// var found = openFileSystems.stream()
|
||||
// .filter(fileSystemModel -> fileSystemModel.getStore().getValue().equals(store))
|
||||
// .findFirst();
|
||||
// if (found.isPresent()) {
|
||||
// selected.setValue(found.get());
|
||||
// return;
|
||||
// }
|
||||
|
||||
var model = new OpenFileSystemModel(this);
|
||||
openFileSystems.add(model);
|
||||
|
|
|
@ -22,7 +22,7 @@ public class ThirdPartyDependencyListComp extends Comp<CompStructure<?>> {
|
|||
tp.setPadding(Insets.EMPTY);
|
||||
tp.setGraphic(link);
|
||||
tp.setAlignment(Pos.CENTER_LEFT);
|
||||
AppFont.medium(tp);
|
||||
AppFont.small(tp);
|
||||
|
||||
var licenseName = new Label("(" + t.licenseName() + ")");
|
||||
var sp = new StackPane(link, licenseName);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.xpipe.app.comp.source.store;
|
||||
|
||||
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.MultiStepComp;
|
||||
import io.xpipe.app.core.AppExtensionManager;
|
||||
|
@ -125,6 +124,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
Consumer<DataStoreEntry> con) {
|
||||
var prop = new SimpleObjectProperty<DataStoreProvider>(provider);
|
||||
var store = new SimpleObjectProperty<DataStore>(s);
|
||||
var loading = new SimpleBooleanProperty();
|
||||
var name = "addConnection";
|
||||
Platform.runLater(() -> {
|
||||
var stage = AppWindowHelper.sideWindow(
|
||||
|
@ -137,6 +137,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
|
||||
@Override
|
||||
protected List<Entry> setup() {
|
||||
loading.bind(creator.busy);
|
||||
return List.of(new Entry(AppI18n.observable("a"), creator));
|
||||
}
|
||||
|
||||
|
@ -150,7 +151,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
};
|
||||
},
|
||||
false,
|
||||
null);
|
||||
loading);
|
||||
stage.show();
|
||||
});
|
||||
}
|
||||
|
@ -226,7 +227,7 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
top.getStyleClass().add("top");
|
||||
layout.setTop(top);
|
||||
// layout.getStyleClass().add("data-input-creation-step");
|
||||
return new LoadingOverlayComp(Comp.of(() -> layout), busy).createStructure();
|
||||
return Comp.of(() -> layout).createStructure();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -281,8 +282,8 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
|
||||
ThreadHelper.runAsync(() -> {
|
||||
try (var b = new BusyProperty(busy)) {
|
||||
entry.getValue().setStore(input.getValue());
|
||||
entry.getValue().refresh(true);
|
||||
var e = DataStoreEntry.createNew(UUID.randomUUID(), entry.getValue().getName(), input.getValue());
|
||||
e.refresh(true);
|
||||
finished.setValue(true);
|
||||
PlatformThread.runLaterIfNeeded(parent::next);
|
||||
} 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 dialog = s.getProvider().dialogForStore(s.getStore());
|
||||
var reference = DialogExchangeImpl.add(dialog, (DataStore newStore) -> {
|
||||
s.setStore(newStore);
|
||||
// s.setStore(newStore);
|
||||
});
|
||||
return Response.builder().dialog(reference).build();
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class PlatformThread {
|
|||
}
|
||||
|
||||
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 =
|
||||
new ConcurrentHashMap<>();
|
||||
|
@ -79,10 +79,12 @@ public class PlatformThread {
|
|||
ov.removeListener(invListenerMap.getOrDefault(listener, listener));
|
||||
}
|
||||
};
|
||||
BindingsHelper.linkPersistently(obs, ov);
|
||||
return obs;
|
||||
}
|
||||
|
||||
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 =
|
||||
new ConcurrentHashMap<>();
|
||||
|
@ -263,6 +265,8 @@ public class PlatformThread {
|
|||
ol.removeListener(invListenerMap.getOrDefault(listener, listener));
|
||||
}
|
||||
};
|
||||
BindingsHelper.linkPersistently(obs, ol);
|
||||
return obs;
|
||||
}
|
||||
|
||||
public static void runLaterIfNeeded(Runnable r) {
|
||||
|
|
|
@ -58,15 +58,15 @@ public class DataStorageParser {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
var storeNode = entry.get().getResolvedNode();
|
||||
if (storeNode == null) {
|
||||
var testNode = entry.get().getResolvedNode();
|
||||
if (testNode == null) {
|
||||
TrackEvent.withWarn("storage", "Encountered disabled store").tag("id", id);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
var newSeenIds = new HashSet<>(seenIds);
|
||||
newSeenIds.add(id);
|
||||
return Optional.of(replaceReferenceIds(storeNode, newSeenIds));
|
||||
return Optional.of(replaceReferenceIds(entry.get().getStoreNode(), newSeenIds));
|
||||
});
|
||||
|
||||
node = replaceReferenceIdsForType(node, "sourceId", id -> {
|
||||
|
@ -86,6 +86,10 @@ public class DataStorageParser {
|
|||
var value = getReferenceIdFromNode(node, replacementKeyName).orElse(null);
|
||||
if (value != null) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -152,12 +152,6 @@ public class DataStoreEntry extends StorageElement {
|
|||
return store;
|
||||
}
|
||||
|
||||
public void setStore(DataStore store) {
|
||||
var node = DataStorageWriter.storeToNode(store);
|
||||
this.storeNode = node;
|
||||
simpleRefresh();
|
||||
}
|
||||
|
||||
public boolean matches(String filter) {
|
||||
return getName().toLowerCase().contains(filter.toLowerCase())
|
||||
|| (!isDisabled()
|
||||
|
@ -204,7 +198,13 @@ public class DataStoreEntry extends StorageElement {
|
|||
dirty = dirty || oldStore != null;
|
||||
listeners.forEach(l -> l.onUpdate());
|
||||
} 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;
|
||||
var complete = newStore.isComplete();
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ public class AppUpdater {
|
|||
event("Was updated is " + hasUpdated);
|
||||
if (hasUpdated) {
|
||||
AppCache.clear("performedUpdate");
|
||||
AppCache.clear("lastUpdateCheckResult");
|
||||
AppCache.clear("downloadedUpdate");
|
||||
event("Found information about recent update");
|
||||
}
|
||||
|
||||
|
@ -217,9 +219,6 @@ public class AppUpdater {
|
|||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
AppCache.clear("lastUpdateCheckResult");
|
||||
AppCache.clear("downloadedUpdate");
|
||||
|
||||
var performedUpdate = new PerformedUpdate(
|
||||
downloadedUpdate.getValue().getVersion(),
|
||||
downloadedUpdate.getValue().getBody(),
|
||||
|
|
|
@ -17,9 +17,9 @@ public class UpdateAvailableAlert {
|
|||
}
|
||||
|
||||
var update = AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("updateReadyTitle"));
|
||||
alert.setHeaderText(AppI18n.get("updateReadyHeader"));
|
||||
alert.setContentText(AppI18n.get("updateReadyContent"));
|
||||
alert.setTitle(AppI18n.get("updateReadyAlertTitle"));
|
||||
alert.setHeaderText(AppI18n.get("updateReadyAlertHeader"));
|
||||
alert.setContentText(AppI18n.get("updateReadyAlertContent"));
|
||||
alert.setAlertType(Alert.AlertType.INFORMATION);
|
||||
})
|
||||
.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
|
||||
more=More
|
||||
pipeDataSource=Pipe Data Source
|
||||
updateReadyTitle=Update Ready
|
||||
updateReadyHeader=An update is ready to be installed
|
||||
updateReadyContent=This will install the new version.
|
||||
updateReadyAlertTitle=Update Ready
|
||||
updateReadyAlertHeader=An update to version $VERSION$ is ready to be installed
|
||||
updateReadyAlertContent=This will install the new version and restart X-Pipe once the installation finished.
|
||||
errorNoDetail=No error details are available
|
||||
updateAvailableTitle=Update Available
|
||||
updateAvailableHeader=An X-Pipe update is available to install
|
||||
|
|
Loading…
Reference in a new issue