Merge pull request #4999 from chimp1984/persist-app-window-layout

Add generic map (cookie) to UserPayload
This commit is contained in:
Christoph Atteneder 2020-12-29 19:44:29 +01:00 committed by GitHub
commit a2a542e11e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 2 deletions

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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<CookieKey, String> {
public void putAsDouble(CookieKey key, double value) {
put(key, String.valueOf(value));
}
public Optional<Double> getAsOptionalDouble(CookieKey key) {
try {
return containsKey(key) ?
Optional.of(Double.parseDouble(get(key))) :
Optional.empty();
} catch (Throwable t) {
return Optional.empty();
}
}
public Map<String, String> toProtoMessage() {
Map<String, String> protoMap = new HashMap<>();
this.forEach((key, value) -> protoMap.put(key.name(), value));
return protoMap;
}
public static Cookie fromProto(@Nullable Map<String, String> protoMap) {
Cookie cookie = new Cookie();
if (protoMap != null) {
protoMap.forEach((key, value) -> cookie.put(ProtoUtil.enumFromProto(CookieKey.class, key), value));
}
return cookie;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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
}

View file

@ -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();
}
}

View file

@ -80,6 +80,11 @@ public class UserPayload implements PersistableEnvelope {
@Nullable
private List<RefundAgent> 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())
);
}
}

View file

@ -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);

View file

@ -1643,6 +1643,7 @@ message UserPayload {
repeated MarketAlertFilter market_alert_filters = 13;
repeated RefundAgent accepted_refund_agents = 14;
RefundAgent registered_refund_agent = 15;
map<string, string> cookie = 16;
}
///////////////////////////////////////////////////////////////////////////////////////////