diff --git a/core/src/main/java/bisq/core/user/Cookie.java b/core/src/main/java/bisq/core/user/Cookie.java
new file mode 100644
index 0000000000..bc73d6bbd0
--- /dev/null
+++ b/core/src/main/java/bisq/core/user/Cookie.java
@@ -0,0 +1,63 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.user;
+
+import bisq.common.proto.ProtoUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+
+/**
+ * Serves as flexible container for persisting UI states, layout,...
+ * Should not be over-used for domain specific data where type safety and data integrity is important.
+ */
+public class Cookie extends HashMap {
+
+ public void putAsDouble(CookieKey key, double value) {
+ put(key, String.valueOf(value));
+ }
+
+ public Optional getAsOptionalDouble(CookieKey key) {
+ try {
+ return containsKey(key) ?
+ Optional.of(Double.parseDouble(get(key))) :
+ Optional.empty();
+ } catch (Throwable t) {
+ return Optional.empty();
+ }
+ }
+
+ public Map toProtoMessage() {
+ Map protoMap = new HashMap<>();
+ this.forEach((key, value) -> protoMap.put(key.name(), value));
+ return protoMap;
+ }
+
+ public static Cookie fromProto(@Nullable Map protoMap) {
+ Cookie cookie = new Cookie();
+ if (protoMap != null) {
+ protoMap.forEach((key, value) -> cookie.put(ProtoUtil.enumFromProto(CookieKey.class, key), value));
+ }
+ return cookie;
+ }
+
+
+}
diff --git a/core/src/main/java/bisq/core/user/CookieKey.java b/core/src/main/java/bisq/core/user/CookieKey.java
new file mode 100644
index 0000000000..c8653e54bb
--- /dev/null
+++ b/core/src/main/java/bisq/core/user/CookieKey.java
@@ -0,0 +1,26 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.user;
+
+// Used for persistence of Cookie. Entries must not be changes or removed. Only adding entries is permitted.
+public enum CookieKey {
+ STAGE_X,
+ STAGE_Y,
+ STAGE_W,
+ STAGE_H
+}
diff --git a/core/src/main/java/bisq/core/user/User.java b/core/src/main/java/bisq/core/user/User.java
index 2f8480e162..04edaf82b5 100644
--- a/core/src/main/java/bisq/core/user/User.java
+++ b/core/src/main/java/bisq/core/user/User.java
@@ -514,4 +514,8 @@ public class User implements PersistedDataHost {
private boolean paymentAccountExists(PaymentAccount paymentAccount) {
return getPaymentAccountsAsObservable().stream().anyMatch(e -> e.equals(paymentAccount));
}
+
+ public Cookie getCookie() {
+ return userPayload.getCookie();
+ }
}
diff --git a/core/src/main/java/bisq/core/user/UserPayload.java b/core/src/main/java/bisq/core/user/UserPayload.java
index 212570a6f7..3f2a892f06 100644
--- a/core/src/main/java/bisq/core/user/UserPayload.java
+++ b/core/src/main/java/bisq/core/user/UserPayload.java
@@ -80,6 +80,11 @@ public class UserPayload implements PersistableEnvelope {
@Nullable
private List acceptedRefundAgents = new ArrayList<>();
+ // Added at 1.5.3
+ // Generic map for persisting various UI states. We keep values un-typed as string to
+ // provide sufficient flexibility.
+ private Cookie cookie = new Cookie();
+
public UserPayload() {
}
@@ -118,6 +123,7 @@ public class UserPayload implements PersistableEnvelope {
Optional.ofNullable(acceptedRefundAgents)
.ifPresent(e -> builder.addAllAcceptedRefundAgents(ProtoUtil.collectionToProto(acceptedRefundAgents,
message -> ((protobuf.StoragePayload) message).getRefundAgent())));
+ Optional.ofNullable(cookie).ifPresent(e -> builder.putAllCookie(cookie.toProtoMessage()));
return protobuf.PersistableEnvelope.newBuilder().setUserPayload(builder).build();
}
@@ -147,7 +153,8 @@ public class UserPayload implements PersistableEnvelope {
proto.hasRegisteredRefundAgent() ? RefundAgent.fromProto(proto.getRegisteredRefundAgent()) : null,
proto.getAcceptedRefundAgentsList().isEmpty() ? new ArrayList<>() : new ArrayList<>(proto.getAcceptedRefundAgentsList().stream()
.map(RefundAgent::fromProto)
- .collect(Collectors.toList()))
+ .collect(Collectors.toList())),
+ Cookie.fromProto(proto.getCookieMap())
);
}
}
diff --git a/desktop/src/main/java/bisq/desktop/app/BisqApp.java b/desktop/src/main/java/bisq/desktop/app/BisqApp.java
index d5c0ac46b2..9a54c68158 100644
--- a/desktop/src/main/java/bisq/desktop/app/BisqApp.java
+++ b/desktop/src/main/java/bisq/desktop/app/BisqApp.java
@@ -38,7 +38,10 @@ import bisq.core.dao.governance.voteresult.MissingDataRequestService;
import bisq.core.locale.Res;
import bisq.core.offer.OpenOffer;
import bisq.core.offer.OpenOfferManager;
+import bisq.core.user.Cookie;
+import bisq.core.user.CookieKey;
import bisq.core.user.Preferences;
+import bisq.core.user.User;
import bisq.common.app.DevEnv;
import bisq.common.app.Log;
@@ -65,6 +68,8 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
+import javafx.geometry.BoundingBox;
+
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
@@ -102,6 +107,7 @@ public class BisqApp extends Application implements UncaughtExceptionHandler {
private boolean popupOpened;
private Scene scene;
private boolean shutDownRequested;
+ private MainView mainView;
public BisqApp() {
shutDownHandler = this::stop;
@@ -126,7 +132,7 @@ public class BisqApp extends Application implements UncaughtExceptionHandler {
public void startApplication(Runnable onApplicationStartedHandler) {
try {
- MainView mainView = loadMainView(injector);
+ mainView = loadMainView(injector);
mainView.setOnApplicationStartedHandler(onApplicationStartedHandler);
scene = createAndConfigScene(mainView, injector);
setupStage(scene);
@@ -256,10 +262,47 @@ public class BisqApp extends Application implements UncaughtExceptionHandler {
stage.setMinHeight(MIN_WINDOW_HEIGHT);
stage.getIcons().add(ImageUtil.getApplicationIconImage());
+ User user = injector.getInstance(User.class);
+ layoutStageFromPersistedData(stage, user);
+ addStageLayoutListeners(stage, user);
+
// make the UI visible
stage.show();
}
+ private void layoutStageFromPersistedData(Stage stage, User user) {
+ Cookie cookie = user.getCookie();
+ cookie.getAsOptionalDouble(CookieKey.STAGE_X).flatMap(x ->
+ cookie.getAsOptionalDouble(CookieKey.STAGE_Y).flatMap(y ->
+ cookie.getAsOptionalDouble(CookieKey.STAGE_W).flatMap(w ->
+ cookie.getAsOptionalDouble(CookieKey.STAGE_H).map(h -> new BoundingBox(x, y, w, h)))))
+ .ifPresent(stageBoundingBox -> {
+ stage.setX(stageBoundingBox.getMinX());
+ stage.setY(stageBoundingBox.getMinY());
+ stage.setWidth(stageBoundingBox.getWidth());
+ stage.setHeight(stageBoundingBox.getHeight());
+ });
+ }
+
+ private void addStageLayoutListeners(Stage stage, User user) {
+ stage.widthProperty().addListener((observable, oldValue, newValue) -> {
+ user.getCookie().putAsDouble(CookieKey.STAGE_W, (double) newValue);
+ user.requestPersistence();
+ });
+ stage.heightProperty().addListener((observable, oldValue, newValue) -> {
+ user.getCookie().putAsDouble(CookieKey.STAGE_H, (double) newValue);
+ user.requestPersistence();
+ });
+ stage.xProperty().addListener((observable, oldValue, newValue) -> {
+ user.getCookie().putAsDouble(CookieKey.STAGE_X, (double) newValue);
+ user.requestPersistence();
+ });
+ stage.yProperty().addListener((observable, oldValue, newValue) -> {
+ user.getCookie().putAsDouble(CookieKey.STAGE_Y, (double) newValue);
+ user.requestPersistence();
+ });
+ }
+
private MainView loadMainView(Injector injector) {
CachingViewLoader viewLoader = injector.getInstance(CachingViewLoader.class);
return (MainView) viewLoader.load(MainView.class);
diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto
index c804938b74..66af295531 100644
--- a/proto/src/main/proto/pb.proto
+++ b/proto/src/main/proto/pb.proto
@@ -1643,6 +1643,7 @@ message UserPayload {
repeated MarketAlertFilter market_alert_filters = 13;
repeated RefundAgent accepted_refund_agents = 14;
RefundAgent registered_refund_agent = 15;
+ map cookie = 16;
}
///////////////////////////////////////////////////////////////////////////////////////////