Redesign controller/model types and apply to gui.main.Main*

Major changes:

 - Introduce Controller base class and FxmlController subclass. The
   latter has awareness of an @FXML "root" Node. Together, these classes
   functionally replace the ViewCB class, however ViewCB has been left
   in place so as to avoid the need to refactor all controllers at once.
   In this commit, the new Controller hierarchy has been applied only to
   the gui.main.MainViewCB controller.

 - Eliminate MainPM in favor of placing all logic in MainModel. This is
   potentially temporary, i.e. the distinction between data model and
   presentation model may be reintroduced in later commits, but for the
   purposes of this change, the goal was to simplify and remove as many
   layers as possible. The precise arrangement of controller and model
   classes is a topic to be discussed when reviewing this change.

Minor changes:

 - Inject model objects into MainModel instead of MainViewCB.
   Previously, model objects such as WalletService were injected into
   both MainModel and MainViewCB. Now this intended separation is more
   strictly observed.

 - Remove comment section markers and empty methods from MainModel and
   MainViewCB

 - Use public constructors in MainModel and elsewhere. This avoids
   unnecessary IDE warnings, allows the possibility of unit testing, and
   generally avoids surprise for the reader.

 - Eliminate Profiler statements in MainModel and elsewhere. These
   statements are fine during debugging or optimization sessions, but
   should otherwise be removed so as not to fill the logs with
   unimportant information.

 - Change signature of User#getCurrentBankAccount to return
   ObjectProperty. Previously, this method returned the underlying
   BankAccount; now returning ObjectProperty allows other components to
   add listeners (such as for user persistence when changing accounts in
   the UI).

 - Handle user persistence on account change elsewhere; namely add a
   listener for it in the MainModel constructor. Previously this was
   done in MainModel#setCurrentBankAccount, which amounts to a side
   effect in a setter method--something to avoid if possible.

 - Expose MainModel#getUser, and eliminate delegate methods previously
   in place that mediated access to the User object. This is mainly for
   consistency and concision.
This commit is contained in:
Chris Beams 2014-11-17 12:59:10 +01:00
parent b9a1095578
commit 3c3d3a507c
No known key found for this signature in database
GPG Key ID: 3D214F8F5BC5ED73
13 changed files with 291 additions and 331 deletions

View File

@ -0,0 +1,52 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import static com.google.common.base.Preconditions.checkNotNull;
public abstract class Controller<M extends Model> implements Initializable {
public static final String TITLE_KEY = "view.title";
protected M model;
protected Controller(M model) {
this.model = checkNotNull(model);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
model.initialize();
doInitialize();
}
public final void terminate() {
//model.terminate();
//doTerminate();
}
protected abstract void doInitialize();
protected void doTerminate() { };
}

View File

@ -0,0 +1,44 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.scene.*;
public abstract class FxmlController<R extends Node, M extends Model> extends Controller<M> {
protected @FXML R root;
protected FxmlController(M model) {
super(model);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
root.sceneProperty().addListener((ov, oldValue, newValue) -> {
// root node has been removed the scene
if (oldValue != null && newValue == null)
terminate();
});
super.initialize(url, rb);
}
}

View File

@ -0,0 +1,22 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui;
public interface Model {
void initialize();
}

View File

@ -40,7 +40,7 @@ public class ViewCB<T extends PresentationModel> implements Initializable {
protected T presentationModel;
protected Initializable childController;
protected ViewCB<? extends PresentationModel> parent;
protected Initializable parent;
@FXML protected Parent root;
@ -88,7 +88,7 @@ public class ViewCB<T extends PresentationModel> implements Initializable {
* @param parent Controller who has created this.getClass().getSimpleName() instance (via
* navigateToView/FXMLLoader).
*/
public void setParent(ViewCB<? extends PresentationModel> parent) {
public void setParent(Initializable parent) {
log.trace("Lifecycle: setParentController " + this.getClass().getSimpleName() + " / parent = " +
parent);
this.parent = parent;

View File

@ -18,9 +18,10 @@
package io.bitsquare.gui.main;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.btc.WalletService;
import io.bitsquare.gui.UIModel;
import io.bitsquare.gui.util.Profiler;
import io.bitsquare.gui.Model;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.msg.MessageService;
import io.bitsquare.msg.listeners.BootstrapListener;
import io.bitsquare.network.BootstrapState;
@ -40,73 +41,121 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class MainModel extends UIModel {
class MainModel implements Model {
private static final Logger log = LoggerFactory.getLogger(MainModel.class);
private final User user;
private final WalletService walletService;
private final MessageService messageService;
private final TradeManager tradeManager;
private final Persistence persistence;
private boolean messageServiceInited;
private boolean walletServiceInited;
private boolean servicesInitialised;
final BooleanProperty backendReady = new SimpleBooleanProperty();
final DoubleProperty networkSyncProgress = new SimpleDoubleProperty(-1);
final IntegerProperty numPendingTrades = new SimpleIntegerProperty(0);
final ObjectProperty<BootstrapState> bootstrapState = new SimpleObjectProperty<>();
final StringProperty bootstrapStateText = new SimpleStringProperty();
final ObjectProperty walletServiceException = new SimpleObjectProperty<Throwable>();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
final StringProperty blockchainSyncState = new SimpleStringProperty("Initializing");
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty();
final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true);
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
final BooleanProperty bootstrapFailed = new SimpleBooleanProperty();
final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
final StringProperty bootstrapIconId = new SimpleStringProperty();
private final User user;
private final WalletService walletService;
private final MessageService messageService;
private final TradeManager tradeManager;
private final BitcoinNetwork bitcoinNetwork;
private final BSFormatter formatter;
private boolean messageServiceInited;
private boolean walletServiceInited;
private boolean servicesInitialised;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private MainModel(User user, WalletService walletService, MessageService messageService,
TradeManager tradeManager, Persistence persistence) {
public MainModel(User user, WalletService walletService, MessageService messageService, TradeManager tradeManager,
BitcoinNetwork bitcoinNetwork, BSFormatter formatter, Persistence persistence) {
this.user = user;
this.walletService = walletService;
this.messageService = messageService;
this.tradeManager = tradeManager;
this.persistence = persistence;
this.formatter = formatter;
this.bitcoinNetwork = bitcoinNetwork;
user.getCurrentBankAccount().addListener((observable, oldValue, newValue) -> persistence.write(user));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
bootstrapState.addListener((ov, oldValue, newValue) -> {
if (newValue == BootstrapState.DIRECT_SUCCESS ||
newValue == BootstrapState.AUTO_PORT_FORWARDING_SUCCESS ||
newValue == BootstrapState.RELAY_SUCCESS) {
bootstrapStateText.set("Successfully connected to P2P network: " + newValue.getMessage());
bootstrapProgress.set(1);
if (newValue == BootstrapState.DIRECT_SUCCESS)
bootstrapIconId.set("image-connection-direct");
else if (newValue == BootstrapState.AUTO_PORT_FORWARDING_SUCCESS)
bootstrapIconId.set("image-connection-nat");
else if (newValue == BootstrapState.RELAY_SUCCESS)
bootstrapIconId.set("image-connection-relay");
}
else if (newValue == BootstrapState.PEER_CREATION_FAILED ||
newValue == BootstrapState.DIRECT_FAILED ||
newValue == BootstrapState.AUTO_PORT_FORWARDING_FAILED ||
newValue == BootstrapState.RELAY_FAILED) {
bootstrapErrorMsg.set(newValue.getMessage());
bootstrapStateText.set("Connection to P2P network failed.");
bootstrapProgress.set(0);
bootstrapFailed.set(true);
}
else {
bootstrapStateText.set("Connecting to P2P network: " + newValue.getMessage());
}
}
);
walletServiceException.addListener((ov, oldValue, newValue) -> {
blockchainSyncProgress.set(0);
blockchainSyncIndicatorVisible.set(false);
blockchainSyncState.set("Startup failed.");
walletServiceErrorMsg.set(((Throwable) newValue).getMessage());
});
networkSyncProgress.addListener((ov, oldValue, newValue) -> {
setNetworkSyncProgress((double) newValue);
if ((double) newValue >= 1)
blockchainSyncIconId.set("image-connection-synced");
});
setNetworkSyncProgress(networkSyncProgress.get());
user.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> {
bankAccountsComboBoxDisable.set(change.getList().isEmpty());
bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : "");
});
bankAccountsComboBoxDisable.set(user.getBankAccounts().isEmpty());
bankAccountsComboBoxPrompt.set(user.getBankAccounts().isEmpty() ? "No accounts" : "");
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public
///////////////////////////////////////////////////////////////////////////////////////////
void initBackend() {
// For testing with the bootstrap node we need the BootstrappedPeerFactory which gets started from
// messageService.init
public void initBackend() {
messageService.init(new BootstrapListener() {
@Override
public void onCompleted() {
@ -125,8 +174,6 @@ class MainModel extends UIModel {
}
});
Profiler.printMsgWithTime("MainModel.initServices");
WalletService.BlockchainDownloadListener blockchainDownloadListener = new WalletService
.BlockchainDownloadListener() {
@Override
@ -164,33 +211,29 @@ class MainModel extends UIModel {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
void setCurrentBankAccount(BankAccount bankAccount) {
user.setCurrentBankAccount(bankAccount);
persistence.write(user);
public User getUser() {
return user;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<BankAccount> getBankAccounts() {
return user.getBankAccounts();
public TradeManager getTradeManager() {
return tradeManager;
}
ObjectProperty<BankAccount> currentBankAccountProperty() {
return user.currentBankAccountProperty();
public StringConverter<BankAccount> getBankAccountsConverter() {
return new StringConverter<BankAccount>() {
@Override
public String toString(BankAccount bankAccount) {
return bankAccount.getNameOfBank();
}
@Override
public BankAccount fromString(String s) {
return null;
}
};
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void onServicesInitialised() {
tradeManager.getPendingTrades().addListener((MapChangeListener<String,
Trade>) change -> updateNumPendingTrades());
@ -206,4 +249,19 @@ class MainModel extends UIModel {
numPendingTrades.set(tradeManager.getPendingTrades().size());
}
private void setNetworkSyncProgress(double value) {
blockchainSyncProgress.set(value);
if (value >= 1)
blockchainSyncState.set("Synchronization completed.");
else if (value > 0.0)
blockchainSyncState.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
else
blockchainSyncState.set("Connecting to bitcoin network...");
blockchainSyncIndicatorVisible.set(value < 1);
}
public BitcoinNetwork getBitcoinNetwork() {
return bitcoinNetwork;
}
}

View File

@ -1,211 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.gui.main;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.gui.PresentationModel;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.network.BootstrapState;
import com.google.inject.Inject;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class MainPM extends PresentationModel<MainModel> {
private static final Logger log = LoggerFactory.getLogger(MainPM.class);
private final BSFormatter formatter;
final BooleanProperty backendReady = new SimpleBooleanProperty();
final StringProperty bankAccountsComboBoxPrompt = new SimpleStringProperty();
final BooleanProperty bankAccountsComboBoxDisable = new SimpleBooleanProperty();
final IntegerProperty numPendingTrades = new SimpleIntegerProperty();
final StringProperty blockchainSyncState = new SimpleStringProperty("Initializing");
final DoubleProperty blockchainSyncProgress = new SimpleDoubleProperty();
final BooleanProperty blockchainSyncIndicatorVisible = new SimpleBooleanProperty(true);
final StringProperty blockchainSyncIconId = new SimpleStringProperty();
final StringProperty walletServiceErrorMsg = new SimpleStringProperty();
final DoubleProperty bootstrapProgress = new SimpleDoubleProperty(-1);
final BooleanProperty bootstrapFailed = new SimpleBooleanProperty();
final StringProperty bootstrapState = new SimpleStringProperty();
final StringProperty bootstrapErrorMsg = new SimpleStringProperty();
final StringProperty bootstrapIconId = new SimpleStringProperty();
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private MainPM(MainModel model, BSFormatter formatter) {
super(model);
this.formatter = formatter;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("EmptyMethod")
@Override
public void initialize() {
super.initialize();
backendReady.bind(model.backendReady);
numPendingTrades.bind(model.numPendingTrades);
model.bootstrapState.addListener((ov, oldValue, newValue) -> {
if (newValue == BootstrapState.DIRECT_SUCCESS ||
newValue == BootstrapState.AUTO_PORT_FORWARDING_SUCCESS ||
newValue == BootstrapState.RELAY_SUCCESS) {
bootstrapState.set("Successfully connected to P2P network: " + newValue.getMessage());
bootstrapProgress.set(1);
if (newValue == BootstrapState.DIRECT_SUCCESS)
bootstrapIconId.set("image-connection-direct");
else if (newValue == BootstrapState.AUTO_PORT_FORWARDING_SUCCESS)
bootstrapIconId.set("image-connection-nat");
else if (newValue == BootstrapState.RELAY_SUCCESS)
bootstrapIconId.set("image-connection-relay");
}
else if (newValue == BootstrapState.PEER_CREATION_FAILED ||
newValue == BootstrapState.DIRECT_FAILED ||
newValue == BootstrapState.AUTO_PORT_FORWARDING_FAILED ||
newValue == BootstrapState.RELAY_FAILED) {
bootstrapErrorMsg.set(newValue.getMessage());
bootstrapState.set("Connection to P2P network failed.");
bootstrapProgress.set(0);
bootstrapFailed.set(true);
}
else {
bootstrapState.set("Connecting to P2P network: " + newValue.getMessage());
}
}
);
model.walletServiceException.addListener((ov, oldValue, newValue) -> {
blockchainSyncProgress.set(0);
blockchainSyncIndicatorVisible.set(false);
blockchainSyncState.set("Startup failed.");
walletServiceErrorMsg.set(((Throwable) newValue).getMessage());
});
model.networkSyncProgress.addListener((ov, oldValue, newValue) -> {
setNetworkSyncProgress((double) newValue);
if ((double) newValue >= 1)
blockchainSyncIconId.set("image-connection-synced");
});
setNetworkSyncProgress(model.networkSyncProgress.get());
model.getBankAccounts().addListener((ListChangeListener<BankAccount>) change -> {
bankAccountsComboBoxDisable.set(change.getList().isEmpty());
bankAccountsComboBoxPrompt.set(change.getList().isEmpty() ? "No accounts" : "");
});
bankAccountsComboBoxDisable.set(model.getBankAccounts().isEmpty());
bankAccountsComboBoxPrompt.set(model.getBankAccounts().isEmpty() ? "No accounts" : "");
}
@SuppressWarnings("EmptyMethod")
@Override
public void terminate() {
super.terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public
///////////////////////////////////////////////////////////////////////////////////////////
void initBackend() {
model.initBackend();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
void setCurrentBankAccount(BankAccount bankAccount) {
model.setCurrentBankAccount(bankAccount);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
ObservableList<BankAccount> getBankAccounts() {
return model.getBankAccounts();
}
ObjectProperty<BankAccount> currentBankAccountProperty() {
return model.currentBankAccountProperty();
}
StringConverter<BankAccount> getBankAccountsConverter() {
return new StringConverter<BankAccount>() {
@Override
public String toString(BankAccount bankAccount) {
return bankAccount.getNameOfBank();
}
@Override
public BankAccount fromString(String s) {
return null;
}
};
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void setNetworkSyncProgress(double value) {
blockchainSyncProgress.set(value);
if (value >= 1)
blockchainSyncState.set("Synchronization completed.");
else if (value > 0.0)
blockchainSyncState.set("Synchronizing blockchain: " + formatter.formatToPercent(value));
else
blockchainSyncState.set("Connecting to bitcoin network...");
blockchainSyncIndicatorVisible.set(value < 1);
}
}

View File

@ -19,7 +19,7 @@ package io.bitsquare.gui.main;
import io.bitsquare.BitsquareException;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.gui.FxmlController;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.OverlayManager;
import io.bitsquare.gui.ViewCB;
@ -27,11 +27,6 @@ import io.bitsquare.gui.ViewLoader;
import io.bitsquare.gui.components.Popups;
import io.bitsquare.gui.components.SystemNotification;
import io.bitsquare.gui.util.Transitions;
import io.bitsquare.trade.TradeManager;
import java.net.URL;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javax.inject.Named;
@ -50,7 +45,7 @@ import javafx.scene.text.*;
import static io.bitsquare.gui.Navigation.Item.*;
import static javafx.scene.layout.AnchorPane.*;
public class MainViewCB extends ViewCB<MainPM> {
public class MainViewCB extends FxmlController<Pane, MainModel> {
private final ToggleGroup navButtons = new ToggleGroup();
@ -58,33 +53,28 @@ public class MainViewCB extends ViewCB<MainPM> {
private final Navigation navigation;
private final OverlayManager overlayManager;
private final Transitions transitions;
private final BitcoinNetwork bitcoinNetwork;
private final String title;
@Inject
public MainViewCB(MainPM presentationModel, ViewLoader viewLoader, Navigation navigation,
OverlayManager overlayManager, TradeManager tradeManager, Transitions transitions,
BitcoinNetwork bitcoinNetwork, @Named(TITLE_KEY) String title) {
super(presentationModel);
public MainViewCB(MainModel model, ViewLoader viewLoader, Navigation navigation, OverlayManager overlayManager,
Transitions transitions, @Named(TITLE_KEY) String title) {
super(model);
this.viewLoader = viewLoader;
this.navigation = navigation;
this.overlayManager = overlayManager;
this.transitions = transitions;
this.bitcoinNetwork = bitcoinNetwork;
this.title = title;
tradeManager.featureNotImplementedWarningProperty().addListener((ov, oldValue, newValue) -> {
model.getTradeManager().featureNotImplementedWarningProperty().addListener((ov, oldValue, newValue) -> {
if (oldValue == null && newValue != null) {
Popups.openWarningPopup(newValue);
tradeManager.setFeatureNotImplementedWarning(null);
model.getTradeManager().setFeatureNotImplementedWarning(null);
}
});
}
@Override
public void initialize(URL url, ResourceBundle rb) {
super.initialize(url, rb);
public void doInitialize() {
ToggleButton homeButton = new NavButton(HOME) {{
setDisable(true); // during irc demo
}};
@ -151,16 +141,16 @@ public class MainViewCB extends ViewCB<MainPM> {
VBox splashScreen = createSplashScreen();
((Pane) root).getChildren().addAll(baseApplicationContainer, splashScreen);
root.getChildren().addAll(baseApplicationContainer, splashScreen);
presentationModel.backendReady.addListener((ov1, prev1, ready) -> {
model.backendReady.addListener((ov1, prev1, ready) -> {
if (!ready)
return;
bankAccountComboBoxHolder.getChildren().setAll(createBankAccountComboBox());
applyPendingTradesInfoIcon(presentationModel.numPendingTrades.get(), portfolioButtonHolder);
presentationModel.numPendingTrades.addListener((ov2, prev2, numPendingTrades) ->
applyPendingTradesInfoIcon(model.numPendingTrades.get(), portfolioButtonHolder);
model.numPendingTrades.addListener((ov2, prev2, numPendingTrades) ->
applyPendingTradesInfoIcon((int) numPendingTrades, portfolioButtonHolder));
navigation.navigateToLastStoredItem();
@ -168,7 +158,7 @@ public class MainViewCB extends ViewCB<MainPM> {
transitions.fadeOutAndRemove(splashScreen, 1500);
});
Platform.runLater(presentationModel::initBackend);
Platform.runLater(model::initBackend);
}
private VBox createSplashScreen() {
@ -181,8 +171,8 @@ public class MainViewCB extends ViewCB<MainPM> {
logo.setId("image-splash-logo");
Label blockchainSyncLabel = new Label();
blockchainSyncLabel.textProperty().bind(presentationModel.blockchainSyncState);
presentationModel.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
blockchainSyncLabel.textProperty().bind(model.blockchainSyncState);
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
blockchainSyncLabel.setId("splash-error-state-msg");
Popups.openErrorPopup("Error", "An error occurred at startup. \n\nError message:\n" +
newValue);
@ -190,13 +180,13 @@ public class MainViewCB extends ViewCB<MainPM> {
ProgressBar blockchainSyncIndicator = new ProgressBar(-1);
blockchainSyncIndicator.setPrefWidth(120);
blockchainSyncIndicator.progressProperty().bind(presentationModel.blockchainSyncProgress);
blockchainSyncIndicator.progressProperty().bind(model.blockchainSyncProgress);
ImageView blockchainSyncIcon = new ImageView();
blockchainSyncIcon.setVisible(false);
blockchainSyncIcon.setManaged(false);
presentationModel.blockchainSyncIconId.addListener((ov, oldValue, newValue) -> {
model.blockchainSyncIconId.addListener((ov, oldValue, newValue) -> {
blockchainSyncIcon.setId(newValue);
blockchainSyncIcon.setVisible(true);
blockchainSyncIcon.setManaged(true);
@ -206,7 +196,7 @@ public class MainViewCB extends ViewCB<MainPM> {
});
Label bitcoinNetworkLabel = new Label();
bitcoinNetworkLabel.setText(bitcoinNetwork.toString());
bitcoinNetworkLabel.setText(model.getBitcoinNetwork().toString());
bitcoinNetworkLabel.setId("splash-bitcoin-network-label");
HBox blockchainSyncBox = new HBox();
@ -221,19 +211,19 @@ public class MainViewCB extends ViewCB<MainPM> {
bootstrapStateLabel.setWrapText(true);
bootstrapStateLabel.setMaxWidth(500);
bootstrapStateLabel.setTextAlignment(TextAlignment.CENTER);
bootstrapStateLabel.textProperty().bind(presentationModel.bootstrapState);
bootstrapStateLabel.textProperty().bind(model.bootstrapStateText);
ProgressIndicator bootstrapIndicator = new ProgressIndicator();
bootstrapIndicator.setMaxSize(24, 24);
bootstrapIndicator.progressProperty().bind(presentationModel.bootstrapProgress);
bootstrapIndicator.progressProperty().bind(model.bootstrapProgress);
presentationModel.bootstrapFailed.addListener((ov, oldValue, newValue) -> {
model.bootstrapFailed.addListener((ov, oldValue, newValue) -> {
if (newValue) {
bootstrapStateLabel.setId("splash-error-state-msg");
bootstrapIndicator.setVisible(false);
Popups.openErrorPopup("Error", "Cannot connect to P2P network. \n\nError message:\n" +
presentationModel.bootstrapErrorMsg.get());
model.bootstrapErrorMsg.get());
}
});
@ -241,7 +231,7 @@ public class MainViewCB extends ViewCB<MainPM> {
bootstrapIcon.setVisible(false);
bootstrapIcon.setManaged(false);
presentationModel.bootstrapIconId.addListener((ov, oldValue, newValue) -> {
model.bootstrapIconId.addListener((ov, oldValue, newValue) -> {
bootstrapIcon.setId(newValue);
bootstrapIcon.setVisible(true);
bootstrapIcon.setManaged(true);
@ -262,21 +252,21 @@ public class MainViewCB extends ViewCB<MainPM> {
}
private VBox createBankAccountComboBox() {
final ComboBox<BankAccount> comboBox = new ComboBox<>(presentationModel.getBankAccounts());
final ComboBox<BankAccount> comboBox = new ComboBox<>(model.getUser().getBankAccounts());
comboBox.setLayoutY(12);
comboBox.setVisibleRowCount(5);
comboBox.setConverter(presentationModel.getBankAccountsConverter());
comboBox.setConverter(model.getBankAccountsConverter());
comboBox.valueProperty().addListener((ov, oldValue, newValue) ->
presentationModel.setCurrentBankAccount(newValue));
model.getUser().setCurrentBankAccount(newValue));
comboBox.disableProperty().bind(presentationModel.bankAccountsComboBoxDisable);
comboBox.promptTextProperty().bind(presentationModel.bankAccountsComboBoxPrompt);
comboBox.disableProperty().bind(model.bankAccountsComboBoxDisable);
comboBox.promptTextProperty().bind(model.bankAccountsComboBoxPrompt);
presentationModel.currentBankAccountProperty().addListener((ov, oldValue, newValue) ->
model.getUser().currentBankAccountProperty().addListener((ov, oldValue, newValue) ->
comboBox.getSelectionModel().select(newValue));
comboBox.getSelectionModel().select(presentationModel.currentBankAccountProperty().get());
comboBox.getSelectionModel().select(model.getUser().currentBankAccountProperty().get());
final Label titleLabel = new Label("Bank account");
titleLabel.setMouseTransparent(true);

View File

@ -152,7 +152,7 @@ class CreateOfferModel extends UIModel {
if (user != null) {
user.currentBankAccountProperty().addListener((ov, oldValue, newValue) -> applyBankAccount(newValue));
applyBankAccount(user.getCurrentBankAccount());
applyBankAccount(user.getCurrentBankAccount().get());
}
if (accountSettings != null)

View File

@ -171,7 +171,7 @@ public class OfferBook {
// TODO Just temporary, will be removed later when we have a push solution
private void startPolling() {
addListeners();
setBankAccount(user.getCurrentBankAccount());
setBankAccount(user.getCurrentBankAccount().get());
pollingTimer = Utilities.setInterval(3000, (animationTimer) -> {
offerRepository.requestInvalidationTimeStampFromDHT(fiatCode);
return null;

View File

@ -121,7 +121,7 @@ class OfferBookModel extends UIModel {
user.currentBankAccountProperty().addListener(bankAccountChangeListener);
btcCode.bind(preferences.btcDenominationProperty());
setBankAccount(user.getCurrentBankAccount());
setBankAccount(user.getCurrentBankAccount().get());
applyFilter();
}
@ -181,16 +181,18 @@ class OfferBookModel extends UIModel {
boolean isTradable(Offer offer) {
// if user has not registered yet we display all
if (user.getCurrentBankAccount() == null)
BankAccount currentBankAccount = user.getCurrentBankAccount().get();
if (currentBankAccount == null)
return true;
boolean countryResult = offer.getAcceptedCountries().contains(user.getCurrentBankAccount().getCountry());
boolean countryResult = offer.getAcceptedCountries().contains(currentBankAccount.getCountry());
// for IRC test version deactivate the check
countryResult = true;
if (!countryResult)
restrictionsInfo.set("This offer requires that the payments account resides in one of those countries:\n" +
formatter.countryLocalesToString(offer.getAcceptedCountries()) +
"\n\nThe country of your payments account (" + user.getCurrentBankAccount().getCountry().getName() +
"\n\nThe country of your payments account (" + user.getCurrentBankAccount().get().getCountry()
.getName() +
") is not included in that list." +
"\n\n Do you want to edit your preferences now?");

View File

@ -18,6 +18,7 @@
package io.bitsquare.trade;
import io.bitsquare.account.AccountSettings;
import io.bitsquare.bank.BankAccount;
import io.bitsquare.btc.BlockChainService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.crypto.SignatureService;
@ -55,6 +56,7 @@ import java.util.Map;
import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
@ -152,16 +154,17 @@ public class TradeManager {
TransactionResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) {
BankAccount currentBankAccount = user.getCurrentBankAccount().get();
Offer offer = new Offer(id,
user.getMessagePublicKey(),
direction,
price.getValue(),
amount,
minAmount,
user.getCurrentBankAccount().getBankAccountType(),
user.getCurrentBankAccount().getCurrency(),
user.getCurrentBankAccount().getCountry(),
user.getCurrentBankAccount().getUid(),
currentBankAccount.getBankAccountType(),
currentBankAccount.getCurrency(),
currentBankAccount.getCountry(),
currentBankAccount.getUid(),
accountSettings.getAcceptedArbitrators(),
accountSettings.getSecurityDeposit(),
accountSettings.getAcceptedCountries(),

View File

@ -154,7 +154,7 @@ public class SellerTakesOfferProtocol {
peersMessagePublicKey = offer.getMessagePublicKey();
bankAccount = user.getCurrentBankAccount();
bankAccount = user.getCurrentBankAccount().get();
accountId = user.getAccountId();
messagePublicKey = user.getMessagePublicKey();

View File

@ -148,8 +148,8 @@ public class User implements Serializable {
return bankAccounts;
}
public BankAccount getCurrentBankAccount() {
return currentBankAccount.get();
public ObjectProperty<BankAccount> getCurrentBankAccount() {
return currentBankAccount;
}
public BankAccount getBankAccount(String bankAccountId) {