diff --git a/src/main/java/io/bitsquare/gui/CachedCodeBehind.java b/src/main/java/io/bitsquare/gui/CachedCodeBehind.java new file mode 100644 index 0000000000..bbdb8b6030 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/CachedCodeBehind.java @@ -0,0 +1,73 @@ +package io.bitsquare.gui; + +import java.net.URL; + +import java.util.ResourceBundle; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CachedCodeBehind extends CodeBehind { + private static final Logger log = LoggerFactory.getLogger(CachedCodeBehind.class); + + public CachedCodeBehind(T pm) { + super(pm); + } + + /** + * Get called form GUI framework when the UI is ready. + * In caching controllers the initialize is only used for static UI setup. + * The activate() method is called to start resources like. + * + * @param url + * @param rb + */ + @Override + public void initialize(URL url, ResourceBundle rb) { + log.trace("Lifecycle: initialize " + this.getClass().getSimpleName()); + root.sceneProperty().addListener((ov, oldValue, newValue) -> { + // we got removed from the scene + // lets terminate + log.trace("Lifecycle: sceneProperty changed: " + this.getClass().getSimpleName() + " / oldValue=" + + oldValue + " / newValue=" + newValue); + if (oldValue == null && newValue != null) activate(); + else if (oldValue != null && newValue == null) deactivate(); + }); + + activate(); + pm.initialized(); + } + + /** + * Used to activate resources (adding listeners, starting timers or animations,...) + */ + public void activate() { + log.trace("Lifecycle: activate " + this.getClass().getSimpleName()); + if (childController instanceof CachedViewController) ((CachedViewController) childController).activate(); + + pm.activate(); + } + + /** + * Used for deactivating resources (removing listeners, stopping timers or animations,...) + */ + public void deactivate() { + log.trace("Lifecycle: deactivate " + this.getClass().getSimpleName()); + if (childController instanceof CachedViewController) ((CachedViewController) childController).deactivate(); + + pm.deactivate(); + } + + /** + * In caching controllers the terminate calls the deactivate method. + */ + @Override + public void terminate() { + log.trace("Lifecycle: terminate " + this.getClass().getSimpleName()); + super.terminate(); + + deactivate(); + pm.terminate(); + } + +} diff --git a/src/main/java/io/bitsquare/gui/CodeBehind.java b/src/main/java/io/bitsquare/gui/CodeBehind.java new file mode 100644 index 0000000000..c2cbf5fbf7 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/CodeBehind.java @@ -0,0 +1,79 @@ +package io.bitsquare.gui; + +import java.net.URL; + +import java.util.ResourceBundle; + +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CodeBehind implements Initializable { + private static final Logger log = LoggerFactory.getLogger(CodeBehind.class); + + protected T pm; + protected ViewController childController; + protected ViewController parentController; + @FXML protected Parent root; + + public CodeBehind(T pm) { + this.pm = pm; + } + + public T pm() { + return (T) pm; + } + + /** + * Get called form GUI framework when the UI is ready. + * + * @param url + * @param rb + */ + @Override + public void initialize(URL url, ResourceBundle rb) { + log.trace("Lifecycle: initialize " + this.getClass().getSimpleName()); + root.sceneProperty().addListener((ov, oldValue, newValue) -> { + // we got removed from the scene + // lets terminate + if (oldValue != null && newValue == null) terminate(); + }); + + pm.initialized(); + } + + /** + * Called automatically when view gets removed. Used for house keeping (removing listeners, + * stopping timers or animations,...). + */ + public void terminate() { + log.trace("Lifecycle: terminate " + this.getClass().getSimpleName()); + if (childController != null) childController.terminate(); + + pm.terminate(); + } + + /** + * @param parentController Controller who has created this.getClass().getSimpleName() instance (via + * navigateToView/FXMLLoader). + */ + public void setParentController(ViewController parentController) { + log.trace("Lifecycle: setParentController " + this.getClass().getSimpleName() + " / parent = " + + parentController); + this.parentController = parentController; + } + + /** + * @param navigationItem NavigationItem to be loaded. + * @return The ViewController of the loaded view. + */ + public ViewController loadViewAndGetChildController(NavigationItem navigationItem) { + log.trace("Lifecycle: loadViewAndGetChildController " + this.getClass().getSimpleName() + " / navigationItem " + + "= " + navigationItem); + return null; + } + +} diff --git a/src/main/java/io/bitsquare/gui/PresentationModel.java b/src/main/java/io/bitsquare/gui/PresentationModel.java new file mode 100644 index 0000000000..64dcc2a9e2 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/PresentationModel.java @@ -0,0 +1,36 @@ +package io.bitsquare.gui; + +public class PresentationModel { + + private T model; + + public T model() { + return (T) model; + } + + public PresentationModel(T model) { + this.model = model; + } + + public PresentationModel() { + } + + public void initialized() { + model.initialized(); + activate(); + } + + public void activate() { + model.activate(); + } + + public void deactivate() { + model.deactivate(); + } + + public void terminate() { + model.terminate(); + deactivate(); + } + +} diff --git a/src/main/java/io/bitsquare/gui/UIModel.java b/src/main/java/io/bitsquare/gui/UIModel.java new file mode 100644 index 0000000000..43143b39b9 --- /dev/null +++ b/src/main/java/io/bitsquare/gui/UIModel.java @@ -0,0 +1,22 @@ +package io.bitsquare.gui; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UIModel { + private static final Logger log = LoggerFactory.getLogger(UIModel.class); + + public void initialized() { + activate(); + } + + public void activate() { + } + + public void deactivate() { + } + + public void terminate() { + deactivate(); + } +} diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java index d57fbc4b6d..c21bfc8399 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferCB.java @@ -17,7 +17,7 @@ package io.bitsquare.gui.trade.createoffer; -import io.bitsquare.gui.CachedViewController; +import io.bitsquare.gui.CachedCodeBehind; import io.bitsquare.gui.components.Popups; import io.bitsquare.gui.components.ValidatingTextField; import io.bitsquare.gui.components.btc.AddressTextField; @@ -39,11 +39,9 @@ import javafx.scene.layout.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CreateOfferCB extends CachedViewController { +public class CreateOfferCB extends CachedCodeBehind { private static final Logger log = LoggerFactory.getLogger(CreateOfferCB.class); - private final CreateOfferPM pm; - @FXML private Label buyLabel, confirmationLabel, txTitleLabel, collateralLabel; @FXML private ValidatingTextField amountTextField, minAmountTextField, priceTextField, volumeTextField; @FXML private Button placeOfferButton, closeButton; @@ -63,7 +61,7 @@ public class CreateOfferCB extends CachedViewController { //TODO find a better solution, handle at base class? @Inject public CreateOfferCB(CreateOfferModel model) { - pm = new CreateOfferPM(model); + super(new CreateOfferPM(model)); } @@ -75,41 +73,27 @@ public class CreateOfferCB extends CachedViewController { public void initialize(URL url, ResourceBundle rb) { super.initialize(url, rb); - //TODO handle in base class - pm.onViewInitialized(); - setupBindings(); setupListeners(); configTextFieldValidators(); - balanceTextField.setup(pm.getWalletFacade(), pm.address.get()); + balanceTextField.setup(pm().getWalletFacade(), pm().address.get()); } @Override public void deactivate() { super.deactivate(); - //TODO handle in base class - pm.deactivate(); - //TODO check that again if (parentController != null) ((TradeController) parentController).onCreateOfferViewRemoved(); } - @Override - public void activate() { - super.activate(); - - //TODO handle in base class - pm.activate(); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Public methods /////////////////////////////////////////////////////////////////////////////////////////// public void setOrderBookFilter(OrderBookFilter orderBookFilter) { - pm.setOrderBookFilter(orderBookFilter); + pm().setOrderBookFilter(orderBookFilter); } @@ -119,12 +103,12 @@ public class CreateOfferCB extends CachedViewController { @FXML public void onPlaceOffer() { - pm.placeOffer(); + pm().placeOffer(); } @FXML public void onClose() { - pm.close(); + pm().close(); TabPane tabPane = ((TabPane) (root.getParent().getParent())); tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem()); @@ -137,91 +121,91 @@ public class CreateOfferCB extends CachedViewController { private void setupListeners() { volumeTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - pm.onFocusOutVolumeTextField(oldValue, newValue); - volumeTextField.setText(pm.volume.get()); + pm().onFocusOutVolumeTextField(oldValue, newValue); + volumeTextField.setText(pm().volume.get()); }); amountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - pm.onFocusOutAmountTextField(oldValue, newValue); - amountTextField.setText(pm.amount.get()); + pm().onFocusOutAmountTextField(oldValue, newValue); + amountTextField.setText(pm().amount.get()); }); priceTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - pm.onFocusOutPriceTextField(oldValue, newValue); - priceTextField.setText(pm.price.get()); + pm().onFocusOutPriceTextField(oldValue, newValue); + priceTextField.setText(pm().price.get()); }); minAmountTextField.focusedProperty().addListener((o, oldValue, newValue) -> { - pm.onFocusOutMinAmountTextField(oldValue, newValue); - minAmountTextField.setText(pm.minAmount.get()); + pm().onFocusOutMinAmountTextField(oldValue, newValue); + minAmountTextField.setText(pm().minAmount.get()); }); - pm.showWarningInvalidBtcDecimalPlaces.addListener((o, oldValue, newValue) -> { + pm().showWarningInvalidBtcDecimalPlaces.addListener((o, oldValue, newValue) -> { if (newValue) { Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + " places.\nThe amount has been adjusted to 4 decimal places."); - pm.showWarningInvalidBtcDecimalPlaces.set(false); + pm().showWarningInvalidBtcDecimalPlaces.set(false); } }); - pm.showWarningInvalidFiatDecimalPlaces.addListener((o, oldValue, newValue) -> { + pm().showWarningInvalidFiatDecimalPlaces.addListener((o, oldValue, newValue) -> { if (newValue) { Popups.openWarningPopup("Warning", "The amount you have entered exceeds the number of allowed decimal" + " places.\nThe amount has been adjusted to 2 decimal places."); - pm.showWarningInvalidFiatDecimalPlaces.set(false); + pm().showWarningInvalidFiatDecimalPlaces.set(false); } }); - pm.showWarningAdjustedVolume.addListener((o, oldValue, newValue) -> { + pm().showWarningAdjustedVolume.addListener((o, oldValue, newValue) -> { if (newValue) { Popups.openWarningPopup("Warning", "The total volume you have entered leads to invalid fractional " + "Bitcoin amounts.\nThe amount has been adjusted and a new total volume be calculated from it."); - pm.showWarningAdjustedVolume.set(false); - volumeTextField.setText(pm.volume.get()); + pm().showWarningAdjustedVolume.set(false); + volumeTextField.setText(pm().volume.get()); } }); - pm.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { + pm().requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { if (newValue) { Popups.openErrorPopup("Error", "An error occurred when placing the offer.\n" + - pm.requestPlaceOfferErrorMessage); - pm.requestPlaceOfferFailed.set(false); + pm().requestPlaceOfferErrorMessage); + pm().requestPlaceOfferFailed.set(false); } }); } private void setupBindings() { - buyLabel.textProperty().bind(pm.directionLabel); - amountTextField.textProperty().bindBidirectional(pm.amount); - priceTextField.textProperty().bindBidirectional(pm.price); - volumeTextField.textProperty().bindBidirectional(pm.volume); + buyLabel.textProperty().bind(pm().directionLabel); + amountTextField.textProperty().bindBidirectional(pm().amount); + priceTextField.textProperty().bindBidirectional(pm().price); + volumeTextField.textProperty().bindBidirectional(pm().volume); - minAmountTextField.textProperty().bindBidirectional(pm.minAmount); - collateralLabel.textProperty().bind(pm.collateralLabel); - collateralTextField.textProperty().bind(pm.collateral); - totalToPayTextField.textProperty().bind(pm.totalToPay); + minAmountTextField.textProperty().bindBidirectional(pm().minAmount); + collateralLabel.textProperty().bind(pm().collateralLabel); + collateralTextField.textProperty().bind(pm().collateral); + totalToPayTextField.textProperty().bind(pm().totalToPay); - addressTextField.amountAsCoinProperty().bind(pm.totalToPayAsCoin); - addressTextField.paymentLabelProperty().bind(pm.paymentLabel); - addressTextField.addressProperty().bind(pm.addressAsString); + addressTextField.amountAsCoinProperty().bind(pm().totalToPayAsCoin); + addressTextField.paymentLabelProperty().bind(pm().paymentLabel); + addressTextField.addressProperty().bind(pm().addressAsString); - bankAccountTypeTextField.textProperty().bind(pm.bankAccountType); - bankAccountCurrencyTextField.textProperty().bind(pm.bankAccountCurrency); - bankAccountCountyTextField.textProperty().bind(pm.bankAccountCounty); + bankAccountTypeTextField.textProperty().bind(pm().bankAccountType); + bankAccountCurrencyTextField.textProperty().bind(pm().bankAccountCurrency); + bankAccountCountyTextField.textProperty().bind(pm().bankAccountCounty); - acceptedCountriesTextField.textProperty().bind(pm.acceptedCountries); - acceptedLanguagesTextField.textProperty().bind(pm.acceptedLanguages); - totalFeesTextField.textProperty().bind(pm.totalFees); - transactionIdTextField.textProperty().bind(pm.transactionId); + acceptedCountriesTextField.textProperty().bind(pm().acceptedCountries); + acceptedLanguagesTextField.textProperty().bind(pm().acceptedLanguages); + totalFeesTextField.textProperty().bind(pm().totalFees); + transactionIdTextField.textProperty().bind(pm().transactionId); - amountTextField.amountValidationResultProperty().bind(pm.amountValidationResult); - minAmountTextField.amountValidationResultProperty().bind(pm.minAmountValidationResult); - priceTextField.amountValidationResultProperty().bind(pm.priceValidationResult); - volumeTextField.amountValidationResultProperty().bind(pm.volumeValidationResult); + amountTextField.amountValidationResultProperty().bind(pm().amountValidationResult); + minAmountTextField.amountValidationResultProperty().bind(pm().minAmountValidationResult); + priceTextField.amountValidationResultProperty().bind(pm().priceValidationResult); + volumeTextField.amountValidationResultProperty().bind(pm().volumeValidationResult); - placeOfferButton.visibleProperty().bind(pm.isPlaceOfferButtonVisible); - placeOfferButton.disableProperty().bind(pm.isPlaceOfferButtonDisabled); - closeButton.visibleProperty().bind(pm.isCloseButtonVisible); + placeOfferButton.visibleProperty().bind(pm().isPlaceOfferButtonVisible); + placeOfferButton.disableProperty().bind(pm().isPlaceOfferButtonDisabled); + closeButton.visibleProperty().bind(pm().isCloseButtonVisible); } private void configTextFieldValidators() { diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java index e4b8b5b5ca..06e70f7a8a 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferModel.java @@ -21,6 +21,7 @@ import io.bitsquare.bank.BankAccount; import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.WalletFacade; +import io.bitsquare.gui.UIModel; import io.bitsquare.locale.Country; import io.bitsquare.settings.Settings; import io.bitsquare.trade.Direction; @@ -58,7 +59,7 @@ import static io.bitsquare.gui.util.BSFormatter.reduceto4Dezimals; * Note that the create offer domain has a deeper scope in the application domain (TradeManager). * That model is just responsible for the domain specific parts displayed needed in that UI element. */ -class CreateOfferModel { +class CreateOfferModel extends UIModel { private static final Logger log = LoggerFactory.getLogger(CreateOfferModel.class); private final TradeManager tradeManager; @@ -99,7 +100,7 @@ class CreateOfferModel { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - CreateOfferModel(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user) { + public CreateOfferModel(TradeManager tradeManager, WalletFacade walletFacade, Settings settings, User user) { this.tradeManager = tradeManager; this.walletFacade = walletFacade; this.settings = settings; @@ -107,35 +108,52 @@ class CreateOfferModel { // static data offerId = UUID.randomUUID().toString(); - totalFeesAsCoin.set(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE)); + totalFeesAsCoin.setValue(FeePolicy.CREATE_OFFER_FEE.add(FeePolicy.TX_FEE)); //TODO just for unit testing, use mockito? if (walletFacade != null && walletFacade.getWallet() != null) addressEntry = walletFacade.getAddressInfoByTradeID(offerId); + + collateralAsLong.setValue(settings.getCollateral()); + + BankAccount bankAccount = user.getCurrentBankAccount(); + if (bankAccount != null) { + bankAccountType.setValue(bankAccount.getBankAccountType().toString()); + bankAccountCurrency.setValue(bankAccount.getCurrency().getCurrencyCode()); + bankAccountCounty.setValue(bankAccount.getCountry().getName()); + } + acceptedCountries.setAll(settings.getAcceptedCountries()); + acceptedLanguages.setAll(settings.getAcceptedLanguageLocales()); + } + /////////////////////////////////////////////////////////////////////////////////////////// + // Lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void initialized() { + super.initialized(); } + @Override + public void activate() { + super.activate(); + } + + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + public void terminate() { + super.terminate(); + } /////////////////////////////////////////////////////////////////////////////////////////// // Methods /////////////////////////////////////////////////////////////////////////////////////////// - void activate() { - // dynamic data, might be changing when switching screen and returning (edit settings) - collateralAsLong.set(settings.getCollateral()); - - BankAccount bankAccount = user.getCurrentBankAccount(); - if (bankAccount != null) { - bankAccountType.set(bankAccount.getBankAccountType().toString()); - bankAccountCurrency.set(bankAccount.getCurrency().getCurrencyCode()); - bankAccountCounty.set(bankAccount.getCountry().getName()); - } - acceptedCountries.setAll(settings.getAcceptedCountries()); - acceptedLanguages.setAll(settings.getAcceptedLanguageLocales()); - } - - void deactivate() { - } void placeOffer() { tradeManager.requestPlaceOffer(offerId, @@ -144,29 +162,29 @@ class CreateOfferModel { amountAsCoin.get(), minAmountAsCoin.get(), (transaction) -> { - requestPlaceOfferSuccess.set(true); - transactionId.set(transaction.getHashAsString()); + requestPlaceOfferSuccess.setValue(true); + transactionId.setValue(transaction.getHashAsString()); }, (errorMessage) -> { - requestPlaceOfferFailed.set(true); - requestPlaceOfferErrorMessage.set(errorMessage); + requestPlaceOfferFailed.setValue(true); + requestPlaceOfferErrorMessage.setValue(errorMessage); } ); } void calculateVolume() { if (priceAsFiat.get() != null && amountAsCoin.get() != null /*&& !amountAsCoin.get().isZero()*/) - volumeAsFiat.set(new ExchangeRate(priceAsFiat.get()).coinToFiat(amountAsCoin.get())); + volumeAsFiat.setValue(new ExchangeRate(priceAsFiat.get()).coinToFiat(amountAsCoin.get())); } void calculateAmount() { if (volumeAsFiat.get() != null && priceAsFiat.get() != null/* && !volumeAsFiat.get().isZero() && !priceAsFiat .get().isZero()*/) { - amountAsCoin.set(new ExchangeRate(priceAsFiat.get()).fiatToCoin(volumeAsFiat.get())); + amountAsCoin.setValue(new ExchangeRate(priceAsFiat.get()).fiatToCoin(volumeAsFiat.get())); // If we got a btc value with more then 4 decimals we convert it to max 4 decimals - amountAsCoin.set(reduceto4Dezimals(amountAsCoin.get())); + amountAsCoin.setValue(reduceto4Dezimals(amountAsCoin.get())); calculateTotalToPay(); calculateCollateral(); } @@ -176,14 +194,14 @@ class CreateOfferModel { calculateCollateral(); if (collateralAsCoin.get() != null) { - totalToPayAsCoin.set(collateralAsCoin.get().add(totalFeesAsCoin.get())); + totalToPayAsCoin.setValue(collateralAsCoin.get().add(totalFeesAsCoin.get())); } } void calculateCollateral() { if (amountAsCoin.get() != null) - collateralAsCoin.set(amountAsCoin.get().multiply(collateralAsLong.get()).divide(1000)); + collateralAsCoin.setValue(amountAsCoin.get().multiply(collateralAsLong.get()).divide(1000)); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java index 3ef2fb372c..e7d76584ad 100644 --- a/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java +++ b/src/main/java/io/bitsquare/gui/trade/createoffer/CreateOfferPM.java @@ -18,6 +18,7 @@ package io.bitsquare.gui.trade.createoffer; import io.bitsquare.btc.WalletFacade; +import io.bitsquare.gui.PresentationModel; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.validation.BtcValidator; import io.bitsquare.gui.util.validation.FiatValidator; @@ -44,10 +45,10 @@ import org.slf4j.LoggerFactory; import static io.bitsquare.gui.util.BSFormatter.*; import static javafx.beans.binding.Bindings.createStringBinding; -class CreateOfferPM { +class CreateOfferPM extends PresentationModel { private static final Logger log = LoggerFactory.getLogger(CreateOfferPM.class); - private CreateOfferModel model; + private BtcValidator btcValidator = new BtcValidator(); private FiatValidator fiatValidator = new FiatValidator(); @@ -86,7 +87,6 @@ class CreateOfferPM { // That is needed for the addressTextField final ObjectProperty totalToPayAsCoin = new SimpleObjectProperty<>(); - final ObjectProperty
address = new SimpleObjectProperty<>(); @@ -95,60 +95,60 @@ class CreateOfferPM { /////////////////////////////////////////////////////////////////////////////////////////// CreateOfferPM(CreateOfferModel model) { - this.model = model; - } + super(model); + paymentLabel.setValue("Bitsquare trade (" + model().getOfferId() + ")"); - /////////////////////////////////////////////////////////////////////////////////////////// - // Lifecycle (called by CB) - /////////////////////////////////////////////////////////////////////////////////////////// - - void onViewInitialized() { - // todo move to contr. - - // static - paymentLabel.set("Bitsquare trade (" + model.getOfferId() + ")"); - - if (model.addressEntry != null) { - addressAsString.set(model.addressEntry.getAddress().toString()); - address.set(model.addressEntry.getAddress()); + if (model().addressEntry != null) { + addressAsString.setValue(model().addressEntry.getAddress().toString()); + address.setValue(model().addressEntry.getAddress()); } setupModelBindings(); setupUIInputListeners(); - - // TODO transactionId, } - void activate() { - //TODO handle in base class - model.activate(); + /////////////////////////////////////////////////////////////////////////////////////////// + // Lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void initialized() { + super.initialized(); } - - void deactivate() { - //TODO handle in base class - model.deactivate(); + @Override + public void activate() { + super.activate(); } + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + public void terminate() { + super.terminate(); + } /////////////////////////////////////////////////////////////////////////////////////////// // Public API methods (called by CB) /////////////////////////////////////////////////////////////////////////////////////////// void setOrderBookFilter(OrderBookFilter orderBookFilter) { - model.setDirection(orderBookFilter.getDirection()); - directionLabel.set(model.getDirection() == Direction.BUY ? "Buy:" : "Sell:"); + model().setDirection(orderBookFilter.getDirection()); + directionLabel.setValue(model().getDirection() == Direction.BUY ? "Buy:" : "Sell:"); if (orderBookFilter.getAmount() != null && isBtcInputValid(orderBookFilter.getAmount().toPlainString()) .isValid) { - model.amountAsCoin.set(orderBookFilter.getAmount()); - model.minAmountAsCoin.set(orderBookFilter.getAmount()); + model().amountAsCoin.setValue(orderBookFilter.getAmount()); + model().minAmountAsCoin.setValue(orderBookFilter.getAmount()); } // TODO use Fiat in orderBookFilter if (orderBookFilter.getPrice() != 0 && isBtcInputValid(String.valueOf(orderBookFilter.getPrice())).isValid) - model.priceAsFiat.set(parseToFiatWith2Decimals(String.valueOf(orderBookFilter.getPrice()))); + model().priceAsFiat.setValue(parseToFiatWith2Decimals(String.valueOf(orderBookFilter.getPrice()))); } @@ -157,9 +157,9 @@ class CreateOfferPM { /////////////////////////////////////////////////////////////////////////////////////////// void placeOffer() { - model.placeOffer(); - isPlaceOfferButtonDisabled.set(true); - isPlaceOfferButtonVisible.set(true); + model().placeOffer(); + isPlaceOfferButtonDisabled.setValue(true); + isPlaceOfferButtonVisible.setValue(true); } void close() { @@ -175,22 +175,22 @@ class CreateOfferPM { if (oldValue && !newValue) { InputValidator.ValidationResult result = isBtcInputValid(amount.get()); boolean isValid = result.isValid; - amountValidationResult.set(result); + amountValidationResult.setValue(result); if (isValid) { - showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(amount.get())); + showWarningInvalidBtcDecimalPlaces.setValue(!hasBtcValidDecimals(amount.get())); // only allow max 4 decimal places for btc values setAmountToModel(); // reformat input to general btc format calculateVolume(); - if (!model.isMinAmountLessOrEqualAmount()) { - amountValidationResult.set(new InputValidator.ValidationResult(false, + if (!model().isMinAmountLessOrEqualAmount()) { + amountValidationResult.setValue(new InputValidator.ValidationResult(false, "Amount cannot be smaller than minimum amount.")); } else { - amountValidationResult.set(result); + amountValidationResult.setValue(result); if (minAmount.get() != null) - minAmountValidationResult.set(isBtcInputValid(minAmount.get())); + minAmountValidationResult.setValue(isBtcInputValid(minAmount.get())); } } } @@ -201,19 +201,19 @@ class CreateOfferPM { if (oldValue && !newValue) { InputValidator.ValidationResult result = isBtcInputValid(minAmount.get()); boolean isValid = result.isValid; - minAmountValidationResult.set(result); + minAmountValidationResult.setValue(result); if (isValid) { - showWarningInvalidBtcDecimalPlaces.set(!hasBtcValidDecimals(minAmount.get())); + showWarningInvalidBtcDecimalPlaces.setValue(!hasBtcValidDecimals(minAmount.get())); setMinAmountToModel(); - if (!model.isMinAmountLessOrEqualAmount()) { - minAmountValidationResult.set(new InputValidator.ValidationResult(false, + if (!model().isMinAmountLessOrEqualAmount()) { + minAmountValidationResult.setValue(new InputValidator.ValidationResult(false, "Minimum amount cannot be larger than amount.")); } else { - minAmountValidationResult.set(result); + minAmountValidationResult.setValue(result); if (amount.get() != null) - amountValidationResult.set(isBtcInputValid(amount.get())); + amountValidationResult.setValue(isBtcInputValid(amount.get())); } } } @@ -223,9 +223,9 @@ class CreateOfferPM { if (oldValue && !newValue) { InputValidator.ValidationResult result = isFiatInputValid(price.get()); boolean isValid = result.isValid; - priceValidationResult.set(result); + priceValidationResult.setValue(result); if (isValid) { - showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(price.get())); + showWarningInvalidFiatDecimalPlaces.setValue(!hasFiatValidDecimals(price.get())); setPriceToModel(); calculateVolume(); @@ -237,17 +237,18 @@ class CreateOfferPM { if (oldValue && !newValue) { InputValidator.ValidationResult result = isBtcInputValid(volume.get()); boolean isValid = result.isValid; - volumeValidationResult.set(result); + volumeValidationResult.setValue(result); if (isValid) { String origVolume = volume.get(); - showWarningInvalidFiatDecimalPlaces.set(!hasFiatValidDecimals(volume.get())); + showWarningInvalidFiatDecimalPlaces.setValue(!hasFiatValidDecimals(volume.get())); setVolumeToModel(); calculateAmount(); // must be after calculateAmount (btc value has been adjusted in case the calculation leads to // invalid decimal places for the amount value - showWarningAdjustedVolume.set(!formatFiat(parseToFiatWith2Decimals(origVolume)).equals(volume.get())); + showWarningAdjustedVolume.setValue(!formatFiat(parseToFiatWith2Decimals(origVolume)).equals(volume + .get())); } } } @@ -258,7 +259,7 @@ class CreateOfferPM { /////////////////////////////////////////////////////////////////////////////////////////// WalletFacade getWalletFacade() { - return model.getWalletFacade(); + return model().getWalletFacade(); } @@ -272,123 +273,111 @@ class CreateOfferPM { // We do volume/amount calculation during input amount.addListener((ov, oldValue, newValue) -> { if (isBtcInputValid(newValue).isValid) { - model.amountAsCoin.set(parseToCoinWith4Decimals(newValue)); + model().amountAsCoin.setValue(parseToCoinWith4Decimals(newValue)); calculateVolume(); - model.calculateTotalToPay(); - model.calculateCollateral(); + model().calculateTotalToPay(); + model().calculateCollateral(); } }); price.addListener((ov, oldValue, newValue) -> { if (isFiatInputValid(newValue).isValid) { - model.priceAsFiat.set(parseToFiatWith2Decimals(newValue)); + model().priceAsFiat.setValue(parseToFiatWith2Decimals(newValue)); calculateVolume(); - model.calculateTotalToPay(); - model.calculateCollateral(); + model().calculateTotalToPay(); + model().calculateCollateral(); } }); volume.addListener((ov, oldValue, newValue) -> { if (isFiatInputValid(newValue).isValid) { - model.volumeAsFiat.set(parseToFiatWith2Decimals(newValue)); + model().volumeAsFiat.setValue(parseToFiatWith2Decimals(newValue)); setVolumeToModel(); setPriceToModel(); - model.calculateAmount(); - model.calculateTotalToPay(); - model.calculateCollateral(); + model().calculateAmount(); + model().calculateTotalToPay(); + model().calculateCollateral(); } }); + + // Binding with Bindings.createObjectBinding does not work becaue of bi-directional binding in CB + model().amountAsCoin.addListener((ov, oldValue, newValue) -> amount.set(formatCoin(newValue))); + model().minAmountAsCoin.addListener((ov, oldValue, newValue) -> minAmount.set(formatCoin(newValue))); + model().priceAsFiat.addListener((ov, oldValue, newValue) -> price.set(formatFiat(newValue))); + model().volumeAsFiat.addListener((ov, oldValue, newValue) -> volume.set(formatFiat(newValue))); } private void setupModelBindings() { - - amount.bind(Bindings.createObjectBinding(() -> formatCoin(model.amountAsCoin.get()), model.amountAsCoin)); - minAmount.bind(Bindings.createObjectBinding(() -> formatCoin(model.minAmountAsCoin.get()), - model.minAmountAsCoin)); - price.bind(Bindings.createObjectBinding(() -> formatFiat(model.priceAsFiat.get()), model.priceAsFiat)); - volume.bind(Bindings.createObjectBinding(() -> formatFiat(model.volumeAsFiat.get()), model.volumeAsFiat)); - - totalToPay.bind(createStringBinding(() -> formatCoinWithCode(model.totalToPayAsCoin.get()), - model.totalToPayAsCoin)); - collateral.bind(createStringBinding(() -> formatCoinWithCode(model.collateralAsCoin.get()), - model.collateralAsCoin)); + totalToPay.bind(createStringBinding(() -> formatCoinWithCode(model().totalToPayAsCoin.get()), + model().totalToPayAsCoin)); + collateral.bind(createStringBinding(() -> formatCoinWithCode(model().collateralAsCoin.get()), + model().collateralAsCoin)); collateralLabel.bind(Bindings.createStringBinding(() -> "Collateral (" + BSFormatter.formatCollateralPercent - (model.collateralAsLong.get()) + "):", model.collateralAsLong)); - totalToPayAsCoin.bind(model.totalToPayAsCoin); + (model().collateralAsLong.get()) + "):", model().collateralAsLong)); + totalToPayAsCoin.bind(model().totalToPayAsCoin); - bankAccountType.bind(Bindings.createStringBinding(() -> Localisation.get(model.bankAccountType.get()), - model.bankAccountType)); - bankAccountCurrency.bind(model.bankAccountCurrency); - bankAccountCounty.bind(model.bankAccountCounty); + bankAccountType.bind(Bindings.createStringBinding(() -> Localisation.get(model().bankAccountType.get()), + model().bankAccountType)); + bankAccountCurrency.bind(model().bankAccountCurrency); + bankAccountCounty.bind(model().bankAccountCounty); // ObservableLists - model.acceptedCountries.addListener((Observable o) -> acceptedCountries.set(BSFormatter - .countryLocalesToString(model.acceptedCountries))); - model.acceptedLanguages.addListener((Observable o) -> acceptedLanguages.set(BSFormatter - .languageLocalesToString(model.acceptedLanguages))); + model().acceptedCountries.addListener((Observable o) -> acceptedCountries.setValue(BSFormatter + .countryLocalesToString(model().acceptedCountries))); + model().acceptedLanguages.addListener((Observable o) -> acceptedLanguages.setValue(BSFormatter + .languageLocalesToString(model().acceptedLanguages))); - isCloseButtonVisible.bind(model.requestPlaceOfferSuccess); - requestPlaceOfferErrorMessage.bind(model.requestPlaceOfferErrorMessage); - requestPlaceOfferFailed.bind(model.requestPlaceOfferFailed); - showTransactionPublishedScreen.bind(model.requestPlaceOfferSuccess); + isCloseButtonVisible.bind(model().requestPlaceOfferSuccess); + requestPlaceOfferErrorMessage.bind(model().requestPlaceOfferErrorMessage); + requestPlaceOfferFailed.bind(model().requestPlaceOfferFailed); + showTransactionPublishedScreen.bind(model().requestPlaceOfferSuccess); + isPlaceOfferButtonDisabled.bind(Bindings.createBooleanBinding(() -> !model().requestPlaceOfferFailed.get(), + model().requestPlaceOfferFailed)); - amount.bind(Bindings.createObjectBinding(() -> formatCoin(model.amountAsCoin.get()), model.amountAsCoin)); - - isPlaceOfferButtonDisabled.bind(Bindings.createBooleanBinding(() -> !model.requestPlaceOfferFailed.get(), - model.requestPlaceOfferFailed)); - - isPlaceOfferButtonVisible.bind(Bindings.createBooleanBinding(() -> !model.requestPlaceOfferSuccess.get(), - model.requestPlaceOfferSuccess)); - - /* model.requestPlaceOfferFailed.addListener((o, oldValue, newValue) -> { - if (newValue) isPlaceOfferButtonDisabled.set(false); - }); - - model.requestPlaceOfferSuccess.addListener((o, oldValue, newValue) -> { - if (newValue) isPlaceOfferButtonVisible.set(false); - });*/ + isPlaceOfferButtonVisible.bind(Bindings.createBooleanBinding(() -> !model().requestPlaceOfferSuccess.get(), + model().requestPlaceOfferSuccess)); } private void calculateVolume() { setAmountToModel(); setPriceToModel(); - model.calculateVolume(); + model().calculateVolume(); } private void calculateAmount() { setVolumeToModel(); setPriceToModel(); - model.calculateAmount(); + model().calculateAmount(); - if (!model.isMinAmountLessOrEqualAmount()) { - amountValidationResult.set(new InputValidator.ValidationResult(false, + if (!model().isMinAmountLessOrEqualAmount()) { + amountValidationResult.setValue(new InputValidator.ValidationResult(false, "Amount cannot be smaller than minimum amount.")); } else { if (amount.get() != null) - amountValidationResult.set(isBtcInputValid(amount.get())); + amountValidationResult.setValue(isBtcInputValid(amount.get())); if (minAmount.get() != null) - minAmountValidationResult.set(isBtcInputValid(minAmount.get())); + minAmountValidationResult.setValue(isBtcInputValid(minAmount.get())); } } private void setAmountToModel() { - model.amountAsCoin.set(parseToCoinWith4Decimals(amount.get())); + model().amountAsCoin.setValue(parseToCoinWith4Decimals(amount.get())); } private void setMinAmountToModel() { - model.minAmountAsCoin.set(parseToCoinWith4Decimals(minAmount.get())); + model().minAmountAsCoin.setValue(parseToCoinWith4Decimals(minAmount.get())); } private void setPriceToModel() { - model.priceAsFiat.set(parseToFiatWith2Decimals(price.get())); + model().priceAsFiat.setValue(parseToFiatWith2Decimals(price.get())); } private void setVolumeToModel() { - model.volumeAsFiat.set(parseToFiatWith2Decimals(volume.get())); + model().volumeAsFiat.setValue(parseToFiatWith2Decimals(volume.get())); } ///////////////////////////////////////////////////////////////////////////////////////////