Refactoring MainViewModel

- Move p2p network setup code code to P2PNetworkSetup
- Move wallet setup code code to WalletAppSetup
- Move marketPrice code to MarketPricePresentation
This commit is contained in:
Manfred Karrer 2018-06-03 20:00:29 +02:00
parent d914eaab00
commit 76879ac13b
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
3 changed files with 522 additions and 898 deletions

View file

@ -229,7 +229,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
priceComboBox.getSelectionModel().select(newValue);
};
model.selectedPriceFeedComboBoxItemProperty.addListener(selectedPriceFeedItemListener);
model.getSelectedPriceFeedComboBoxItemProperty().addListener(selectedPriceFeedItemListener);
priceComboBox.setItems(model.priceFeedComboBoxItems);
HBox.setMargin(marketPriceBox.second, new Insets(0, 0, 0, 0));
@ -300,7 +300,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
root.getChildren().addAll(baseApplicationContainer, splashScreen);
model.showAppScreen.addListener((ov, oldValue, newValue) -> {
model.getShowAppScreen().addListener((ov, oldValue, newValue) -> {
if (newValue) {
navigation.navigateToPreviousVisitedView();
@ -366,16 +366,16 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
btcAverageIconButton.getStyleClass().add("hidden-icon-button");
HBox.setMargin(btcAverageIconButton, new Insets(0, 5, 0, 0));
btcAverageIconButton.setOnAction(e -> GUIUtil.openWebPage("https://bitcoinaverage.com"));
btcAverageIconButton.setVisible(model.isFiatCurrencyPriceFeedSelected.get());
btcAverageIconButton.setVisible(model.getIsFiatCurrencyPriceFeedSelected().get());
btcAverageIconButton.setManaged(btcAverageIconButton.isVisible());
btcAverageIconButton.visibleProperty().bind(model.isFiatCurrencyPriceFeedSelected);
btcAverageIconButton.managedProperty().bind(model.isFiatCurrencyPriceFeedSelected);
btcAverageIconButton.visibleProperty().bind(model.getIsFiatCurrencyPriceFeedSelected());
btcAverageIconButton.managedProperty().bind(model.getIsFiatCurrencyPriceFeedSelected());
btcAverageIconButton.setOnMouseEntered(e -> {
String res = Res.get("mainView.marketPrice.tooltip",
"https://bitcoinaverage.com",
"",
formatter.formatTime(model.priceFeedService.getLastRequestTimeStampBtcAverage()),
model.priceFeedService.getProviderNodeAddress());
formatter.formatTime(model.getPriceFeedService().getLastRequestTimeStampBtcAverage()),
model.getPriceFeedService().getProviderNodeAddress());
btcAverageIconButton.setTooltip(
new Tooltip(res)
);
@ -390,17 +390,17 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
poloniexIconButton.getStyleClass().add("hidden-icon-button");
HBox.setMargin(poloniexIconButton, new Insets(2, 3, 0, 0));
poloniexIconButton.setOnAction(e -> GUIUtil.openWebPage("https://poloniex.com"));
poloniexIconButton.setVisible(model.isCryptoCurrencyPriceFeedSelected.get());
poloniexIconButton.setVisible(model.getIsCryptoCurrencyPriceFeedSelected().get());
poloniexIconButton.setManaged(poloniexIconButton.isVisible());
poloniexIconButton.visibleProperty().bind(model.isCryptoCurrencyPriceFeedSelected);
poloniexIconButton.managedProperty().bind(model.isCryptoCurrencyPriceFeedSelected);
poloniexIconButton.visibleProperty().bind(model.getIsCryptoCurrencyPriceFeedSelected());
poloniexIconButton.managedProperty().bind(model.getIsCryptoCurrencyPriceFeedSelected());
poloniexIconButton.setOnMouseEntered(e -> {
String altcoinExtra = "\n" + Res.get("mainView.marketPrice.tooltip.altcoinExtra");
String res = Res.get("mainView.marketPrice.tooltip",
"https://poloniex.com",
altcoinExtra,
formatter.formatTime(model.priceFeedService.getLastRequestTimeStampPoloniex()),
model.priceFeedService.getProviderNodeAddress());
formatter.formatTime(model.getPriceFeedService().getLastRequestTimeStampPoloniex()),
model.getPriceFeedService().getProviderNodeAddress());
poloniexIconButton.setTooltip(
new Tooltip(res)
);
@ -410,7 +410,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
label.setId("nav-balance-label");
label.setPadding(new Insets(0, 5, 0, 2));
model.marketPriceUpdated.addListener((observable, oldValue, newValue) -> {
model.getMarketPriceUpdated().addListener((observable, oldValue, newValue) -> {
updateMarketPriceLabel(label);
});
@ -425,8 +425,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
private void updateMarketPriceLabel(Label label) {
if (model.isPriceAvailable.get()) {
if (model.isExternallyProvidedPrice.get()) {
if (model.getIsPriceAvailable().get()) {
if (model.getIsExternallyProvidedPrice().get()) {
label.setText(Res.get("mainView.marketPrice.provider"));
label.setTooltip(null);
} else {
@ -453,16 +453,16 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
// createBitcoinInfoBox
btcSplashInfo = new AutoTooltipLabel();
btcSplashInfo.textProperty().bind(model.btcInfo);
btcSplashInfo.textProperty().bind(model.getBtcInfo());
walletServiceErrorMsgListener = (ov, oldValue, newValue) -> {
btcSplashInfo.setId("splash-error-state-msg");
btcSplashInfo.getStyleClass().add("error-text");
};
model.walletServiceErrorMsg.addListener(walletServiceErrorMsgListener);
model.getWalletServiceErrorMsg().addListener(walletServiceErrorMsgListener);
btcSyncIndicator = new ProgressBar();
btcSyncIndicator.setPrefWidth(120);
btcSyncIndicator.progressProperty().bind(model.btcSyncProgress);
btcSyncIndicator.progressProperty().bind(model.getBtcSyncProgress());
ImageView btcSyncIcon = new ImageView();
btcSyncIcon.setVisible(false);
@ -476,7 +476,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
btcSyncIndicator.setVisible(false);
btcSyncIndicator.setManaged(false);
};
model.btcSplashSyncIconId.addListener(btcSyncIconIdListener);
model.getBtcSplashSyncIconId().addListener(btcSyncIconIdListener);
HBox blockchainSyncBox = new HBox();
@ -492,7 +492,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
splashP2PNetworkLabel.setWrapText(true);
splashP2PNetworkLabel.setMaxWidth(500);
splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER);
splashP2PNetworkLabel.textProperty().bind(model.p2PNetworkInfo);
splashP2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
splashP2PNetworkBusyAnimation = new BusyAnimation();
@ -501,18 +501,18 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
splashP2PNetworkLabel.setId("splash-error-state-msg");
splashP2PNetworkLabel.getStyleClass().add("error-text");
splashP2PNetworkBusyAnimation.stop();
} else if (model.splashP2PNetworkAnimationVisible.get()) {
} else if (model.getSplashP2PNetworkAnimationVisible().get()) {
splashP2PNetworkBusyAnimation.play();
}
};
model.p2pNetworkWarnMsg.addListener(splashP2PNetworkErrorMsgListener);
model.getP2pNetworkWarnMsg().addListener(splashP2PNetworkErrorMsgListener);
Button showTorNetworkSettingsButton = new AutoTooltipButton(Res.get("settings.net.openTorSettingsButton"));
showTorNetworkSettingsButton.setVisible(false);
showTorNetworkSettingsButton.setManaged(false);
showTorNetworkSettingsButton.setOnAction(e -> {
model.torNetworkSettingsWindow.show();
model.getTorNetworkSettingsWindow().show();
});
ImageView splashP2PNetworkIcon = new ImageView();
@ -534,10 +534,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
// if we can connect in 10 sec. we know that tor is working
showTorNetworkSettingsTimer.stop();
};
model.p2PNetworkIconId.addListener(splashP2PNetworkIconIdListener);
model.getP2PNetworkIconId().addListener(splashP2PNetworkIconIdListener);
splashP2PNetworkVisibleListener = (ov, oldValue, newValue) -> splashP2PNetworkBusyAnimation.setIsRunning(newValue);
model.splashP2PNetworkAnimationVisible.addListener(splashP2PNetworkVisibleListener);
model.getSplashP2PNetworkAnimationVisible().addListener(splashP2PNetworkVisibleListener);
HBox splashP2PNetworkBox = new HBox();
splashP2PNetworkBox.setSpacing(10);
@ -550,12 +550,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
private void disposeSplashScreen() {
model.walletServiceErrorMsg.removeListener(walletServiceErrorMsgListener);
model.btcSplashSyncIconId.removeListener(btcSyncIconIdListener);
model.getWalletServiceErrorMsg().removeListener(walletServiceErrorMsgListener);
model.getBtcSplashSyncIconId().removeListener(btcSyncIconIdListener);
model.p2pNetworkWarnMsg.removeListener(splashP2PNetworkErrorMsgListener);
model.p2PNetworkIconId.removeListener(splashP2PNetworkIconIdListener);
model.splashP2PNetworkAnimationVisible.removeListener(splashP2PNetworkVisibleListener);
model.getP2pNetworkWarnMsg().removeListener(splashP2PNetworkErrorMsgListener);
model.getP2PNetworkIconId().removeListener(splashP2PNetworkIconIdListener);
model.getSplashP2PNetworkAnimationVisible().removeListener(splashP2PNetworkVisibleListener);
btcSplashInfo.textProperty().unbind();
btcSyncIndicator.progressProperty().unbind();
@ -578,14 +578,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
// BTC
Label btcInfoLabel = new AutoTooltipLabel();
btcInfoLabel.setId("footer-pane");
btcInfoLabel.textProperty().bind(model.btcInfo);
btcInfoLabel.textProperty().bind(model.getBtcInfo());
ProgressBar blockchainSyncIndicator = new ProgressBar(-1);
blockchainSyncIndicator.setPrefWidth(120);
blockchainSyncIndicator.setMaxHeight(10);
blockchainSyncIndicator.progressProperty().bind(model.btcSyncProgress);
blockchainSyncIndicator.progressProperty().bind(model.getBtcSyncProgress());
model.walletServiceErrorMsg.addListener((ov, oldValue, newValue) -> {
model.getWalletServiceErrorMsg().addListener((ov, oldValue, newValue) -> {
if (newValue != null) {
btcInfoLabel.setId("splash-error-state-msg");
btcInfoLabel.getStyleClass().add("error-text");
@ -600,7 +600,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
});
model.btcSyncProgress.addListener((ov, oldValue, newValue) -> {
model.getBtcSyncProgress().addListener((ov, oldValue, newValue) -> {
if ((double) newValue >= 1) {
blockchainSyncIndicator.setVisible(false);
blockchainSyncIndicator.setManaged(false);
@ -624,11 +624,11 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
versionLabel.setLayoutX(((double) newValue - versionLabel.getWidth()) / 2);
});
setBottomAnchor(versionLabel, 7d);
model.newVersionAvailableProperty.addListener((observable, oldValue, newValue) -> {
model.getNewVersionAvailableProperty().addListener((observable, oldValue, newValue) -> {
versionLabel.getStyleClass().removeAll("version-new", "version");
if (newValue) {
versionLabel.getStyleClass().add("version-new");
versionLabel.setOnMouseClicked(e -> model.openDownloadWindow());
versionLabel.setOnMouseClicked(e -> model.onOpenDownloadWindow());
versionLabel.setText("v" + Version.VERSION + " " + Res.get("mainView.version.update"));
} else {
versionLabel.getStyleClass().add("version");
@ -642,15 +642,15 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
p2PNetworkLabel.setId("footer-pane");
setRightAnchor(p2PNetworkLabel, 33d);
setBottomAnchor(p2PNetworkLabel, 7d);
p2PNetworkLabel.textProperty().bind(model.p2PNetworkInfo);
p2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
ImageView p2PNetworkIcon = new ImageView();
setRightAnchor(p2PNetworkIcon, 10d);
setBottomAnchor(p2PNetworkIcon, 7d);
p2PNetworkIcon.setOpacity(0.4);
p2PNetworkIcon.idProperty().bind(model.p2PNetworkIconId);
p2PNetworkLabel.idProperty().bind(model.p2pNetworkLabelId);
model.p2pNetworkWarnMsg.addListener((ov, oldValue, newValue) -> {
p2PNetworkIcon.idProperty().bind(model.getP2PNetworkIconId());
p2PNetworkLabel.idProperty().bind(model.getP2pNetworkLabelId());
model.getP2pNetworkWarnMsg().addListener((ov, oldValue, newValue) -> {
if (newValue != null) {
p2PNetworkWarnMsgPopup = new Popup<>().warning(newValue);
p2PNetworkWarnMsgPopup.show();
@ -659,7 +659,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
});
model.bootstrapComplete.addListener((observable, oldValue, newValue) -> {
model.getUpdatedDataReceived().addListener((observable, oldValue, newValue) -> {
p2PNetworkIcon.setOpacity(1);
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/*
* This file is part of Bisq.
*
* Bisq 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.
*
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main;
import bisq.desktop.components.BalanceWithConfirmationTextField;
import bisq.desktop.components.TxIdTextField;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;
import bisq.common.UserThread;
import javax.inject.Inject;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
import org.fxmisc.easybind.monadic.MonadicBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class MarketPricePresentation {
private final Preferences preferences;
private final BSFormatter formatter;
private final PriceFeedService priceFeedService;
private final ObservableList<PriceFeedComboBoxItem> priceFeedComboBoxItems = FXCollections.observableArrayList();
@SuppressWarnings("FieldCanBeLocal")
private MonadicBinding<String> marketPriceBinding;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private Subscription priceFeedAllLoadedSubscription;
private final StringProperty marketPriceCurrencyCode = new SimpleStringProperty("");
private final ObjectProperty<PriceFeedComboBoxItem> selectedPriceFeedComboBoxItemProperty = new SimpleObjectProperty<>();
private final BooleanProperty isFiatCurrencyPriceFeedSelected = new SimpleBooleanProperty(true);
private final BooleanProperty isCryptoCurrencyPriceFeedSelected = new SimpleBooleanProperty(false);
private final BooleanProperty isExternallyProvidedPrice = new SimpleBooleanProperty(true);
private final BooleanProperty isPriceAvailable = new SimpleBooleanProperty(false);
private final IntegerProperty marketPriceUpdated = new SimpleIntegerProperty(0);
private final StringProperty marketPrice = new SimpleStringProperty(Res.get("shared.na"));
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("WeakerAccess")
@Inject
public MarketPricePresentation(BtcWalletService btcWalletService,
PriceFeedService priceFeedService,
Preferences preferences,
FeeService feeService,
BSFormatter formatter) {
this.priceFeedService = priceFeedService;
this.preferences = preferences;
this.formatter = formatter;
TxIdTextField.setPreferences(preferences);
// TODO
TxIdTextField.setWalletService(btcWalletService);
BalanceWithConfirmationTextField.setWalletService(btcWalletService);
GUIUtil.setFeeService(feeService);
}
public void setup() {
fillPriceFeedComboBoxItems();
setupMarketPriceFeed();
}
public void setPriceFeedComboBoxItem(PriceFeedComboBoxItem item) {
if (item != null) {
Optional<PriceFeedComboBoxItem> itemOptional = findPriceFeedComboBoxItem(priceFeedService.currencyCodeProperty().get());
if (itemOptional.isPresent())
selectedPriceFeedComboBoxItemProperty.set(itemOptional.get());
else
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
priceFeedService.setCurrencyCode(item.currencyCode);
} else {
findPriceFeedComboBoxItem(preferences.getPreferredTradeCurrency().getCode())
.ifPresent(selectedPriceFeedComboBoxItemProperty::set);
}
}
private void fillPriceFeedComboBoxItems() {
List<PriceFeedComboBoxItem> currencyItems = preferences.getTradeCurrenciesAsObservable()
.stream()
.map(tradeCurrency -> new PriceFeedComboBoxItem(tradeCurrency.getCode()))
.collect(Collectors.toList());
priceFeedComboBoxItems.setAll(currencyItems);
}
private void setupMarketPriceFeed() {
priceFeedService.requestPriceFeed(price -> marketPrice.set(formatter.formatMarketPrice(price, priceFeedService.getCurrencyCode())),
(errorMessage, throwable) -> marketPrice.set(Res.get("shared.na")));
marketPriceBinding = EasyBind.combine(
marketPriceCurrencyCode, marketPrice,
(currencyCode, price) -> formatter.getCurrencyPair(currencyCode) + ": " + price);
marketPriceBinding.subscribe((observable, oldValue, newValue) -> {
if (newValue != null && !newValue.equals(oldValue)) {
setMarketPriceInItems();
String code = priceFeedService.currencyCodeProperty().get();
Optional<PriceFeedComboBoxItem> itemOptional = findPriceFeedComboBoxItem(code);
if (itemOptional.isPresent()) {
itemOptional.get().setDisplayString(newValue);
selectedPriceFeedComboBoxItemProperty.set(itemOptional.get());
} else {
if (CurrencyUtil.isCryptoCurrency(code)) {
CurrencyUtil.getCryptoCurrency(code).ifPresent(cryptoCurrency -> {
preferences.addCryptoCurrency(cryptoCurrency);
fillPriceFeedComboBoxItems();
});
} else {
CurrencyUtil.getFiatCurrency(code).ifPresent(fiatCurrency -> {
preferences.addFiatCurrency(fiatCurrency);
fillPriceFeedComboBoxItems();
});
}
}
if (selectedPriceFeedComboBoxItemProperty.get() != null)
selectedPriceFeedComboBoxItemProperty.get().setDisplayString(newValue);
}
});
marketPriceCurrencyCode.bind(priceFeedService.currencyCodeProperty());
priceFeedAllLoadedSubscription = EasyBind.subscribe(priceFeedService.updateCounterProperty(), updateCounter -> setMarketPriceInItems());
preferences.getTradeCurrenciesAsObservable().addListener((ListChangeListener<TradeCurrency>) c -> UserThread.runAfter(() -> {
fillPriceFeedComboBoxItems();
setMarketPriceInItems();
}, 100, TimeUnit.MILLISECONDS));
}
private Optional<PriceFeedComboBoxItem> findPriceFeedComboBoxItem(String currencyCode) {
return priceFeedComboBoxItems.stream()
.filter(item -> item.currencyCode.equals(currencyCode))
.findAny();
}
private void setMarketPriceInItems() {
priceFeedComboBoxItems.forEach(item -> {
String currencyCode = item.currencyCode;
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
String priceString;
if (marketPrice != null && marketPrice.isPriceAvailable()) {
priceString = formatter.formatMarketPrice(marketPrice.getPrice(), currencyCode);
item.setPriceAvailable(true);
item.setExternallyProvidedPrice(marketPrice.isExternallyProvidedPrice());
} else {
priceString = Res.get("shared.na");
item.setPriceAvailable(false);
}
item.setDisplayString(formatter.getCurrencyPair(currencyCode) + ": " + priceString);
final String code = item.currencyCode;
if (selectedPriceFeedComboBoxItemProperty.get() != null &&
selectedPriceFeedComboBoxItemProperty.get().currencyCode.equals(code)) {
isFiatCurrencyPriceFeedSelected.set(CurrencyUtil.isFiatCurrency(code) && CurrencyUtil.getFiatCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isCryptoCurrencyPriceFeedSelected.set(CurrencyUtil.isCryptoCurrency(code) && CurrencyUtil.getCryptoCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isExternallyProvidedPrice.set(item.isExternallyProvidedPrice());
isPriceAvailable.set(item.isPriceAvailable());
marketPriceUpdated.set(marketPriceUpdated.get() + 1);
}
});
}
public ObjectProperty<PriceFeedComboBoxItem> getSelectedPriceFeedComboBoxItemProperty() {
return selectedPriceFeedComboBoxItemProperty;
}
public BooleanProperty getIsFiatCurrencyPriceFeedSelected() {
return isFiatCurrencyPriceFeedSelected;
}
public BooleanProperty getIsCryptoCurrencyPriceFeedSelected() {
return isCryptoCurrencyPriceFeedSelected;
}
public BooleanProperty getIsExternallyProvidedPrice() {
return isExternallyProvidedPrice;
}
public BooleanProperty getIsPriceAvailable() {
return isPriceAvailable;
}
public IntegerProperty getMarketPriceUpdated() {
return marketPriceUpdated;
}
}