Skip to content

Commit

Permalink
Add alert banner for official communications
Browse files Browse the repository at this point in the history
  • Loading branch information
axpoems committed Mar 20, 2024
1 parent 42a57c4 commit 4e528b5
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import bisq.application.ApplicationService;
import bisq.bisq_easy.NavigationTarget;
import bisq.bonded_roles.security_manager.alert.AlertService;
import bisq.bonded_roles.security_manager.alert.AlertType;
import bisq.bonded_roles.security_manager.alert.AuthorizedAlertData;
import bisq.common.observable.collection.CollectionObserver;
import bisq.desktop.ServiceProvider;
Expand All @@ -28,6 +29,7 @@
import bisq.desktop.common.view.Navigation;
import bisq.desktop.common.view.NavigationController;
import bisq.desktop.components.overlay.Popup;
import bisq.desktop.main.alert.AlertBannerController;
import bisq.desktop.main.content.ContentController;
import bisq.desktop.main.left.LeftNavController;
import bisq.desktop.main.notification.NotificationPanelController;
Expand All @@ -53,6 +55,7 @@ public class MainController extends NavigationController {
private final SettingsService settingsService;
private final UpdaterService updaterService;
private final ApplicationService.Config config;
private final AlertBannerController alertBannerController;

public MainController(ServiceProvider serviceProvider) {
super(NavigationTarget.MAIN);
Expand All @@ -66,11 +69,13 @@ public MainController(ServiceProvider serviceProvider) {
leftNavController = new LeftNavController(serviceProvider);
TopPanelController topPanelController = new TopPanelController(serviceProvider);
NotificationPanelController notificationPanelController = new NotificationPanelController(serviceProvider);
alertBannerController = new AlertBannerController();
view = new MainView(model,
this,
leftNavController.getView().getRoot(),
topPanelController.getView().getRoot(),
notificationPanelController.getView().getRoot());
notificationPanelController.getView().getRoot(),
alertBannerController.getView().getRoot());
}

@Override
Expand Down Expand Up @@ -105,18 +110,12 @@ public void add(AuthorizedAlertData authorizedAlertData) {
}
settingsService.getConsumedAlertIds().add(authorizedAlertData.getId());
Optional<String> optionalMessage = authorizedAlertData.getMessage();
switch (authorizedAlertData.getAlertType()) {
case INFO:
optionalMessage.ifPresentOrElse(message -> new Popup().attention(message).show(),
() -> log.warn("optionalMessage not present"));
break;
case WARN:
case EMERGENCY:
optionalMessage.ifPresentOrElse(message -> new Popup().warning(message).show(),
() -> log.warn("optionalMessage not present"));
break;
case BAN:
break;

if (optionalMessage.isPresent()) {
log.info("Showing alert with message {}", optionalMessage.get());
alertBannerController.showAlert(optionalMessage.get(), authorizedAlertData.getAlertType());
} else {
log.warn("optionalMessage not present");
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ public MainView(MainModel model,
MainController controller,
AnchorPane leftNav,
HBox topPanel,
BorderPane notificationPanel) {
BorderPane notificationPanel,
BorderPane alertBanner) {
super(new HBox(), model, controller);

anchorPane = new AnchorPane();
VBox.setVgrow(anchorPane, Priority.ALWAYS);
VBox vBox = new VBox(topPanel, notificationPanel, anchorPane);
VBox vBox = new VBox(topPanel, notificationPanel, alertBanner, anchorPane);
vBox.setFillWidth(true);
HBox.setHgrow(vBox, Priority.ALWAYS);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.desktop.main.alert;

import bisq.bonded_roles.security_manager.alert.AlertType;
import bisq.desktop.common.view.Controller;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AlertBannerController implements Controller {
private final AlertBannerModel model;
@Getter
private final AlertBannerView view;

public AlertBannerController() {
model = new AlertBannerModel();
view = new AlertBannerView(model, this);
}

@Override
public void onActivate() {
}

@Override
public void onDeactivate() {
}

public void showAlert(String message, AlertType alertType) {
model.getMessage().set(message);
model.getAlertType().set(alertType);
model.getIsAlertVisible().set(true);
}

void onClose() {
model.getIsAlertVisible().set(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.desktop.main.alert;

import bisq.bonded_roles.security_manager.alert.AlertType;
import bisq.desktop.common.view.Model;
import javafx.beans.property.*;
import lombok.Getter;

@Getter
public class AlertBannerModel implements Model {
private final BooleanProperty isAlertVisible = new SimpleBooleanProperty();
private final StringProperty message = new SimpleStringProperty();
private final ObjectProperty<AlertType> alertType = new SimpleObjectProperty<>();

public AlertBannerModel() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* 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.desktop.main.alert;

import bisq.bonded_roles.security_manager.alert.AlertType;
import bisq.desktop.common.Transitions;
import bisq.desktop.common.view.View;
import bisq.desktop.components.containers.Spacer;
import bisq.desktop.components.controls.BisqIconButton;
import javafx.animation.Timeline;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import lombok.extern.slf4j.Slf4j;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;

@Slf4j
public class AlertBannerView extends View<BorderPane, AlertBannerModel, AlertBannerController> {
public static final int DURATION = Transitions.DEFAULT_DURATION / 2;

Label content = new Label();
private final Button closeButton;
private final HBox banner;
private final ChangeListener<Number> contentHeightListener;
private Timeline slideInRightTimeline, slideOutTopTimeline;
private Subscription isVisiblePin, alertTypePin;

public AlertBannerView(AlertBannerModel model, AlertBannerController controller) {
super(new BorderPane(), model, controller);

root.setManaged(false);
root.setVisible(false);

content.setWrapText(true);

closeButton = BisqIconButton.createIconButton("close-white");

banner = new HBox(content, Spacer.fillHBox(), closeButton);
banner.setAlignment(Pos.TOP_CENTER);
banner.setPadding(new Insets(10, 10, 10, 15));

contentHeightListener = ((observable, oldValue, newValue) -> banner.setMinHeight(newValue.doubleValue() + 25)); // padding = 25

root.setCenter(banner);
root.setPadding(new Insets(20, 40, 20, 40));
}

@Override
protected void onViewAttached() {
content.textProperty().bind(model.getMessage());

isVisiblePin = EasyBind.subscribe(model.getIsAlertVisible(), isVisible -> {
if (slideInRightTimeline != null) {
slideInRightTimeline.stop();
slideInRightTimeline = null;
root.setTranslateX(0);
root.setOpacity(1);
}
if (slideOutTopTimeline != null) {
slideOutTopTimeline.stop();
slideOutTopTimeline = null;
root.setTranslateY(0);
root.setOpacity(0);
root.setManaged(false);
root.setVisible(false);
}
if (isVisible) {
root.setManaged(true);
root.setVisible(true);
root.setTranslateY(0);
slideInRightTimeline = Transitions.slideInRight(root, DURATION, () -> {
});
} else {
root.setTranslateX(0);
root.setTranslateY(0);
slideOutTopTimeline = Transitions.slideAndFadeOutTop(root, DURATION, () -> {
root.setManaged(false);
root.setVisible(false);
});
}
});

alertTypePin = EasyBind.subscribe(model.getAlertType(), this::addAlertTypeStyleClass);

content.heightProperty().addListener(contentHeightListener);

closeButton.setOnAction(e -> controller.onClose());
}

@Override
protected void onViewDetached() {
content.textProperty().unbind();

isVisiblePin.unsubscribe();
alertTypePin.unsubscribe();

content.heightProperty().removeListener(contentHeightListener);

closeButton.setOnAction(null);
}

private void addAlertTypeStyleClass(AlertType alertType) {
banner.getStyleClass().clear();
String alertTypeClass;
if (alertType == AlertType.INFO) {
alertTypeClass = "info-banner";
} else if (alertType == AlertType.WARN) {
alertTypeClass = "warn-banner";
} else {
alertTypeClass = "emergency-banner";
}
banner.getStyleClass().addAll("alert-banner", alertTypeClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
@Slf4j
public class NotificationPanelView extends View<BorderPane, NotificationPanelModel, NotificationPanelController> {
public static final int DURATION = Transitions.DEFAULT_DURATION / 2;

private final Label notificationHeadline;
private final Button closeButton;
private final Hyperlink hyperlink;
Expand Down
32 changes: 31 additions & 1 deletion apps/desktop/desktop/src/main/resources/css/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,39 @@
-fx-background-color: -bisq-dark-grey-20;
}

/*******************************************************************************
* AlertBanner *
******************************************************************************/

.alert-banner {
-fx-fill: -bisq-dark-grey-50;
-fx-text-fill: -bisq-dark-grey-50;
-fx-font-size: 1.15em;
-fx-font-family: "IBM Plex Sans";
}

.info-banner,
.warn-banner,
.emergency-banner {
-fx-background-radius: 8;
-fx-border-color: transparent;
}

.info-banner {
-fx-background-color: -bisq-mid-grey-10;
}

.warn-banner {
-fx-background-color: -bisq2-yellow-dim-50;
}

.emergency-banner {
-fx-background-color: -bisq2-red-dim-50;
}


/*******************************************************************************
* NotificationPane *
* NotificationPane *
******************************************************************************/

.notification-pane {
Expand Down

0 comments on commit 4e528b5

Please sign in to comment.