mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-04 03:03:48 +01:00
Add pre-release software update notifications
This commit is contained in:
parent
80cd4a8ad6
commit
da45b8e6cf
10 changed files with 99 additions and 28 deletions
|
@ -17,6 +17,8 @@
|
|||
|
||||
package bisq.core.alert;
|
||||
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import bisq.network.p2p.storage.payload.ExpirablePayload;
|
||||
import bisq.network.p2p.storage.payload.ProtectedStoragePayload;
|
||||
|
||||
|
@ -51,6 +53,7 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
|
||||
private final String message;
|
||||
private final boolean isUpdateInfo;
|
||||
private final boolean isPreReleaseInfo;
|
||||
private final String version;
|
||||
|
||||
@Nullable
|
||||
|
@ -68,9 +71,11 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
|
||||
public Alert(String message,
|
||||
boolean isUpdateInfo,
|
||||
boolean isPreReleaseInfo,
|
||||
String version) {
|
||||
this.message = message;
|
||||
this.isUpdateInfo = isUpdateInfo;
|
||||
this.isPreReleaseInfo = isPreReleaseInfo;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
@ -82,12 +87,14 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
@SuppressWarnings("NullableProblems")
|
||||
public Alert(String message,
|
||||
boolean isUpdateInfo,
|
||||
boolean isPreReleaseInfo,
|
||||
String version,
|
||||
byte[] ownerPubKeyBytes,
|
||||
String signatureAsBase64,
|
||||
Map<String, String> extraDataMap) {
|
||||
this.message = message;
|
||||
this.isUpdateInfo = isUpdateInfo;
|
||||
this.isPreReleaseInfo = isPreReleaseInfo;
|
||||
this.version = version;
|
||||
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
||||
this.signatureAsBase64 = signatureAsBase64;
|
||||
|
@ -103,6 +110,7 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
protobuf.Alert.Builder builder = protobuf.Alert.newBuilder()
|
||||
.setMessage(message)
|
||||
.setIsUpdateInfo(isUpdateInfo)
|
||||
.setIsPreReleaseInfo(isPreReleaseInfo)
|
||||
.setVersion(version)
|
||||
.setOwnerPubKeyBytes(ByteString.copyFrom(ownerPubKeyBytes))
|
||||
.setSignatureAsBase64(signatureAsBase64);
|
||||
|
@ -119,6 +127,7 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
|
||||
return new Alert(proto.getMessage(),
|
||||
proto.getIsUpdateInfo(),
|
||||
proto.getIsPreReleaseInfo(),
|
||||
proto.getVersion(),
|
||||
proto.getOwnerPubKeyBytes().toByteArray(),
|
||||
proto.getSignatureAsBase64(),
|
||||
|
@ -143,7 +152,28 @@ public final class Alert implements ProtectedStoragePayload, ExpirablePayload {
|
|||
ownerPubKeyBytes = Sig.getPublicKeyBytes(ownerPubKey);
|
||||
}
|
||||
|
||||
public boolean isNewVersion() {
|
||||
return Version.isNewVersion(version);
|
||||
public boolean isSoftwareUpdateNotification() {
|
||||
return (isUpdateInfo || isPreReleaseInfo);
|
||||
}
|
||||
|
||||
public boolean isNewVersion(Preferences preferences) {
|
||||
// regular release: always notify user
|
||||
// pre-release: if user has set preference to receive pre-release notification
|
||||
if (isUpdateInfo ||
|
||||
(isPreReleaseInfo && preferences.isNotifyOnPreRelease())) {
|
||||
return Version.isNewVersion(version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canShowPopup(Preferences preferences) {
|
||||
// only show popup if its version is newer than current
|
||||
// and only if user has not checked "don't show again"?
|
||||
return isNewVersion(preferences) && preferences.showAgain(showAgainKey());
|
||||
}
|
||||
|
||||
public String showAgainKey() {
|
||||
return "Update_" + version;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -250,20 +250,23 @@ public class BisqSetup {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void displayAlertIfPresent(Alert alert, boolean openNewVersionPopup) {
|
||||
if (alert != null) {
|
||||
if (alert.isUpdateInfo()) {
|
||||
user.setDisplayedAlert(alert);
|
||||
final boolean isNewVersion = alert.isNewVersion();
|
||||
newVersionAvailableProperty.set(isNewVersion);
|
||||
String key = "Update_" + alert.getVersion();
|
||||
if (isNewVersion && (preferences.showAgain(key) || openNewVersionPopup) && displayUpdateHandler != null) {
|
||||
displayUpdateHandler.accept(alert, key);
|
||||
if (alert == null)
|
||||
return;
|
||||
|
||||
if (alert.isSoftwareUpdateNotification()) {
|
||||
// only process if the alert version is "newer" than ours
|
||||
if (alert.isNewVersion(preferences)) {
|
||||
user.setDisplayedAlert(alert); // save context to compare later
|
||||
newVersionAvailableProperty.set(true); // shows link in footer bar
|
||||
if ((alert.canShowPopup(preferences) || openNewVersionPopup) && displayUpdateHandler != null) {
|
||||
displayUpdateHandler.accept(alert, alert.showAgainKey());
|
||||
}
|
||||
} else {
|
||||
final Alert displayedAlert = user.getDisplayedAlert();
|
||||
if ((displayedAlert == null || !displayedAlert.equals(alert)) && displayAlertHandler != null)
|
||||
displayAlertHandler.accept(alert);
|
||||
}
|
||||
} else {
|
||||
// it is a normal message alert
|
||||
final Alert displayedAlert = user.getDisplayedAlert();
|
||||
if ((displayedAlert == null || !displayedAlert.equals(alert)) && displayAlertHandler != null)
|
||||
displayAlertHandler.accept(alert);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -782,6 +782,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
requestPersistence();
|
||||
}
|
||||
|
||||
public void setNotifyOnPreRelease(boolean value) {
|
||||
prefPayload.setNotifyOnPreRelease(value);
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Getter
|
||||
|
@ -1095,5 +1100,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
void setShowOffersMatchingMyAccounts(boolean value);
|
||||
|
||||
void setDenyApiTaker(boolean value);
|
||||
|
||||
void setNotifyOnPreRelease(boolean value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
private boolean hideNonAccountPaymentMethods;
|
||||
private boolean showOffersMatchingMyAccounts;
|
||||
private boolean denyApiTaker;
|
||||
private boolean notifyOnPreRelease;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -199,7 +200,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
.collect(Collectors.toList()))
|
||||
.setHideNonAccountPaymentMethods(hideNonAccountPaymentMethods)
|
||||
.setShowOffersMatchingMyAccounts(showOffersMatchingMyAccounts)
|
||||
.setDenyApiTaker(denyApiTaker);
|
||||
.setDenyApiTaker(denyApiTaker)
|
||||
.setNotifyOnPreRelease(notifyOnPreRelease);
|
||||
|
||||
Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
|
||||
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((protobuf.TradeCurrency) e.toProtoMessage()));
|
||||
|
@ -296,7 +298,8 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
.collect(Collectors.toList())),
|
||||
proto.getHideNonAccountPaymentMethods(),
|
||||
proto.getShowOffersMatchingMyAccounts(),
|
||||
proto.getDenyApiTaker()
|
||||
proto.getDenyApiTaker(),
|
||||
proto.getNotifyOnPreRelease()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1223,6 +1223,7 @@ setting.preferences.useDarkMode=Use dark mode
|
|||
setting.preferences.sortWithNumOffers=Sort market lists with no. of offers/trades
|
||||
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
|
||||
setting.preferences.denyApiTaker=Deny takers using the API
|
||||
setting.preferences.notifyOnPreRelease=Receive pre-release notifications
|
||||
setting.preferences.resetAllFlags=Reset all \"Don't show again\" flags
|
||||
settings.preferences.languageChange=To apply the language change to all screens requires a restart.
|
||||
settings.preferences.supportLanguageWarning=In case of a dispute, please note that mediation is handled in {0} and arbitration in {1}.
|
||||
|
@ -2658,7 +2659,9 @@ selectDepositTxWindow.select=Select deposit transaction
|
|||
sendAlertMessageWindow.headline=Send global notification
|
||||
sendAlertMessageWindow.alertMsg=Alert message
|
||||
sendAlertMessageWindow.enterMsg=Enter message
|
||||
sendAlertMessageWindow.isUpdate=Is update notification
|
||||
sendAlertMessageWindow.isSoftwareUpdate=Software download notification
|
||||
sendAlertMessageWindow.isUpdate=Is full release
|
||||
sendAlertMessageWindow.isPreRelease=Is pre-release
|
||||
sendAlertMessageWindow.version=New version no.
|
||||
sendAlertMessageWindow.send=Send notification
|
||||
sendAlertMessageWindow.remove=Remove notification
|
||||
|
|
|
@ -41,7 +41,7 @@ public class UserPayloadModelVOTest {
|
|||
public void testRoundtripFull() {
|
||||
UserPayload vo = new UserPayload();
|
||||
vo.setAccountId("accountId");
|
||||
vo.setDisplayedAlert(new Alert("message", true, "version", new byte[]{12, -64, 12}, "string", null));
|
||||
vo.setDisplayedAlert(new Alert("message", true, false, "version", new byte[]{12, -64, 12}, "string", null));
|
||||
vo.setDevelopersFilter(new Filter(Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
Lists.newArrayList(),
|
||||
|
|
|
@ -50,7 +50,7 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow
|
|||
|
||||
checkNotNull(alert, "alertMessage must not be null");
|
||||
|
||||
if (alert.isUpdateInfo()) {
|
||||
if (alert.isUpdateInfo() || alert.isPreReleaseInfo()) {
|
||||
information("");
|
||||
headLine = Res.get("displayAlertMessageWindow.update.headline");
|
||||
} else {
|
||||
|
@ -78,7 +78,7 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow
|
|||
private void addContent() {
|
||||
checkNotNull(alert, "alertMessage must not be null");
|
||||
addMultilineLabel(gridPane, ++rowIndex, alert.getMessage(), 10);
|
||||
if (alert.isUpdateInfo()) {
|
||||
if (alert.isUpdateInfo() || alert.isPreReleaseInfo()) {
|
||||
String url = "https://bisq.network/downloads";
|
||||
HyperlinkWithIcon hyperlinkWithIcon = FormBuilder.addLabelHyperlinkWithIcon(gridPane, ++rowIndex,
|
||||
Res.get("displayAlertMessageWindow.update.download"), url, url).second;
|
||||
|
|
|
@ -39,7 +39,9 @@ import javafx.scene.Scene;
|
|||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
@ -49,6 +51,7 @@ import javafx.geometry.Insets;
|
|||
|
||||
import static bisq.desktop.util.FormBuilder.addInputTextField;
|
||||
import static bisq.desktop.util.FormBuilder.addLabelCheckBox;
|
||||
import static bisq.desktop.util.FormBuilder.addRadioButton;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelTextArea;
|
||||
|
||||
public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> {
|
||||
|
@ -107,13 +110,26 @@ public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> {
|
|||
TextArea alertMessageTextArea = labelTextAreaTuple2.second;
|
||||
Label first = labelTextAreaTuple2.first;
|
||||
first.setMinWidth(150);
|
||||
CheckBox isUpdateCheckBox = addLabelCheckBox(gridPane, ++rowIndex,
|
||||
Res.get("sendAlertMessageWindow.isUpdate"));
|
||||
CheckBox isSoftwareUpdateCheckBox = addLabelCheckBox(gridPane, ++rowIndex,
|
||||
Res.get("sendAlertMessageWindow.isSoftwareUpdate"));
|
||||
HBox hBoxRelease = new HBox();
|
||||
hBoxRelease.setSpacing(10);
|
||||
GridPane.setRowIndex(hBoxRelease, ++rowIndex);
|
||||
|
||||
ToggleGroup toggleGroup = new ToggleGroup();
|
||||
RadioButton isUpdateCheckBox = addRadioButton(gridPane, rowIndex, toggleGroup, Res.get("sendAlertMessageWindow.isUpdate"));
|
||||
RadioButton isPreReleaseCheckBox = addRadioButton(gridPane, rowIndex, toggleGroup, Res.get("sendAlertMessageWindow.isPreRelease"));
|
||||
hBoxRelease.getChildren().addAll(new Label(""), isUpdateCheckBox, isPreReleaseCheckBox);
|
||||
gridPane.getChildren().add(hBoxRelease);
|
||||
|
||||
isSoftwareUpdateCheckBox.setSelected(true);
|
||||
isUpdateCheckBox.setSelected(true);
|
||||
|
||||
InputTextField versionInputTextField = FormBuilder.addInputTextField(gridPane, ++rowIndex,
|
||||
Res.get("sendAlertMessageWindow.version"));
|
||||
versionInputTextField.disableProperty().bind(isUpdateCheckBox.selectedProperty().not());
|
||||
versionInputTextField.disableProperty().bind(isSoftwareUpdateCheckBox.selectedProperty().not());
|
||||
isUpdateCheckBox.disableProperty().bind(isSoftwareUpdateCheckBox.selectedProperty().not());
|
||||
isPreReleaseCheckBox.disableProperty().bind(isSoftwareUpdateCheckBox.selectedProperty().not());
|
||||
|
||||
Button sendButton = new AutoTooltipButton(Res.get("sendAlertMessageWindow.send"));
|
||||
sendButton.getStyleClass().add("action-button");
|
||||
|
@ -121,8 +137,9 @@ public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> {
|
|||
sendButton.setOnAction(e -> {
|
||||
final String version = versionInputTextField.getText();
|
||||
boolean versionOK = false;
|
||||
final boolean isUpdate = isUpdateCheckBox.isSelected();
|
||||
if (isUpdate) {
|
||||
final boolean isUpdate = (isSoftwareUpdateCheckBox.isSelected() && isUpdateCheckBox.isSelected());
|
||||
final boolean isPreRelease = (isSoftwareUpdateCheckBox.isSelected() && isPreReleaseCheckBox.isSelected());
|
||||
if (isUpdate || isPreRelease) {
|
||||
final String[] split = version.split("\\.");
|
||||
versionOK = split.length == 3;
|
||||
if (!versionOK) // Do not translate as only used by devs
|
||||
|
@ -130,10 +147,10 @@ public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> {
|
|||
.onClose(this::blurAgain)
|
||||
.show();
|
||||
}
|
||||
if (!isUpdate || versionOK) {
|
||||
if (!isSoftwareUpdateCheckBox.isSelected() || versionOK) {
|
||||
if (alertMessageTextArea.getText().length() > 0 && keyInputTextField.getText().length() > 0) {
|
||||
if (alertManager.addAlertMessageIfKeyIsValid(
|
||||
new Alert(alertMessageTextArea.getText(), isUpdate, version),
|
||||
new Alert(alertMessageTextArea.getText(), isUpdate, isPreRelease, version),
|
||||
keyInputTextField.getText())
|
||||
)
|
||||
hide();
|
||||
|
|
|
@ -120,7 +120,8 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
|
||||
|
||||
private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically,
|
||||
avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle;
|
||||
avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle,
|
||||
notifyOnPreReleaseToggle;
|
||||
private int gridRow = 0;
|
||||
private int displayCurrenciesGridRowIndex = 0;
|
||||
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
|
||||
|
@ -612,6 +613,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
sortMarketCurrenciesNumerically = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.sortWithNumOffers"));
|
||||
hideNonAccountPaymentMethodsToggle = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.onlyShowPaymentMethodsFromAccount"));
|
||||
denyApiTakerToggle = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.denyApiTaker"));
|
||||
notifyOnPreReleaseToggle = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.notifyOnPreRelease"));
|
||||
resetDontShowAgainButton = addButton(root, ++gridRow, Res.get("setting.preferences.resetAllFlags"), 0);
|
||||
resetDontShowAgainButton.getStyleClass().add("compact-button");
|
||||
resetDontShowAgainButton.setMaxWidth(Double.MAX_VALUE);
|
||||
|
@ -954,6 +956,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
denyApiTakerToggle.setSelected(preferences.isDenyApiTaker());
|
||||
denyApiTakerToggle.setOnAction(e -> preferences.setDenyApiTaker(denyApiTakerToggle.isSelected()));
|
||||
|
||||
notifyOnPreReleaseToggle.setSelected(preferences.isNotifyOnPreRelease());
|
||||
notifyOnPreReleaseToggle.setOnAction(e -> preferences.setNotifyOnPreRelease(notifyOnPreReleaseToggle.isSelected()));
|
||||
|
||||
resetDontShowAgainButton.setOnAction(e -> preferences.resetDontShowAgain());
|
||||
|
||||
editCustomBtcExplorer.setOnAction(e -> {
|
||||
|
@ -1133,6 +1138,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
sortMarketCurrenciesNumerically.setOnAction(null);
|
||||
hideNonAccountPaymentMethodsToggle.setOnAction(null);
|
||||
denyApiTakerToggle.setOnAction(null);
|
||||
notifyOnPreReleaseToggle.setOnAction(null);
|
||||
showOwnOffersInOfferBook.setOnAction(null);
|
||||
resetDontShowAgainButton.setOnAction(null);
|
||||
if (displayStandbyModeFeature) {
|
||||
|
|
|
@ -620,6 +620,7 @@ message Alert {
|
|||
string signature_as_base64 = 4;
|
||||
bytes owner_pub_key_bytes = 5;
|
||||
map<string, string> extra_data = 6;
|
||||
bool is_pre_release_info = 7;
|
||||
}
|
||||
|
||||
message Arbitrator {
|
||||
|
@ -1638,6 +1639,7 @@ message PreferencesPayload {
|
|||
bool hide_non_account_payment_methods = 58;
|
||||
bool show_offers_matching_my_accounts = 59;
|
||||
bool deny_api_taker = 60;
|
||||
bool notify_on_pre_release = 61;
|
||||
}
|
||||
|
||||
message AutoConfirmSettings {
|
||||
|
|
Loading…
Add table
Reference in a new issue