mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 23:18:17 +01:00
Add Notification and Instructions popups. Cleanup MainViewModel
This commit is contained in:
parent
cdccd57968
commit
6bf2adae7f
23 changed files with 637 additions and 514 deletions
|
@ -48,6 +48,7 @@ public class Dispute implements Serializable {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final String tradeId;
|
||||
private final String id;
|
||||
private final int traderId;
|
||||
private final boolean disputeOpenerIsBuyer;
|
||||
private final boolean disputeOpenerIsOfferer;
|
||||
|
@ -123,6 +124,8 @@ public class Dispute implements Serializable {
|
|||
this.arbitratorPubKeyRing = arbitratorPubKeyRing;
|
||||
this.isSupportTicket = isSupportTicket;
|
||||
this.openingDate = new Date().getTime();
|
||||
|
||||
id = tradeId + "_" + traderId;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
|
@ -177,6 +180,10 @@ public class Dispute implements Serializable {
|
|||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getTradeId() {
|
||||
return tradeId;
|
||||
}
|
||||
|
|
|
@ -381,8 +381,12 @@ public class TradeManager {
|
|||
return offer.isMyOffer(keyRing);
|
||||
}
|
||||
|
||||
public boolean isMyOfferInBtcBuyerRole(Offer offer) {
|
||||
return !(isMyOffer(offer) ^ offer.getDirection() == Offer.Direction.BUY);
|
||||
public boolean isBuyer(Offer offer) {
|
||||
// If I am the offerer, the offer direction is taken, otherwise the mirrored direction
|
||||
if (isMyOffer(offer))
|
||||
return offer.getDirection() == Offer.Direction.BUY;
|
||||
else
|
||||
return offer.getDirection() == Offer.Direction.SELL;
|
||||
}
|
||||
|
||||
public Optional<Trade> getTradeById(String tradeId) {
|
||||
|
|
|
@ -66,8 +66,7 @@ public class SetupDepositBalanceListener extends TradeTask {
|
|||
|| newValue == Trade.State.DEPOSIT_SEEN_IN_NETWORK) {
|
||||
|
||||
walletService.removeBalanceListener(balanceListener);
|
||||
log.debug(" UserThread.execute(this::unSubscribe);");
|
||||
// TODO is that allowed?
|
||||
// hack to remove tradeStateSubscription at callback
|
||||
UserThread.execute(this::unSubscribe);
|
||||
}
|
||||
});
|
||||
|
@ -81,8 +80,6 @@ public class SetupDepositBalanceListener extends TradeTask {
|
|||
}
|
||||
|
||||
private void unSubscribe() {
|
||||
//TODO investigate, seems to not get called sometimes
|
||||
log.debug("unSubscribe tradeStateSubscription");
|
||||
tradeStateSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ public class Preferences implements Serializable {
|
|||
private final ArrayList<TradeCurrency> tradeCurrencies;
|
||||
private BlockChainExplorer blockChainExplorerMainNet;
|
||||
private BlockChainExplorer blockChainExplorerTestNet;
|
||||
private boolean showPlaceOfferConfirmation;
|
||||
private boolean showTakeOfferConfirmation;
|
||||
private boolean showNotifications = true;
|
||||
private boolean showInstructions = true;
|
||||
private String backupDirectory;
|
||||
private boolean autoSelectArbitrators = true;
|
||||
private final Map<String, Boolean> showAgainMap;
|
||||
|
@ -140,8 +140,8 @@ public class Preferences implements Serializable {
|
|||
if (blockChainExplorerMainNet == null)
|
||||
setBlockChainExplorerTestNet(blockChainExplorersMainNet.get(0));
|
||||
|
||||
showPlaceOfferConfirmation = persisted.getShowPlaceOfferConfirmation();
|
||||
showTakeOfferConfirmation = persisted.getShowTakeOfferConfirmation();
|
||||
showNotifications = persisted.getShowNotifications();
|
||||
showInstructions = persisted.getShowInstructions();
|
||||
backupDirectory = persisted.getBackupDirectory();
|
||||
autoSelectArbitrators = persisted.getAutoSelectArbitrators();
|
||||
showAgainMap = persisted.getShowAgainMap();
|
||||
|
@ -163,8 +163,6 @@ public class Preferences implements Serializable {
|
|||
tradeCurrencies = new ArrayList<>(tradeCurrenciesAsObservable);
|
||||
setBlockChainExplorerTestNet(blockChainExplorersTestNet.get(0));
|
||||
setBlockChainExplorerMainNet(blockChainExplorersMainNet.get(0));
|
||||
showPlaceOfferConfirmation = true;
|
||||
showTakeOfferConfirmation = true;
|
||||
|
||||
showAgainMap = new HashMap<>();
|
||||
showAgainMap.put(PopupId.TRADE_WALLET, true);
|
||||
|
@ -253,13 +251,13 @@ public class Preferences implements Serializable {
|
|||
setBlockChainExplorerTestNet(blockChainExplorer);
|
||||
}
|
||||
|
||||
public void setShowPlaceOfferConfirmation(boolean showPlaceOfferConfirmation) {
|
||||
this.showPlaceOfferConfirmation = showPlaceOfferConfirmation;
|
||||
public void setShowNotifications(boolean showNotifications) {
|
||||
this.showNotifications = showNotifications;
|
||||
storage.queueUpForSave(2000);
|
||||
}
|
||||
|
||||
public void setShowTakeOfferConfirmation(boolean showTakeOfferConfirmation) {
|
||||
this.showTakeOfferConfirmation = showTakeOfferConfirmation;
|
||||
public void setShowInstructions(boolean showInstructions) {
|
||||
this.showInstructions = showInstructions;
|
||||
storage.queueUpForSave(2000);
|
||||
}
|
||||
|
||||
|
@ -356,13 +354,12 @@ public class Preferences implements Serializable {
|
|||
return blockChainExplorersTestNet;
|
||||
}
|
||||
|
||||
public boolean getShowPlaceOfferConfirmation() {
|
||||
return showPlaceOfferConfirmation;
|
||||
public boolean getShowNotifications() {
|
||||
return showNotifications;
|
||||
}
|
||||
|
||||
|
||||
public boolean getShowTakeOfferConfirmation() {
|
||||
return showTakeOfferConfirmation;
|
||||
public boolean getShowInstructions() {
|
||||
return showInstructions;
|
||||
}
|
||||
|
||||
public String getBackupDirectory() {
|
||||
|
|
|
@ -26,6 +26,7 @@ import io.bitsquare.common.crypto.KeyStorage;
|
|||
import io.bitsquare.crypto.EncryptionServiceModule;
|
||||
import io.bitsquare.gui.GuiModule;
|
||||
import io.bitsquare.gui.common.view.CachingViewLoader;
|
||||
import io.bitsquare.gui.main.intructions.InstructionCenter;
|
||||
import io.bitsquare.gui.main.notifications.NotificationCenter;
|
||||
import io.bitsquare.p2p.P2PModule;
|
||||
import io.bitsquare.storage.Storage;
|
||||
|
@ -60,6 +61,7 @@ class BitsquareAppModule extends AppModule {
|
|||
bind(User.class).in(Singleton.class);
|
||||
bind(Preferences.class).in(Singleton.class);
|
||||
bind(NotificationCenter.class).in(Singleton.class);
|
||||
bind(InstructionCenter.class).in(Singleton.class);
|
||||
|
||||
File storageDir = new File(env.getRequiredProperty(Storage.DIR_KEY));
|
||||
bind(File.class).annotatedWith(named(Storage.DIR_KEY)).toInstance(storageDir);
|
||||
|
|
|
@ -26,21 +26,23 @@ import io.bitsquare.app.Version;
|
|||
import io.bitsquare.arbitration.ArbitratorManager;
|
||||
import io.bitsquare.arbitration.Dispute;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.btc.*;
|
||||
import io.bitsquare.btc.AddressEntry;
|
||||
import io.bitsquare.btc.FeePolicy;
|
||||
import io.bitsquare.btc.TradeWalletService;
|
||||
import io.bitsquare.btc.WalletService;
|
||||
import io.bitsquare.btc.listeners.BalanceListener;
|
||||
import io.bitsquare.btc.pricefeed.MarketPriceFeed;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.gui.Navigation;
|
||||
import io.bitsquare.gui.common.model.ViewModel;
|
||||
import io.bitsquare.gui.common.view.ViewPath;
|
||||
import io.bitsquare.gui.components.BalanceTextField;
|
||||
import io.bitsquare.gui.components.BalanceWithConfirmationTextField;
|
||||
import io.bitsquare.gui.components.TxIdTextField;
|
||||
import io.bitsquare.gui.main.notifications.NotificationCenter;
|
||||
import io.bitsquare.gui.main.popups.DisplayAlertMessagePopup;
|
||||
import io.bitsquare.gui.main.popups.Popup;
|
||||
import io.bitsquare.gui.main.popups.TacPopup;
|
||||
import io.bitsquare.gui.main.popups.WalletPasswordPopup;
|
||||
import io.bitsquare.gui.main.portfolio.PortfolioView;
|
||||
import io.bitsquare.gui.main.portfolio.pendingtrades.PendingTradesView;
|
||||
import io.bitsquare.gui.util.BSFormatter;
|
||||
import io.bitsquare.locale.CountryUtil;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
|
@ -69,9 +71,9 @@ import org.reactfx.util.Timer;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -89,6 +91,8 @@ public class MainViewModel implements ViewModel {
|
|||
private final Preferences preferences;
|
||||
private final AlertManager alertManager;
|
||||
private final WalletPasswordPopup walletPasswordPopup;
|
||||
private NotificationCenter notificationCenter;
|
||||
private TacPopup tacPopup;
|
||||
private Navigation navigation;
|
||||
private final BSFormatter formatter;
|
||||
|
||||
|
@ -133,8 +137,7 @@ public class MainViewModel implements ViewModel {
|
|||
private java.util.Timer numberofBtcPeersTimer;
|
||||
private java.util.Timer numberofP2PNetworkPeersTimer;
|
||||
private Timer startupTimeout;
|
||||
private Set<Subscription> tradeStateSubscriptions = new HashSet<>();
|
||||
private Set<Subscription> disputeStateSubscriptions = new HashSet<>();
|
||||
private final Map<String, Subscription> disputeIsClosedSubscriptionsMap = new HashMap<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -147,6 +150,7 @@ public class MainViewModel implements ViewModel {
|
|||
ArbitratorManager arbitratorManager, P2PService p2PService, TradeManager tradeManager,
|
||||
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
|
||||
User user, AlertManager alertManager, WalletPasswordPopup walletPasswordPopup,
|
||||
NotificationCenter notificationCenter, TacPopup tacPopup,
|
||||
Navigation navigation, BSFormatter formatter) {
|
||||
this.marketPriceFeed = marketPriceFeed;
|
||||
this.user = user;
|
||||
|
@ -160,6 +164,8 @@ public class MainViewModel implements ViewModel {
|
|||
this.preferences = preferences;
|
||||
this.alertManager = alertManager;
|
||||
this.walletPasswordPopup = walletPasswordPopup;
|
||||
this.notificationCenter = notificationCenter;
|
||||
this.tacPopup = tacPopup;
|
||||
this.navigation = navigation;
|
||||
this.formatter = formatter;
|
||||
|
||||
|
@ -172,8 +178,6 @@ public class MainViewModel implements ViewModel {
|
|||
BalanceWithConfirmationTextField.setWalletService(walletService);
|
||||
|
||||
if (BitsquareApp.DEV_MODE) {
|
||||
preferences.setShowPlaceOfferConfirmation(false);
|
||||
preferences.setShowTakeOfferConfirmation(false);
|
||||
preferences.setUseAnimations(false);
|
||||
preferences.setUseEffects(false);
|
||||
}
|
||||
|
@ -221,6 +225,16 @@ public class MainViewModel implements ViewModel {
|
|||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI handlers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onSplashScreenRemoved() {
|
||||
isSplashScreenRemoved.set(true);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialisation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -360,33 +374,23 @@ public class MainViewModel implements ViewModel {
|
|||
startupTimeout.stop();
|
||||
|
||||
// disputeManager
|
||||
disputeManager.onAllServicesInitialized();
|
||||
disputeManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) change -> {
|
||||
change.next();
|
||||
addDisputeClosedChangeListener(change.getAddedSubList());
|
||||
updateDisputeStates();
|
||||
onDisputesChangeListener(change.getAddedSubList(), change.getRemoved());
|
||||
});
|
||||
addDisputeClosedChangeListener(disputeManager.getDisputesAsObservableList());
|
||||
updateDisputeStates();
|
||||
disputeManager.onAllServicesInitialized();
|
||||
|
||||
onDisputesChangeListener(disputeManager.getDisputesAsObservableList(), null);
|
||||
|
||||
// tradeManager
|
||||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) c -> updateBalance());
|
||||
|
||||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
|
||||
change.next();
|
||||
setDisputeStateSubscriptions();
|
||||
setTradeStateSubscriptions();
|
||||
pendingTradesChanged();
|
||||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> onTradesChanged());
|
||||
onTradesChanged();
|
||||
// We handle the trade period here as we display a global popup if we reached dispute time
|
||||
tradesAndUIReady = EasyBind.combine(isSplashScreenRemoved, tradeManager.pendingTradesInitializedProperty(), (a, b) -> a && b);
|
||||
tradesAndUIReady.subscribe((observable, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
applyTradePeriodState();
|
||||
});
|
||||
pendingTradesChanged();
|
||||
setDisputeStateSubscriptions();
|
||||
setTradeStateSubscriptions();
|
||||
|
||||
|
||||
// arbitratorManager
|
||||
arbitratorManager.onAllServicesInitialized();
|
||||
|
||||
|
||||
// walletService
|
||||
// In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically
|
||||
|
@ -398,77 +402,120 @@ public class MainViewModel implements ViewModel {
|
|||
|| disputeManager.getDisputesAsObservableList().size() > 0)) {
|
||||
walletPasswordPopup.onAesKey(aesKey -> tradeWalletService.setAesKey(aesKey)).show();
|
||||
}
|
||||
|
||||
// We handle the trade period here as we display a global popup if we reached dispute time
|
||||
tradesAndUIReady = EasyBind.combine(isSplashScreenRemoved, tradeManager.pendingTradesInitializedProperty(), (a, b) -> a && b);
|
||||
tradesAndUIReady.subscribe((observable, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
applyTradePeriodState();
|
||||
});
|
||||
|
||||
walletService.addBalanceListener(new BalanceListener() {
|
||||
@Override
|
||||
public void onBalanceChanged(Coin balance, Transaction tx) {
|
||||
updateBalance();
|
||||
}
|
||||
});
|
||||
updateBalance();
|
||||
|
||||
setBitcoinNetworkSyncProgress(walletService.downloadPercentageProperty().get());
|
||||
checkPeriodicallyForBtcSyncState();
|
||||
|
||||
// openOfferManager
|
||||
openOfferManager.getOpenOffers().addListener((ListChangeListener<OpenOffer>) c -> updateBalance());
|
||||
openOfferManager.onAllServicesInitialized();
|
||||
|
||||
|
||||
// alertManager
|
||||
arbitratorManager.onAllServicesInitialized();
|
||||
alertManager.alertMessageProperty().addListener((observable, oldValue, newValue) -> displayAlertIfPresent(newValue));
|
||||
displayAlertIfPresent(alertManager.alertMessageProperty().get());
|
||||
|
||||
setupP2PPeersInfo();
|
||||
updateBalance();
|
||||
setupDevDummyPaymentAccount();
|
||||
setupMarketPriceFeed();
|
||||
|
||||
// tac
|
||||
// TODO add link: https://bitsquare.io/arbitration_system.pdf
|
||||
String text = "1. This software is experimental and provided \"as is\", without warranty of any kind, " +
|
||||
"express or implied, including but not limited to the warranties of " +
|
||||
"merchantability, fitness for a particular purpose and non-infringement.\n" +
|
||||
"In no event shall the authors or copyright holders be liable for any claim, damages or other " +
|
||||
"liability, whether in an action of contract, tort or otherwise, " +
|
||||
"arising from, out of or in connection with the software or the use or other dealings in the software.\n\n" +
|
||||
"2. The user is responsible to use the software in compliance with local laws.\n\n" +
|
||||
"3. The user confirms that he has read and agreed to the rules defined in our " +
|
||||
"Wiki regrading the dispute process\n" +
|
||||
"(https://github.com/bitsquare/bitsquare/wiki/Arbitration-system).";
|
||||
if (!preferences.getTacAccepted() && !BitsquareApp.DEV_MODE) {
|
||||
new Popup().headLine("USER AGREEMENT")
|
||||
.message(text)
|
||||
.actionButtonText("I agree")
|
||||
.closeButtonText("I disagree and quit")
|
||||
.onAction(() -> {
|
||||
preferences.setTacAccepted(true);
|
||||
if (preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET)
|
||||
UserThread.runAfter(() -> new Popup()
|
||||
.warning("This software is still in alpha version.\n" +
|
||||
"Please be aware that using Mainnet comes with the risk to lose funds " +
|
||||
"in case of software bugs.\n" +
|
||||
"To limit the possible losses the maximum allowed trading amount and the " +
|
||||
"security deposit have been reduced to 0.01 BTC for the alpha version " +
|
||||
"when using Mainnet.")
|
||||
.headLine("Important information!")
|
||||
.actionButtonText("I understand and want to use Mainnet")
|
||||
.closeButtonText("Restart and use Testnet")
|
||||
.onClose(() -> {
|
||||
UserThread.execute(() -> preferences.setBitcoinNetwork(BitcoinNetwork.TESTNET));
|
||||
UserThread.runAfter(BitsquareApp.shutDownHandler::run, 300, TimeUnit.MILLISECONDS);
|
||||
})
|
||||
.width(600)
|
||||
.show(), 300, TimeUnit.MILLISECONDS);
|
||||
})
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
}
|
||||
tacPopup.showIfNeeded();
|
||||
notificationCenter.onAllServicesInitialized();
|
||||
|
||||
// update nr of peers in footer
|
||||
// now show app
|
||||
showAppScreen.set(true);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// States
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void applyTradePeriodState() {
|
||||
updateTradePeriodState();
|
||||
tradeWalletService.addBlockChainListener(new BlockChainListener() {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
updateTradePeriodState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks)
|
||||
throws VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset)
|
||||
throws VerificationException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, AbstractBlockChain.NewBlockType blockType,
|
||||
int relativityOffset) throws VerificationException {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateTradePeriodState() {
|
||||
tradeManager.getTrades().stream().forEach(trade -> {
|
||||
int bestChainHeight = tradeWalletService.getBestChainHeight();
|
||||
|
||||
if (trade.getOpenDisputeTimeAsBlockHeight() > 0 && bestChainHeight >= trade.getOpenDisputeTimeAsBlockHeight())
|
||||
trade.setTradePeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER);
|
||||
else if (trade.getCheckPaymentTimeAsBlockHeight() > 0 && bestChainHeight >= trade.getCheckPaymentTimeAsBlockHeight())
|
||||
trade.setTradePeriodState(Trade.TradePeriodState.HALF_REACHED);
|
||||
|
||||
String id;
|
||||
String limitDate = formatter.addBlocksToNowDateFormatted(trade.getOpenDisputeTimeAsBlockHeight() - tradeWalletService.getBestChainHeight());
|
||||
switch (trade.getTradePeriodState()) {
|
||||
case NORMAL:
|
||||
break;
|
||||
case HALF_REACHED:
|
||||
id = "displayHalfTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the half of the max. allowed trading period and " +
|
||||
"is still not completed.\n\n" +
|
||||
"The trade period ends on " + limitDate + "\n\n" +
|
||||
"Please check your trade state at \"Portfolio/Open trades\" for further information.")
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
case TRADE_PERIOD_OVER:
|
||||
id = "displayTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the max. allowed trading period and is " +
|
||||
"not completed.\n\n" +
|
||||
"The trade period ended on " + limitDate + "\n\n" +
|
||||
"Please check your trade at \"Portfolio/Open trades\" for contacting " +
|
||||
"the arbitrator.")
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void setupP2PPeersInfo() {
|
||||
numConnectedPeersListener = (observable, oldValue, newValue) -> {
|
||||
if ((int) oldValue > 0 && (int) newValue == 0) {
|
||||
// give a bit of tolerance
|
||||
|
@ -492,19 +539,10 @@ public class MainViewModel implements ViewModel {
|
|||
updateP2pNetworkInfoWithPeersChanged((int) newValue);
|
||||
};
|
||||
p2PService.getNumConnectedPeers().addListener(numConnectedPeersListener);
|
||||
}
|
||||
|
||||
// now show app
|
||||
showAppScreen.set(true);
|
||||
|
||||
if (BitsquareApp.DEV_MODE && user.getPaymentAccounts().isEmpty()) {
|
||||
OKPayAccount okPayAccount = new OKPayAccount();
|
||||
okPayAccount.setAccountNr("dummy");
|
||||
okPayAccount.setAccountName("OKPay dummy");
|
||||
okPayAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency());
|
||||
okPayAccount.setCountry(CountryUtil.getDefaultCountry());
|
||||
user.addPaymentAccount(okPayAccount);
|
||||
}
|
||||
|
||||
private void setupMarketPriceFeed() {
|
||||
if (marketPriceFeed.getCurrencyCode() == null)
|
||||
marketPriceFeed.setCurrencyCode(preferences.getPreferredTradeCurrency().getCode());
|
||||
if (marketPriceFeed.getType() == null)
|
||||
|
@ -605,130 +643,39 @@ public class MainViewModel implements ViewModel {
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI callbacks
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void onSplashScreenRemoved() {
|
||||
isSplashScreenRemoved.set(true);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Apply states
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void applyTradePeriodState() {
|
||||
updateTradePeriodState();
|
||||
tradeWalletService.addBlockChainListener(new BlockChainListener() {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
updateTradePeriodState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks)
|
||||
throws VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset)
|
||||
throws VerificationException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, AbstractBlockChain.NewBlockType blockType,
|
||||
int relativityOffset) throws VerificationException {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setWalletServiceException(Throwable error) {
|
||||
setBitcoinNetworkSyncProgress(0);
|
||||
btcSplashInfo.set("Nr. of Bitcoin network peers: " + numBTCPeers + " / connecting to " + btcNetworkAsString + " failed");
|
||||
btcFooterInfo.set(btcSplashInfo.get());
|
||||
if (error instanceof TimeoutException) {
|
||||
walletServiceErrorMsg.set("Connecting to the bitcoin network failed because of a timeout.");
|
||||
} else if (error.getCause() instanceof BlockStoreException) {
|
||||
new Popup().warning("Bitsquare is already running. You cannot run 2 instances of Bitsquare.")
|
||||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
} else if (error.getMessage() != null) {
|
||||
walletServiceErrorMsg.set("Connection to the bitcoin network failed because of an error:" + error.getMessage());
|
||||
} else {
|
||||
walletServiceErrorMsg.set("Connection to the bitcoin network failed because of an error:" + error.toString());
|
||||
private void onDisputesChangeListener(List<? extends Dispute> addedList, @Nullable List<? extends Dispute> removedList) {
|
||||
if (removedList != null) {
|
||||
removedList.stream().forEach(dispute -> {
|
||||
String id = dispute.getId();
|
||||
if (disputeIsClosedSubscriptionsMap.containsKey(id)) {
|
||||
disputeIsClosedSubscriptionsMap.get(id).unsubscribe();
|
||||
disputeIsClosedSubscriptionsMap.remove(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
addedList.stream().forEach(dispute -> {
|
||||
String id = dispute.getId();
|
||||
if (disputeIsClosedSubscriptionsMap.containsKey(id)) {
|
||||
log.warn("We have already an entry in disputeStateSubscriptionsMap. That should never happen.");
|
||||
} else {
|
||||
Subscription disputeStateSubscription = EasyBind.subscribe(dispute.isClosedProperty(),
|
||||
disputeState -> {
|
||||
int openDisputes = disputeManager.getDisputesAsObservableList().stream()
|
||||
.filter(e -> !e.isClosed())
|
||||
.collect(Collectors.toList()).size();
|
||||
if (openDisputes > 0)
|
||||
numOpenDisputesAsString.set(String.valueOf(openDisputes));
|
||||
if (openDisputes > 9)
|
||||
numOpenDisputesAsString.set("?");
|
||||
|
||||
private void updateTradePeriodState() {
|
||||
tradeManager.getTrades().stream().forEach(trade -> {
|
||||
int bestChainHeight = tradeWalletService.getBestChainHeight();
|
||||
|
||||
if (trade.getOpenDisputeTimeAsBlockHeight() > 0 && bestChainHeight >= trade.getOpenDisputeTimeAsBlockHeight())
|
||||
trade.setTradePeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER);
|
||||
else if (trade.getCheckPaymentTimeAsBlockHeight() > 0 && bestChainHeight >= trade.getCheckPaymentTimeAsBlockHeight())
|
||||
trade.setTradePeriodState(Trade.TradePeriodState.HALF_REACHED);
|
||||
|
||||
String id;
|
||||
String limitDate = formatter.addBlocksToNowDateFormatted(trade.getOpenDisputeTimeAsBlockHeight() - tradeWalletService.getBestChainHeight());
|
||||
switch (trade.getTradePeriodState()) {
|
||||
case NORMAL:
|
||||
break;
|
||||
case HALF_REACHED:
|
||||
id = "displayHalfTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the half of the max. allowed trading period and " +
|
||||
"is still not completed.\n\n" +
|
||||
"The trade period ends on " + limitDate + "\n\n" +
|
||||
"Please check your trade state at \"Portfolio/Open trades\" for further information.")
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
case TRADE_PERIOD_OVER:
|
||||
id = "displayTradePeriodOver" + trade.getId();
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE) {
|
||||
preferences.dontShowAgain(id);
|
||||
new Popup().warning("Your trade with ID " + trade.getShortId() +
|
||||
" has reached the max. allowed trading period and is " +
|
||||
"not completed.\n\n" +
|
||||
"The trade period ended on " + limitDate + "\n\n" +
|
||||
"Please check your trade at \"Portfolio/Open trades\" for contacting " +
|
||||
"the arbitrator.")
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
showOpenDisputesNotification.set(openDisputes > 0);
|
||||
});
|
||||
disputeIsClosedSubscriptionsMap.put(id, disputeStateSubscription);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addDisputeClosedChangeListener(List<? extends Dispute> list) {
|
||||
list.stream().forEach(e -> e.isClosedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue)
|
||||
updateDisputeStates();
|
||||
}));
|
||||
}
|
||||
|
||||
private void updateDisputeStates() {
|
||||
int openDisputes = disputeManager.getDisputesAsObservableList().stream().filter(e -> !e.isClosed()).collect(Collectors.toList()).size();
|
||||
if (openDisputes > 0)
|
||||
numOpenDisputesAsString.set(String.valueOf(openDisputes));
|
||||
if (openDisputes > 9)
|
||||
numOpenDisputesAsString.set("?");
|
||||
|
||||
showOpenDisputesNotification.set(openDisputes > 0);
|
||||
}
|
||||
|
||||
private void pendingTradesChanged() {
|
||||
private void onTradesChanged() {
|
||||
long numPendingTrades = tradeManager.getTrades().size();
|
||||
if (numPendingTrades > 0)
|
||||
numPendingTradesAsString.set(String.valueOf(numPendingTrades));
|
||||
|
@ -738,132 +685,6 @@ public class MainViewModel implements ViewModel {
|
|||
showPendingTradesNotification.set(numPendingTrades > 0);
|
||||
}
|
||||
|
||||
private void setTradeStateSubscriptions() {
|
||||
tradeStateSubscriptions.stream().forEach(Subscription::unsubscribe);
|
||||
tradeStateSubscriptions.clear();
|
||||
|
||||
tradeManager.getTrades().stream().forEach(trade -> {
|
||||
Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
|
||||
if (newValue != null) {
|
||||
applyTradeState(trade);
|
||||
}
|
||||
});
|
||||
tradeStateSubscriptions.add(tradeStateSubscription);
|
||||
});
|
||||
}
|
||||
|
||||
private void applyTradeState(Trade trade) {
|
||||
Trade.State state = trade.getState();
|
||||
log.debug("addTradeStateListeners " + state);
|
||||
boolean isBtcBuyer = tradeManager.isMyOfferInBtcBuyerRole(trade.getOffer());
|
||||
String headLine = "Notification for trade with ID " + trade.getShortId();
|
||||
String message = null;
|
||||
String id = "notificationPopup_" + state + trade.getId();
|
||||
if (isBtcBuyer) {
|
||||
switch (state) {
|
||||
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||
message = "Your offer has been accepted by a seller.\n" +
|
||||
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
message = "The deposit transaction of your trade has got the first blockchain confirmation.\n" +
|
||||
"You have to start the payment to the bitcoin seller now.";
|
||||
|
||||
break;
|
||||
/* case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
||||
case PAYOUT_TX_COMMITTED:
|
||||
case PAYOUT_TX_SENT:*/
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
message = "The bitcoin seller has confirmed the receipt of your payment and the payout transaction has been published.\n" +
|
||||
"The trade is now completed and you can withdraw your funds.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (state) {
|
||||
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||
message = "Your offer has been accepted by a buyer.\n" +
|
||||
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||
break;
|
||||
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
||||
message = "The bitcoin buyer has started the payment.\n" +
|
||||
"Please check your payment account if you have received his payment.";
|
||||
break;
|
||||
/* case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
||||
case PAYOUT_TX_RECEIVED:
|
||||
case PAYOUT_TX_COMMITTED:*/
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
message = "The payout transaction has been published.\n" +
|
||||
"The trade is now completed and you can withdraw your funds.";
|
||||
}
|
||||
}
|
||||
|
||||
ViewPath currentPath = navigation.getCurrentPath();
|
||||
boolean isPendingTradesViewCurrentView = currentPath != null &&
|
||||
currentPath.size() == 3 &&
|
||||
currentPath.get(2).equals(PendingTradesView.class);
|
||||
if (message != null) {
|
||||
//TODO we get that called initially before the navigation is inited
|
||||
if (isPendingTradesViewCurrentView || currentPath == null) {
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE)
|
||||
new Popup().headLine(headLine)
|
||||
.message(message)
|
||||
.show();
|
||||
preferences.dontShowAgain(id);
|
||||
} else {
|
||||
if (preferences.showAgain(id) && !BitsquareApp.DEV_MODE)
|
||||
new Popup().headLine(headLine)
|
||||
.message(message)
|
||||
.actionButtonText("Go to \"Portfolio/Open trades\"")
|
||||
.onAction(() -> {
|
||||
FxTimer.runLater(Duration.ofMillis(100),
|
||||
() -> navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class)
|
||||
);
|
||||
})
|
||||
.show();
|
||||
preferences.dontShowAgain(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setDisputeStateSubscriptions() {
|
||||
disputeStateSubscriptions.stream().forEach(Subscription::unsubscribe);
|
||||
disputeStateSubscriptions.clear();
|
||||
|
||||
tradeManager.getTrades().stream().forEach(trade -> {
|
||||
Subscription disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> {
|
||||
if (disputeState != null) {
|
||||
applyDisputeState(trade, disputeState);
|
||||
}
|
||||
});
|
||||
disputeStateSubscriptions.add(disputeStateSubscription);
|
||||
});
|
||||
}
|
||||
|
||||
private void applyDisputeState(Trade trade, Trade.DisputeState disputeState) {
|
||||
switch (disputeState) {
|
||||
case NONE:
|
||||
break;
|
||||
case DISPUTE_REQUESTED:
|
||||
break;
|
||||
case DISPUTE_STARTED_BY_PEER:
|
||||
disputeManager.findOwnDispute(trade.getId()).ifPresent(dispute -> {
|
||||
String msg;
|
||||
if (dispute.isSupportTicket())
|
||||
msg = "Your trading peer has encountered technical problems and requested support for trade with ID " + trade.getShortId() + ".\n" +
|
||||
"Please await further instructions from the arbitrator.\n" +
|
||||
"Your funds are safe and will be refunded as soon the problem is resolved.";
|
||||
else
|
||||
msg = "Your trading peer has requested a dispute for trade with ID " + trade.getShortId() + ".";
|
||||
|
||||
new Popup().information(msg).show();
|
||||
});
|
||||
break;
|
||||
case DISPUTE_CLOSED:
|
||||
new Popup().information("A support ticket for trade with ID " + trade.getShortId() + " has been closed.").show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setBitcoinNetworkSyncProgress(double value) {
|
||||
btcSyncProgress.set(value);
|
||||
String numPeers = "Nr. of Bitcoin network peers: " + numBTCPeers;
|
||||
|
@ -885,10 +706,39 @@ public class MainViewModel implements ViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
private void setWalletServiceException(Throwable error) {
|
||||
setBitcoinNetworkSyncProgress(0);
|
||||
btcSplashInfo.set("Nr. of Bitcoin network peers: " + numBTCPeers + " / connecting to " + btcNetworkAsString + " failed");
|
||||
btcFooterInfo.set(btcSplashInfo.get());
|
||||
if (error instanceof TimeoutException) {
|
||||
walletServiceErrorMsg.set("Connecting to the bitcoin network failed because of a timeout.");
|
||||
} else if (error.getCause() instanceof BlockStoreException) {
|
||||
new Popup().warning("Bitsquare is already running. You cannot run 2 instances of Bitsquare.")
|
||||
.closeButtonText("Shut down")
|
||||
.onClose(BitsquareApp.shutDownHandler::run)
|
||||
.show();
|
||||
} else if (error.getMessage() != null) {
|
||||
walletServiceErrorMsg.set("Connection to the bitcoin network failed because of an error:" + error.getMessage());
|
||||
} else {
|
||||
walletServiceErrorMsg.set("Connection to the bitcoin network failed because of an error:" + error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void stopCheckForBtcSyncStateTimer() {
|
||||
if (checkForBtcSyncStateTimer != null) {
|
||||
checkForBtcSyncStateTimer.stop();
|
||||
checkForBtcSyncStateTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDevDummyPaymentAccount() {
|
||||
if (BitsquareApp.DEV_MODE && user.getPaymentAccounts().isEmpty()) {
|
||||
OKPayAccount okPayAccount = new OKPayAccount();
|
||||
okPayAccount.setAccountNr("dummy");
|
||||
okPayAccount.setAccountName("OKPay dummy");
|
||||
okPayAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency());
|
||||
okPayAccount.setCountry(CountryUtil.getDefaultCountry());
|
||||
user.addPaymentAccount(okPayAccount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -575,7 +575,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
// TODO There are still some cell rendering issues on updates
|
||||
setGraphic(messageAnchorPane);
|
||||
} else {
|
||||
if (sendMsgProgressIndicator != null)
|
||||
if (sendMsgProgressIndicator != null && sendMsgProgressIndicatorListener != null)
|
||||
sendMsgProgressIndicator.progressProperty().removeListener(sendMsgProgressIndicatorListener);
|
||||
|
||||
messageAnchorPane.prefWidthProperty().unbind();
|
||||
|
@ -796,7 +796,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
|
|||
} else {
|
||||
if (closedProperty != null)
|
||||
closedProperty.removeListener(listener);
|
||||
|
||||
|
||||
setText("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package io.bitsquare.gui.main.intructions;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.gui.main.popups.Popup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Instruction extends Popup {
|
||||
private static final Logger log = LoggerFactory.getLogger(Instruction.class);
|
||||
|
||||
@Inject
|
||||
public Instruction() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package io.bitsquare.gui.main.intructions;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.gui.main.notifications.Notification;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class InstructionCenter {
|
||||
private final Logger log = LoggerFactory.getLogger(InstructionCenter.class);
|
||||
private Queue<io.bitsquare.gui.main.notifications.Notification> notifications = new LinkedBlockingQueue<>(3);
|
||||
private io.bitsquare.gui.main.notifications.Notification displayedNotification;
|
||||
private TradeManager tradeManager;
|
||||
|
||||
@Inject
|
||||
public InstructionCenter(TradeManager tradeManager) {
|
||||
this.tradeManager = tradeManager;
|
||||
}
|
||||
|
||||
void queueForDisplay(io.bitsquare.gui.main.notifications.Notification notification) {
|
||||
boolean result = notifications.offer(notification);
|
||||
if (!result)
|
||||
log.warn("The capacity is full with popups in the queue.\n\t" +
|
||||
"Not added new notification=" + notification);
|
||||
displayNext();
|
||||
}
|
||||
|
||||
void isHidden(Notification notification) {
|
||||
if (displayedNotification == null || displayedNotification == notification) {
|
||||
displayedNotification = null;
|
||||
displayNext();
|
||||
} else {
|
||||
log.warn("We got a isHidden called with a wrong notification.\n\t" +
|
||||
"notification (argument)=" + notification + "\n\tdisplayedPopup=" + displayedNotification);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayNext() {
|
||||
if (displayedNotification == null) {
|
||||
if (!notifications.isEmpty()) {
|
||||
displayedNotification = notifications.poll();
|
||||
displayedNotification.display();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package io.bitsquare.gui.main.notifications;
|
||||
|
||||
import io.bitsquare.gui.main.popups.Popup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Notification extends Popup {
|
||||
private static final Logger log = LoggerFactory.getLogger(Notification.class);
|
||||
private boolean hasBeenDisplayed;
|
||||
|
||||
public Notification() {
|
||||
NotificationCenter.add(this);
|
||||
}
|
||||
|
||||
public Notification headLine(String headLine) {
|
||||
return (Notification) super.headLine(headLine);
|
||||
}
|
||||
|
||||
public Notification tradeHeadLine(String tradeId) {
|
||||
return headLine("Notification for trade with ID " + tradeId);
|
||||
}
|
||||
|
||||
public Notification disputeHeadLine(String tradeId) {
|
||||
return headLine("Support ticket for trade with ID " + tradeId);
|
||||
}
|
||||
|
||||
public Notification message(String message) {
|
||||
return (Notification) super.message(message);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
super.show();
|
||||
hasBeenDisplayed = true;
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
super.hide();
|
||||
}
|
||||
|
||||
public boolean isHasBeenDisplayed() {
|
||||
return hasBeenDisplayed;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,195 @@
|
|||
package io.bitsquare.gui.main.notifications;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.app.Log;
|
||||
import io.bitsquare.arbitration.DisputeManager;
|
||||
import io.bitsquare.trade.Trade;
|
||||
import io.bitsquare.trade.TradeManager;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.fxmisc.easybind.Subscription;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class NotificationCenter {
|
||||
private static final Logger log = LoggerFactory.getLogger(NotificationCenter.class);
|
||||
|
||||
@Inject
|
||||
public NotificationCenter() {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Static
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private final static List<Notification> notifications = new ArrayList<>();
|
||||
|
||||
static void add(Notification notification) {
|
||||
notifications.add(notification);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Instance fields
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private TradeManager tradeManager;
|
||||
private DisputeManager disputeManager;
|
||||
|
||||
private final Map<String, Subscription> disputeStateSubscriptionsMap = new HashMap<>();
|
||||
private final Map<String, Subscription> tradeStateSubscriptionsMap = new HashMap<>();
|
||||
private String selectedTradeId;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, initialisation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public NotificationCenter(TradeManager tradeManager, DisputeManager disputeManager) {
|
||||
this.tradeManager = tradeManager;
|
||||
this.disputeManager = disputeManager;
|
||||
}
|
||||
|
||||
public void onAllServicesInitialized() {
|
||||
tradeManager.getTrades().addListener((ListChangeListener<Trade>) change -> {
|
||||
change.next();
|
||||
log.error("change getRemoved " + change.getRemoved());
|
||||
log.error("change getAddedSubList " + change.getAddedSubList());
|
||||
if (change.wasRemoved()) {
|
||||
change.getRemoved().stream().forEach(trade -> {
|
||||
String tradeId = trade.getId();
|
||||
if (disputeStateSubscriptionsMap.containsKey(tradeId)) {
|
||||
disputeStateSubscriptionsMap.get(tradeId).unsubscribe();
|
||||
disputeStateSubscriptionsMap.remove(tradeId);
|
||||
}
|
||||
|
||||
if (tradeStateSubscriptionsMap.containsKey(tradeId)) {
|
||||
tradeStateSubscriptionsMap.get(tradeId).unsubscribe();
|
||||
tradeStateSubscriptionsMap.remove(tradeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (change.wasAdded()) {
|
||||
change.getAddedSubList().stream().forEach(trade -> {
|
||||
String tradeId = trade.getId();
|
||||
if (disputeStateSubscriptionsMap.containsKey(tradeId)) {
|
||||
log.warn("We have already an entry in disputeStateSubscriptionsMap. That should never happen.");
|
||||
} else {
|
||||
Subscription disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> onDisputeStateChanged(trade, disputeState));
|
||||
disputeStateSubscriptionsMap.put(tradeId, disputeStateSubscription);
|
||||
}
|
||||
|
||||
if (tradeStateSubscriptionsMap.containsKey(tradeId)) {
|
||||
log.warn("We have already an entry in tradeStateSubscriptionsMap. That should never happen.");
|
||||
} else {
|
||||
Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), tradeState -> onTradeStateChanged(trade, tradeState));
|
||||
tradeStateSubscriptionsMap.put(tradeId, tradeStateSubscription);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
tradeManager.getTrades().stream()
|
||||
.forEach(trade -> {
|
||||
String tradeId = trade.getId();
|
||||
Subscription disputeStateSubscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> onDisputeStateChanged(trade, disputeState));
|
||||
disputeStateSubscriptionsMap.put(tradeId, disputeStateSubscription);
|
||||
|
||||
Subscription tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), tradeState -> onTradeStateChanged(trade, tradeState));
|
||||
tradeStateSubscriptionsMap.put(tradeId, tradeStateSubscription);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setter/Getter
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getSelectedTradeId() {
|
||||
return selectedTradeId;
|
||||
}
|
||||
|
||||
public void setSelectedTradeId(String selectedTradeId) {
|
||||
this.selectedTradeId = selectedTradeId;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onTradeStateChanged(Trade trade, Trade.State tradeState) {
|
||||
Log.traceCall(tradeState.toString());
|
||||
String message = null;
|
||||
if (tradeManager.isBuyer(trade.getOffer())) {
|
||||
switch (tradeState) {
|
||||
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||
message = "Your offer has been accepted by a seller.\n" +
|
||||
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||
break;
|
||||
case DEPOSIT_CONFIRMED:
|
||||
message = "The deposit transaction of your trade has got the first blockchain confirmation.\n" +
|
||||
"You have to start the payment to the bitcoin seller now.";
|
||||
|
||||
break;
|
||||
/* case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
||||
case PAYOUT_TX_COMMITTED:
|
||||
case PAYOUT_TX_SENT:*/
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
message = "The bitcoin seller has confirmed the receipt of your payment and the payout transaction has been published.\n" +
|
||||
"The trade is now completed and you can withdraw your funds.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (tradeState) {
|
||||
case DEPOSIT_PUBLISHED_MSG_RECEIVED:
|
||||
message = "Your offer has been accepted by a buyer.\n" +
|
||||
"You need to wait for one blockchain confirmation before starting the payment.";
|
||||
break;
|
||||
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
||||
message = "The bitcoin buyer has started the payment.\n" +
|
||||
"Please check your payment account if you have received his payment.";
|
||||
break;
|
||||
/* case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
||||
case PAYOUT_TX_RECEIVED:
|
||||
case PAYOUT_TX_COMMITTED:*/
|
||||
case PAYOUT_BROAD_CASTED:
|
||||
message = "The payout transaction has been published.\n" +
|
||||
"The trade is now completed and you can withdraw your funds.";
|
||||
}
|
||||
}
|
||||
|
||||
if (message != null && !trade.getId().equals(selectedTradeId))
|
||||
new Notification().tradeHeadLine(trade.getShortId()).message(message).show();
|
||||
}
|
||||
|
||||
private void onDisputeStateChanged(Trade trade, Trade.DisputeState disputeState) {
|
||||
Log.traceCall(disputeState.toString());
|
||||
String message = null;
|
||||
switch (disputeState) {
|
||||
case NONE:
|
||||
break;
|
||||
case DISPUTE_REQUESTED:
|
||||
break;
|
||||
case DISPUTE_STARTED_BY_PEER:
|
||||
if (disputeManager.findOwnDispute(trade.getId()).isPresent()) {
|
||||
if (disputeManager.findOwnDispute(trade.getId()).get().isSupportTicket())
|
||||
message = "Your trading peer has encountered technical problems and requested support for trade with ID " + trade.getShortId() + ".\n" +
|
||||
"Please await further instructions from the arbitrator.\n" +
|
||||
"Your funds are safe and will be refunded as soon the problem is resolved.";
|
||||
else
|
||||
message = "Your trading peer has requested a dispute for trade with ID " + trade.getShortId() + ".";
|
||||
}
|
||||
break;
|
||||
case DISPUTE_CLOSED:
|
||||
message = "A support ticket for trade with ID " + trade.getShortId() + " has been closed.";
|
||||
break;
|
||||
}
|
||||
if (message != null)
|
||||
new Notification().tradeHeadLine(trade.getShortId()).message(message).show();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -391,14 +391,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
|||
return user.getAcceptedArbitrators();
|
||||
}
|
||||
|
||||
public void setShowPlaceOfferConfirmation(boolean selected) {
|
||||
preferences.setShowPlaceOfferConfirmation(selected);
|
||||
}
|
||||
|
||||
public boolean getShowPlaceOfferConfirmation() {
|
||||
return preferences.getShowPlaceOfferConfirmation();
|
||||
}
|
||||
|
||||
public Preferences getPreferences() {
|
||||
return preferences;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import io.bitsquare.locale.BSResources;
|
|||
import io.bitsquare.locale.TradeCurrency;
|
||||
import io.bitsquare.payment.PaymentAccount;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
|
@ -109,6 +110,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
|
||||
private EventHandler<ActionEvent> currencyComboBoxSelectionHandler;
|
||||
private int gridRow = 0;
|
||||
private Preferences preferences;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -116,11 +118,12 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private CreateOfferView(CreateOfferViewModel model, Navigation navigation, OfferDetailsPopup offerDetailsPopup) {
|
||||
private CreateOfferView(CreateOfferViewModel model, Navigation navigation, OfferDetailsPopup offerDetailsPopup, Preferences preferences) {
|
||||
super(model);
|
||||
|
||||
this.navigation = navigation;
|
||||
this.offerDetailsPopup = offerDetailsPopup;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,8 +213,11 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
|||
private void onPlaceOffer() {
|
||||
if (model.isBootstrapped()) {
|
||||
Offer offer = model.createAndGetOffer();
|
||||
if (model.getShowPlaceOfferConfirmation()) {
|
||||
offerDetailsPopup.onPlaceOffer(o -> model.onPlaceOffer(o)).show(offer);
|
||||
String id = "CreatOfferConfirmation";
|
||||
if (preferences.showAgain(id)) {
|
||||
offerDetailsPopup.onPlaceOffer(model::onPlaceOffer)
|
||||
.dontShowAgainId(id)
|
||||
.show(offer);
|
||||
} else {
|
||||
if (model.hasAcceptedArbitrators()) {
|
||||
model.onPlaceOffer(offer);
|
||||
|
|
|
@ -577,13 +577,4 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
|
|||
public List<Arbitrator> getArbitrators() {
|
||||
return dataModel.getArbitrators();
|
||||
}
|
||||
|
||||
public void setShowPlaceOfferConfirmation(boolean selected) {
|
||||
dataModel.setShowPlaceOfferConfirmation(selected);
|
||||
}
|
||||
|
||||
public boolean getShowPlaceOfferConfirmation() {
|
||||
return dataModel.getShowPlaceOfferConfirmation();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -377,14 +377,6 @@ class TakeOfferDataModel extends ActivatableDataModel {
|
|||
return addressEntry;
|
||||
}
|
||||
|
||||
public boolean getShowTakeOfferConfirmation() {
|
||||
return preferences.getShowTakeOfferConfirmation();
|
||||
}
|
||||
|
||||
public void setShowTakeOfferConfirmation(boolean selected) {
|
||||
preferences.setShowTakeOfferConfirmation(selected);
|
||||
}
|
||||
|
||||
public List<Arbitrator> getArbitrators() {
|
||||
return user.getAcceptedArbitrators();
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import io.bitsquare.gui.util.Layout;
|
|||
import io.bitsquare.locale.BSResources;
|
||||
import io.bitsquare.payment.PaymentAccount;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.geometry.*;
|
||||
|
@ -71,6 +72,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
private final Navigation navigation;
|
||||
private final BSFormatter formatter;
|
||||
private final OfferDetailsPopup offerDetailsPopup;
|
||||
private Preferences preferences;
|
||||
private ScrollPane scrollPane;
|
||||
private GridPane gridPane;
|
||||
private ImageView imageView;
|
||||
|
@ -108,12 +110,14 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private TakeOfferView(TakeOfferViewModel model, Navigation navigation, BSFormatter formatter, OfferDetailsPopup offerDetailsPopup) {
|
||||
private TakeOfferView(TakeOfferViewModel model, Navigation navigation, BSFormatter formatter,
|
||||
OfferDetailsPopup offerDetailsPopup, Preferences preferences) {
|
||||
super(model);
|
||||
|
||||
this.navigation = navigation;
|
||||
this.formatter = formatter;
|
||||
this.offerDetailsPopup = offerDetailsPopup;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -349,8 +353,11 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
|
||||
private void onTakeOffer() {
|
||||
Offer offer = model.getOffer();
|
||||
if (model.getShowTakeOfferConfirmation()) {
|
||||
offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer()).show(offer, model.dataModel.amountAsCoin.get());
|
||||
String id = "TakeOfferConfirmation";
|
||||
if (preferences.showAgain(id)) {
|
||||
offerDetailsPopup.onTakeOffer(() -> model.onTakeOffer())
|
||||
.dontShowAgainId(id)
|
||||
.show(offer, model.dataModel.amountAsCoin.get());
|
||||
} else {
|
||||
if (model.hasAcceptedArbitrators()) {
|
||||
model.onTakeOffer();
|
||||
|
|
|
@ -543,10 +543,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
|
|||
return dataModel.getTradeCurrency();
|
||||
}
|
||||
|
||||
public boolean getShowTakeOfferConfirmation() {
|
||||
return dataModel.getShowTakeOfferConfirmation();
|
||||
}
|
||||
|
||||
public List<Arbitrator> getArbitrators() {
|
||||
return dataModel.getArbitrators();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import io.bitsquare.user.Preferences;
|
|||
import io.bitsquare.user.User;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
@ -51,7 +50,7 @@ public class OfferDetailsPopup extends Popup {
|
|||
protected static final Logger log = LoggerFactory.getLogger(OfferDetailsPopup.class);
|
||||
|
||||
private final BSFormatter formatter;
|
||||
private final Preferences preferences;
|
||||
protected final Preferences preferences;
|
||||
private final User user;
|
||||
private KeyRing keyRing;
|
||||
private final Navigation navigation;
|
||||
|
@ -97,6 +96,11 @@ public class OfferDetailsPopup extends Popup {
|
|||
return this;
|
||||
}
|
||||
|
||||
public OfferDetailsPopup dontShowAgainId(String dontShowAgainId) {
|
||||
this.dontShowAgainId = dontShowAgainId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OfferDetailsPopup onPlaceOffer(Consumer<Offer> placeOfferHandler) {
|
||||
this.placeOfferHandlerOptional = Optional.of(placeOfferHandler);
|
||||
return this;
|
||||
|
@ -189,13 +193,13 @@ public class OfferDetailsPopup extends Popup {
|
|||
addLabelTextField(gridPane, rowIndex, "Please note:", Offer.TAC_OFFERER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
|
||||
Button cancelButton = addConfirmButton(true);
|
||||
addCancelButton(cancelButton, true);
|
||||
addCancelButton(cancelButton);
|
||||
} else if (takeOfferHandlerOptional.isPresent()) {
|
||||
addTitledGroupBg(gridPane, ++rowIndex, 1, "Contract", Layout.GROUP_DISTANCE);
|
||||
addLabelTextField(gridPane, rowIndex, "Terms and conditions:", Offer.TAC_TAKER, Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
|
||||
Button cancelButton = addConfirmButton(false);
|
||||
addCancelButton(cancelButton, false);
|
||||
addCancelButton(cancelButton);
|
||||
} else {
|
||||
Button cancelButton = addButtonAfterGroup(gridPane, ++rowIndex, "Close");
|
||||
cancelButton.setOnAction(e -> {
|
||||
|
@ -229,19 +233,10 @@ public class OfferDetailsPopup extends Popup {
|
|||
return tuple.second;
|
||||
}
|
||||
|
||||
private void addCancelButton(Button cancelButton, boolean isPlaceOffer) {
|
||||
private void addCancelButton(Button cancelButton) {
|
||||
cancelButton.setOnAction(e -> {
|
||||
closeHandlerOptional.ifPresent(closeHandler -> closeHandler.run());
|
||||
hide();
|
||||
});
|
||||
|
||||
CheckBox checkBox = addCheckBox(gridPane, ++rowIndex, "Don't show again", 5);
|
||||
if (isPlaceOffer) {
|
||||
checkBox.setSelected(!preferences.getShowPlaceOfferConfirmation());
|
||||
checkBox.setOnAction(e -> preferences.setShowPlaceOfferConfirmation(!checkBox.isSelected()));
|
||||
} else {
|
||||
checkBox.setSelected(!preferences.getShowTakeOfferConfirmation());
|
||||
checkBox.setOnAction(e -> preferences.setShowTakeOfferConfirmation(!checkBox.isSelected()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public class Popup {
|
|||
private boolean showProgressIndicator;
|
||||
private Button actionButton;
|
||||
protected Label headLineLabel;
|
||||
private String dontShowAgainId;
|
||||
protected String dontShowAgainId;
|
||||
private Preferences preferences;
|
||||
private ChangeListener<Number> positionListener;
|
||||
private Timer centerTime;
|
||||
|
|
63
gui/src/main/java/io/bitsquare/gui/main/popups/TacPopup.java
Normal file
63
gui/src/main/java/io/bitsquare/gui/main/popups/TacPopup.java
Normal file
|
@ -0,0 +1,63 @@
|
|||
package io.bitsquare.gui.main.popups;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bitsquare.app.BitsquareApp;
|
||||
import io.bitsquare.btc.BitcoinNetwork;
|
||||
import io.bitsquare.common.UserThread;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TacPopup extends Popup {
|
||||
private static final Logger log = LoggerFactory.getLogger(TacPopup.class);
|
||||
private Preferences preferences;
|
||||
|
||||
@Inject
|
||||
public TacPopup(Preferences preferences) {
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
public void showIfNeeded() {
|
||||
if (!preferences.getTacAccepted() && !BitsquareApp.DEV_MODE) {
|
||||
// TODO add link: https://bitsquare.io/arbitration_system.pdf
|
||||
headLine("USER AGREEMENT");
|
||||
String text = "1. This software is experimental and provided \"as is\", without warranty of any kind, " +
|
||||
"express or implied, including but not limited to the warranties of " +
|
||||
"merchantability, fitness for a particular purpose and non-infringement.\n" +
|
||||
"In no event shall the authors or copyright holders be liable for any claim, damages or other " +
|
||||
"liability, whether in an action of contract, tort or otherwise, " +
|
||||
"arising from, out of or in connection with the software or the use or other dealings in the software.\n\n" +
|
||||
"2. The user is responsible to use the software in compliance with local laws.\n\n" +
|
||||
"3. The user confirms that he has read and agreed to the rules defined in our " +
|
||||
"Wiki regrading the dispute process\n" +
|
||||
"(https://github.com/bitsquare/bitsquare/wiki/Arbitration-system).";
|
||||
message(text);
|
||||
actionButtonText("I agree");
|
||||
closeButtonText("I disagree and quit");
|
||||
onAction(() -> {
|
||||
preferences.setTacAccepted(true);
|
||||
if (preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET)
|
||||
UserThread.runAfter(() -> new Popup()
|
||||
.warning("This software is still in alpha version.\n" +
|
||||
"Please be aware that using Mainnet comes with the risk to lose funds " +
|
||||
"in case of software bugs.\n" +
|
||||
"To limit the possible losses the maximum allowed trading amount and the " +
|
||||
"security deposit have been reduced to 0.01 BTC for the alpha version " +
|
||||
"when using Mainnet.")
|
||||
.headLine("Important information!")
|
||||
.actionButtonText("I understand and want to use Mainnet")
|
||||
.closeButtonText("Restart and use Testnet")
|
||||
.onClose(() -> {
|
||||
UserThread.execute(() -> preferences.setBitcoinNetwork(BitcoinNetwork.TESTNET));
|
||||
UserThread.runAfter(BitsquareApp.shutDownHandler::run, 300, TimeUnit.MILLISECONDS);
|
||||
})
|
||||
.width(600)
|
||||
.show(), 300, TimeUnit.MILLISECONDS);
|
||||
});
|
||||
onClose(BitsquareApp.shutDownHandler::run);
|
||||
super.show();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -127,12 +127,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||
selectedSubView.deactivate();
|
||||
|
||||
if (selectedItem.getTrade() != null) {
|
||||
// If we are the offerer the direction is like expected
|
||||
// If we are the taker the direction is mirrored
|
||||
if (model.dataModel.isOfferer())
|
||||
selectedSubView = model.dataModel.isBuyOffer() ? new BuyerSubView(model) : new SellerSubView(model);
|
||||
else
|
||||
selectedSubView = model.dataModel.isBuyOffer() ? new SellerSubView(model) : new BuyerSubView(model);
|
||||
selectedSubView = model.dataModel.tradeManager.isBuyer(model.dataModel.getOffer()) ?
|
||||
new BuyerSubView(model) : new SellerSubView(model);
|
||||
|
||||
selectedSubView.setMinHeight(430);
|
||||
VBox.setVgrow(selectedSubView, Priority.ALWAYS);
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.gui.util.Layout;
|
|||
import io.bitsquare.locale.LanguageUtil;
|
||||
import io.bitsquare.locale.TradeCurrency;
|
||||
import io.bitsquare.user.BlockChainExplorer;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
|
@ -38,30 +39,32 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
|
||||
// not supported yet
|
||||
//private ComboBox<String> btcDenominationComboBox;
|
||||
private ComboBox<BlockChainExplorer> blockExplorerComboBox;
|
||||
private ComboBox<BlockChainExplorer> blockChainExplorerComboBox;
|
||||
private ComboBox<String> languageComboBox;
|
||||
private ComboBox<TradeCurrency> tradeCurrencyComboBox;
|
||||
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
|
||||
|
||||
private CheckBox useAnimationsCheckBox, useEffectsCheckBox, showPlaceOfferConfirmationCheckBox, showTakeOfferConfirmationCheckBox,
|
||||
private CheckBox useAnimationsCheckBox, useEffectsCheckBox, showNotificationsCheckBox, showInstructionsCheckBox,
|
||||
autoSelectArbitratorsCheckBox;
|
||||
private int gridRow = 0;
|
||||
//private InputTextField transactionFeeInputTextField;
|
||||
private ChangeListener<Boolean> transactionFeeFocusedListener;
|
||||
private Preferences preferences;
|
||||
|
||||
@Inject
|
||||
public PreferencesView(PreferencesViewModel model) {
|
||||
public PreferencesView(PreferencesViewModel model, Preferences preferences) {
|
||||
super(model);
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
addTitledGroupBg(root, gridRow, 4, "Preferences");
|
||||
tradeCurrencyComboBox = addLabelComboBox(root, gridRow, "Preferred currency:", Layout.FIRST_ROW_DISTANCE).second;
|
||||
preferredTradeCurrencyComboBox = addLabelComboBox(root, gridRow, "Preferred currency:", Layout.FIRST_ROW_DISTANCE).second;
|
||||
languageComboBox = addLabelComboBox(root, ++gridRow, "Language:").second;
|
||||
// btcDenominationComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin denomination:").second;
|
||||
blockExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
|
||||
blockChainExplorerComboBox = addLabelComboBox(root, ++gridRow, "Bitcoin block explorer:").second;
|
||||
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow, "Auto select arbitrators by language:", "").second;
|
||||
|
||||
|
||||
// TODO need a bit extra work to separate trade and non trade tx fees before it can be used
|
||||
/*transactionFeeInputTextField = addLabelInputTextField(root, ++gridRow, "Transaction fee (satoshi/byte):").second;
|
||||
transactionFeeFocusedListener = (o, oldValue, newValue) -> {
|
||||
|
@ -71,8 +74,8 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
addTitledGroupBg(root, ++gridRow, 4, "Display options", Layout.GROUP_DISTANCE);
|
||||
useAnimationsCheckBox = addLabelCheckBox(root, gridRow, "Use animations:", "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
useEffectsCheckBox = addLabelCheckBox(root, ++gridRow, "Use effects:", "").second;
|
||||
showPlaceOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at place offer:", "").second;
|
||||
showTakeOfferConfirmationCheckBox = addLabelCheckBox(root, ++gridRow, "Show confirmation at take offer:", "").second;
|
||||
showNotificationsCheckBox = addLabelCheckBox(root, ++gridRow, "Show notifications:", "").second;
|
||||
showInstructionsCheckBox = addLabelCheckBox(root, ++gridRow, "Show instruction popups:", "").second;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,9 +85,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
btcDenominationComboBox.getSelectionModel().select(model.getBtcDenomination());
|
||||
btcDenominationComboBox.setOnAction(e -> model.onSelectBtcDenomination(btcDenominationComboBox.getSelectionModel().getSelectedItem()));*/
|
||||
|
||||
tradeCurrencyComboBox.setItems(model.tradeCurrencies);
|
||||
tradeCurrencyComboBox.getSelectionModel().select(model.getTradeCurrency());
|
||||
tradeCurrencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
preferredTradeCurrencyComboBox.setItems(model.tradeCurrencies);
|
||||
preferredTradeCurrencyComboBox.getSelectionModel().select(preferences.getPreferredTradeCurrency());
|
||||
preferredTradeCurrencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
@Override
|
||||
public String toString(TradeCurrency tradeCurrency) {
|
||||
return tradeCurrency.getNameAndCode();
|
||||
|
@ -95,7 +98,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
return null;
|
||||
}
|
||||
});
|
||||
tradeCurrencyComboBox.setOnAction(e -> model.onSelectTradeCurrency(tradeCurrencyComboBox.getSelectionModel().getSelectedItem()));
|
||||
preferredTradeCurrencyComboBox.setOnAction(e -> preferences.setPreferredTradeCurrency(preferredTradeCurrencyComboBox.getSelectionModel().getSelectedItem()));
|
||||
|
||||
languageComboBox.setItems(model.languageCodes);
|
||||
languageComboBox.getSelectionModel().select(model.getLanguageCode());
|
||||
|
@ -113,9 +116,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
languageComboBox.setOnAction(e -> model.onSelectLanguageCode(languageComboBox.getSelectionModel().getSelectedItem()));
|
||||
|
||||
|
||||
blockExplorerComboBox.setItems(model.blockExplorers);
|
||||
blockExplorerComboBox.getSelectionModel().select(model.getBlockExplorer());
|
||||
blockExplorerComboBox.setConverter(new StringConverter<BlockChainExplorer>() {
|
||||
blockChainExplorerComboBox.setItems(model.blockExplorers);
|
||||
blockChainExplorerComboBox.getSelectionModel().select(preferences.getBlockChainExplorer());
|
||||
blockChainExplorerComboBox.setConverter(new StringConverter<BlockChainExplorer>() {
|
||||
@Override
|
||||
public String toString(BlockChainExplorer blockChainExplorer) {
|
||||
return blockChainExplorer.name;
|
||||
|
@ -126,39 +129,39 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
return null;
|
||||
}
|
||||
});
|
||||
blockExplorerComboBox.setOnAction(e -> model.onSelectBlockExplorer(blockExplorerComboBox.getSelectionModel().getSelectedItem()));
|
||||
blockChainExplorerComboBox.setOnAction(e -> preferences.setBlockChainExplorer(blockChainExplorerComboBox.getSelectionModel().getSelectedItem()));
|
||||
|
||||
// transactionFeeInputTextField.textProperty().bindBidirectional(model.transactionFeePerByte);
|
||||
// transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener);
|
||||
|
||||
useAnimationsCheckBox.setSelected(model.getUseAnimations());
|
||||
useAnimationsCheckBox.setOnAction(e -> model.onSelectUseAnimations(useAnimationsCheckBox.isSelected()));
|
||||
useAnimationsCheckBox.setSelected(preferences.getUseAnimations());
|
||||
useAnimationsCheckBox.setOnAction(e -> preferences.setUseAnimations(useAnimationsCheckBox.isSelected()));
|
||||
|
||||
useEffectsCheckBox.setSelected(model.getUseEffects());
|
||||
useEffectsCheckBox.setOnAction(e -> model.onSelectUseEffects(useEffectsCheckBox.isSelected()));
|
||||
useEffectsCheckBox.setSelected(preferences.getUseEffects());
|
||||
useEffectsCheckBox.setOnAction(e -> preferences.setUseEffects(useEffectsCheckBox.isSelected()));
|
||||
|
||||
showPlaceOfferConfirmationCheckBox.setSelected(model.getShowPlaceOfferConfirmation());
|
||||
showPlaceOfferConfirmationCheckBox.setOnAction(e -> model.onSelectShowPlaceOfferConfirmation(showPlaceOfferConfirmationCheckBox.isSelected()));
|
||||
showNotificationsCheckBox.setSelected(preferences.getShowNotifications());
|
||||
showNotificationsCheckBox.setOnAction(e -> preferences.setShowNotifications(showNotificationsCheckBox.isSelected()));
|
||||
|
||||
showTakeOfferConfirmationCheckBox.setSelected(model.getShowTakeOfferConfirmation());
|
||||
showTakeOfferConfirmationCheckBox.setOnAction(e -> model.onSelectShowTakeOfferConfirmation(showTakeOfferConfirmationCheckBox.isSelected()));
|
||||
showInstructionsCheckBox.setSelected(preferences.getShowInstructions());
|
||||
showInstructionsCheckBox.setOnAction(e -> preferences.setShowInstructions(showInstructionsCheckBox.isSelected()));
|
||||
|
||||
autoSelectArbitratorsCheckBox.setSelected(model.getAutoSelectArbitrators());
|
||||
autoSelectArbitratorsCheckBox.setOnAction(e -> model.onSelectAutoSelectArbitratorsCheckBox(autoSelectArbitratorsCheckBox.isSelected()));
|
||||
autoSelectArbitratorsCheckBox.setSelected(preferences.getAutoSelectArbitrators());
|
||||
autoSelectArbitratorsCheckBox.setOnAction(e -> preferences.setAutoSelectArbitrators(autoSelectArbitratorsCheckBox.isSelected()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
//btcDenominationComboBox.setOnAction(null);
|
||||
languageComboBox.setOnAction(null);
|
||||
tradeCurrencyComboBox.setOnAction(null);
|
||||
blockExplorerComboBox.setOnAction(null);
|
||||
preferredTradeCurrencyComboBox.setOnAction(null);
|
||||
blockChainExplorerComboBox.setOnAction(null);
|
||||
showNotificationsCheckBox.setOnAction(null);
|
||||
showInstructionsCheckBox.setOnAction(null);
|
||||
// transactionFeeInputTextField.textProperty().unbind();
|
||||
/// transactionFeeInputTextField.focusedProperty().removeListener(transactionFeeFocusedListener);
|
||||
useAnimationsCheckBox.setOnAction(null);
|
||||
useEffectsCheckBox.setOnAction(null);
|
||||
showPlaceOfferConfirmationCheckBox.setOnAction(null);
|
||||
showTakeOfferConfirmationCheckBox.setOnAction(null);
|
||||
autoSelectArbitratorsCheckBox.setOnAction(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,42 +65,11 @@ class PreferencesViewModel extends ActivatableViewModel {
|
|||
protected void deactivate() {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI actions
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void onSelectBtcDenomination(String selectedItem) {
|
||||
preferences.setBtcDenomination(selectedItem);
|
||||
}
|
||||
|
||||
public void onSelectUseEffects(boolean selected) {
|
||||
preferences.setUseEffects(selected);
|
||||
}
|
||||
|
||||
public void onSelectUseAnimations(boolean selected) {
|
||||
preferences.setUseAnimations(selected);
|
||||
}
|
||||
|
||||
public void onSelectShowPlaceOfferConfirmation(boolean selected) {
|
||||
preferences.setShowPlaceOfferConfirmation(selected);
|
||||
}
|
||||
|
||||
public void onSelectShowTakeOfferConfirmation(boolean selected) {
|
||||
preferences.setShowTakeOfferConfirmation(selected);
|
||||
}
|
||||
|
||||
public void onSelectAutoSelectArbitratorsCheckBox(boolean selected) {
|
||||
preferences.setAutoSelectArbitrators(selected);
|
||||
}
|
||||
|
||||
public void onSelectBlockExplorer(BlockChainExplorer selectedItem) {
|
||||
preferences.setBlockChainExplorer(selectedItem);
|
||||
}
|
||||
|
||||
public void onSelectTradeCurrency(TradeCurrency selectedItem) {
|
||||
preferences.setPreferredTradeCurrency(selectedItem);
|
||||
}
|
||||
|
||||
public void onSelectLanguageCode(String code) {
|
||||
preferences.setPreferredLocale(new Locale(code, preferences.getPreferredLocale().getCountry()));
|
||||
}
|
||||
|
@ -124,40 +93,8 @@ class PreferencesViewModel extends ActivatableViewModel {
|
|||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getBtcDenomination() {
|
||||
return preferences.getBtcDenomination();
|
||||
}
|
||||
|
||||
public boolean getUseAnimations() {
|
||||
return preferences.getUseAnimations();
|
||||
}
|
||||
|
||||
public boolean getUseEffects() {
|
||||
return preferences.getUseEffects();
|
||||
}
|
||||
|
||||
public boolean getShowPlaceOfferConfirmation() {
|
||||
return preferences.getShowPlaceOfferConfirmation();
|
||||
}
|
||||
|
||||
public boolean getShowTakeOfferConfirmation() {
|
||||
return preferences.getShowTakeOfferConfirmation();
|
||||
}
|
||||
|
||||
public boolean getAutoSelectArbitrators() {
|
||||
return preferences.getAutoSelectArbitrators();
|
||||
}
|
||||
|
||||
public BlockChainExplorer getBlockExplorer() {
|
||||
return preferences.getBlockChainExplorer();
|
||||
}
|
||||
|
||||
public String getLanguageCode() {
|
||||
return preferences.getPreferredLocale().getLanguage();
|
||||
}
|
||||
|
||||
public TradeCurrency getTradeCurrency() {
|
||||
return preferences.getPreferredTradeCurrency();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue