mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add popups
This commit is contained in:
parent
8bf207b656
commit
cb8761b74e
@ -21,7 +21,9 @@ public class PopupId {
|
||||
|
||||
// We don't use an enum because it would break updates if we add a new item in a new version
|
||||
|
||||
public static String SEC_DEPOSIT = "SEC_DEPOSIT";
|
||||
public static String TRADE_WALLET = "TRADE_WALLET";
|
||||
public static String TRADE_WALLET = "tradeWallet";
|
||||
public static String SEND_PAYMENT_INFO = "sendPaymentInfo";
|
||||
public static String PAYMENT_SENT = "paymentSent";
|
||||
public static String PAYMENT_RECEIVED = "paymentReceived";
|
||||
|
||||
}
|
||||
|
@ -143,8 +143,10 @@ public class Preferences implements Serializable {
|
||||
showTakeOfferConfirmation = true;
|
||||
|
||||
showAgainMap = new HashMap<>();
|
||||
showAgainMap.put(PopupId.SEC_DEPOSIT, true);
|
||||
showAgainMap.put(PopupId.TRADE_WALLET, true);
|
||||
showAgainMap.put(PopupId.SEND_PAYMENT_INFO, true);
|
||||
showAgainMap.put(PopupId.PAYMENT_SENT, true);
|
||||
showAgainMap.put(PopupId.PAYMENT_RECEIVED, true);
|
||||
|
||||
storage.queueUpForSave();
|
||||
}
|
||||
@ -345,6 +347,10 @@ public class Preferences implements Serializable {
|
||||
return showAgainMap;
|
||||
}
|
||||
|
||||
public boolean showAgain(String key) {
|
||||
return getShowAgainMap().containsKey(key) && getShowAgainMap().get(key);
|
||||
}
|
||||
|
||||
public boolean getTacAccepted() {
|
||||
return tacAccepted;
|
||||
}
|
||||
|
@ -269,7 +269,11 @@ public class User implements Serializable {
|
||||
}*/
|
||||
|
||||
public Arbitrator getAcceptedArbitratorByAddress(Address address) {
|
||||
return acceptedArbitrators.stream().filter(e -> e.getArbitratorAddress().equals(address)).findFirst().get();
|
||||
Optional<Arbitrator> arbitratorOptional = acceptedArbitrators.stream().filter(e -> e.getArbitratorAddress().equals(address)).findFirst();
|
||||
if (arbitratorOptional.isPresent())
|
||||
return arbitratorOptional.get();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,7 +73,7 @@ import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
|
||||
public class BitsquareApp extends Application {
|
||||
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class);
|
||||
|
||||
public static final boolean DEV_MODE = true;
|
||||
public static final boolean DEV_MODE = false;
|
||||
|
||||
private static Environment env;
|
||||
|
||||
|
@ -31,6 +31,7 @@ import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import org.slf4j.Logger;
|
||||
@ -94,6 +95,7 @@ public class OKPayForm extends PaymentMethodForm {
|
||||
checkBox.setSelected(okPayAccount.getTradeCurrencies().contains(e));
|
||||
checkBox.setMinWidth(60);
|
||||
checkBox.setMaxWidth(checkBox.getMinWidth());
|
||||
checkBox.setTooltip(new Tooltip(e.getName()));
|
||||
checkBox.setOnAction(event -> {
|
||||
if (checkBox.isSelected())
|
||||
okPayAccount.addCurrency(e);
|
||||
|
@ -34,6 +34,7 @@ import javafx.geometry.VPos;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.FlowPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.text.TextAlignment;
|
||||
import javafx.util.StringConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -98,9 +99,9 @@ public class SepaForm extends PaymentMethodForm {
|
||||
|
||||
});
|
||||
|
||||
Tuple2<Label, ComboBox> tuple2 = addLabelComboBox(gridPane, ++gridRow, "Country of Bank:");
|
||||
Tuple2<Label, ComboBox> tuple2 = addLabelComboBox(gridPane, ++gridRow, "Country of your Bank:");
|
||||
ComboBox<Country> countryComboBox = tuple2.second;
|
||||
countryComboBox.setPromptText("Select country of Bank");
|
||||
countryComboBox.setPromptText("Select country of your Bank");
|
||||
countryComboBox.setConverter(new StringConverter<Country>() {
|
||||
@Override
|
||||
public String toString(Country country) {
|
||||
@ -141,15 +142,18 @@ public class SepaForm extends PaymentMethodForm {
|
||||
}
|
||||
|
||||
private void addEuroCountriesGrid(boolean isEditable) {
|
||||
addCountriesGrid(isEditable, "Accept taker countries (Euro):", euroCountryCheckBoxes, CountryUtil.getAllSepaEuroCountries());
|
||||
addCountriesGrid(isEditable, "Accept trades from those Euro countries:", euroCountryCheckBoxes, CountryUtil.getAllSepaEuroCountries());
|
||||
}
|
||||
|
||||
private void addNonEuroCountriesGrid(boolean isEditable) {
|
||||
addCountriesGrid(isEditable, "Accepted taker countries (non-Euro):", nonEuroCountryCheckBoxes, CountryUtil.getAllSepaNonEuroCountries());
|
||||
addCountriesGrid(isEditable, "Accept trades from those non-Euro countries:", nonEuroCountryCheckBoxes, CountryUtil.getAllSepaNonEuroCountries());
|
||||
}
|
||||
|
||||
private void addCountriesGrid(boolean isEditable, String title, List<CheckBox> checkBoxList, List<Country> dataProvider) {
|
||||
Label label = addLabel(gridPane, ++gridRow, title, 0);
|
||||
label.setWrapText(true);
|
||||
label.setPrefWidth(200);
|
||||
label.setTextAlignment(TextAlignment.RIGHT);
|
||||
GridPane.setValignment(label, VPos.TOP);
|
||||
FlowPane flowPane = new FlowPane();
|
||||
flowPane.setPadding(new Insets(10, 10, 10, 10));
|
||||
@ -169,7 +173,6 @@ public class SepaForm extends PaymentMethodForm {
|
||||
checkBoxList.add(checkBox);
|
||||
checkBox.setMouseTransparent(!isEditable);
|
||||
checkBox.setMinWidth(45);
|
||||
checkBox.setMaxWidth(checkBox.getMinWidth());
|
||||
checkBox.setTooltip(new Tooltip(country.name));
|
||||
checkBox.setOnAction(event -> {
|
||||
if (checkBox.isSelected())
|
||||
|
@ -338,7 +338,7 @@ class MainViewModel implements ViewModel {
|
||||
|
||||
// tac
|
||||
if (!preferences.getTacAccepted() && !BitsquareApp.DEV_MODE)
|
||||
new TacPopup().url(WebViewPopup.getLocalUrl("tac.html")).onAgree(() -> preferences.setTacAccepted(true)).show();
|
||||
new TacPopup().url(WebViewPopup.getLocalUrl("tac")).onAgree(() -> preferences.setTacAccepted(true)).show();
|
||||
|
||||
|
||||
// update nr of peers in footer
|
||||
|
@ -196,8 +196,8 @@ public class ArbitratorRegistrationView extends ActivatableViewAndModel<VBox, Ar
|
||||
addTitledGroupBg(gridPane, ++gridRow, 2, "Information", Layout.GROUP_DISTANCE);
|
||||
Label infoLabel = addMultilineLabel(gridPane, gridRow);
|
||||
GridPane.setMargin(infoLabel, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
|
||||
infoLabel.setText("Please not that you need to stay available for 15 days after revoking as there might be trades which are using you as " +
|
||||
"arbitrator. The max. allowed trader period is 8 days and the dispute process might take up to 7 days.");
|
||||
infoLabel.setText("Please note that you need to stay available for 15 days after revoking as there might be trades which are using you as " +
|
||||
"arbitrator. The max. allowed trade period is 8 days and the dispute process might take up to 7 days.");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -28,7 +28,6 @@ import io.bitsquare.gui.util.Layout;
|
||||
import io.bitsquare.locale.LanguageUtil;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.control.*;
|
||||
@ -192,12 +191,6 @@ public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, A
|
||||
GridPane.setMargin(autoSelectAllMatchingCheckBox, new Insets(0, -10, 0, -10));
|
||||
autoSelectAllMatchingCheckBox.setOnAction(event -> model.setAutoSelectArbitrators(autoSelectAllMatchingCheckBox.isSelected()));
|
||||
|
||||
Button reloadButton = addButton(root, gridRow, "Reload");
|
||||
GridPane.setColumnIndex(reloadButton, 1);
|
||||
GridPane.setHalignment(reloadButton, HPos.RIGHT);
|
||||
GridPane.setMargin(reloadButton, new Insets(0, -10, 0, -10));
|
||||
reloadButton.setOnAction(event -> model.reload());
|
||||
|
||||
TableColumn<ArbitratorListItem, String> dateColumn = new TableColumn("Registration date");
|
||||
dateColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper(param.getValue().getRegistrationDate()));
|
||||
dateColumn.setMinWidth(130);
|
||||
|
@ -130,10 +130,6 @@ class ArbitratorSelectionViewModel extends ActivatableDataModel {
|
||||
return user.isMyOwnRegisteredArbitrator(arbitrator);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
arbitratorManager.applyArbitrators();
|
||||
}
|
||||
|
||||
private void updateAutoSelectArbitrators() {
|
||||
if (preferences.getAutoSelectArbitrators()) {
|
||||
arbitratorListItems.stream().forEach(item -> {
|
||||
|
@ -25,7 +25,7 @@ import io.bitsquare.gui.main.MainView;
|
||||
import io.bitsquare.gui.main.funds.reserved.ReservedView;
|
||||
import io.bitsquare.gui.main.funds.transactions.TransactionsView;
|
||||
import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView;
|
||||
import io.bitsquare.gui.popups.FirstTimePopup;
|
||||
import io.bitsquare.gui.popups.FirstTimeWebViewPopup;
|
||||
import io.bitsquare.gui.popups.WebViewPopup;
|
||||
import io.bitsquare.user.PopupId;
|
||||
import io.bitsquare.user.Preferences;
|
||||
@ -85,8 +85,9 @@ public class FundsView extends ActivatableViewAndModel<TabPane, Activatable> {
|
||||
else if (root.getSelectionModel().getSelectedItem() == transactionsTab)
|
||||
navigation.navigateTo(MainView.class, FundsView.class, TransactionsView.class);
|
||||
|
||||
if (preferences.getShowAgainMap().get(PopupId.TRADE_WALLET) && !BitsquareApp.DEV_MODE)
|
||||
new FirstTimePopup(preferences).url(WebViewPopup.getLocalUrl("tradeWallet.html")).show();
|
||||
String key = PopupId.TRADE_WALLET;
|
||||
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE)
|
||||
new FirstTimeWebViewPopup(preferences).id(key).url(WebViewPopup.getLocalUrl(key)).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,19 +21,14 @@ import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.listeners.AddressConfidenceListener;
|
||||
import io.bitsquare.gui.components.confidence.ConfidenceProgressIndicator;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionConfidence;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import org.bitcoinj.core.*;
|
||||
|
||||
public class TransactionsListItem {
|
||||
|
||||
|
||||
private final StringProperty date = new SimpleStringProperty();
|
||||
private final StringProperty amount = new SimpleStringProperty();
|
||||
private final StringProperty type = new SimpleStringProperty();
|
||||
@ -44,6 +39,7 @@ public class TransactionsListItem {
|
||||
|
||||
private final Tooltip tooltip;
|
||||
private String addressString;
|
||||
private boolean notAnAddress;
|
||||
private AddressConfidenceListener confidenceListener;
|
||||
|
||||
public TransactionsListItem(Transaction transaction, WalletService walletService, BSFormatter formatter) {
|
||||
@ -64,14 +60,13 @@ public class TransactionsListItem {
|
||||
address =
|
||||
transactionOutput.getScriptPubKey().getToAddress(walletService.getWallet().getParams());
|
||||
addressString = address.toString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addressString = "No sent to address script used.";
|
||||
notAnAddress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (valueSentFromMe.isZero()) {
|
||||
} else if (valueSentFromMe.isZero()) {
|
||||
amount.set(formatter.formatCoin(valueSentToMe));
|
||||
type.set("Received with");
|
||||
|
||||
@ -82,14 +77,13 @@ public class TransactionsListItem {
|
||||
address =
|
||||
transactionOutput.getScriptPubKey().getToAddress(walletService.getWallet().getParams());
|
||||
addressString = address.toString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addressString = "No sent to address script used.";
|
||||
notAnAddress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
amount.set(formatter.formatCoin(valueSentToMe.subtract(valueSentFromMe)));
|
||||
boolean outgoing = false;
|
||||
for (TransactionOutput transactionOutput : transaction.getOutputs()) {
|
||||
@ -100,19 +94,19 @@ public class TransactionsListItem {
|
||||
address = transactionOutput.getScriptPubKey().getToAddress(walletService.getWallet().getParams
|
||||
());
|
||||
addressString = address.toString();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addressString = "No sent to address script used.";
|
||||
notAnAddress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outgoing) {
|
||||
type.set("Sent to");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
type.set("Internal (TX Fee)");
|
||||
addressString = "Internal swap between addresses.";
|
||||
notAnAddress = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,5 +188,9 @@ public class TransactionsListItem {
|
||||
public String getAddressString() {
|
||||
return addressString;
|
||||
}
|
||||
|
||||
public boolean isNotAnAddress() {
|
||||
return notAnAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,10 @@ import java.util.stream.Collectors;
|
||||
@FxmlView
|
||||
public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
|
||||
@FXML TableView<TransactionsListItem> table;
|
||||
@FXML TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, addressColumn, amountColumn, typeColumn,
|
||||
@FXML
|
||||
TableView<TransactionsListItem> table;
|
||||
@FXML
|
||||
TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, addressColumn, amountColumn, typeColumn,
|
||||
confidenceColumn;
|
||||
|
||||
private ObservableList<TransactionsListItem> transactionsListItems;
|
||||
@ -85,12 +87,14 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
// TODO Open popup with details view
|
||||
log.debug("openTxDetails " + item);
|
||||
|
||||
try {
|
||||
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
new Popup().warning("Opening browser failed. Please check your internet " +
|
||||
"connection.").show();
|
||||
if (!item.isNotAnAddress()) {
|
||||
try {
|
||||
Utilities.openWebPage(preferences.getBlockChainExplorer().addressUrl + item.getAddressString());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
new Popup().warning("Opening browser failed. Please check your internet " +
|
||||
"connection.").show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,8 +118,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
hyperlink = new Hyperlink(item.getAddressString());
|
||||
hyperlink.setOnAction(event -> openTxDetails(item));
|
||||
setGraphic(hyperlink);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setGraphic(null);
|
||||
setId(null);
|
||||
}
|
||||
@ -143,8 +146,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||
|
||||
if (item != null && !empty) {
|
||||
setGraphic(item.getProgressIndicator());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
|
||||
formatter.formatCoinWithCode(FeePolicy.TX_FEE) + "\n" +
|
||||
"Receivers amount: " +
|
||||
formatter.formatCoinWithCode(amount.subtract(FeePolicy.TX_FEE)) + " BTC\n\n" +
|
||||
"Are you sure you withdraw that amount?")
|
||||
"Are you sure you want to withdraw that amount?")
|
||||
.onAction(() -> {
|
||||
doWithdraw(amount, callback);
|
||||
})
|
||||
|
@ -56,8 +56,8 @@ public class BuyerSubView extends TradeSubView {
|
||||
@Override
|
||||
protected void addWizards() {
|
||||
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
|
||||
startPayment = new TradeWizardItem(StartPaymentView.class, "Start EUR payment");
|
||||
waitPaymentReceived = new TradeWizardItem(WaitPaymentReceivedView.class, "Wait until EUR payment arrived");
|
||||
startPayment = new TradeWizardItem(StartPaymentView.class, "Start payment");
|
||||
waitPaymentReceived = new TradeWizardItem(WaitPaymentReceivedView.class, "Wait until payment arrived");
|
||||
waitPayoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock");
|
||||
completed = new TradeWizardItem(CompletedView.class, "Completed");
|
||||
|
||||
|
@ -36,6 +36,7 @@ import io.bitsquare.gui.popups.WalletPasswordPopup;
|
||||
import io.bitsquare.payment.PaymentAccountContractData;
|
||||
import io.bitsquare.trade.*;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
@ -69,6 +70,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
||||
private final ObjectProperty<Trade> tradeProperty = new SimpleObjectProperty<>();
|
||||
private final StringProperty txId = new SimpleStringProperty();
|
||||
private Trade trade;
|
||||
private Preferences preferences;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -77,7 +79,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
||||
|
||||
@Inject
|
||||
public PendingTradesDataModel(TradeManager tradeManager, WalletService walletService, TradeWalletService tradeWalletService,
|
||||
User user, KeyRing keyRing, DisputeManager disputeManager,
|
||||
User user, KeyRing keyRing, DisputeManager disputeManager, Preferences preferences,
|
||||
Navigation navigation, WalletPasswordPopup walletPasswordPopup) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.walletService = walletService;
|
||||
@ -85,6 +87,7 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
||||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
this.disputeManager = disputeManager;
|
||||
this.preferences = preferences;
|
||||
this.navigation = navigation;
|
||||
this.walletPasswordPopup = walletPasswordPopup;
|
||||
|
||||
@ -323,6 +326,10 @@ public class PendingTradesDataModel extends ActivatableDataModel {
|
||||
return disputeManager;
|
||||
}
|
||||
|
||||
public Preferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
|
@ -56,8 +56,8 @@ public class SellerSubView extends TradeSubView {
|
||||
@Override
|
||||
protected void addWizards() {
|
||||
waitTxInBlockchain = new TradeWizardItem(WaitTxInBlockchainView.class, "Wait for blockchain confirmation");
|
||||
waitPaymentStarted = new TradeWizardItem(WaitPaymentStartedView.class, "Wait until EUR payment has started");
|
||||
confirmPaymentReceived = new TradeWizardItem(ConfirmPaymentReceivedView.class, "Confirm EUR payment received");
|
||||
waitPaymentStarted = new TradeWizardItem(WaitPaymentStartedView.class, "Wait until payment has started");
|
||||
confirmPaymentReceived = new TradeWizardItem(ConfirmPaymentReceivedView.class, "Confirm payment received");
|
||||
waitPayoutUnlock = new TradeWizardItem(WaitPayoutLockTimeView.class, "Wait for payout unlock");
|
||||
completed = new TradeWizardItem(CompletedView.class, "Completed");
|
||||
|
||||
@ -110,11 +110,11 @@ public class SellerSubView extends TradeSubView {
|
||||
showItem(confirmPaymentReceived);
|
||||
|
||||
if (model.isBlockChainMethod()) {
|
||||
((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The Bitcoin buyer has started the {0} payment." +
|
||||
((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The Bitcoin buyer has started the {0} payment. " +
|
||||
"Check your Altcoin wallet or Block explorer and confirm when you have received the payment.",
|
||||
model.getCurrencyCode()));
|
||||
} else {
|
||||
((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The Bitcoin buyer has started the {0} payment." +
|
||||
((ConfirmPaymentReceivedView) tradeStepDetailsView).setInfoLabelText(BSResources.get("The Bitcoin buyer has started the {0} payment. " +
|
||||
"Check your payment account and confirm when you have received the payment.",
|
||||
model.getCurrencyCode()));
|
||||
}
|
||||
|
@ -17,10 +17,13 @@
|
||||
|
||||
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||
|
||||
import io.bitsquare.app.BitsquareApp;
|
||||
import io.bitsquare.gui.components.TxIdTextField;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||
import io.bitsquare.gui.popups.Popup;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import io.bitsquare.user.PopupId;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.HPos;
|
||||
@ -105,13 +108,23 @@ public class ConfirmPaymentReceivedView extends TradeStepDetailsView {
|
||||
private void onPaymentReceived(ActionEvent actionEvent) {
|
||||
log.debug("onPaymentReceived");
|
||||
if (model.isAuthenticated()) {
|
||||
confirmFiatReceivedButton.setDisable(true);
|
||||
Preferences preferences = model.dataModel.getPreferences();
|
||||
String key = PopupId.PAYMENT_RECEIVED;
|
||||
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
|
||||
new Popup().information("Please note that as soon you have confirmed that you have received the " +
|
||||
"payment the locked Bitcoin will be released.\n" +
|
||||
"There is no way to reverse a Bitcoin payment. Confirm only if you are sure.")
|
||||
.onClose(() -> preferences.dontShowAgain(key))
|
||||
.show();
|
||||
} else {
|
||||
confirmFiatReceivedButton.setDisable(true);
|
||||
|
||||
statusProgressIndicator.setVisible(true);
|
||||
statusProgressIndicator.setProgress(-1);
|
||||
statusLabel.setText("Sending message to trading partner...");
|
||||
statusProgressIndicator.setVisible(true);
|
||||
statusProgressIndicator.setProgress(-1);
|
||||
statusLabel.setText("Sending message to trading partner...");
|
||||
|
||||
model.fiatPaymentReceived();
|
||||
model.fiatPaymentReceived();
|
||||
}
|
||||
} else {
|
||||
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
|
||||
"That might take up to about 2 minutes at startup.").show();
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package io.bitsquare.gui.main.portfolio.pendingtrades.steps;
|
||||
|
||||
import io.bitsquare.app.BitsquareApp;
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
import io.bitsquare.gui.components.TitledGroupBg;
|
||||
import io.bitsquare.gui.components.TxIdTextField;
|
||||
@ -26,6 +27,8 @@ import io.bitsquare.gui.popups.Popup;
|
||||
import io.bitsquare.gui.util.Layout;
|
||||
import io.bitsquare.payment.PaymentAccountContractData;
|
||||
import io.bitsquare.payment.PaymentMethod;
|
||||
import io.bitsquare.user.PopupId;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
@ -37,6 +40,7 @@ import javafx.scene.layout.GridPane;
|
||||
import static io.bitsquare.gui.util.FormBuilder.*;
|
||||
|
||||
public class StartPaymentView extends TradeStepDetailsView {
|
||||
private final Preferences preferences;
|
||||
private TxIdTextField txIdTextField;
|
||||
|
||||
private Button paymentStartedButton;
|
||||
@ -55,6 +59,7 @@ public class StartPaymentView extends TradeStepDetailsView {
|
||||
public StartPaymentView(PendingTradesViewModel model) {
|
||||
super(model);
|
||||
txIdChangeListener = (ov, oldValue, newValue) -> txIdTextField.setup(newValue);
|
||||
preferences = model.dataModel.getPreferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,6 +68,16 @@ public class StartPaymentView extends TradeStepDetailsView {
|
||||
|
||||
model.getTxId().addListener(txIdChangeListener);
|
||||
txIdTextField.setup(model.getTxId().get());
|
||||
|
||||
String key = PopupId.SEND_PAYMENT_INFO;
|
||||
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
|
||||
new Popup().information("You need to transfer now the agreed amount to your trading partner.\n" +
|
||||
"Please take care that you use the exact data presented here, including the reference text\n" +
|
||||
"Please do not click the \"Payment started\" button if you have before you have completed the transfer.\n" +
|
||||
"Take care that you make the transfer soon to not miss the exceed trading period.")
|
||||
.onClose(() -> preferences.dontShowAgain(key))
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,13 +141,21 @@ public class StartPaymentView extends TradeStepDetailsView {
|
||||
private void onPaymentStarted(ActionEvent actionEvent) {
|
||||
log.debug("onPaymentStarted");
|
||||
if (model.isAuthenticated()) {
|
||||
paymentStartedButton.setDisable(true);
|
||||
String key = PopupId.PAYMENT_SENT;
|
||||
if (preferences.showAgain(key) && !BitsquareApp.DEV_MODE) {
|
||||
new Popup().information("You are confirming that you have transferred the payment to your trading partner.\n" +
|
||||
"Please click the \"Payment started\" button only if you have completed the transfer.")
|
||||
.onClose(() -> preferences.dontShowAgain(key))
|
||||
.show();
|
||||
} else {
|
||||
paymentStartedButton.setDisable(true);
|
||||
|
||||
statusProgressIndicator.setVisible(true);
|
||||
statusProgressIndicator.setProgress(-1);
|
||||
statusLabel.setText("Sending message to trading partner...");
|
||||
statusProgressIndicator.setVisible(true);
|
||||
statusProgressIndicator.setProgress(-1);
|
||||
statusLabel.setText("Sending message to trading partner...");
|
||||
|
||||
model.fiatPaymentStarted();
|
||||
model.fiatPaymentStarted();
|
||||
}
|
||||
} else {
|
||||
new Popup().warning("You need to wait until your client is authenticated in the network.\n" +
|
||||
"That might take up to about 2 minutes at startup.").show();
|
||||
|
@ -29,8 +29,8 @@ import java.util.Optional;
|
||||
|
||||
import static io.bitsquare.gui.util.FormBuilder.addCheckBox;
|
||||
|
||||
public class FirstTimePopup extends WebViewPopup {
|
||||
private static final Logger log = LoggerFactory.getLogger(FirstTimePopup.class);
|
||||
public class FirstTimeWebViewPopup extends WebViewPopup {
|
||||
private static final Logger log = LoggerFactory.getLogger(FirstTimeWebViewPopup.class);
|
||||
private Preferences preferences;
|
||||
private String id;
|
||||
|
||||
@ -39,22 +39,22 @@ public class FirstTimePopup extends WebViewPopup {
|
||||
// Public API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public FirstTimePopup(Preferences preferences) {
|
||||
public FirstTimeWebViewPopup(Preferences preferences) {
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FirstTimePopup url(String url) {
|
||||
public FirstTimeWebViewPopup url(String url) {
|
||||
super.url(url);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FirstTimePopup onClose(Runnable closeHandler) {
|
||||
public FirstTimeWebViewPopup onClose(Runnable closeHandler) {
|
||||
this.closeHandlerOptional = Optional.of(closeHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FirstTimePopup id(String id) {
|
||||
public FirstTimeWebViewPopup id(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
@ -110,7 +110,7 @@ public class OfferDetailsPopup extends Popup {
|
||||
}
|
||||
|
||||
private void addContent() {
|
||||
int rows = 9;
|
||||
int rows = 11;
|
||||
if (offer.getPaymentMethodCountryCode() != null)
|
||||
rows++;
|
||||
if (offer.getOfferFeePaymentTxID() != null)
|
||||
@ -124,7 +124,8 @@ public class OfferDetailsPopup extends Popup {
|
||||
addLabelTextField(gridPane, rowIndex, "Offer ID:", offer.getId(), Layout.FIRST_ROW_DISTANCE);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Creation date:", formatter.formatDateTime(offer.getDate()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offer direction:", Offer.Direction.BUY.name());
|
||||
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
|
||||
addLabelTextField(gridPane, ++rowIndex, "Currency:", offer.getCurrencyCode());
|
||||
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode() + "/" + "BTC");
|
||||
addLabelTextField(gridPane, ++rowIndex, "Amount:", formatter.formatCoinWithCode(offer.getAmount()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Min. amount:", formatter.formatCoinWithCode(offer.getMinAmount()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(offer.getPaymentMethod().getId()));
|
||||
@ -192,6 +193,7 @@ public class OfferDetailsPopup extends Popup {
|
||||
});
|
||||
|
||||
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
|
||||
checkBox.setPadding(new Insets(10, 0, 15, 0));
|
||||
checkBox.setSelected(!preferences.getShowTakeOfferConfirmation());
|
||||
checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected()));
|
||||
} else {
|
||||
|
@ -30,6 +30,7 @@ import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -126,15 +127,19 @@ public class TradeDetailsPopup extends Popup {
|
||||
addLabelTextField(gridPane, ++rowIndex, "Offer direction:", direction);
|
||||
addLabelTextField(gridPane, ++rowIndex, "Price:", formatter.formatFiat(offer.getPrice()) + " " + offer.getCurrencyCode());
|
||||
addLabelTextField(gridPane, ++rowIndex, "Trade amount:", formatter.formatCoinWithCode(trade.getTradeAmount()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Selected arbitrator:", formatter.arbitratorAddressToShortAddress(trade.getArbitratorAddress()));
|
||||
addLabelTextField(gridPane, ++rowIndex, "Selected arbitrator:", trade.getArbitratorAddress().getFullAddress());
|
||||
|
||||
if (contract != null) {
|
||||
if (buyerPaymentAccountContractData != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Buyer payment details:", BSResources.get(buyerPaymentAccountContractData.getPaymentDetails()));
|
||||
|
||||
if (sellerPaymentAccountContractData != null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Seller payment details:", BSResources.get(sellerPaymentAccountContractData.getPaymentDetails()));
|
||||
|
||||
if (buyerPaymentAccountContractData != null) {
|
||||
TextField tf = addLabelTextField(gridPane, ++rowIndex, "Buyer payment details:", BSResources.get(buyerPaymentAccountContractData.getPaymentDetails())).second;
|
||||
tf.setTooltip(new Tooltip(tf.getText()));
|
||||
tf.setMouseTransparent(false);
|
||||
}
|
||||
if (sellerPaymentAccountContractData != null) {
|
||||
TextField tf = addLabelTextField(gridPane, ++rowIndex, "Seller payment details:", BSResources.get(sellerPaymentAccountContractData.getPaymentDetails())).second;
|
||||
tf.setTooltip(new Tooltip(tf.getText()));
|
||||
tf.setMouseTransparent(false);
|
||||
}
|
||||
if (buyerPaymentAccountContractData == null && sellerPaymentAccountContractData == null)
|
||||
addLabelTextField(gridPane, ++rowIndex, "Payment method:", BSResources.get(contract.getPaymentMethodName()));
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class WebViewPopup extends Popup {
|
||||
protected String url;
|
||||
|
||||
public static String getLocalUrl(String htmlFile) {
|
||||
return WebViewPopup.class.getResource("/html/" + htmlFile).toExternalForm();
|
||||
return WebViewPopup.class.getResource("/html/" + htmlFile + ".html").toExternalForm();
|
||||
}
|
||||
|
||||
public WebViewPopup() {
|
||||
|
@ -308,14 +308,9 @@ public class BSFormatter {
|
||||
|
||||
|
||||
public String arbitratorAddressesToString(List<Address> addresses) {
|
||||
//return addresses.stream().map(e -> e.getFullAddress().substring(0, 8)).collect(Collectors.joining(", "));
|
||||
return addresses.stream().map(e -> e.getFullAddress()).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
public String arbitratorAddressToShortAddress(Address address) {
|
||||
return address.getFullAddress().substring(0, 8);
|
||||
}
|
||||
|
||||
public String languageCodesToString(List<String> languageLocales) {
|
||||
return languageLocales.stream().map(LanguageUtil::getDisplayName).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
@ -18,7 +18,8 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
a {
|
||||
|
@ -75,7 +75,7 @@ createOffer.advancedBox.currency=Currency:
|
||||
createOffer.advancedBox.county=Payments account country:
|
||||
createOffer.advancedBox.info=Your trading partners must fulfill your offer restrictions. You can edit the accepted countries, languages and arbitrators in the settings. The payments account details are used from your current selected payments account (if you have multiple payments accounts).
|
||||
|
||||
createOffer.success.headline=Your offer has been successfully published to the distributed offerbook.
|
||||
createOffer.success.headline=Your offer has been published to the offerbook.
|
||||
createOffer.success.info=In the portfolio screen you can manage your open offers.
|
||||
|
||||
createOffer.error.message=An error occurred when placing the offer.\n\n{0}
|
||||
|
@ -186,7 +186,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||
// We set connectionType to that connection to avoid that is get closed when
|
||||
// we get too many connection attempts.
|
||||
// That is used as protection against eclipse attacks.
|
||||
connection.setConnectionType(ConnectionType.DIRECT_MSG);
|
||||
connection.setConnectionType(ConnectionMode.DIRECT_MSG);
|
||||
|
||||
log.info("Received SealedAndSignedMessage and decrypted it: " + decryptedMsgWithPubKey);
|
||||
decryptedMailListeners.stream().forEach(
|
||||
@ -305,7 +305,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||
Log.traceCall();
|
||||
checkArgument(networkNode.getAddress() != null, "Address must be set when we have the hidden service ready");
|
||||
if (myOnionAddress != null)
|
||||
checkArgument(networkNode.getAddress() == myOnionAddress, "networkNode.getAddress() must be same as myOnionAddress");
|
||||
checkArgument(networkNode.getAddress().equals(myOnionAddress),
|
||||
"networkNode.getAddress() must be same as myOnionAddress.");
|
||||
|
||||
myOnionAddress = networkNode.getAddress();
|
||||
dbStorage.queueUpForSave(myOnionAddress);
|
||||
@ -709,7 +710,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||
return blurredAddressHash != null &&
|
||||
Arrays.equals(blurredAddressHash, sealedAndSignedMessage.addressPrefixHash);
|
||||
} else {
|
||||
log.warn("myOnionAddress must not be null at verifyAddressPrefixHash");
|
||||
log.debug("myOnionAddress is null at verifyAddressPrefixHash. That is expected at startup.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class Connection implements MessageListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(Connection.class);
|
||||
private static final int MAX_MSG_SIZE = 5 * 1024 * 1024; // 5 MB of compressed data
|
||||
private static final int SOCKET_TIMEOUT = 30 * 60 * 1000; // 30 min.
|
||||
private ConnectionType connectionType;
|
||||
private ConnectionMode connectionType;
|
||||
|
||||
public static int getMaxMsgSize() {
|
||||
return MAX_MSG_SIZE;
|
||||
@ -123,7 +123,7 @@ public class Connection implements MessageListener {
|
||||
connectionListener.onPeerAddressAuthenticated(peerAddress, connection);
|
||||
}
|
||||
|
||||
public void setConnectionType(ConnectionType connectionType) {
|
||||
public void setConnectionType(ConnectionMode connectionType) {
|
||||
this.connectionType = connectionType;
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ public class Connection implements MessageListener {
|
||||
return stopped;
|
||||
}
|
||||
|
||||
public ConnectionType getConnectionType() {
|
||||
public ConnectionMode getConnectionType() {
|
||||
return connectionType;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
package io.bitsquare.p2p.network;
|
||||
|
||||
public enum ConnectionMode {
|
||||
PASSIVE, // for connections initiated by other peer
|
||||
ACTIVE, // for connections initiated by us
|
||||
DIRECT_MSG, // for connections used for direct messaging
|
||||
AUTH_REQUEST // for connections used for starting the authentication
|
||||
}
|
@ -8,7 +8,7 @@ import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.p2p.Address;
|
||||
import io.bitsquare.p2p.Message;
|
||||
import io.bitsquare.p2p.network.Connection;
|
||||
import io.bitsquare.p2p.network.ConnectionType;
|
||||
import io.bitsquare.p2p.network.ConnectionMode;
|
||||
import io.bitsquare.p2p.network.MessageListener;
|
||||
import io.bitsquare.p2p.network.NetworkNode;
|
||||
import io.bitsquare.p2p.peers.messages.auth.*;
|
||||
@ -72,7 +72,7 @@ public class AuthenticationHandshake implements MessageListener {
|
||||
|
||||
// We use the active connectionType if we started the authentication request to another peer
|
||||
// That is used for protecting eclipse attacks
|
||||
connection.setConnectionType(ConnectionType.ACTIVE);
|
||||
connection.setConnectionType(ConnectionMode.ACTIVE);
|
||||
|
||||
AuthenticationResponse authenticationResponse = (AuthenticationResponse) message;
|
||||
Address peerAddress = authenticationResponse.address;
|
||||
@ -180,7 +180,7 @@ public class AuthenticationHandshake implements MessageListener {
|
||||
log.trace("send AuthenticationRequest to " + peerAddress + " succeeded.");
|
||||
connection.setPeerAddress(peerAddress);
|
||||
// We protect that connection from getting closed by maintenance cleanup...
|
||||
connection.setConnectionType(ConnectionType.AUTH_REQUEST);
|
||||
connection.setConnectionType(ConnectionMode.AUTH_REQUEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -228,7 +228,7 @@ public class AuthenticationHandshake implements MessageListener {
|
||||
connection.setPeerAddress(peerAddress);
|
||||
// We use passive connectionType for connections created from received authentication requests from other peers
|
||||
// That is used for protecting eclipse attacks
|
||||
connection.setConnectionType(ConnectionType.PASSIVE);
|
||||
connection.setConnectionType(ConnectionMode.PASSIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -168,7 +168,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
|
||||
Address peerAddress = message.address;
|
||||
if (!authenticationHandshakes.containsKey(peerAddress)) {
|
||||
// We protect that connection from getting closed by maintenance cleanup...
|
||||
connection.setConnectionType(ConnectionType.AUTH_REQUEST);
|
||||
connection.setConnectionType(ConnectionMode.AUTH_REQUEST);
|
||||
AuthenticationHandshake authenticationHandshake = new AuthenticationHandshake(networkNode, PeerGroup.this, getMyAddress());
|
||||
authenticationHandshakes.put(peerAddress, authenticationHandshake);
|
||||
SettableFuture<Connection> future = authenticationHandshake.respondToAuthenticationRequest(message, connection);
|
||||
@ -186,8 +186,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Throwable throwable) {
|
||||
log.error("AuthenticationHandshake failed. " + throwable.getMessage());
|
||||
throwable.printStackTrace();
|
||||
log.info("AuthenticationHandshake failed. That is expected if peer went offline. " + throwable.getMessage());
|
||||
removePeer(connection.getPeerAddress());
|
||||
}
|
||||
});
|
||||
@ -468,7 +467,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
|
||||
|
||||
List<Connection> authenticatedConnections = allConnections.stream()
|
||||
.filter(e -> e.isAuthenticated())
|
||||
.filter(e -> e.getConnectionType() == ConnectionType.PASSIVE)
|
||||
.filter(e -> e.getConnectionType() == ConnectionMode.PASSIVE)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (authenticatedConnections.size() == 0) {
|
||||
@ -477,7 +476,7 @@ public class PeerGroup implements MessageListener, ConnectionListener {
|
||||
if (size > MAX_CONNECTIONS_NORMAL_PRIO) {
|
||||
authenticatedConnections = allConnections.stream()
|
||||
.filter(e -> e.isAuthenticated())
|
||||
.filter(e -> e.getConnectionType() == ConnectionType.PASSIVE || e.getConnectionType() == ConnectionType.ACTIVE)
|
||||
.filter(e -> e.getConnectionType() == ConnectionMode.PASSIVE || e.getConnectionType() == ConnectionMode.ACTIVE)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (authenticatedConnections.size() == 0) {
|
||||
|
@ -285,7 +285,7 @@ public class ProtectedExpirableDataStorage implements MessageListener {
|
||||
Log.traceCall();
|
||||
int newSequenceNumber = data.sequenceNumber;
|
||||
Integer storedSequenceNumber = sequenceNumberMap.get(hashOfData);
|
||||
if (sequenceNumberMap.containsKey(hashOfData) && newSequenceNumber <= storedSequenceNumber) {
|
||||
if (sequenceNumberMap.containsKey(hashOfData) && newSequenceNumber < storedSequenceNumber) {
|
||||
log.trace("Sequence number is invalid. newSequenceNumber="
|
||||
+ newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber);
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user