mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Change comp request view
This commit is contained in:
parent
2d89453736
commit
526e81bb7c
@ -48,8 +48,7 @@ import bisq.core.btc.wallet.WalletService;
|
|||||||
import bisq.core.btc.wallet.WalletsManager;
|
import bisq.core.btc.wallet.WalletsManager;
|
||||||
import bisq.core.btc.wallet.WalletsSetup;
|
import bisq.core.btc.wallet.WalletsSetup;
|
||||||
import bisq.core.dao.DaoManager;
|
import bisq.core.dao.DaoManager;
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||||
import bisq.core.dao.vote.VotingManager;
|
|
||||||
import bisq.core.filter.FilterManager;
|
import bisq.core.filter.FilterManager;
|
||||||
import bisq.core.offer.OpenOfferManager;
|
import bisq.core.offer.OpenOfferManager;
|
||||||
import bisq.core.trade.TradeManager;
|
import bisq.core.trade.TradeManager;
|
||||||
@ -228,8 +227,7 @@ public class BisqApp extends Application {
|
|||||||
persistedDataHosts.add(injector.getInstance(FailedTradesManager.class));
|
persistedDataHosts.add(injector.getInstance(FailedTradesManager.class));
|
||||||
persistedDataHosts.add(injector.getInstance(DisputeManager.class));
|
persistedDataHosts.add(injector.getInstance(DisputeManager.class));
|
||||||
persistedDataHosts.add(injector.getInstance(P2PService.class));
|
persistedDataHosts.add(injector.getInstance(P2PService.class));
|
||||||
persistedDataHosts.add(injector.getInstance(VotingManager.class));
|
persistedDataHosts.add(injector.getInstance(ProposalCollectionsManager.class));
|
||||||
persistedDataHosts.add(injector.getInstance(CompensationRequestManager.class));
|
|
||||||
|
|
||||||
// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
|
// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
|
||||||
persistedDataHosts.forEach(e -> {
|
persistedDataHosts.forEach(e -> {
|
||||||
|
@ -25,7 +25,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
|||||||
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
@ -68,9 +67,9 @@ public class FundsTextField extends InfoTextField {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AnchorPane.setRightAnchor(copyIcon, 30.0);
|
setRightAnchor(copyIcon, 30.0);
|
||||||
AnchorPane.setRightAnchor(infoIcon, 62.0);
|
setRightAnchor(infoIcon, 62.0);
|
||||||
AnchorPane.setRightAnchor(textField, 55.0);
|
setRightAnchor(textField, 55.0);
|
||||||
|
|
||||||
getChildren().add(copyIcon);
|
getChildren().add(copyIcon);
|
||||||
}
|
}
|
||||||
|
99
src/main/java/bisq/desktop/components/MenuItem.java
Normal file
99
src/main/java/bisq/desktop/components/MenuItem.java
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.components;
|
||||||
|
|
||||||
|
import bisq.desktop.Navigation;
|
||||||
|
import bisq.desktop.common.view.View;
|
||||||
|
import bisq.desktop.main.MainView;
|
||||||
|
import bisq.desktop.main.dao.DaoView;
|
||||||
|
import bisq.desktop.main.dao.proposal.ProposalView;
|
||||||
|
import bisq.desktop.util.Colors;
|
||||||
|
|
||||||
|
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||||
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
public class MenuItem extends AutoTooltipToggleButton {
|
||||||
|
|
||||||
|
private final ChangeListener<Boolean> selectedPropertyChangeListener;
|
||||||
|
private final ChangeListener<Boolean> disablePropertyChangeListener;
|
||||||
|
private final Navigation navigation;
|
||||||
|
private final Class<? extends View> viewClass;
|
||||||
|
|
||||||
|
public MenuItem(Navigation navigation, ToggleGroup toggleGroup, String title, Class<? extends View> viewClass, AwesomeIcon awesomeIcon) {
|
||||||
|
this.navigation = navigation;
|
||||||
|
this.viewClass = viewClass;
|
||||||
|
|
||||||
|
setToggleGroup(toggleGroup);
|
||||||
|
setText(title);
|
||||||
|
setId("account-settings-item-background-active");
|
||||||
|
setPrefHeight(40);
|
||||||
|
setPrefWidth(240);
|
||||||
|
setAlignment(Pos.CENTER_LEFT);
|
||||||
|
|
||||||
|
Label icon = new Label();
|
||||||
|
AwesomeDude.setIcon(icon, awesomeIcon);
|
||||||
|
icon.setTextFill(Paint.valueOf("#333"));
|
||||||
|
icon.setPadding(new Insets(0, 5, 0, 0));
|
||||||
|
icon.setAlignment(Pos.CENTER);
|
||||||
|
icon.setMinWidth(25);
|
||||||
|
icon.setMaxWidth(25);
|
||||||
|
setGraphic(icon);
|
||||||
|
|
||||||
|
selectedPropertyChangeListener = (ov, oldValue, newValue) -> {
|
||||||
|
if (newValue) {
|
||||||
|
setId("account-settings-item-background-selected");
|
||||||
|
icon.setTextFill(Colors.BLUE);
|
||||||
|
} else {
|
||||||
|
setId("account-settings-item-background-active");
|
||||||
|
icon.setTextFill(Paint.valueOf("#333"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
disablePropertyChangeListener = (ov, oldValue, newValue) -> {
|
||||||
|
if (newValue) {
|
||||||
|
setId("account-settings-item-background-disabled");
|
||||||
|
icon.setTextFill(Paint.valueOf("#ccc"));
|
||||||
|
} else {
|
||||||
|
setId("account-settings-item-background-active");
|
||||||
|
icon.setTextFill(Paint.valueOf("#333"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activate() {
|
||||||
|
//noinspection unchecked
|
||||||
|
setOnAction((event) -> navigation.navigateTo(MainView.class, DaoView.class, ProposalView.class, viewClass));
|
||||||
|
selectedProperty().addListener(selectedPropertyChangeListener);
|
||||||
|
disableProperty().addListener(disablePropertyChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deactivate() {
|
||||||
|
setOnAction(null);
|
||||||
|
selectedProperty().removeListener(selectedPropertyChangeListener);
|
||||||
|
disableProperty().removeListener(disablePropertyChangeListener);
|
||||||
|
}
|
||||||
|
}
|
@ -100,14 +100,14 @@ public class SeparatedPhaseBars extends HBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addLabels() {
|
private void addLabels() {
|
||||||
Label titleLabel = new Label(Res.get("dao.compensation.active.phase"));
|
Label titleLabel = new Label(Res.get("dao.proposal.active.phase"));
|
||||||
|
|
||||||
Label startLabel = new Label(Res.get("dao.compensation.active.startBlock"));
|
Label startLabel = new Label(Res.get("dao.proposal.active.startBlock"));
|
||||||
AnchorPane startLabelPane = new AnchorPane();
|
AnchorPane startLabelPane = new AnchorPane();
|
||||||
AnchorPane.setLeftAnchor(startLabel, 0d);
|
AnchorPane.setLeftAnchor(startLabel, 0d);
|
||||||
startLabelPane.getChildren().add(startLabel);
|
startLabelPane.getChildren().add(startLabel);
|
||||||
|
|
||||||
Label endLabel = new Label(Res.get("dao.compensation.active.endBlock"));
|
Label endLabel = new Label(Res.get("dao.proposal.active.endBlock"));
|
||||||
AnchorPane endLabelPane = new AnchorPane();
|
AnchorPane endLabelPane = new AnchorPane();
|
||||||
AnchorPane.setRightAnchor(endLabel, 0d);
|
AnchorPane.setRightAnchor(endLabel, 0d);
|
||||||
endLabelPane.getChildren().add(endLabel);
|
endLabelPane.getChildren().add(endLabel);
|
||||||
|
@ -25,7 +25,7 @@ import bisq.desktop.common.view.FxmlView;
|
|||||||
import bisq.desktop.common.view.View;
|
import bisq.desktop.common.view.View;
|
||||||
import bisq.desktop.common.view.ViewLoader;
|
import bisq.desktop.common.view.ViewLoader;
|
||||||
import bisq.desktop.main.MainView;
|
import bisq.desktop.main.MainView;
|
||||||
import bisq.desktop.main.dao.compensation.CompensationView;
|
import bisq.desktop.main.dao.proposal.ProposalView;
|
||||||
import bisq.desktop.main.dao.voting.VotingView;
|
import bisq.desktop.main.dao.voting.VotingView;
|
||||||
import bisq.desktop.main.dao.wallet.BsqWalletView;
|
import bisq.desktop.main.dao.wallet.BsqWalletView;
|
||||||
import bisq.desktop.main.dao.wallet.dashboard.BsqDashboardView;
|
import bisq.desktop.main.dao.wallet.dashboard.BsqDashboardView;
|
||||||
@ -67,7 +67,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
compensationTab = new Tab(Res.get("dao.tab.compensation"));
|
compensationTab = new Tab(Res.get("dao.tab.proposals"));
|
||||||
votingTab = new Tab(Res.get("dao.tab.voting"));
|
votingTab = new Tab(Res.get("dao.tab.voting"));
|
||||||
compensationTab.setClosable(false);
|
compensationTab.setClosable(false);
|
||||||
votingTab.setClosable(false);
|
votingTab.setClosable(false);
|
||||||
@ -101,7 +101,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
|||||||
navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class, selectedViewClass);
|
navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class, selectedViewClass);
|
||||||
} else if (newValue == compensationTab) {
|
} else if (newValue == compensationTab) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
navigation.navigateTo(MainView.class, DaoView.class, CompensationView.class);
|
navigation.navigateTo(MainView.class, DaoView.class, ProposalView.class);
|
||||||
} else if (newValue == votingTab) {
|
} else if (newValue == votingTab) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class);
|
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class);
|
||||||
@ -121,7 +121,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
|||||||
navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class);
|
navigation.navigateTo(MainView.class, DaoView.class, BsqWalletView.class);
|
||||||
else if (selectedItem == compensationTab)
|
else if (selectedItem == compensationTab)
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
navigation.navigateTo(MainView.class, DaoView.class, CompensationView.class);
|
navigation.navigateTo(MainView.class, DaoView.class, ProposalView.class);
|
||||||
else if (selectedItem == votingTab)
|
else if (selectedItem == votingTab)
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class);
|
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class);
|
||||||
@ -139,7 +139,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
|||||||
if (view instanceof BsqWalletView) {
|
if (view instanceof BsqWalletView) {
|
||||||
selectedTab = bsqWalletTab;
|
selectedTab = bsqWalletTab;
|
||||||
bsqWalletView = (BsqWalletView) view;
|
bsqWalletView = (BsqWalletView) view;
|
||||||
} else if (view instanceof CompensationView) {
|
} else if (view instanceof ProposalView) {
|
||||||
selectedTab = compensationTab;
|
selectedTab = compensationTab;
|
||||||
} else if (view instanceof VotingView) {
|
} else if (view instanceof VotingView) {
|
||||||
selectedTab = votingTab;
|
selectedTab = votingTab;
|
||||||
|
@ -1,349 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation;
|
|
||||||
|
|
||||||
import bisq.desktop.components.AutoTooltipLabel;
|
|
||||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
|
||||||
import bisq.desktop.components.InputTextField;
|
|
||||||
import bisq.desktop.components.TableGroupHeadline;
|
|
||||||
import bisq.desktop.components.TxIdTextField;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.GUIUtil;
|
|
||||||
import bisq.desktop.util.Layout;
|
|
||||||
import bisq.desktop.util.validation.BsqAddressValidator;
|
|
||||||
import bisq.desktop.util.validation.BsqValidator;
|
|
||||||
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestPayload;
|
|
||||||
import bisq.core.dao.request.compensation.consensus.Restrictions;
|
|
||||||
import bisq.core.provider.fee.FeeService;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.control.SplitPane;
|
|
||||||
import javafx.scene.control.TableCell;
|
|
||||||
import javafx.scene.control.TableColumn;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.control.TextArea;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.Priority;
|
|
||||||
|
|
||||||
import javafx.geometry.HPos;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Orientation;
|
|
||||||
|
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
|
||||||
|
|
||||||
import javafx.util.Callback;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.*;
|
|
||||||
|
|
||||||
public class CompensationRequestDisplay {
|
|
||||||
private final GridPane gridPane;
|
|
||||||
private BsqFormatter bsqFormatter;
|
|
||||||
private BsqWalletService bsqWalletService;
|
|
||||||
public InputTextField uidTextField, nameTextField, titleTextField, linkInputTextField,
|
|
||||||
requestedBsqTextField, bsqAddressTextField;
|
|
||||||
private int gridRow = 0;
|
|
||||||
public TextArea descriptionTextArea;
|
|
||||||
private HyperlinkWithIcon linkHyperlinkWithIcon;
|
|
||||||
public TxIdTextField txIdTextField;
|
|
||||||
private FeeService feeService;
|
|
||||||
|
|
||||||
public CompensationRequestDisplay(GridPane gridPane, BsqFormatter bsqFormatter, BsqWalletService bsqWalletService, @Nullable FeeService feeService) {
|
|
||||||
this.gridPane = gridPane;
|
|
||||||
this.bsqFormatter = bsqFormatter;
|
|
||||||
this.bsqWalletService = bsqWalletService;
|
|
||||||
this.feeService = feeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createAllFields(String title, double top) {
|
|
||||||
addTitledGroupBg(gridPane, gridRow, 8, title, top);
|
|
||||||
uidTextField = addLabelInputTextField(gridPane, gridRow, Res.getWithCol("shared.id"), top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE).second;
|
|
||||||
uidTextField.setEditable(false);
|
|
||||||
nameTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.compensation.display.name")).second;
|
|
||||||
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.compensation.display.title")).second;
|
|
||||||
descriptionTextArea = addLabelTextArea(gridPane, ++gridRow, Res.get("dao.compensation.display.description"), Res.get("dao.compensation.display.description.prompt")).second;
|
|
||||||
linkInputTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.compensation.display.link")).second;
|
|
||||||
linkHyperlinkWithIcon = addLabelHyperlinkWithIcon(gridPane, gridRow, Res.get("dao.compensation.display.link"), "", "").second;
|
|
||||||
linkHyperlinkWithIcon.setVisible(false);
|
|
||||||
linkHyperlinkWithIcon.setManaged(false);
|
|
||||||
linkInputTextField.setPromptText(Res.get("dao.compensation.display.link.prompt"));
|
|
||||||
requestedBsqTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.compensation.display.requestedBsq")).second;
|
|
||||||
|
|
||||||
if (feeService != null) {
|
|
||||||
BsqValidator bsqValidator = new BsqValidator(bsqFormatter);
|
|
||||||
//TODO should we use the BSQ or a BTC validator? Technically it is BTC at that stage...
|
|
||||||
//bsqValidator.setMinValue(feeService.getCreateCompensationRequestFee());
|
|
||||||
bsqValidator.setMinValue(Restrictions.getMinCompensationRequestAmount());
|
|
||||||
requestedBsqTextField.setValidator(bsqValidator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO validator, addressTF
|
|
||||||
bsqAddressTextField = addLabelInputTextField(gridPane, ++gridRow,
|
|
||||||
Res.get("dao.compensation.display.bsqAddress")).second;
|
|
||||||
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
|
|
||||||
bsqAddressTextField.setValidator(new BsqAddressValidator(bsqFormatter));
|
|
||||||
|
|
||||||
txIdTextField = addLabelTxIdTextField(gridPane, ++gridRow,
|
|
||||||
Res.get("dao.compensation.display.txId"), "").second;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillWithData(CompensationRequestPayload data) {
|
|
||||||
uidTextField.setText(data.getUid());
|
|
||||||
nameTextField.setText(data.getName());
|
|
||||||
titleTextField.setText(data.getTitle());
|
|
||||||
descriptionTextArea.setText(data.getDescription());
|
|
||||||
linkInputTextField.setVisible(false);
|
|
||||||
linkInputTextField.setManaged(false);
|
|
||||||
linkHyperlinkWithIcon.setVisible(true);
|
|
||||||
linkHyperlinkWithIcon.setManaged(true);
|
|
||||||
linkHyperlinkWithIcon.setText(data.getLink());
|
|
||||||
linkHyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(data.getLink()));
|
|
||||||
requestedBsqTextField.setText(bsqFormatter.formatCoinWithCode(data.getRequestedBsq()));
|
|
||||||
bsqAddressTextField.setText(data.getBsqAddress());
|
|
||||||
txIdTextField.setup(data.getTxId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearForm() {
|
|
||||||
uidTextField.clear();
|
|
||||||
nameTextField.clear();
|
|
||||||
titleTextField.clear();
|
|
||||||
descriptionTextArea.clear();
|
|
||||||
linkInputTextField.clear();
|
|
||||||
linkHyperlinkWithIcon.clear();
|
|
||||||
requestedBsqTextField.clear();
|
|
||||||
bsqAddressTextField.clear();
|
|
||||||
txIdTextField.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillWithMock() {
|
|
||||||
uidTextField.setText(UUID.randomUUID().toString());
|
|
||||||
nameTextField.setText("Manfred Karrer");
|
|
||||||
titleTextField.setText("Development work November 2017");
|
|
||||||
descriptionTextArea.setText("Development work");
|
|
||||||
linkInputTextField.setText("https://github.com/bisq-network/compensation/issues/12");
|
|
||||||
requestedBsqTextField.setText("14000");
|
|
||||||
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAllFieldsEditable(boolean isEditable) {
|
|
||||||
nameTextField.setEditable(isEditable);
|
|
||||||
titleTextField.setEditable(isEditable);
|
|
||||||
descriptionTextArea.setEditable(isEditable);
|
|
||||||
linkInputTextField.setEditable(isEditable);
|
|
||||||
requestedBsqTextField.setEditable(isEditable);
|
|
||||||
bsqAddressTextField.setEditable(isEditable);
|
|
||||||
|
|
||||||
linkInputTextField.setVisible(true);
|
|
||||||
linkInputTextField.setManaged(true);
|
|
||||||
linkHyperlinkWithIcon.setVisible(false);
|
|
||||||
linkHyperlinkWithIcon.setManaged(false);
|
|
||||||
linkHyperlinkWithIcon.setOnAction(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAllFields() {
|
|
||||||
gridPane.getChildren().clear();
|
|
||||||
gridRow = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int incrementAndGetGridRow() {
|
|
||||||
return ++gridRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GridPane createCompensationList(TableView<CompensationRequestListItem> tableView, String headerString) {
|
|
||||||
GridPane compensationList = new GridPane();
|
|
||||||
|
|
||||||
TableGroupHeadline header = new TableGroupHeadline(headerString);
|
|
||||||
GridPane.setMargin(header, new Insets(10, 0, 0, 0));
|
|
||||||
GridPane.setRowIndex(header, 0);
|
|
||||||
compensationList.getChildren().add(header);
|
|
||||||
header.setMinHeight(20);
|
|
||||||
header.setMaxHeight(20);
|
|
||||||
|
|
||||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
|
||||||
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
|
||||||
tableView.setMinHeight(90);
|
|
||||||
GridPane.setRowIndex(tableView, 1);
|
|
||||||
GridPane.setColumnSpan(tableView, 1);
|
|
||||||
GridPane.setMargin(tableView, new Insets(5, 10, -10, 10));
|
|
||||||
GridPane.setVgrow(tableView, Priority.ALWAYS);
|
|
||||||
GridPane.setHgrow(tableView, Priority.ALWAYS);
|
|
||||||
compensationList.getChildren().add(tableView);
|
|
||||||
|
|
||||||
createColumns(tableView);
|
|
||||||
|
|
||||||
return compensationList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScrollPane createCompensationRequestDisplay() {
|
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
|
||||||
scrollPane.setFitToWidth(true);
|
|
||||||
scrollPane.setFitToHeight(true);
|
|
||||||
scrollPane.setMinHeight(100);
|
|
||||||
|
|
||||||
AnchorPane bottomAnchorPane = new AnchorPane();
|
|
||||||
scrollPane.setContent(bottomAnchorPane);
|
|
||||||
|
|
||||||
gridPane.setHgap(5);
|
|
||||||
gridPane.setVgap(5);
|
|
||||||
ColumnConstraints columnConstraints1 = new ColumnConstraints();
|
|
||||||
columnConstraints1.setHalignment(HPos.RIGHT);
|
|
||||||
columnConstraints1.setHgrow(Priority.SOMETIMES);
|
|
||||||
columnConstraints1.setMinWidth(140);
|
|
||||||
ColumnConstraints columnConstraints2 = new ColumnConstraints();
|
|
||||||
columnConstraints2.setHgrow(Priority.ALWAYS);
|
|
||||||
columnConstraints2.setMinWidth(300);
|
|
||||||
|
|
||||||
gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
|
|
||||||
AnchorPane.setBottomAnchor(gridPane, 20d);
|
|
||||||
AnchorPane.setRightAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setLeftAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setTopAnchor(gridPane, -20d);
|
|
||||||
bottomAnchorPane.getChildren().add(gridPane);
|
|
||||||
|
|
||||||
return scrollPane;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SplitPane createCompensationRequestPane(TableView<CompensationRequestListItem> tableView, String headerString) {
|
|
||||||
SplitPane compensationRequestPane = new SplitPane();
|
|
||||||
compensationRequestPane.setOrientation(Orientation.VERTICAL);
|
|
||||||
compensationRequestPane.setDividerPositions(0.2, 0.7);
|
|
||||||
compensationRequestPane.setStyle("-fx-padding: 0; -fx-box-border: transparent;");
|
|
||||||
|
|
||||||
compensationRequestPane.getItems().add(createCompensationList(tableView, headerString));
|
|
||||||
compensationRequestPane.getItems().add(createCompensationRequestDisplay());
|
|
||||||
return compensationRequestPane;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createColumns(TableView<CompensationRequestListItem> tableView) {
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> dateColumn = new AutoTooltipTableColumn<CompensationRequestListItem, CompensationRequestListItem>(Res.get("shared.dateTime")) {
|
|
||||||
{
|
|
||||||
setMinWidth(190);
|
|
||||||
setMaxWidth(190);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
dateColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
|
||||||
dateColumn.setCellFactory(
|
|
||||||
new Callback<TableColumn<CompensationRequestListItem, CompensationRequestListItem>, TableCell<CompensationRequestListItem,
|
|
||||||
CompensationRequestListItem>>() {
|
|
||||||
@Override
|
|
||||||
public TableCell<CompensationRequestListItem, CompensationRequestListItem> call(
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> column) {
|
|
||||||
return new TableCell<CompensationRequestListItem, CompensationRequestListItem>() {
|
|
||||||
@Override
|
|
||||||
public void updateItem(final CompensationRequestListItem item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
if (item != null)
|
|
||||||
setText(bsqFormatter.formatDateTime(item.getCompensationRequest().getPayload().getCreationDate()));
|
|
||||||
else
|
|
||||||
setText("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dateColumn.setComparator((o1, o2) -> o1.getCompensationRequest().getPayload().getCreationDate().compareTo(o2.getCompensationRequest().getPayload().getCreationDate()));
|
|
||||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
|
||||||
tableView.getColumns().add(dateColumn);
|
|
||||||
tableView.getSortOrder().add(dateColumn);
|
|
||||||
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.name"));
|
|
||||||
nameColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
|
||||||
nameColumn.setCellFactory(
|
|
||||||
new Callback<TableColumn<CompensationRequestListItem, CompensationRequestListItem>, TableCell<CompensationRequestListItem,
|
|
||||||
CompensationRequestListItem>>() {
|
|
||||||
@Override
|
|
||||||
public TableCell<CompensationRequestListItem, CompensationRequestListItem> call(
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> column) {
|
|
||||||
return new TableCell<CompensationRequestListItem, CompensationRequestListItem>() {
|
|
||||||
@Override
|
|
||||||
public void updateItem(final CompensationRequestListItem item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
if (item != null)
|
|
||||||
setText(item.getCompensationRequest().getPayload().getName());
|
|
||||||
else
|
|
||||||
setText("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
nameColumn.setComparator((o1, o2) -> o1.getCompensationRequest().getPayload().getName().compareTo(o2.getCompensationRequest().getPayload().getName()));
|
|
||||||
tableView.getColumns().add(nameColumn);
|
|
||||||
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id"));
|
|
||||||
uidColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
|
||||||
uidColumn.setCellFactory(
|
|
||||||
new Callback<TableColumn<CompensationRequestListItem, CompensationRequestListItem>, TableCell<CompensationRequestListItem,
|
|
||||||
CompensationRequestListItem>>() {
|
|
||||||
@Override
|
|
||||||
public TableCell<CompensationRequestListItem, CompensationRequestListItem> call(
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> column) {
|
|
||||||
return new TableCell<CompensationRequestListItem, CompensationRequestListItem>() {
|
|
||||||
@Override
|
|
||||||
public void updateItem(final CompensationRequestListItem item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
if (item != null)
|
|
||||||
setText(item.getCompensationRequest().getPayload().getUid());
|
|
||||||
else
|
|
||||||
setText("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
uidColumn.setComparator((o1, o2) -> o1.getCompensationRequest().getPayload().getUid().compareTo(o2.getCompensationRequest().getPayload().getUid()));
|
|
||||||
tableView.getColumns().add(uidColumn);
|
|
||||||
|
|
||||||
TableColumn<CompensationRequestListItem, CompensationRequestListItem> confidenceColumn = new TableColumn<>(Res.get("shared.confirmations"));
|
|
||||||
confidenceColumn.setMinWidth(130);
|
|
||||||
confidenceColumn.setMaxWidth(confidenceColumn.getMinWidth());
|
|
||||||
|
|
||||||
confidenceColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
|
||||||
|
|
||||||
confidenceColumn.setCellFactory(new Callback<TableColumn<CompensationRequestListItem, CompensationRequestListItem>,
|
|
||||||
TableCell<CompensationRequestListItem, CompensationRequestListItem>>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TableCell<CompensationRequestListItem, CompensationRequestListItem> call(TableColumn<CompensationRequestListItem,
|
|
||||||
CompensationRequestListItem> column) {
|
|
||||||
return new TableCell<CompensationRequestListItem, CompensationRequestListItem>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateItem(final CompensationRequestListItem item, boolean empty) {
|
|
||||||
super.updateItem(item, empty);
|
|
||||||
|
|
||||||
if (item != null && !empty) {
|
|
||||||
setGraphic(item.getTxConfidenceIndicator());
|
|
||||||
} else {
|
|
||||||
setGraphic(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
confidenceColumn.setComparator((o1, o2) -> o1.getConfirmations().compareTo(o2.getConfirmations()));
|
|
||||||
tableView.getColumns().add(confidenceColumn);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation;
|
|
||||||
|
|
||||||
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
|
|
||||||
import bisq.core.btc.listeners.TxConfidenceListener;
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChain;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
|
||||||
import bisq.core.dao.blockchain.vo.Tx;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
|
||||||
|
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.ToString;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@ToString
|
|
||||||
@Slf4j
|
|
||||||
@EqualsAndHashCode
|
|
||||||
public class CompensationRequestListItem implements BsqBlockChainListener {
|
|
||||||
@Getter
|
|
||||||
private final CompensationRequest compensationRequest;
|
|
||||||
private final BsqWalletService bsqWalletService;
|
|
||||||
private final BsqBlockChain bsqBlockChain;
|
|
||||||
private final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
|
|
||||||
private final BsqFormatter bsqFormatter;
|
|
||||||
private final ChangeListener<Number> chainHeightListener;
|
|
||||||
@Getter
|
|
||||||
private TxConfidenceIndicator txConfidenceIndicator;
|
|
||||||
@Getter
|
|
||||||
private Integer confirmations = 0;
|
|
||||||
|
|
||||||
private TxConfidenceListener txConfidenceListener;
|
|
||||||
private Tooltip tooltip = new Tooltip(Res.get("confidence.unknown"));
|
|
||||||
private Transaction walletTransaction;
|
|
||||||
|
|
||||||
public CompensationRequestListItem(CompensationRequest compensationRequest,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
BsqBlockChain bsqBlockChain,
|
|
||||||
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
|
||||||
BsqFormatter bsqFormatter) {
|
|
||||||
this.compensationRequest = compensationRequest;
|
|
||||||
this.bsqWalletService = bsqWalletService;
|
|
||||||
this.bsqBlockChain = bsqBlockChain;
|
|
||||||
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
|
|
||||||
this.bsqFormatter = bsqFormatter;
|
|
||||||
|
|
||||||
|
|
||||||
txConfidenceIndicator = new TxConfidenceIndicator();
|
|
||||||
txConfidenceIndicator.setId("funds-confidence");
|
|
||||||
|
|
||||||
txConfidenceIndicator.setProgress(-1);
|
|
||||||
txConfidenceIndicator.setPrefSize(24, 24);
|
|
||||||
txConfidenceIndicator.setTooltip(tooltip);
|
|
||||||
|
|
||||||
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
|
|
||||||
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
|
|
||||||
setupConfidence();
|
|
||||||
|
|
||||||
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBsqBlockChainChanged() {
|
|
||||||
setupConfidence();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupConfidence() {
|
|
||||||
final Tx tx = bsqBlockChain.getTxMap().get(compensationRequest.getPayload().getTxId());
|
|
||||||
if (tx != null) {
|
|
||||||
final String txId = tx.getId();
|
|
||||||
|
|
||||||
// We cache the walletTransaction once found
|
|
||||||
if (walletTransaction == null) {
|
|
||||||
final Optional<Transaction> transactionOptional = bsqWalletService.isWalletTransaction(txId);
|
|
||||||
if (transactionOptional.isPresent())
|
|
||||||
walletTransaction = transactionOptional.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (walletTransaction != null) {
|
|
||||||
// It is our tx so we get confidence updates
|
|
||||||
if (txConfidenceListener == null) {
|
|
||||||
txConfidenceListener = new TxConfidenceListener(txId) {
|
|
||||||
@Override
|
|
||||||
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
|
||||||
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// tx from other users, we dont get confidence updates but as we have the bsq tx we can calculate it
|
|
||||||
// we get setupConfidence called at each new block from above listener so no need to register a new listener
|
|
||||||
int depth = bsqWalletService.getChainHeightProperty().get() - tx.getBlockHeight() + 1;
|
|
||||||
if (depth > 0)
|
|
||||||
updateConfidence(TransactionConfidence.ConfidenceType.BUILDING, depth, -1);
|
|
||||||
//log.error("name={}, id ={}, depth={}", compensationRequest.getPayload().getName(), compensationRequest.getPayload().getUid(), depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
final TransactionConfidence confidence = bsqWalletService.getConfidenceForTxId(txId);
|
|
||||||
if (confidence != null)
|
|
||||||
updateConfidence(confidence, confidence.getDepthInBlocks());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateConfidence(TransactionConfidence confidence, int depthInBlocks) {
|
|
||||||
if (confidence != null) {
|
|
||||||
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
|
||||||
confirmations = depthInBlocks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanup() {
|
|
||||||
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
|
|
||||||
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
|
|
||||||
if (txConfidenceListener != null)
|
|
||||||
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) {
|
|
||||||
switch (confidenceType) {
|
|
||||||
case UNKNOWN:
|
|
||||||
tooltip.setText(Res.get("confidence.unknown"));
|
|
||||||
txConfidenceIndicator.setProgress(0);
|
|
||||||
break;
|
|
||||||
case PENDING:
|
|
||||||
tooltip.setText(Res.get("confidence.seen", numBroadcastPeers > -1 ? numBroadcastPeers : Res.get("shared.na")));
|
|
||||||
txConfidenceIndicator.setProgress(-1.0);
|
|
||||||
break;
|
|
||||||
case BUILDING:
|
|
||||||
tooltip.setText(Res.get("confidence.confirmed", depthInBlocks));
|
|
||||||
txConfidenceIndicator.setProgress(Math.min(1, (double) depthInBlocks / 6.0));
|
|
||||||
break;
|
|
||||||
case DEAD:
|
|
||||||
tooltip.setText(Res.get("confidence.invalid"));
|
|
||||||
txConfidenceIndicator.setProgress(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
txConfidenceIndicator.setPrefSize(24, 24);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation;
|
|
||||||
|
|
||||||
import bisq.desktop.common.view.ActivatableView;
|
|
||||||
import bisq.desktop.common.view.FxmlView;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.Layout;
|
|
||||||
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChain;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import javafx.scene.control.SplitPane;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
|
|
||||||
import org.fxmisc.easybind.EasyBind;
|
|
||||||
import org.fxmisc.easybind.Subscription;
|
|
||||||
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ListChangeListener;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
import javafx.collections.transformation.FilteredList;
|
|
||||||
import javafx.collections.transformation.SortedList;
|
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@FxmlView
|
|
||||||
public abstract class CompensationRequestView extends ActivatableView<GridPane, Void> implements BsqBlockChainListener {
|
|
||||||
|
|
||||||
protected final CompensationRequestManager compensationRequestManger;
|
|
||||||
protected final BsqBlockChain bsqBlockChain;
|
|
||||||
protected final ObservableList<CompensationRequestListItem> observableList = FXCollections.observableArrayList();
|
|
||||||
protected TableView<CompensationRequestListItem> tableView;
|
|
||||||
protected final BsqWalletService bsqWalletService;
|
|
||||||
protected final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
|
|
||||||
protected final BsqFormatter bsqFormatter;
|
|
||||||
protected SortedList<CompensationRequestListItem> sortedList = new SortedList<>(observableList);
|
|
||||||
protected Subscription selectedCompensationRequestSubscription;
|
|
||||||
protected CompensationRequestDisplay compensationRequestDisplay;
|
|
||||||
protected int gridRow = 0;
|
|
||||||
protected GridPane detailsGridPane, gridPane;
|
|
||||||
protected SplitPane compensationRequestPane;
|
|
||||||
protected CompensationRequestListItem selectedCompensationRequest;
|
|
||||||
protected ChangeListener<Number> chainHeightChangeListener;
|
|
||||||
protected ListChangeListener<CompensationRequest> compensationRequestListChangeListener;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor, lifecycle
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected CompensationRequestView(CompensationRequestManager compensationRequestManger,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
BsqBlockChain bsqBlockChain,
|
|
||||||
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
|
||||||
BsqFormatter bsqFormatter) {
|
|
||||||
this.compensationRequestManger = compensationRequestManger;
|
|
||||||
this.bsqWalletService = bsqWalletService;
|
|
||||||
this.bsqBlockChain = bsqBlockChain;
|
|
||||||
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
|
|
||||||
this.bsqFormatter = bsqFormatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void activate() {
|
|
||||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
|
||||||
|
|
||||||
selectedCompensationRequestSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), this::onSelectCompensationRequest);
|
|
||||||
|
|
||||||
bsqWalletService.getChainHeightProperty().addListener(chainHeightChangeListener);
|
|
||||||
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
|
|
||||||
compensationRequestManger.getAllRequests().addListener(compensationRequestListChangeListener);
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deactivate() {
|
|
||||||
sortedList.comparatorProperty().unbind();
|
|
||||||
|
|
||||||
selectedCompensationRequestSubscription.unsubscribe();
|
|
||||||
|
|
||||||
bsqWalletService.getChainHeightProperty().removeListener(chainHeightChangeListener);
|
|
||||||
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
|
|
||||||
compensationRequestManger.getAllRequests().removeListener(compensationRequestListChangeListener);
|
|
||||||
|
|
||||||
observableList.forEach(CompensationRequestListItem::cleanup);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// API
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBsqBlockChainChanged() {
|
|
||||||
// Need delay otherwise we modify list while dispatching and cause a ConcurrentModificationException
|
|
||||||
UserThread.execute(this::updateList);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected void updateList();
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Protected
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
protected void doUpdateList(FilteredList<CompensationRequest> list) {
|
|
||||||
observableList.forEach(CompensationRequestListItem::cleanup);
|
|
||||||
|
|
||||||
observableList.setAll(list.stream()
|
|
||||||
.map(e -> new CompensationRequestListItem(e, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, bsqFormatter))
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
|
|
||||||
if (list.isEmpty() && compensationRequestDisplay != null)
|
|
||||||
compensationRequestDisplay.removeAllFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onSelectCompensationRequest(CompensationRequestListItem item) {
|
|
||||||
selectedCompensationRequest = item;
|
|
||||||
if (item != null) {
|
|
||||||
final CompensationRequest compensationRequest = item.getCompensationRequest();
|
|
||||||
compensationRequestDisplay.removeAllFields();
|
|
||||||
compensationRequestDisplay.createAllFields(Res.get("dao.compensation.selectedRequest"), Layout.GROUP_DISTANCE);
|
|
||||||
compensationRequestDisplay.setAllFieldsEditable(false);
|
|
||||||
compensationRequestDisplay.fillWithData(compensationRequest.getPayload());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
~ 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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<AnchorPane fx:id="root" fx:controller="bisq.desktop.main.dao.compensation.CompensationView"
|
|
||||||
prefHeight="660.0" prefWidth="1000.0"
|
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
|
||||||
|
|
||||||
<VBox fx:id="leftVBox" spacing="5" prefWidth="240" AnchorPane.bottomAnchor="20" AnchorPane.leftAnchor="15"
|
|
||||||
AnchorPane.topAnchor="20"/>
|
|
||||||
<AnchorPane fx:id="content" AnchorPane.bottomAnchor="10" AnchorPane.rightAnchor="25" AnchorPane.leftAnchor="290"
|
|
||||||
AnchorPane.topAnchor="30"/>
|
|
||||||
</AnchorPane>
|
|
||||||
|
|
@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation;
|
|
||||||
|
|
||||||
import bisq.desktop.Navigation;
|
|
||||||
import bisq.desktop.common.view.ActivatableViewAndModel;
|
|
||||||
import bisq.desktop.common.view.CachingViewLoader;
|
|
||||||
import bisq.desktop.common.view.FxmlView;
|
|
||||||
import bisq.desktop.common.view.View;
|
|
||||||
import bisq.desktop.common.view.ViewLoader;
|
|
||||||
import bisq.desktop.common.view.ViewPath;
|
|
||||||
import bisq.desktop.components.AutoTooltipToggleButton;
|
|
||||||
import bisq.desktop.main.MainView;
|
|
||||||
import bisq.desktop.main.dao.DaoView;
|
|
||||||
import bisq.desktop.main.dao.compensation.active.ActiveCompensationRequestView;
|
|
||||||
import bisq.desktop.main.dao.compensation.create.CreateCompensationRequestView;
|
|
||||||
import bisq.desktop.main.dao.compensation.past.PastCompensationRequestView;
|
|
||||||
import bisq.desktop.util.Colors;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.ToggleGroup;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.scene.paint.Paint;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.geometry.Pos;
|
|
||||||
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
@FxmlView
|
|
||||||
public class CompensationView extends ActivatableViewAndModel {
|
|
||||||
|
|
||||||
private final ViewLoader viewLoader;
|
|
||||||
private final Navigation navigation;
|
|
||||||
|
|
||||||
private MenuItem create, active, past;
|
|
||||||
private Navigation.Listener listener;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private VBox leftVBox;
|
|
||||||
@FXML
|
|
||||||
private AnchorPane content;
|
|
||||||
|
|
||||||
private Class<? extends View> selectedViewClass;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private CompensationView(CachingViewLoader viewLoader, Navigation navigation) {
|
|
||||||
this.viewLoader = viewLoader;
|
|
||||||
this.navigation = navigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
listener = viewPath -> {
|
|
||||||
if (viewPath.size() != 4 || viewPath.indexOf(CompensationView.class) != 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
selectedViewClass = viewPath.tip();
|
|
||||||
loadView(selectedViewClass);
|
|
||||||
};
|
|
||||||
|
|
||||||
ToggleGroup toggleGroup = new ToggleGroup();
|
|
||||||
create = new MenuItem(navigation, toggleGroup, Res.get("dao.compensation.menuItem.createRequest"), CreateCompensationRequestView.class, AwesomeIcon.EDIT);
|
|
||||||
active = new MenuItem(navigation, toggleGroup, Res.get("dao.compensation.menuItem.activeRequests"), ActiveCompensationRequestView.class, AwesomeIcon.ARROW_RIGHT);
|
|
||||||
past = new MenuItem(navigation, toggleGroup, Res.get("dao.compensation.menuItem.pastRequests"), PastCompensationRequestView.class, AwesomeIcon.LIST);
|
|
||||||
leftVBox.getChildren().addAll(create, active, past);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void activate() {
|
|
||||||
create.activate();
|
|
||||||
active.activate();
|
|
||||||
past.activate();
|
|
||||||
|
|
||||||
navigation.addListener(listener);
|
|
||||||
ViewPath viewPath = navigation.getCurrentPath();
|
|
||||||
if (viewPath.size() == 3 && viewPath.indexOf(CompensationView.class) == 2 ||
|
|
||||||
viewPath.size() == 2 && viewPath.indexOf(DaoView.class) == 1) {
|
|
||||||
if (selectedViewClass == null)
|
|
||||||
selectedViewClass = CreateCompensationRequestView.class;
|
|
||||||
|
|
||||||
loadView(selectedViewClass);
|
|
||||||
|
|
||||||
} else if (viewPath.size() == 4 && viewPath.indexOf(CompensationView.class) == 2) {
|
|
||||||
selectedViewClass = viewPath.get(3);
|
|
||||||
loadView(selectedViewClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deactivate() {
|
|
||||||
navigation.removeListener(listener);
|
|
||||||
|
|
||||||
create.deactivate();
|
|
||||||
active.deactivate();
|
|
||||||
past.deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadView(Class<? extends View> viewClass) {
|
|
||||||
View view = viewLoader.load(viewClass);
|
|
||||||
content.getChildren().setAll(view.getRoot());
|
|
||||||
|
|
||||||
if (view instanceof CreateCompensationRequestView) create.setSelected(true);
|
|
||||||
else if (view instanceof ActiveCompensationRequestView) active.setSelected(true);
|
|
||||||
else if (view instanceof PastCompensationRequestView) past.setSelected(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends View> getSelectedViewClass() {
|
|
||||||
return selectedViewClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MenuItem extends AutoTooltipToggleButton {
|
|
||||||
|
|
||||||
private final ChangeListener<Boolean> selectedPropertyChangeListener;
|
|
||||||
private final ChangeListener<Boolean> disablePropertyChangeListener;
|
|
||||||
private final Navigation navigation;
|
|
||||||
private final Class<? extends View> viewClass;
|
|
||||||
|
|
||||||
MenuItem(Navigation navigation, ToggleGroup toggleGroup, String title, Class<? extends View> viewClass, AwesomeIcon awesomeIcon) {
|
|
||||||
this.navigation = navigation;
|
|
||||||
this.viewClass = viewClass;
|
|
||||||
|
|
||||||
setToggleGroup(toggleGroup);
|
|
||||||
setText(title);
|
|
||||||
setId("account-settings-item-background-active");
|
|
||||||
setPrefHeight(40);
|
|
||||||
setPrefWidth(240);
|
|
||||||
setAlignment(Pos.CENTER_LEFT);
|
|
||||||
|
|
||||||
Label icon = new Label();
|
|
||||||
AwesomeDude.setIcon(icon, awesomeIcon);
|
|
||||||
icon.setTextFill(Paint.valueOf("#333"));
|
|
||||||
icon.setPadding(new Insets(0, 5, 0, 0));
|
|
||||||
icon.setAlignment(Pos.CENTER);
|
|
||||||
icon.setMinWidth(25);
|
|
||||||
icon.setMaxWidth(25);
|
|
||||||
setGraphic(icon);
|
|
||||||
|
|
||||||
selectedPropertyChangeListener = (ov, oldValue, newValue) -> {
|
|
||||||
if (newValue) {
|
|
||||||
setId("account-settings-item-background-selected");
|
|
||||||
icon.setTextFill(Colors.BLUE);
|
|
||||||
} else {
|
|
||||||
setId("account-settings-item-background-active");
|
|
||||||
icon.setTextFill(Paint.valueOf("#333"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
disablePropertyChangeListener = (ov, oldValue, newValue) -> {
|
|
||||||
if (newValue) {
|
|
||||||
setId("account-settings-item-background-disabled");
|
|
||||||
icon.setTextFill(Paint.valueOf("#ccc"));
|
|
||||||
} else {
|
|
||||||
setId("account-settings-item-background-active");
|
|
||||||
icon.setTextFill(Paint.valueOf("#333"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void activate() {
|
|
||||||
//noinspection unchecked
|
|
||||||
setOnAction((event) -> navigation.navigateTo(MainView.class, DaoView.class, CompensationView.class, viewClass));
|
|
||||||
selectedProperty().addListener(selectedPropertyChangeListener);
|
|
||||||
disableProperty().addListener(disablePropertyChangeListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deactivate() {
|
|
||||||
setOnAction(null);
|
|
||||||
selectedProperty().removeListener(selectedPropertyChangeListener);
|
|
||||||
disableProperty().removeListener(disablePropertyChangeListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
~ 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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.compensation.active.ActiveCompensationRequestView"
|
|
||||||
AnchorPane.bottomAnchor="-20.0" AnchorPane.leftAnchor="-10.0"
|
|
||||||
AnchorPane.rightAnchor="-10.0" AnchorPane.topAnchor="-20.0"
|
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
|
||||||
</GridPane>
|
|
@ -1,279 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation.active;
|
|
||||||
|
|
||||||
import bisq.desktop.Navigation;
|
|
||||||
import bisq.desktop.common.view.FxmlView;
|
|
||||||
import bisq.desktop.components.SeparatedPhaseBars;
|
|
||||||
import bisq.desktop.main.MainView;
|
|
||||||
import bisq.desktop.main.dao.DaoView;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestDisplay;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestListItem;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestView;
|
|
||||||
import bisq.desktop.main.dao.voting.VotingView;
|
|
||||||
import bisq.desktop.main.dao.voting.vote.VoteView;
|
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.Layout;
|
|
||||||
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.DaoPeriodService;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChain;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
|
||||||
import bisq.core.provider.fee.FeeService;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
|
|
||||||
import org.fxmisc.easybind.EasyBind;
|
|
||||||
import org.fxmisc.easybind.Subscription;
|
|
||||||
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|
||||||
|
|
||||||
@FxmlView
|
|
||||||
public class ActiveCompensationRequestView extends CompensationRequestView implements BsqBlockChainListener {
|
|
||||||
|
|
||||||
private List<SeparatedPhaseBars.SeparatedPhaseBarsItem> phaseBarsItems;
|
|
||||||
private Button removeButton, voteButton;
|
|
||||||
private final Navigation navigation;
|
|
||||||
private final DaoPeriodService daoPeriodService;
|
|
||||||
private DaoPeriodService.Phase currentPhase;
|
|
||||||
private ChangeListener<DaoPeriodService.Phase> phaseChangeListener;
|
|
||||||
private Subscription phaseSubscription;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor, lifecycle
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ActiveCompensationRequestView(CompensationRequestManager compensationRequestManger,
|
|
||||||
DaoPeriodService daoPeriodService,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
BsqBlockChain bsqBlockChain,
|
|
||||||
FeeService feeService,
|
|
||||||
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
|
||||||
Navigation navigation,
|
|
||||||
BsqFormatter bsqFormatter) {
|
|
||||||
super(compensationRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, bsqFormatter);
|
|
||||||
this.daoPeriodService = daoPeriodService;
|
|
||||||
this.navigation = navigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
root.getStyleClass().add("compensation-root");
|
|
||||||
AnchorPane topAnchorPane = new AnchorPane();
|
|
||||||
root.getChildren().add(topAnchorPane);
|
|
||||||
|
|
||||||
gridPane = new GridPane();
|
|
||||||
gridPane.setHgap(5);
|
|
||||||
gridPane.setVgap(5);
|
|
||||||
AnchorPane.setBottomAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setRightAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setLeftAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setTopAnchor(gridPane, 10d);
|
|
||||||
topAnchorPane.getChildren().add(gridPane);
|
|
||||||
|
|
||||||
// Add phase info
|
|
||||||
addTitledGroupBg(gridPane, gridRow, 1, Res.get("dao.compensation.active.phase.header"));
|
|
||||||
SeparatedPhaseBars separatedPhaseBars = createSeparatedPhaseBars();
|
|
||||||
GridPane.setColumnSpan(separatedPhaseBars, 2);
|
|
||||||
GridPane.setColumnIndex(separatedPhaseBars, 0);
|
|
||||||
GridPane.setMargin(separatedPhaseBars, new Insets(Layout.FIRST_ROW_DISTANCE - 6, 0, 0, 0));
|
|
||||||
GridPane.setRowIndex(separatedPhaseBars, gridRow);
|
|
||||||
gridPane.getChildren().add(separatedPhaseBars);
|
|
||||||
|
|
||||||
/* final Tuple2<Label, TextField> tuple2 = addLabelTextField(gridPane, ++gridRow, Res.get("dao.compensation.active.cycle"));
|
|
||||||
final Label label = tuple2.first;
|
|
||||||
GridPane.setHalignment(label, HPos.RIGHT);
|
|
||||||
cycleTextField = tuple2.second;*/
|
|
||||||
|
|
||||||
// Add compensationrequest pane
|
|
||||||
tableView = new TableView<>();
|
|
||||||
detailsGridPane = new GridPane();
|
|
||||||
compensationRequestDisplay = new CompensationRequestDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
|
||||||
compensationRequestPane = compensationRequestDisplay.createCompensationRequestPane(tableView, Res.get("dao.compensation.active.header"));
|
|
||||||
GridPane.setColumnSpan(compensationRequestPane, 2);
|
|
||||||
GridPane.setMargin(compensationRequestPane, new Insets(Layout.FIRST_ROW_DISTANCE - 6, -10, 0, -10));
|
|
||||||
GridPane.setRowIndex(compensationRequestPane, ++gridRow);
|
|
||||||
gridPane.getChildren().add(compensationRequestPane);
|
|
||||||
|
|
||||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
|
||||||
tableView.setItems(sortedList);
|
|
||||||
|
|
||||||
chainHeightChangeListener = (observable, oldValue, newValue) -> {
|
|
||||||
onChainHeightChanged((int) newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
compensationRequestListChangeListener = c -> updateList();
|
|
||||||
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private SeparatedPhaseBars createSeparatedPhaseBars() {
|
|
||||||
phaseBarsItems = Arrays.asList(
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.COMPENSATION_REQUESTS, true),
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK1, false),
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.OPEN_FOR_VOTING, true),
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK2, false),
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.VOTE_CONFIRMATION, true),
|
|
||||||
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK3, false));
|
|
||||||
SeparatedPhaseBars separatedPhaseBars = new SeparatedPhaseBars(phaseBarsItems);
|
|
||||||
return separatedPhaseBars;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void activate() {
|
|
||||||
super.activate();
|
|
||||||
phaseSubscription = EasyBind.subscribe(daoPeriodService.getPhaseProperty(), phase -> {
|
|
||||||
if (!phase.equals(this.currentPhase)) {
|
|
||||||
this.currentPhase = phase;
|
|
||||||
onSelectCompensationRequest(selectedCompensationRequest);
|
|
||||||
}
|
|
||||||
phaseBarsItems.stream().forEach(item -> {
|
|
||||||
if (item.getPhase() == phase) {
|
|
||||||
item.setActive();
|
|
||||||
} else {
|
|
||||||
item.setInActive();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
daoPeriodService.getPhaseProperty().addListener(phaseChangeListener);
|
|
||||||
onChainHeightChanged(bsqWalletService.getChainHeightProperty().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deactivate() {
|
|
||||||
super.deactivate();
|
|
||||||
phaseSubscription.unsubscribe();
|
|
||||||
daoPeriodService.getPhaseProperty().removeListener(phaseChangeListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateList() {
|
|
||||||
doUpdateList(compensationRequestManger.getActiveRequests());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onChainHeightChanged(int height) {
|
|
||||||
phaseBarsItems.stream().forEach(item -> {
|
|
||||||
int startBlock = daoPeriodService.getAbsoluteStartBlockOfPhase(height, item.getPhase());
|
|
||||||
int endBlock = daoPeriodService.getAbsoluteEndBlockOfPhase(height, item.getPhase());
|
|
||||||
item.setStartAndEnd(startBlock, endBlock);
|
|
||||||
double progress = 0;
|
|
||||||
if (height >= startBlock && height <= endBlock) {
|
|
||||||
progress = (double) (height - startBlock + 1) / (double) item.getPhase().getDurationInBlocks();
|
|
||||||
} else if (height < startBlock) {
|
|
||||||
progress = 0;
|
|
||||||
} else if (height > endBlock) {
|
|
||||||
progress = 1;
|
|
||||||
}
|
|
||||||
item.getProgressProperty().set(progress);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onSelectCompensationRequest(CompensationRequestListItem item) {
|
|
||||||
super.onSelectCompensationRequest(item);
|
|
||||||
if (item != null) {
|
|
||||||
if (removeButton != null) {
|
|
||||||
removeButton.setManaged(false);
|
|
||||||
removeButton.setVisible(false);
|
|
||||||
removeButton = null;
|
|
||||||
}
|
|
||||||
if (voteButton != null) {
|
|
||||||
voteButton.setManaged(false);
|
|
||||||
voteButton.setVisible(false);
|
|
||||||
voteButton = null;
|
|
||||||
}
|
|
||||||
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPhaseChanged(DaoPeriodService.Phase phase) {
|
|
||||||
if (removeButton != null) {
|
|
||||||
removeButton.setManaged(false);
|
|
||||||
removeButton.setVisible(false);
|
|
||||||
removeButton = null;
|
|
||||||
}
|
|
||||||
if (selectedCompensationRequest != null && compensationRequestDisplay != null) {
|
|
||||||
final CompensationRequest compensationRequest = selectedCompensationRequest.getCompensationRequest();
|
|
||||||
switch (phase) {
|
|
||||||
case COMPENSATION_REQUESTS:
|
|
||||||
if (compensationRequestManger.isMine(compensationRequest)) {
|
|
||||||
if (removeButton == null) {
|
|
||||||
removeButton = addButtonAfterGroup(detailsGridPane, compensationRequestDisplay.incrementAndGetGridRow(), Res.get("dao.compensation.active.remove"));
|
|
||||||
removeButton.setOnAction(event -> {
|
|
||||||
if (compensationRequestManger.removeCompensationRequest(compensationRequest))
|
|
||||||
compensationRequestDisplay.removeAllFields();
|
|
||||||
else
|
|
||||||
new Popup<>().warning(Res.get("dao.compensation.active.remove.failed")).show();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
removeButton.setManaged(true);
|
|
||||||
removeButton.setVisible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BREAK1:
|
|
||||||
break;
|
|
||||||
case OPEN_FOR_VOTING:
|
|
||||||
if (voteButton == null) {
|
|
||||||
voteButton = addButtonAfterGroup(detailsGridPane, compensationRequestDisplay.incrementAndGetGridRow(), Res.get("dao.compensation.active.vote"));
|
|
||||||
voteButton.setOnAction(event -> {
|
|
||||||
//noinspection unchecked
|
|
||||||
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class, VoteView.class);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
voteButton.setManaged(true);
|
|
||||||
voteButton.setVisible(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BREAK2:
|
|
||||||
break;
|
|
||||||
case VOTE_CONFIRMATION:
|
|
||||||
//TODO
|
|
||||||
log.warn("VOTE_CONFIRMATION");
|
|
||||||
break;
|
|
||||||
case BREAK3:
|
|
||||||
break;
|
|
||||||
case UNDEFINED:
|
|
||||||
default:
|
|
||||||
log.warn("Undefined phase: " + daoPeriodService.getPhaseProperty());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
~ 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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.compensation.create.CreateCompensationRequestView"
|
|
||||||
hgap="5.0" vgap="5.0"
|
|
||||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
|
||||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-10.0"
|
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
|
||||||
|
|
||||||
<columnConstraints>
|
|
||||||
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="140.0"/>
|
|
||||||
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
|
||||||
</columnConstraints>
|
|
||||||
|
|
||||||
</GridPane>
|
|
@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation.create;
|
|
||||||
|
|
||||||
import bisq.desktop.common.view.ActivatableView;
|
|
||||||
import bisq.desktop.common.view.FxmlView;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestDisplay;
|
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
|
||||||
import bisq.desktop.util.BSFormatter;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.GUIUtil;
|
|
||||||
|
|
||||||
import bisq.core.btc.exceptions.TransactionVerificationException;
|
|
||||||
import bisq.core.btc.exceptions.WalletException;
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.btc.wallet.BtcWalletService;
|
|
||||||
import bisq.core.btc.wallet.InsufficientBsqException;
|
|
||||||
import bisq.core.btc.wallet.WalletsSetup;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationAmountException;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestPayload;
|
|
||||||
import bisq.core.provider.fee.FeeService;
|
|
||||||
import bisq.core.util.CoinUtil;
|
|
||||||
|
|
||||||
import bisq.network.p2p.NodeAddress;
|
|
||||||
import bisq.network.p2p.P2PService;
|
|
||||||
|
|
||||||
import bisq.common.crypto.KeyRing;
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
import org.bitcoinj.core.InsufficientMoneyException;
|
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
@FxmlView
|
|
||||||
public class CreateCompensationRequestView extends ActivatableView<GridPane, Void> {
|
|
||||||
|
|
||||||
private CompensationRequestDisplay compensationRequestDisplay;
|
|
||||||
private Button createButton;
|
|
||||||
|
|
||||||
private final BsqWalletService bsqWalletService;
|
|
||||||
private final BtcWalletService btcWalletService;
|
|
||||||
private final WalletsSetup walletsSetup;
|
|
||||||
private final P2PService p2PService;
|
|
||||||
private final FeeService feeService;
|
|
||||||
private final CompensationRequestManager compensationRequestManager;
|
|
||||||
private final BSFormatter btcFormatter;
|
|
||||||
private final BsqFormatter bsqFormatter;
|
|
||||||
private final PublicKey p2pStorageSignaturePubKey;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor, lifecycle
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private CreateCompensationRequestView(BsqWalletService bsqWalletService,
|
|
||||||
BtcWalletService btcWalletService,
|
|
||||||
WalletsSetup walletsSetup,
|
|
||||||
P2PService p2PService,
|
|
||||||
FeeService feeService,
|
|
||||||
CompensationRequestManager compensationRequestManager,
|
|
||||||
KeyRing keyRing,
|
|
||||||
BSFormatter btcFormatter,
|
|
||||||
BsqFormatter bsqFormatter) {
|
|
||||||
this.bsqWalletService = bsqWalletService;
|
|
||||||
this.btcWalletService = btcWalletService;
|
|
||||||
this.walletsSetup = walletsSetup;
|
|
||||||
this.p2PService = p2PService;
|
|
||||||
this.feeService = feeService;
|
|
||||||
this.compensationRequestManager = compensationRequestManager;
|
|
||||||
this.btcFormatter = btcFormatter;
|
|
||||||
this.bsqFormatter = bsqFormatter;
|
|
||||||
|
|
||||||
p2pStorageSignaturePubKey = keyRing.getPubKeyRing().getSignaturePubKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
compensationRequestDisplay = new CompensationRequestDisplay(root, bsqFormatter, bsqWalletService, feeService);
|
|
||||||
compensationRequestDisplay.createAllFields(Res.get("dao.compensation.create.createNew"), 0);
|
|
||||||
createButton = addButtonAfterGroup(root, compensationRequestDisplay.incrementAndGetGridRow(), Res.get("dao.compensation.create.create.button"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void activate() {
|
|
||||||
compensationRequestDisplay.fillWithMock();
|
|
||||||
|
|
||||||
createButton.setOnAction(event -> {
|
|
||||||
// TODO break up in methods
|
|
||||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
|
||||||
NodeAddress nodeAddress = p2PService.getAddress();
|
|
||||||
checkNotNull(nodeAddress, "nodeAddress must not be null");
|
|
||||||
CompensationRequestPayload compensationRequestPayload = new CompensationRequestPayload(
|
|
||||||
UUID.randomUUID().toString(),
|
|
||||||
compensationRequestDisplay.nameTextField.getText(),
|
|
||||||
compensationRequestDisplay.titleTextField.getText(),
|
|
||||||
compensationRequestDisplay.descriptionTextArea.getText(),
|
|
||||||
compensationRequestDisplay.linkInputTextField.getText(),
|
|
||||||
bsqFormatter.parseToCoin(compensationRequestDisplay.requestedBsqTextField.getText()),
|
|
||||||
compensationRequestDisplay.bsqAddressTextField.getText(),
|
|
||||||
nodeAddress,
|
|
||||||
p2pStorageSignaturePubKey,
|
|
||||||
new Date()
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
CompensationRequest compensationRequest = compensationRequestManager.prepareCompensationRequest(compensationRequestPayload);
|
|
||||||
Coin miningFee = compensationRequest.getTx().getFee();
|
|
||||||
int txSize = compensationRequest.getTx().bitcoinSerialize().length;
|
|
||||||
new Popup<>().headLine(Res.get("dao.compensation.create.confirm"))
|
|
||||||
.confirmation(Res.get("dao.compensation.create.confirm.info",
|
|
||||||
bsqFormatter.formatCoinWithCode(compensationRequest.getRequestedBsq()),
|
|
||||||
bsqFormatter.formatCoinWithCode(compensationRequest.getCompensationRequestFee()),
|
|
||||||
btcFormatter.formatCoinWithCode(miningFee),
|
|
||||||
CoinUtil.getFeePerByte(miningFee, txSize),
|
|
||||||
(txSize / 1000d)))
|
|
||||||
.actionButtonText(Res.get("shared.yes"))
|
|
||||||
.onAction(() -> {
|
|
||||||
compensationRequestManager.commitCompensationRequest(compensationRequest, new FutureCallback<Transaction>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable Transaction transaction) {
|
|
||||||
compensationRequestDisplay.clearForm();
|
|
||||||
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NotNull Throwable t) {
|
|
||||||
log.error(t.toString());
|
|
||||||
new Popup<>().warning(t.toString()).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.closeButtonText(Res.get("shared.cancel"))
|
|
||||||
.show();
|
|
||||||
} catch (InsufficientMoneyException e) {
|
|
||||||
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
|
|
||||||
new Popup<>().warning(Res.get("dao.compensation.create.missingFunds", formatter.formatCoinWithCode(e.missing))).show();
|
|
||||||
} catch (CompensationAmountException e) {
|
|
||||||
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount", bsqFormatter.formatCoinWithCode(e.required))).show();
|
|
||||||
} catch (TransactionVerificationException | WalletException e) {
|
|
||||||
log.error(e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
new Popup<>().warning(e.toString()).show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void deactivate() {
|
|
||||||
createButton.setOnAction(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
~ 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/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.GridPane?>
|
|
||||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.compensation.past.PastCompensationRequestView"
|
|
||||||
AnchorPane.bottomAnchor="-20.0" AnchorPane.leftAnchor="-10.0"
|
|
||||||
AnchorPane.rightAnchor="-10.0" AnchorPane.topAnchor="-20.0"
|
|
||||||
xmlns:fx="http://javafx.com/fxml">
|
|
||||||
</GridPane>
|
|
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.compensation.past;
|
|
||||||
|
|
||||||
import bisq.desktop.common.view.FxmlView;
|
|
||||||
import bisq.desktop.components.SeparatedPhaseBars;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestDisplay;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestView;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.DaoPeriodService;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChain;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
|
||||||
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@FxmlView
|
|
||||||
public class PastCompensationRequestView extends CompensationRequestView implements BsqBlockChainListener {
|
|
||||||
|
|
||||||
private List<SeparatedPhaseBars.SeparatedPhaseBarsItem> phaseBarsItems;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor, lifecycle
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PastCompensationRequestView(CompensationRequestManager compensationRequestManger,
|
|
||||||
DaoPeriodService daoPeriodService,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
BsqBlockChain bsqBlockChain,
|
|
||||||
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
|
||||||
BsqFormatter bsqFormatter) {
|
|
||||||
super(compensationRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, bsqFormatter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize() {
|
|
||||||
root.getStyleClass().add("compensation-root");
|
|
||||||
AnchorPane topAnchorPane = new AnchorPane();
|
|
||||||
root.getChildren().add(topAnchorPane);
|
|
||||||
|
|
||||||
gridPane = new GridPane();
|
|
||||||
gridPane.setHgap(5);
|
|
||||||
gridPane.setVgap(5);
|
|
||||||
AnchorPane.setBottomAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setRightAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setLeftAnchor(gridPane, 10d);
|
|
||||||
AnchorPane.setTopAnchor(gridPane, 0d);
|
|
||||||
topAnchorPane.getChildren().add(gridPane);
|
|
||||||
|
|
||||||
// Add compensationrequest pane
|
|
||||||
tableView = new TableView<>();
|
|
||||||
detailsGridPane = new GridPane();
|
|
||||||
compensationRequestDisplay = new CompensationRequestDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
|
||||||
compensationRequestPane = compensationRequestDisplay.createCompensationRequestPane(tableView, Res.get("dao.compensation.past.header"));
|
|
||||||
compensationRequestPane.setMinWidth(800);
|
|
||||||
GridPane.setColumnSpan(compensationRequestPane, 2);
|
|
||||||
GridPane.setColumnIndex(compensationRequestPane, 0);
|
|
||||||
GridPane.setMargin(compensationRequestPane, new Insets(0, -10, 0, -10));
|
|
||||||
GridPane.setRowIndex(compensationRequestPane, gridRow);
|
|
||||||
|
|
||||||
gridPane.getChildren().add(compensationRequestPane);
|
|
||||||
|
|
||||||
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
|
||||||
tableView.setItems(sortedList);
|
|
||||||
|
|
||||||
compensationRequestListChangeListener = c -> updateList();
|
|
||||||
chainHeightChangeListener = (observable, oldValue, newValue) -> {
|
|
||||||
updateList();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateList() {
|
|
||||||
doUpdateList(compensationRequestManger.getPastRequests());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal;
|
||||||
|
|
||||||
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.components.AutoTooltipLabel;
|
||||||
|
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||||
|
import bisq.desktop.components.TableGroupHeadline;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.DaoPeriodService;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChain;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
||||||
|
import bisq.core.dao.proposal.Proposal;
|
||||||
|
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||||
|
|
||||||
|
import bisq.common.UserThread;
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.control.TableCell;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
|
||||||
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.collections.transformation.SortedList;
|
||||||
|
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public abstract class BaseProposalView extends ActivatableView<GridPane, Void> implements BsqBlockChainListener {
|
||||||
|
|
||||||
|
protected final ProposalCollectionsManager proposalCollectionsManager;
|
||||||
|
protected final BsqBlockChain bsqBlockChain;
|
||||||
|
protected final ObservableList<ProposalListItem> proposalListItems = FXCollections.observableArrayList();
|
||||||
|
protected TableView<ProposalListItem> tableView;
|
||||||
|
protected final BsqWalletService bsqWalletService;
|
||||||
|
protected final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
|
||||||
|
protected final BsqFormatter bsqFormatter;
|
||||||
|
protected SortedList<ProposalListItem> sortedList = new SortedList<>(proposalListItems);
|
||||||
|
protected Subscription selectedProposalSubscription;
|
||||||
|
protected ProposalDisplay proposalDisplay;
|
||||||
|
protected int gridRow = 0;
|
||||||
|
protected GridPane detailsGridPane, gridPane;
|
||||||
|
protected ProposalListItem selectedProposalListItem;
|
||||||
|
protected ListChangeListener<Proposal> proposalListChangeListener;
|
||||||
|
protected ChangeListener<DaoPeriodService.Phase> phaseChangeListener;
|
||||||
|
protected final DaoPeriodService daoPeriodService;
|
||||||
|
protected DaoPeriodService.Phase currentPhase;
|
||||||
|
protected Subscription phaseSubscription;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor, lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected BaseProposalView(ProposalCollectionsManager proposalCollectionsManager,
|
||||||
|
BsqWalletService bsqWalletService,
|
||||||
|
BsqBlockChain bsqBlockChain,
|
||||||
|
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
||||||
|
DaoPeriodService daoPeriodService,
|
||||||
|
BsqFormatter bsqFormatter) {
|
||||||
|
this.proposalCollectionsManager = proposalCollectionsManager;
|
||||||
|
this.bsqWalletService = bsqWalletService;
|
||||||
|
this.bsqBlockChain = bsqBlockChain;
|
||||||
|
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
|
||||||
|
this.daoPeriodService = daoPeriodService;
|
||||||
|
this.bsqFormatter = bsqFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
root.getStyleClass().add("vote-root");
|
||||||
|
|
||||||
|
TableGroupHeadline headline = new TableGroupHeadline(Res.get("dao.proposal.active.header"));
|
||||||
|
GridPane.setRowIndex(headline, ++gridRow);
|
||||||
|
GridPane.setMargin(headline, new Insets(-10, -10, -10, -10));
|
||||||
|
root.getChildren().add(headline);
|
||||||
|
|
||||||
|
tableView = new TableView<>();
|
||||||
|
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
||||||
|
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
tableView.setMinHeight(90);
|
||||||
|
createColumns(tableView);
|
||||||
|
GridPane.setRowIndex(tableView, gridRow);
|
||||||
|
GridPane.setMargin(tableView, new Insets(10, -10, 5, -10));
|
||||||
|
root.getChildren().add(tableView);
|
||||||
|
|
||||||
|
detailsGridPane = new GridPane();
|
||||||
|
proposalDisplay = new ProposalDisplay(detailsGridPane, bsqFormatter, bsqWalletService, null);
|
||||||
|
|
||||||
|
final ScrollPane proposalDisplayView = proposalDisplay.getView();
|
||||||
|
GridPane.setMargin(proposalDisplayView, new Insets(10, -10, 0, -10));
|
||||||
|
GridPane.setRowIndex(proposalDisplayView, ++gridRow);
|
||||||
|
root.getChildren().add(proposalDisplayView);
|
||||||
|
|
||||||
|
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||||
|
tableView.setItems(sortedList);
|
||||||
|
|
||||||
|
proposalListChangeListener = c -> updateList();
|
||||||
|
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
phaseSubscription = EasyBind.subscribe(daoPeriodService.getPhaseProperty(), phase -> {
|
||||||
|
if (!phase.equals(this.currentPhase)) {
|
||||||
|
this.currentPhase = phase;
|
||||||
|
onSelectProposal(selectedProposalListItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
daoPeriodService.getPhaseProperty().addListener(phaseChangeListener);
|
||||||
|
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
|
||||||
|
|
||||||
|
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
|
||||||
|
|
||||||
|
selectedProposalSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), this::onSelectProposal);
|
||||||
|
|
||||||
|
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
|
||||||
|
proposalCollectionsManager.getAllProposals().addListener(proposalListChangeListener);
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
phaseSubscription.unsubscribe();
|
||||||
|
daoPeriodService.getPhaseProperty().removeListener(phaseChangeListener);
|
||||||
|
|
||||||
|
sortedList.comparatorProperty().unbind();
|
||||||
|
|
||||||
|
selectedProposalSubscription.unsubscribe();
|
||||||
|
|
||||||
|
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
|
||||||
|
proposalCollectionsManager.getAllProposals().removeListener(proposalListChangeListener);
|
||||||
|
|
||||||
|
proposalListItems.forEach(ProposalListItem::cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// API
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBsqBlockChainChanged() {
|
||||||
|
// Need delay otherwise we modify list while dispatching and cause a ConcurrentModificationException
|
||||||
|
UserThread.execute(this::updateList);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected void updateList();
|
||||||
|
|
||||||
|
protected void onPhaseChanged(DaoPeriodService.Phase phase) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Protected
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
protected void doUpdateList(FilteredList<Proposal> list) {
|
||||||
|
proposalListItems.forEach(ProposalListItem::cleanup);
|
||||||
|
|
||||||
|
proposalListItems.setAll(list.stream()
|
||||||
|
.map(e -> new ProposalListItem(e, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, bsqFormatter))
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
if (list.isEmpty() && proposalDisplay != null)
|
||||||
|
proposalDisplay.removeAllFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onSelectProposal(ProposalListItem item) {
|
||||||
|
selectedProposalListItem = item;
|
||||||
|
if (item != null) {
|
||||||
|
final Proposal proposal = item.getProposal();
|
||||||
|
proposalDisplay.removeAllFields();
|
||||||
|
proposalDisplay.createAllFields(Res.get("dao.proposal.selectedProposal"), 0, 0, item.getProposal().getType(), false);
|
||||||
|
proposalDisplay.setAllFieldsEditable(false);
|
||||||
|
proposalDisplay.fillWithData(proposal.getProposalPayload());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createColumns(TableView<ProposalListItem> tableView) {
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> dateColumn = new AutoTooltipTableColumn<ProposalListItem, ProposalListItem>(Res.get("shared.dateTime")) {
|
||||||
|
{
|
||||||
|
setMinWidth(190);
|
||||||
|
setMaxWidth(190);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dateColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
||||||
|
dateColumn.setCellFactory(
|
||||||
|
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
|
||||||
|
ProposalListItem>>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<ProposalListItem, ProposalListItem> call(
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> column) {
|
||||||
|
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null)
|
||||||
|
setText(bsqFormatter.formatDateTime(item.getProposal().getProposalPayload().getCreationDate()));
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dateColumn.setComparator(Comparator.comparing(o3 -> o3.getProposal().getProposalPayload().getCreationDate()));
|
||||||
|
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||||
|
tableView.getColumns().add(dateColumn);
|
||||||
|
tableView.getSortOrder().add(dateColumn);
|
||||||
|
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.name"));
|
||||||
|
nameColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
||||||
|
nameColumn.setCellFactory(
|
||||||
|
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
|
||||||
|
ProposalListItem>>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<ProposalListItem, ProposalListItem> call(
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> column) {
|
||||||
|
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null)
|
||||||
|
setText(item.getProposal().getProposalPayload().getName());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nameColumn.setComparator(Comparator.comparing(o2 -> o2.getProposal().getProposalPayload().getName()));
|
||||||
|
tableView.getColumns().add(nameColumn);
|
||||||
|
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id"));
|
||||||
|
uidColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
|
||||||
|
uidColumn.setCellFactory(
|
||||||
|
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
|
||||||
|
ProposalListItem>>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<ProposalListItem, ProposalListItem> call(
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> column) {
|
||||||
|
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null)
|
||||||
|
setText(item.getProposal().getProposalPayload().getUid());
|
||||||
|
else
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
uidColumn.setComparator(Comparator.comparing(o -> o.getProposal().getProposalPayload().getUid()));
|
||||||
|
tableView.getColumns().add(uidColumn);
|
||||||
|
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> confidenceColumn = new TableColumn<>(Res.get("shared.confirmations"));
|
||||||
|
confidenceColumn.setMinWidth(130);
|
||||||
|
confidenceColumn.setMaxWidth(confidenceColumn.getMinWidth());
|
||||||
|
|
||||||
|
confidenceColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||||
|
|
||||||
|
confidenceColumn.setCellFactory(new Callback<TableColumn<ProposalListItem, ProposalListItem>,
|
||||||
|
TableCell<ProposalListItem, ProposalListItem>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableCell<ProposalListItem, ProposalListItem> call(TableColumn<ProposalListItem,
|
||||||
|
ProposalListItem> column) {
|
||||||
|
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty) {
|
||||||
|
setGraphic(item.getTxConfidenceIndicator());
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
confidenceColumn.setComparator(Comparator.comparing(ProposalListItem::getConfirmations));
|
||||||
|
tableView.getColumns().add(confidenceColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal;
|
||||||
|
|
||||||
|
import bisq.desktop.components.HyperlinkWithIcon;
|
||||||
|
import bisq.desktop.components.InputTextField;
|
||||||
|
import bisq.desktop.components.TxIdTextField;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
import bisq.desktop.util.Layout;
|
||||||
|
import bisq.desktop.util.validation.BsqAddressValidator;
|
||||||
|
import bisq.desktop.util.validation.BsqValidator;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.proposal.ProposalPayload;
|
||||||
|
import bisq.core.dao.proposal.ProposalRestrictions;
|
||||||
|
import bisq.core.dao.proposal.ProposalType;
|
||||||
|
import bisq.core.dao.proposal.compensation.CompensationRequestPayload;
|
||||||
|
import bisq.core.dao.proposal.compensation.consensus.Restrictions;
|
||||||
|
import bisq.core.provider.fee.FeeService;
|
||||||
|
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.ColumnConstraints;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
|
|
||||||
|
import javafx.geometry.HPos;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.*;
|
||||||
|
|
||||||
|
// TODO add listener for descriptionTextArea and restrict size of 100 chars. show popup if exceeds.
|
||||||
|
// we store data locally so we want to keep it small. external link is intended for more info....
|
||||||
|
// use ProposalRestrictions.getMaxLengthDescriptionText()
|
||||||
|
public class ProposalDisplay {
|
||||||
|
private final GridPane gridPane;
|
||||||
|
private BsqFormatter bsqFormatter;
|
||||||
|
private BsqWalletService bsqWalletService;
|
||||||
|
public InputTextField uidTextField, nameTextField, titleTextField, linkInputTextField;
|
||||||
|
@Nullable
|
||||||
|
public InputTextField requestedBsqTextField, bsqAddressTextField;
|
||||||
|
private int gridRow;
|
||||||
|
public TextArea descriptionTextArea;
|
||||||
|
private HyperlinkWithIcon linkHyperlinkWithIcon;
|
||||||
|
@Nullable
|
||||||
|
private TxIdTextField txIdTextField;
|
||||||
|
private FeeService feeService;
|
||||||
|
|
||||||
|
public ProposalDisplay(GridPane gridPane, BsqFormatter bsqFormatter, BsqWalletService bsqWalletService, @Nullable FeeService feeService) {
|
||||||
|
this.gridPane = gridPane;
|
||||||
|
this.bsqFormatter = bsqFormatter;
|
||||||
|
this.bsqWalletService = bsqWalletService;
|
||||||
|
this.feeService = feeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createAllFields(String title, int index, double top, ProposalType proposalType, boolean isMakeProposalScreen) {
|
||||||
|
this.gridRow = index;
|
||||||
|
int rowSpan = 5;
|
||||||
|
if (proposalType == ProposalType.COMPENSATION_REQUEST)
|
||||||
|
rowSpan += 2;
|
||||||
|
if (!isMakeProposalScreen)
|
||||||
|
rowSpan += 1;
|
||||||
|
|
||||||
|
addTitledGroupBg(gridPane, gridRow, rowSpan, title, top);
|
||||||
|
uidTextField = addLabelInputTextField(gridPane, gridRow, Res.getWithCol("shared.id"), top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE).second;
|
||||||
|
uidTextField.setEditable(false);
|
||||||
|
nameTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.name")).second;
|
||||||
|
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.title")).second;
|
||||||
|
descriptionTextArea = addLabelTextArea(gridPane, ++gridRow, Res.get("dao.proposal.display.description"), Res.get("dao.proposal.display.description.prompt", ProposalRestrictions.getMaxLengthDescriptionText())).second;
|
||||||
|
linkInputTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.link")).second;
|
||||||
|
linkHyperlinkWithIcon = addLabelHyperlinkWithIcon(gridPane, gridRow, Res.get("dao.proposal.display.link"), "", "").second;
|
||||||
|
linkHyperlinkWithIcon.setVisible(false);
|
||||||
|
linkHyperlinkWithIcon.setManaged(false);
|
||||||
|
linkInputTextField.setPromptText(Res.get("dao.proposal.display.link.prompt"));
|
||||||
|
|
||||||
|
if (proposalType == ProposalType.COMPENSATION_REQUEST) {
|
||||||
|
requestedBsqTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.requestedBsq")).second;
|
||||||
|
|
||||||
|
if (feeService != null) {
|
||||||
|
BsqValidator bsqValidator = new BsqValidator(bsqFormatter);
|
||||||
|
//TODO should we use the BSQ or a BTC validator? Technically it is BTC at that stage...
|
||||||
|
//bsqValidator.setMinValue(feeService.getCreateCompensationRequestFee());
|
||||||
|
bsqValidator.setMinValue(Restrictions.getMinCompensationRequestAmount());
|
||||||
|
Objects.requireNonNull(requestedBsqTextField).setValidator(bsqValidator);
|
||||||
|
}
|
||||||
|
// TODO validator, addressTF
|
||||||
|
bsqAddressTextField = addLabelInputTextField(gridPane, ++gridRow,
|
||||||
|
Res.get("dao.proposal.display.bsqAddress")).second;
|
||||||
|
Objects.requireNonNull(bsqAddressTextField).setText("B" + bsqWalletService.getUnusedAddress().toBase58());
|
||||||
|
bsqAddressTextField.setValidator(new BsqAddressValidator(bsqFormatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMakeProposalScreen)
|
||||||
|
txIdTextField = addLabelTxIdTextField(gridPane, ++gridRow,
|
||||||
|
Res.get("dao.proposal.display.txId"), "").second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillWithData(ProposalPayload proposalPayload) {
|
||||||
|
uidTextField.setText(proposalPayload.getUid());
|
||||||
|
nameTextField.setText(proposalPayload.getName());
|
||||||
|
titleTextField.setText(proposalPayload.getTitle());
|
||||||
|
descriptionTextArea.setText(proposalPayload.getDescription());
|
||||||
|
linkInputTextField.setVisible(false);
|
||||||
|
linkInputTextField.setManaged(false);
|
||||||
|
linkHyperlinkWithIcon.setVisible(true);
|
||||||
|
linkHyperlinkWithIcon.setManaged(true);
|
||||||
|
linkHyperlinkWithIcon.setText(proposalPayload.getLink());
|
||||||
|
linkHyperlinkWithIcon.setOnAction(e -> GUIUtil.openWebPage(proposalPayload.getLink()));
|
||||||
|
if (proposalPayload instanceof CompensationRequestPayload) {
|
||||||
|
CompensationRequestPayload compensationRequestPayload = (CompensationRequestPayload) proposalPayload;
|
||||||
|
Objects.requireNonNull(requestedBsqTextField).setText(bsqFormatter.formatCoinWithCode(compensationRequestPayload.getRequestedBsq()));
|
||||||
|
Objects.requireNonNull(bsqAddressTextField).setText(compensationRequestPayload.getBsqAddress());
|
||||||
|
}
|
||||||
|
if (txIdTextField != null)
|
||||||
|
txIdTextField.setup(proposalPayload.getTxId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearForm() {
|
||||||
|
uidTextField.clear();
|
||||||
|
nameTextField.clear();
|
||||||
|
titleTextField.clear();
|
||||||
|
descriptionTextArea.clear();
|
||||||
|
linkInputTextField.clear();
|
||||||
|
linkHyperlinkWithIcon.clear();
|
||||||
|
if (requestedBsqTextField != null)
|
||||||
|
requestedBsqTextField.clear();
|
||||||
|
if (bsqAddressTextField != null)
|
||||||
|
bsqAddressTextField.clear();
|
||||||
|
if (txIdTextField != null)
|
||||||
|
txIdTextField.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillWithMock() {
|
||||||
|
uidTextField.setText(UUID.randomUUID().toString());
|
||||||
|
nameTextField.setText("Manfred Karrer");
|
||||||
|
titleTextField.setText("Development work November 2017");
|
||||||
|
descriptionTextArea.setText("Development work");
|
||||||
|
linkInputTextField.setText("https://github.com/bisq-network/compensation/issues/12");
|
||||||
|
if (requestedBsqTextField != null)
|
||||||
|
requestedBsqTextField.setText("14000");
|
||||||
|
if (bsqAddressTextField != null)
|
||||||
|
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllFieldsEditable(boolean isEditable) {
|
||||||
|
nameTextField.setEditable(isEditable);
|
||||||
|
titleTextField.setEditable(isEditable);
|
||||||
|
descriptionTextArea.setEditable(isEditable);
|
||||||
|
linkInputTextField.setEditable(isEditable);
|
||||||
|
if (requestedBsqTextField != null)
|
||||||
|
requestedBsqTextField.setEditable(isEditable);
|
||||||
|
if (bsqAddressTextField != null)
|
||||||
|
bsqAddressTextField.setEditable(isEditable);
|
||||||
|
|
||||||
|
linkInputTextField.setVisible(true);
|
||||||
|
linkInputTextField.setManaged(true);
|
||||||
|
linkHyperlinkWithIcon.setVisible(false);
|
||||||
|
linkHyperlinkWithIcon.setManaged(false);
|
||||||
|
linkHyperlinkWithIcon.setOnAction(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllFields() {
|
||||||
|
gridPane.getChildren().clear();
|
||||||
|
gridRow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int incrementAndGetGridRow() {
|
||||||
|
return ++gridRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ScrollPane getView() {
|
||||||
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
scrollPane.setFitToWidth(true);
|
||||||
|
scrollPane.setFitToHeight(true);
|
||||||
|
scrollPane.setMinHeight(100);
|
||||||
|
|
||||||
|
AnchorPane anchorPane = new AnchorPane();
|
||||||
|
scrollPane.setContent(anchorPane);
|
||||||
|
|
||||||
|
gridPane.setHgap(5);
|
||||||
|
gridPane.setVgap(5);
|
||||||
|
ColumnConstraints columnConstraints1 = new ColumnConstraints();
|
||||||
|
columnConstraints1.setHalignment(HPos.RIGHT);
|
||||||
|
columnConstraints1.setHgrow(Priority.SOMETIMES);
|
||||||
|
columnConstraints1.setMinWidth(140);
|
||||||
|
ColumnConstraints columnConstraints2 = new ColumnConstraints();
|
||||||
|
columnConstraints2.setHgrow(Priority.ALWAYS);
|
||||||
|
columnConstraints2.setMinWidth(300);
|
||||||
|
|
||||||
|
gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
|
||||||
|
AnchorPane.setBottomAnchor(gridPane, 20d);
|
||||||
|
AnchorPane.setRightAnchor(gridPane, 10d);
|
||||||
|
AnchorPane.setLeftAnchor(gridPane, 10d);
|
||||||
|
AnchorPane.setTopAnchor(gridPane, 20d);
|
||||||
|
anchorPane.getChildren().add(gridPane);
|
||||||
|
|
||||||
|
return scrollPane;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal;
|
||||||
|
|
||||||
|
import bisq.desktop.components.indicator.TxConfidenceIndicator;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
|
||||||
|
import bisq.core.btc.listeners.TxConfidenceListener;
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChain;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainListener;
|
||||||
|
import bisq.core.dao.blockchain.vo.Tx;
|
||||||
|
import bisq.core.dao.proposal.Proposal;
|
||||||
|
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
|
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
|
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@Slf4j
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class ProposalListItem implements BsqBlockChainListener {
|
||||||
|
@Getter
|
||||||
|
private final Proposal proposal;
|
||||||
|
private final BsqWalletService bsqWalletService;
|
||||||
|
private final BsqBlockChain bsqBlockChain;
|
||||||
|
private final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher;
|
||||||
|
private final BsqFormatter bsqFormatter;
|
||||||
|
private final ChangeListener<Number> chainHeightListener;
|
||||||
|
@Getter
|
||||||
|
private TxConfidenceIndicator txConfidenceIndicator;
|
||||||
|
@Getter
|
||||||
|
private Integer confirmations = 0;
|
||||||
|
|
||||||
|
private TxConfidenceListener txConfidenceListener;
|
||||||
|
private Tooltip tooltip = new Tooltip(Res.get("confidence.unknown"));
|
||||||
|
private Transaction walletTransaction;
|
||||||
|
|
||||||
|
public ProposalListItem(Proposal proposal,
|
||||||
|
BsqWalletService bsqWalletService,
|
||||||
|
BsqBlockChain bsqBlockChain,
|
||||||
|
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
||||||
|
BsqFormatter bsqFormatter) {
|
||||||
|
this.proposal = proposal;
|
||||||
|
this.bsqWalletService = bsqWalletService;
|
||||||
|
this.bsqBlockChain = bsqBlockChain;
|
||||||
|
this.bsqBlockChainChangeDispatcher = bsqBlockChainChangeDispatcher;
|
||||||
|
this.bsqFormatter = bsqFormatter;
|
||||||
|
|
||||||
|
|
||||||
|
txConfidenceIndicator = new TxConfidenceIndicator();
|
||||||
|
txConfidenceIndicator.setId("funds-confidence");
|
||||||
|
|
||||||
|
txConfidenceIndicator.setProgress(-1);
|
||||||
|
txConfidenceIndicator.setPrefSize(24, 24);
|
||||||
|
txConfidenceIndicator.setTooltip(tooltip);
|
||||||
|
|
||||||
|
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
|
||||||
|
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
|
||||||
|
setupConfidence();
|
||||||
|
|
||||||
|
bsqBlockChainChangeDispatcher.addBsqBlockChainListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBsqBlockChainChanged() {
|
||||||
|
setupConfidence();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupConfidence() {
|
||||||
|
final Tx tx = bsqBlockChain.getTxMap().get(proposal.getProposalPayload().getTxId());
|
||||||
|
if (tx != null) {
|
||||||
|
final String txId = tx.getId();
|
||||||
|
|
||||||
|
// We cache the walletTransaction once found
|
||||||
|
if (walletTransaction == null) {
|
||||||
|
final Optional<Transaction> transactionOptional = bsqWalletService.isWalletTransaction(txId);
|
||||||
|
transactionOptional.ifPresent(transaction -> walletTransaction = transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (walletTransaction != null) {
|
||||||
|
// It is our tx so we get confidence updates
|
||||||
|
if (txConfidenceListener == null) {
|
||||||
|
txConfidenceListener = new TxConfidenceListener(txId) {
|
||||||
|
@Override
|
||||||
|
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
|
||||||
|
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// tx from other users, we dont get confidence updates but as we have the bsq tx we can calculate it
|
||||||
|
// we get setupConfidence called at each new block from above listener so no need to register a new listener
|
||||||
|
int depth = bsqWalletService.getChainHeightProperty().get() - tx.getBlockHeight() + 1;
|
||||||
|
if (depth > 0)
|
||||||
|
updateConfidence(TransactionConfidence.ConfidenceType.BUILDING, depth, -1);
|
||||||
|
//log.error("name={}, id ={}, depth={}", compensationRequest.getPayload().getName(), compensationRequest.getPayload().getUid(), depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TransactionConfidence confidence = bsqWalletService.getConfidenceForTxId(txId);
|
||||||
|
if (confidence != null)
|
||||||
|
updateConfidence(confidence, confidence.getDepthInBlocks());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfidence(TransactionConfidence confidence, int depthInBlocks) {
|
||||||
|
if (confidence != null) {
|
||||||
|
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
|
||||||
|
confirmations = depthInBlocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
bsqBlockChainChangeDispatcher.removeBsqBlockChainListener(this);
|
||||||
|
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
|
||||||
|
if (txConfidenceListener != null)
|
||||||
|
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) {
|
||||||
|
switch (confidenceType) {
|
||||||
|
case UNKNOWN:
|
||||||
|
tooltip.setText(Res.get("confidence.unknown"));
|
||||||
|
txConfidenceIndicator.setProgress(0);
|
||||||
|
break;
|
||||||
|
case PENDING:
|
||||||
|
tooltip.setText(Res.get("confidence.seen", numBroadcastPeers > -1 ? numBroadcastPeers : Res.get("shared.na")));
|
||||||
|
txConfidenceIndicator.setProgress(-1.0);
|
||||||
|
break;
|
||||||
|
case BUILDING:
|
||||||
|
tooltip.setText(Res.get("confidence.confirmed", depthInBlocks));
|
||||||
|
txConfidenceIndicator.setProgress(Math.min(1, (double) depthInBlocks / 6.0));
|
||||||
|
break;
|
||||||
|
case DEAD:
|
||||||
|
tooltip.setText(Res.get("confidence.invalid"));
|
||||||
|
txConfidenceIndicator.setProgress(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
txConfidenceIndicator.setPrefSize(24, 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<AnchorPane fx:id="root" fx:controller="bisq.desktop.main.dao.proposal.ProposalView"
|
||||||
|
prefHeight="660.0" prefWidth="1000.0"
|
||||||
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
|
<VBox fx:id="leftVBox" spacing="5" prefWidth="240" AnchorPane.bottomAnchor="20" AnchorPane.leftAnchor="15"
|
||||||
|
AnchorPane.topAnchor="20"/>
|
||||||
|
<AnchorPane fx:id="content" AnchorPane.bottomAnchor="10" AnchorPane.rightAnchor="25" AnchorPane.leftAnchor="290"
|
||||||
|
AnchorPane.topAnchor="30"/>
|
||||||
|
</AnchorPane>
|
||||||
|
|
133
src/main/java/bisq/desktop/main/dao/proposal/ProposalView.java
Normal file
133
src/main/java/bisq/desktop/main/dao/proposal/ProposalView.java
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal;
|
||||||
|
|
||||||
|
import bisq.desktop.Navigation;
|
||||||
|
import bisq.desktop.common.view.ActivatableViewAndModel;
|
||||||
|
import bisq.desktop.common.view.CachingViewLoader;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.common.view.View;
|
||||||
|
import bisq.desktop.common.view.ViewLoader;
|
||||||
|
import bisq.desktop.common.view.ViewPath;
|
||||||
|
import bisq.desktop.components.MenuItem;
|
||||||
|
import bisq.desktop.main.dao.DaoView;
|
||||||
|
import bisq.desktop.main.dao.proposal.active.ActiveProposalsView;
|
||||||
|
import bisq.desktop.main.dao.proposal.closed.ClosedProposalsView;
|
||||||
|
import bisq.desktop.main.dao.proposal.dashboard.ProposalDashboardView;
|
||||||
|
import bisq.desktop.main.dao.proposal.make.MakeProposalView;
|
||||||
|
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class ProposalView extends ActivatableViewAndModel {
|
||||||
|
|
||||||
|
private final ViewLoader viewLoader;
|
||||||
|
private final Navigation navigation;
|
||||||
|
|
||||||
|
private MenuItem dashboard, create, proposed, past;
|
||||||
|
private Navigation.Listener listener;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private VBox leftVBox;
|
||||||
|
@FXML
|
||||||
|
private AnchorPane content;
|
||||||
|
|
||||||
|
private Class<? extends View> selectedViewClass;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ProposalView(CachingViewLoader viewLoader, Navigation navigation) {
|
||||||
|
this.viewLoader = viewLoader;
|
||||||
|
this.navigation = navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
listener = viewPath -> {
|
||||||
|
if (viewPath.size() != 4 || viewPath.indexOf(ProposalView.class) != 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectedViewClass = viewPath.tip();
|
||||||
|
loadView(selectedViewClass);
|
||||||
|
};
|
||||||
|
|
||||||
|
ToggleGroup toggleGroup = new ToggleGroup();
|
||||||
|
dashboard = new MenuItem(navigation, toggleGroup, Res.get("shared.dashboard"), ProposalDashboardView.class, AwesomeIcon.DASHBOARD);
|
||||||
|
create = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.make"), MakeProposalView.class, AwesomeIcon.EDIT);
|
||||||
|
proposed = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.active"), ActiveProposalsView.class, AwesomeIcon.STACKEXCHANGE);
|
||||||
|
past = new MenuItem(navigation, toggleGroup, Res.get("dao.proposal.menuItem.closed"), ClosedProposalsView.class, AwesomeIcon.LIST);
|
||||||
|
leftVBox.getChildren().addAll(dashboard, create, proposed, past);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
dashboard.activate();
|
||||||
|
create.activate();
|
||||||
|
proposed.activate();
|
||||||
|
past.activate();
|
||||||
|
|
||||||
|
navigation.addListener(listener);
|
||||||
|
ViewPath viewPath = navigation.getCurrentPath();
|
||||||
|
if (viewPath.size() == 3 && viewPath.indexOf(ProposalView.class) == 2 ||
|
||||||
|
viewPath.size() == 2 && viewPath.indexOf(DaoView.class) == 1) {
|
||||||
|
if (selectedViewClass == null)
|
||||||
|
selectedViewClass = MakeProposalView.class;
|
||||||
|
|
||||||
|
loadView(selectedViewClass);
|
||||||
|
|
||||||
|
} else if (viewPath.size() == 4 && viewPath.indexOf(ProposalView.class) == 2) {
|
||||||
|
selectedViewClass = viewPath.get(3);
|
||||||
|
loadView(selectedViewClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
navigation.removeListener(listener);
|
||||||
|
|
||||||
|
dashboard.deactivate();
|
||||||
|
create.deactivate();
|
||||||
|
proposed.deactivate();
|
||||||
|
past.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadView(Class<? extends View> viewClass) {
|
||||||
|
View view = viewLoader.load(viewClass);
|
||||||
|
content.getChildren().setAll(view.getRoot());
|
||||||
|
|
||||||
|
if (view instanceof ProposalDashboardView) dashboard.setSelected(true);
|
||||||
|
else if (view instanceof MakeProposalView) create.setSelected(true);
|
||||||
|
else if (view instanceof ActiveProposalsView) proposed.setSelected(true);
|
||||||
|
else if (view instanceof ClosedProposalsView) past.setSelected(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends View> getSelectedViewClass() {
|
||||||
|
return selectedViewClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.proposal.active.ActiveProposalsView"
|
||||||
|
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||||
|
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0.0"
|
||||||
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
</GridPane>
|
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal.active;
|
||||||
|
|
||||||
|
import bisq.desktop.Navigation;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.components.AutoTooltipButton;
|
||||||
|
import bisq.desktop.main.MainView;
|
||||||
|
import bisq.desktop.main.dao.DaoView;
|
||||||
|
import bisq.desktop.main.dao.proposal.BaseProposalView;
|
||||||
|
import bisq.desktop.main.dao.proposal.ProposalListItem;
|
||||||
|
import bisq.desktop.main.dao.voting.VotingView;
|
||||||
|
import bisq.desktop.main.dao.voting.vote.VoteView;
|
||||||
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.DaoPeriodService;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChain;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
||||||
|
import bisq.core.dao.proposal.Proposal;
|
||||||
|
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||||
|
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.TableCell;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
|
||||||
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class ActiveProposalsView extends BaseProposalView {
|
||||||
|
|
||||||
|
private Button removeButton, voteButton;
|
||||||
|
private final Navigation navigation;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor, lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ActiveProposalsView(ProposalCollectionsManager voteRequestManger,
|
||||||
|
DaoPeriodService daoPeriodService,
|
||||||
|
BsqWalletService bsqWalletService,
|
||||||
|
BsqBlockChain bsqBlockChain,
|
||||||
|
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
||||||
|
Navigation navigation,
|
||||||
|
BsqFormatter bsqFormatter) {
|
||||||
|
super(voteRequestManger, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
|
||||||
|
bsqFormatter);
|
||||||
|
this.navigation = navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
super.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateList() {
|
||||||
|
doUpdateList(proposalCollectionsManager.getActiveProposals());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onSelectProposal(ProposalListItem item) {
|
||||||
|
super.onSelectProposal(item);
|
||||||
|
if (item != null) {
|
||||||
|
if (removeButton != null) {
|
||||||
|
removeButton.setManaged(false);
|
||||||
|
removeButton.setVisible(false);
|
||||||
|
removeButton = null;
|
||||||
|
}
|
||||||
|
if (voteButton != null) {
|
||||||
|
voteButton.setManaged(false);
|
||||||
|
voteButton.setVisible(false);
|
||||||
|
voteButton = null;
|
||||||
|
}
|
||||||
|
onPhaseChanged(daoPeriodService.getPhaseProperty().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onVote() {
|
||||||
|
//noinspection unchecked
|
||||||
|
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class, VoteView.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRemove(Proposal proposal) {
|
||||||
|
if (proposalCollectionsManager.removeProposal(proposal))
|
||||||
|
proposalDisplay.removeAllFields();
|
||||||
|
else
|
||||||
|
new Popup<>().warning(Res.get("dao.proposal.active.remove.failed")).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPhaseChanged(DaoPeriodService.Phase phase) {
|
||||||
|
if (removeButton != null) {
|
||||||
|
removeButton.setManaged(false);
|
||||||
|
removeButton.setVisible(false);
|
||||||
|
removeButton = null;
|
||||||
|
}
|
||||||
|
if (selectedProposalListItem != null && proposalDisplay != null && !selectedProposalListItem.getProposal().isClosed()) {
|
||||||
|
final Proposal proposal = selectedProposalListItem.getProposal();
|
||||||
|
switch (phase) {
|
||||||
|
case COMPENSATION_REQUESTS:
|
||||||
|
if (proposalCollectionsManager.isMine(proposal)) {
|
||||||
|
if (removeButton == null) {
|
||||||
|
removeButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.remove"));
|
||||||
|
removeButton.setOnAction(event -> onRemove(proposal));
|
||||||
|
} else {
|
||||||
|
removeButton.setManaged(true);
|
||||||
|
removeButton.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BREAK1:
|
||||||
|
break;
|
||||||
|
case OPEN_FOR_VOTING:
|
||||||
|
if (voteButton == null) {
|
||||||
|
voteButton = addButtonAfterGroup(detailsGridPane, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.active.vote"));
|
||||||
|
voteButton.setOnAction(event -> onVote());
|
||||||
|
} else {
|
||||||
|
voteButton.setManaged(true);
|
||||||
|
voteButton.setVisible(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BREAK2:
|
||||||
|
break;
|
||||||
|
case VOTE_REVEAL:
|
||||||
|
break;
|
||||||
|
case BREAK3:
|
||||||
|
break;
|
||||||
|
case UNDEFINED:
|
||||||
|
default:
|
||||||
|
log.warn("Undefined phase: " + phase);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createColumns(TableView<ProposalListItem> tableView) {
|
||||||
|
super.createColumns(tableView);
|
||||||
|
|
||||||
|
TableColumn<ProposalListItem, ProposalListItem> actionColumn = new TableColumn<>();
|
||||||
|
actionColumn.setMinWidth(130);
|
||||||
|
actionColumn.setMaxWidth(actionColumn.getMinWidth());
|
||||||
|
|
||||||
|
actionColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||||
|
|
||||||
|
actionColumn.setCellFactory(new Callback<TableColumn<ProposalListItem, ProposalListItem>,
|
||||||
|
TableCell<ProposalListItem, ProposalListItem>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableCell<ProposalListItem, ProposalListItem> call(TableColumn<ProposalListItem,
|
||||||
|
ProposalListItem> column) {
|
||||||
|
return new TableCell<ProposalListItem, ProposalListItem>() {
|
||||||
|
final ImageView iconView = new ImageView();
|
||||||
|
Button button;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateItem(final ProposalListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (item != null && !empty) {
|
||||||
|
final Proposal proposal = item.getProposal();
|
||||||
|
if (button == null) {
|
||||||
|
button = new AutoTooltipButton(getActionButtonText());
|
||||||
|
button.setMinWidth(70);
|
||||||
|
iconView.setId(getActionButtonIconStyle());
|
||||||
|
button.setGraphic(iconView);
|
||||||
|
button.setVisible(getActionButtonVisibility(proposal));
|
||||||
|
setGraphic(button);
|
||||||
|
}
|
||||||
|
button.setOnAction(event -> onActionButton(proposal));
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
if (button != null) {
|
||||||
|
button.setOnAction(null);
|
||||||
|
button = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actionColumn.setComparator(Comparator.comparing(ProposalListItem::getConfirmations));
|
||||||
|
tableView.getColumns().add(actionColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onActionButton(Proposal proposal) {
|
||||||
|
if (showVoteButton())
|
||||||
|
onVote();
|
||||||
|
else if (showRemoveButton())
|
||||||
|
onRemove(proposal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getActionButtonVisibility(Proposal proposal) {
|
||||||
|
return !proposal.isClosed() && (showRemoveButton() || showVoteButton());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getActionButtonIconStyle() {
|
||||||
|
// TODO find better icon
|
||||||
|
return showRemoveButton() ? "image-remove" : "image-tick";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getActionButtonText() {
|
||||||
|
return showRemoveButton() ? Res.get("shared.remove") : Res.get("shared.vote");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean showVoteButton() {
|
||||||
|
return isTxInVotePhase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean showRemoveButton() {
|
||||||
|
return isTxInRequestPhase() && selectedProposalListItem != null && proposalCollectionsManager.isMine(selectedProposalListItem.getProposal());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTxInRequestPhase() {
|
||||||
|
return daoPeriodService.getPhaseProperty().get().equals(DaoPeriodService.Phase.COMPENSATION_REQUESTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTxInVotePhase() {
|
||||||
|
return daoPeriodService.getPhaseProperty().get().equals(DaoPeriodService.Phase.OPEN_FOR_VOTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.proposal.closed.ClosedProposalsView"
|
||||||
|
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||||
|
AnchorPane.rightAnchor="0" AnchorPane.topAnchor="0.0"
|
||||||
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||||
|
</columnConstraints>
|
||||||
|
</GridPane>
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal.closed;
|
||||||
|
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.main.dao.proposal.BaseProposalView;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.DaoPeriodService;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChain;
|
||||||
|
import bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher;
|
||||||
|
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class ClosedProposalsView extends BaseProposalView {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor, lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ClosedProposalsView(ProposalCollectionsManager proposalCollectionsManager,
|
||||||
|
DaoPeriodService daoPeriodService,
|
||||||
|
BsqWalletService bsqWalletService,
|
||||||
|
BsqBlockChain bsqBlockChain,
|
||||||
|
BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher,
|
||||||
|
BsqFormatter bsqFormatter) {
|
||||||
|
super(proposalCollectionsManager, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, daoPeriodService,
|
||||||
|
bsqFormatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
super.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateList() {
|
||||||
|
doUpdateList(proposalCollectionsManager.getClosedProposals());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.proposal.dashboard.ProposalDashboardView"
|
||||||
|
AnchorPane.bottomAnchor="-20.0" AnchorPane.leftAnchor="-10.0"
|
||||||
|
AnchorPane.rightAnchor="-10.0" AnchorPane.topAnchor="-20.0"
|
||||||
|
xmlns:fx="http://javafx.com/fxml">
|
||||||
|
</GridPane>
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal.dashboard;
|
||||||
|
|
||||||
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.components.SeparatedPhaseBars;
|
||||||
|
import bisq.desktop.util.Layout;
|
||||||
|
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.dao.DaoPeriodService;
|
||||||
|
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import javafx.scene.layout.AnchorPane;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
|
||||||
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class ProposalDashboardView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
|
private List<SeparatedPhaseBars.SeparatedPhaseBarsItem> phaseBarsItems;
|
||||||
|
private final BsqWalletService bsqWalletService;
|
||||||
|
private final DaoPeriodService daoPeriodService;
|
||||||
|
private DaoPeriodService.Phase currentPhase;
|
||||||
|
private Subscription phaseSubscription;
|
||||||
|
private GridPane gridPane;
|
||||||
|
private int gridRow = 0;
|
||||||
|
private ChangeListener<Number> chainHeightChangeListener;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor, lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ProposalDashboardView(DaoPeriodService daoPeriodService,
|
||||||
|
BsqWalletService bsqWalletService) {
|
||||||
|
this.daoPeriodService = daoPeriodService;
|
||||||
|
this.bsqWalletService = bsqWalletService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
root.getStyleClass().add("compensation-root");
|
||||||
|
AnchorPane topAnchorPane = new AnchorPane();
|
||||||
|
root.getChildren().add(topAnchorPane);
|
||||||
|
|
||||||
|
gridPane = new GridPane();
|
||||||
|
gridPane.setHgap(5);
|
||||||
|
gridPane.setVgap(5);
|
||||||
|
AnchorPane.setBottomAnchor(gridPane, 10d);
|
||||||
|
AnchorPane.setRightAnchor(gridPane, 10d);
|
||||||
|
AnchorPane.setLeftAnchor(gridPane, 10d);
|
||||||
|
AnchorPane.setTopAnchor(gridPane, 10d);
|
||||||
|
topAnchorPane.getChildren().add(gridPane);
|
||||||
|
|
||||||
|
// Add phase info
|
||||||
|
addTitledGroupBg(gridPane, gridRow, 1, Res.get("dao.proposal.active.phase.header"));
|
||||||
|
SeparatedPhaseBars separatedPhaseBars = createSeparatedPhaseBars();
|
||||||
|
GridPane.setColumnSpan(separatedPhaseBars, 2);
|
||||||
|
GridPane.setColumnIndex(separatedPhaseBars, 0);
|
||||||
|
GridPane.setMargin(separatedPhaseBars, new Insets(Layout.FIRST_ROW_DISTANCE - 6, 0, 0, 0));
|
||||||
|
GridPane.setRowIndex(separatedPhaseBars, gridRow);
|
||||||
|
gridPane.getChildren().add(separatedPhaseBars);
|
||||||
|
|
||||||
|
chainHeightChangeListener = (observable, oldValue, newValue) -> onChainHeightChanged((int) newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SeparatedPhaseBars createSeparatedPhaseBars() {
|
||||||
|
phaseBarsItems = Arrays.asList(
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.COMPENSATION_REQUESTS, true),
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK1, false),
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.OPEN_FOR_VOTING, true),
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK2, false),
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.VOTE_REVEAL, true),
|
||||||
|
new SeparatedPhaseBars.SeparatedPhaseBarsItem(DaoPeriodService.Phase.BREAK3, false));
|
||||||
|
return new SeparatedPhaseBars(phaseBarsItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
super.activate();
|
||||||
|
|
||||||
|
bsqWalletService.getChainHeightProperty().addListener(chainHeightChangeListener);
|
||||||
|
|
||||||
|
phaseSubscription = EasyBind.subscribe(daoPeriodService.getPhaseProperty(), phase -> {
|
||||||
|
if (!phase.equals(this.currentPhase)) {
|
||||||
|
this.currentPhase = phase;
|
||||||
|
}
|
||||||
|
phaseBarsItems.forEach(item -> {
|
||||||
|
if (item.getPhase() == phase) {
|
||||||
|
item.setActive();
|
||||||
|
} else {
|
||||||
|
item.setInActive();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onChainHeightChanged(bsqWalletService.getChainHeightProperty().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
super.deactivate();
|
||||||
|
|
||||||
|
bsqWalletService.getChainHeightProperty().removeListener(chainHeightChangeListener);
|
||||||
|
phaseSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void onChainHeightChanged(int height) {
|
||||||
|
phaseBarsItems.forEach(item -> {
|
||||||
|
int startBlock = daoPeriodService.getAbsoluteStartBlockOfPhase(height, item.getPhase());
|
||||||
|
int endBlock = daoPeriodService.getAbsoluteEndBlockOfPhase(height, item.getPhase());
|
||||||
|
item.setStartAndEnd(startBlock, endBlock);
|
||||||
|
double progress = 0;
|
||||||
|
if (height >= startBlock && height <= endBlock) {
|
||||||
|
progress = (double) (height - startBlock + 1) / (double) item.getPhase().getDurationInBlocks();
|
||||||
|
} else if (height < startBlock) {
|
||||||
|
progress = 0;
|
||||||
|
} else if (height > endBlock) {
|
||||||
|
progress = 1;
|
||||||
|
}
|
||||||
|
item.getProgressProperty().set(progress);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@
|
|||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
<?import javafx.scene.layout.GridPane?>
|
<?import javafx.scene.layout.GridPane?>
|
||||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.voting.dashboard.VotingDashboardView"
|
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.proposal.make.MakeProposalView"
|
||||||
hgap="5.0" vgap="5.0"
|
hgap="5.0" vgap="5.0"
|
||||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-10.0"
|
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="-10.0"
|
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* 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.dao.proposal.make;
|
||||||
|
|
||||||
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
|
import bisq.desktop.common.view.FxmlView;
|
||||||
|
import bisq.desktop.main.dao.proposal.ProposalDisplay;
|
||||||
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
|
import bisq.desktop.util.BSFormatter;
|
||||||
|
import bisq.desktop.util.BsqFormatter;
|
||||||
|
import bisq.desktop.util.GUIUtil;
|
||||||
|
import bisq.desktop.util.Layout;
|
||||||
|
|
||||||
|
import bisq.core.btc.exceptions.TransactionVerificationException;
|
||||||
|
import bisq.core.btc.exceptions.WalletException;
|
||||||
|
import bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
import bisq.core.btc.wallet.InsufficientBsqException;
|
||||||
|
import bisq.core.btc.wallet.WalletsSetup;
|
||||||
|
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||||
|
import bisq.core.dao.proposal.ProposalType;
|
||||||
|
import bisq.core.dao.proposal.compensation.CompensationAmountException;
|
||||||
|
import bisq.core.dao.proposal.compensation.CompensationRequest;
|
||||||
|
import bisq.core.dao.proposal.compensation.CompensationRequestManager;
|
||||||
|
import bisq.core.dao.proposal.compensation.CompensationRequestPayload;
|
||||||
|
import bisq.core.dao.proposal.generic.GenericProposal;
|
||||||
|
import bisq.core.dao.proposal.generic.GenericProposalManager;
|
||||||
|
import bisq.core.dao.proposal.generic.GenericProposalPayload;
|
||||||
|
import bisq.core.provider.fee.FeeService;
|
||||||
|
import bisq.core.util.CoinUtil;
|
||||||
|
|
||||||
|
import bisq.network.p2p.P2PService;
|
||||||
|
|
||||||
|
import bisq.common.app.DevEnv;
|
||||||
|
import bisq.common.locale.Res;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.InsufficientMoneyException;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
||||||
|
import static bisq.desktop.util.FormBuilder.addLabelComboBox;
|
||||||
|
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||||
|
|
||||||
|
@FxmlView
|
||||||
|
public class MakeProposalView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
|
private ProposalDisplay proposalDisplay;
|
||||||
|
private Button createButton;
|
||||||
|
|
||||||
|
private final BsqWalletService bsqWalletService;
|
||||||
|
private final WalletsSetup walletsSetup;
|
||||||
|
private final P2PService p2PService;
|
||||||
|
private final FeeService feeService;
|
||||||
|
private final ProposalCollectionsManager proposalCollectionsManager;
|
||||||
|
private final CompensationRequestManager compensationRequestManager;
|
||||||
|
private final GenericProposalManager genericProposalManager;
|
||||||
|
private final BSFormatter btcFormatter;
|
||||||
|
private final BsqFormatter bsqFormatter;
|
||||||
|
private ComboBox<ProposalType> proposalTypeComboBox;
|
||||||
|
private ChangeListener<ProposalType> proposalTypeChangeListener;
|
||||||
|
private ProposalType selectedProposalType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor, lifecycle
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private MakeProposalView(BsqWalletService bsqWalletService,
|
||||||
|
WalletsSetup walletsSetup,
|
||||||
|
P2PService p2PService,
|
||||||
|
FeeService feeService,
|
||||||
|
ProposalCollectionsManager proposalCollectionsManager,
|
||||||
|
CompensationRequestManager compensationRequestManager,
|
||||||
|
GenericProposalManager genericProposalManager,
|
||||||
|
BSFormatter btcFormatter,
|
||||||
|
BsqFormatter bsqFormatter) {
|
||||||
|
this.bsqWalletService = bsqWalletService;
|
||||||
|
this.walletsSetup = walletsSetup;
|
||||||
|
this.p2PService = p2PService;
|
||||||
|
this.feeService = feeService;
|
||||||
|
this.proposalCollectionsManager = proposalCollectionsManager;
|
||||||
|
this.compensationRequestManager = compensationRequestManager;
|
||||||
|
this.genericProposalManager = genericProposalManager;
|
||||||
|
this.btcFormatter = btcFormatter;
|
||||||
|
this.bsqFormatter = bsqFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
addTitledGroupBg(root, 0, 1, Res.get("dao.proposal.create.selectProposalType"));
|
||||||
|
proposalTypeComboBox = addLabelComboBox(root, 0, Res.getWithCol("dao.proposal.create.proposalType"), Layout.FIRST_ROW_DISTANCE).second;
|
||||||
|
proposalTypeComboBox.setConverter(new StringConverter<ProposalType>() {
|
||||||
|
@Override
|
||||||
|
public String toString(ProposalType object) {
|
||||||
|
return Res.get(object.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProposalType fromString(String string) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
proposalTypeComboBox.setPromptText(Res.get("shared.select"));
|
||||||
|
proposalTypeChangeListener = (observable, oldValue, newValue) -> {
|
||||||
|
selectedProposalType = newValue;
|
||||||
|
addProposalDisplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
proposalTypeComboBox.setItems(FXCollections.observableArrayList(Arrays.asList(ProposalType.values())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate() {
|
||||||
|
proposalTypeComboBox.getSelectionModel().selectedItemProperty().addListener(proposalTypeChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void deactivate() {
|
||||||
|
proposalTypeComboBox.getSelectionModel().selectedItemProperty().removeListener(proposalTypeChangeListener);
|
||||||
|
if (createButton != null)
|
||||||
|
createButton.setOnAction(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCompensationRequest() {
|
||||||
|
CompensationRequestPayload compensationRequestPayload = compensationRequestManager.getNewCompensationRequestPayload(
|
||||||
|
proposalDisplay.nameTextField.getText(),
|
||||||
|
proposalDisplay.titleTextField.getText(),
|
||||||
|
proposalDisplay.descriptionTextArea.getText(),
|
||||||
|
proposalDisplay.linkInputTextField.getText(),
|
||||||
|
bsqFormatter.parseToCoin(Objects.requireNonNull(proposalDisplay.requestedBsqTextField).getText()),
|
||||||
|
Objects.requireNonNull(proposalDisplay.bsqAddressTextField).getText());
|
||||||
|
try {
|
||||||
|
CompensationRequest compensationRequest = compensationRequestManager.prepareCompensationRequest(compensationRequestPayload);
|
||||||
|
Coin miningFee = compensationRequest.getTx().getFee();
|
||||||
|
int txSize = compensationRequest.getTx().bitcoinSerialize().length;
|
||||||
|
new Popup<>().headLine(Res.get("dao.proposal.create.confirm"))
|
||||||
|
.confirmation(Res.get("dao.proposal.create.confirm.info",
|
||||||
|
bsqFormatter.formatCoinWithCode(compensationRequest.getRequestedBsq()),
|
||||||
|
bsqFormatter.formatCoinWithCode(compensationRequest.getFeeAsCoin()),
|
||||||
|
btcFormatter.formatCoinWithCode(miningFee),
|
||||||
|
CoinUtil.getFeePerByte(miningFee, txSize),
|
||||||
|
(txSize / 1000d)))
|
||||||
|
.actionButtonText(Res.get("shared.yes"))
|
||||||
|
.onAction(() -> {
|
||||||
|
proposalCollectionsManager.publishProposal(compensationRequest, new FutureCallback<Transaction>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable Transaction transaction) {
|
||||||
|
proposalDisplay.clearForm();
|
||||||
|
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NotNull Throwable t) {
|
||||||
|
log.error(t.toString());
|
||||||
|
new Popup<>().warning(t.toString()).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.closeButtonText(Res.get("shared.cancel"))
|
||||||
|
.show();
|
||||||
|
} catch (InsufficientMoneyException e) {
|
||||||
|
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
|
||||||
|
new Popup<>().warning(Res.get("dao.proposal.create.missingFunds", formatter.formatCoinWithCode(e.missing))).show();
|
||||||
|
} catch (CompensationAmountException e) {
|
||||||
|
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount", bsqFormatter.formatCoinWithCode(e.required))).show();
|
||||||
|
} catch (TransactionVerificationException | WalletException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
new Popup<>().warning(e.toString()).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGenericProposal() {
|
||||||
|
GenericProposalPayload genericProposalPayload = genericProposalManager.getNewGenericProposalPayload(
|
||||||
|
proposalDisplay.nameTextField.getText(),
|
||||||
|
proposalDisplay.titleTextField.getText(),
|
||||||
|
proposalDisplay.descriptionTextArea.getText(),
|
||||||
|
proposalDisplay.linkInputTextField.getText());
|
||||||
|
try {
|
||||||
|
GenericProposal genericProposal = genericProposalManager.prepareGenericProposal(genericProposalPayload);
|
||||||
|
Coin miningFee = genericProposal.getTx().getFee();
|
||||||
|
int txSize = genericProposal.getTx().bitcoinSerialize().length;
|
||||||
|
new Popup<>().headLine(Res.get("dao.proposal.create.confirm"))
|
||||||
|
.confirmation(Res.get("dao.proposal.create.confirm.info",
|
||||||
|
bsqFormatter.formatCoinWithCode(Coin.valueOf(10000)), // TODO dummy
|
||||||
|
bsqFormatter.formatCoinWithCode(genericProposal.getFeeAsCoin()),
|
||||||
|
btcFormatter.formatCoinWithCode(miningFee),
|
||||||
|
CoinUtil.getFeePerByte(miningFee, txSize),
|
||||||
|
(txSize / 1000d)))
|
||||||
|
.actionButtonText(Res.get("shared.yes"))
|
||||||
|
.onAction(() -> {
|
||||||
|
proposalCollectionsManager.publishProposal(genericProposal, new FutureCallback<Transaction>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@Nullable Transaction transaction) {
|
||||||
|
proposalDisplay.clearForm();
|
||||||
|
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NotNull Throwable t) {
|
||||||
|
log.error(t.toString());
|
||||||
|
new Popup<>().warning(t.toString()).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.closeButtonText(Res.get("shared.cancel"))
|
||||||
|
.show();
|
||||||
|
} catch (InsufficientMoneyException e) {
|
||||||
|
BSFormatter formatter = e instanceof InsufficientBsqException ? bsqFormatter : btcFormatter;
|
||||||
|
new Popup<>().warning(Res.get("dao.proposal.create.missingFunds", formatter.formatCoinWithCode(e.missing))).show();
|
||||||
|
} catch (CompensationAmountException e) {
|
||||||
|
new Popup<>().warning(Res.get("validation.bsq.amountBelowMinAmount", bsqFormatter.formatCoinWithCode(e.required))).show();
|
||||||
|
} catch (TransactionVerificationException | WalletException e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
new Popup<>().warning(e.toString()).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addProposalDisplay() {
|
||||||
|
// TODO need to update removed fields when switching.
|
||||||
|
if (proposalDisplay != null) {
|
||||||
|
root.getChildren().remove(3, root.getChildren().size());
|
||||||
|
}
|
||||||
|
proposalDisplay = new ProposalDisplay(root, bsqFormatter, bsqWalletService, feeService);
|
||||||
|
proposalDisplay.createAllFields(Res.get("dao.proposal.create.createNew"), 1, Layout.GROUP_DISTANCE, selectedProposalType, true);
|
||||||
|
proposalDisplay.fillWithMock();
|
||||||
|
|
||||||
|
createButton = addButtonAfterGroup(root, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.create.create.button"));
|
||||||
|
createButton.setOnAction(event -> {
|
||||||
|
// TODO break up in methods
|
||||||
|
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
||||||
|
switch (selectedProposalType) {
|
||||||
|
case COMPENSATION_REQUEST:
|
||||||
|
createCompensationRequest();
|
||||||
|
break;
|
||||||
|
case GENERIC:
|
||||||
|
createGenericProposal();
|
||||||
|
break;
|
||||||
|
case CHANGE_PARAM:
|
||||||
|
//TODO
|
||||||
|
break;
|
||||||
|
case REMOVE_ALTCOIN:
|
||||||
|
//TODO
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
final String msg = "Undefined ProposalType " + selectedProposalType;
|
||||||
|
log.error(msg);
|
||||||
|
if (DevEnv.isDevMode())
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.voting.vote;
|
|
||||||
|
|
||||||
import bisq.desktop.components.AutoTooltipButton;
|
|
||||||
import bisq.desktop.components.AutoTooltipCheckBox;
|
|
||||||
import bisq.desktop.components.HyperlinkWithIcon;
|
|
||||||
import bisq.desktop.main.MainView;
|
|
||||||
import bisq.desktop.main.dao.compensation.CompensationRequestDisplay;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.Layout;
|
|
||||||
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestPayload;
|
|
||||||
import bisq.core.dao.vote.CompensationRequestVoteItem;
|
|
||||||
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
|
||||||
|
|
||||||
import javafx.stage.Modality;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
import javafx.stage.StageStyle;
|
|
||||||
import javafx.stage.Window;
|
|
||||||
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.ColumnConstraints;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import javafx.scene.layout.Pane;
|
|
||||||
import javafx.scene.layout.Priority;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
import javafx.geometry.HPos;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
|
|
||||||
import javafx.beans.property.DoubleProperty;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class CompensationViewItem {
|
|
||||||
private static final List<CompensationViewItem> instances = new ArrayList<>();
|
|
||||||
|
|
||||||
private final Button removeButton;
|
|
||||||
private final CheckBox acceptCheckBox, declineCheckBox;
|
|
||||||
public final CompensationRequestVoteItem compensationRequestVoteItem;
|
|
||||||
private Pane owner;
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedParameters")
|
|
||||||
public static void attach(CompensationRequestVoteItem compensationRequestVoteItem,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
VBox vBox,
|
|
||||||
DoubleProperty labelWidth,
|
|
||||||
BsqFormatter bsqFormatter,
|
|
||||||
Runnable removeHandler) {
|
|
||||||
instances.add(new CompensationViewItem(compensationRequestVoteItem, bsqWalletService, vBox, bsqFormatter, removeHandler));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cleanupAllInstances() {
|
|
||||||
instances.forEach(CompensationViewItem::cleanupInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean contains(CompensationRequestVoteItem selectedItem) {
|
|
||||||
return instances.stream()
|
|
||||||
.anyMatch(e -> e.compensationRequestVoteItem.compensationRequest.getPayload().getUid().equals(
|
|
||||||
selectedItem.compensationRequest.getPayload().getUid()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
|
||||||
public static boolean isEmpty() {
|
|
||||||
return instances.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompensationViewItem(CompensationRequestVoteItem compensationRequestVoteItem,
|
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
VBox vBox,
|
|
||||||
BsqFormatter bsqFormatter,
|
|
||||||
Runnable removeHandler) {
|
|
||||||
this.compensationRequestVoteItem = compensationRequestVoteItem;
|
|
||||||
CompensationRequest compensationRequest = compensationRequestVoteItem.compensationRequest;
|
|
||||||
CompensationRequestPayload compensationRequestPayload = compensationRequest.getPayload();
|
|
||||||
|
|
||||||
HBox hBox = new HBox();
|
|
||||||
hBox.setSpacing(5);
|
|
||||||
vBox.getChildren().add(hBox);
|
|
||||||
|
|
||||||
String title = compensationRequestPayload.getTitle() + " (" + compensationRequestPayload.getShortId() + ")";
|
|
||||||
|
|
||||||
HyperlinkWithIcon infoLabelWithLink = new HyperlinkWithIcon(title, AwesomeIcon.EXTERNAL_LINK);
|
|
||||||
infoLabelWithLink.setPrefWidth(220);
|
|
||||||
HBox.setMargin(infoLabelWithLink, new Insets(2, 0, 0, 0));
|
|
||||||
|
|
||||||
infoLabelWithLink.setOnAction(e -> {
|
|
||||||
GridPane gridPane = new GridPane();
|
|
||||||
gridPane.setHgap(5);
|
|
||||||
gridPane.setVgap(5);
|
|
||||||
ColumnConstraints columnConstraints1 = new ColumnConstraints();
|
|
||||||
columnConstraints1.setHalignment(HPos.RIGHT);
|
|
||||||
columnConstraints1.setHgrow(Priority.SOMETIMES);
|
|
||||||
columnConstraints1.setMinWidth(140);
|
|
||||||
ColumnConstraints columnConstraints2 = new ColumnConstraints();
|
|
||||||
columnConstraints2.setHgrow(Priority.ALWAYS);
|
|
||||||
columnConstraints2.setMinWidth(300);
|
|
||||||
gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2);
|
|
||||||
AnchorPane anchorPane = new AnchorPane();
|
|
||||||
anchorPane.getChildren().add(gridPane);
|
|
||||||
AnchorPane.setBottomAnchor(gridPane, 25d);
|
|
||||||
AnchorPane.setRightAnchor(gridPane, 25d);
|
|
||||||
AnchorPane.setLeftAnchor(gridPane, 25d);
|
|
||||||
AnchorPane.setTopAnchor(gridPane, -20d);
|
|
||||||
|
|
||||||
CompensationRequestDisplay compensationRequestDisplay = new CompensationRequestDisplay(gridPane, bsqFormatter, bsqWalletService, null);
|
|
||||||
compensationRequestDisplay.createAllFields(Res.get("dao.voting.item.title"), Layout.GROUP_DISTANCE);
|
|
||||||
compensationRequestDisplay.setAllFieldsEditable(false);
|
|
||||||
compensationRequestDisplay.fillWithData(compensationRequestPayload);
|
|
||||||
|
|
||||||
Scene scene = new Scene(anchorPane);
|
|
||||||
scene.getStylesheets().setAll(
|
|
||||||
"/bisq/desktop/bisq.css",
|
|
||||||
"/bisq/desktop/images.css");
|
|
||||||
Stage stage = new Stage();
|
|
||||||
stage.setTitle(Res.get("dao.voting.item.stage.title", compensationRequestPayload.getShortId()));
|
|
||||||
stage.setScene(scene);
|
|
||||||
if (owner == null)
|
|
||||||
owner = MainView.getRootContainer();
|
|
||||||
Scene rootScene = owner.getScene();
|
|
||||||
stage.initOwner(rootScene.getWindow());
|
|
||||||
stage.initModality(Modality.NONE);
|
|
||||||
stage.initStyle(StageStyle.UTILITY);
|
|
||||||
stage.show();
|
|
||||||
|
|
||||||
|
|
||||||
Window window = rootScene.getWindow();
|
|
||||||
double titleBarHeight = window.getHeight() - rootScene.getHeight();
|
|
||||||
stage.setX(Math.round(window.getX() + (owner.getWidth() - stage.getWidth()) / 2) + 200);
|
|
||||||
stage.setY(Math.round(window.getY() + titleBarHeight + (owner.getHeight() - stage.getHeight()) / 2) + 50);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
acceptCheckBox = new AutoTooltipCheckBox(Res.get("shared.accept"));
|
|
||||||
HBox.setMargin(acceptCheckBox, new Insets(5, 0, 0, 0));
|
|
||||||
|
|
||||||
declineCheckBox = new AutoTooltipCheckBox(Res.get("shared.decline"));
|
|
||||||
HBox.setMargin(declineCheckBox, new Insets(5, 0, 0, 0));
|
|
||||||
|
|
||||||
|
|
||||||
acceptCheckBox.setOnAction(event -> {
|
|
||||||
boolean selected = acceptCheckBox.isSelected();
|
|
||||||
compensationRequestVoteItem.setAcceptedVote(selected);
|
|
||||||
if (declineCheckBox.isSelected()) {
|
|
||||||
declineCheckBox.setSelected(!selected);
|
|
||||||
compensationRequestVoteItem.setDeclineVote(!selected);
|
|
||||||
} else if (!selected) {
|
|
||||||
compensationRequestVoteItem.setHasVoted(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
acceptCheckBox.setSelected(compensationRequestVoteItem.isAcceptedVote());
|
|
||||||
|
|
||||||
declineCheckBox.setOnAction(event -> {
|
|
||||||
boolean selected = declineCheckBox.isSelected();
|
|
||||||
compensationRequestVoteItem.setDeclineVote(selected);
|
|
||||||
if (acceptCheckBox.isSelected()) {
|
|
||||||
acceptCheckBox.setSelected(!selected);
|
|
||||||
compensationRequestVoteItem.setAcceptedVote(!selected);
|
|
||||||
} else if (!selected) {
|
|
||||||
compensationRequestVoteItem.setHasVoted(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
declineCheckBox.setSelected(compensationRequestVoteItem.isDeclineVote());
|
|
||||||
|
|
||||||
removeButton = new AutoTooltipButton(Res.get("shared.remove"));
|
|
||||||
removeButton.setOnAction(event -> {
|
|
||||||
vBox.getChildren().remove(hBox);
|
|
||||||
cleanupInstance();
|
|
||||||
instances.remove(this);
|
|
||||||
removeHandler.run();
|
|
||||||
});
|
|
||||||
|
|
||||||
Pane spacer = new Pane();
|
|
||||||
spacer.setMaxWidth(Double.MAX_VALUE);
|
|
||||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
|
||||||
|
|
||||||
hBox.getChildren().addAll(infoLabelWithLink, acceptCheckBox, declineCheckBox, spacer, removeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanupInstance() {
|
|
||||||
acceptCheckBox.setOnAction(null);
|
|
||||||
declineCheckBox.setOnAction(null);
|
|
||||||
removeButton.setOnAction(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.dao.voting.vote;
|
|
||||||
|
|
||||||
import bisq.desktop.components.AutoTooltipButton;
|
|
||||||
import bisq.desktop.components.AutoTooltipLabel;
|
|
||||||
import bisq.desktop.components.InputTextField;
|
|
||||||
|
|
||||||
import bisq.core.dao.vote.VoteItem;
|
|
||||||
import bisq.core.dao.vote.VotingDefaultValues;
|
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import javafx.scene.layout.Priority;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
|
|
||||||
import javafx.beans.property.DoubleProperty;
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
import javafx.util.StringConverter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ParameterViewItem {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ParameterViewItem.class);
|
|
||||||
|
|
||||||
private static final List<ParameterViewItem> instances = new ArrayList<>();
|
|
||||||
|
|
||||||
private final long originalValue;
|
|
||||||
private final ChangeListener<String> inputTextFieldChangeListener;
|
|
||||||
private final ChangeListener<Boolean> inputTextFieldFocusListener;
|
|
||||||
private final ChangeListener<Number> sliderListener;
|
|
||||||
private final InputTextField inputTextField;
|
|
||||||
private final Slider slider;
|
|
||||||
private final Button resetButton, removeButton;
|
|
||||||
private final Label label;
|
|
||||||
private ChangeListener<Number> numberChangeListener;
|
|
||||||
public final VoteItem voteItem;
|
|
||||||
|
|
||||||
public static void attach(VoteItem voteItem, VBox vBox, DoubleProperty labelWidth, VotingDefaultValues votingDefaultValues, Runnable removeHandler) {
|
|
||||||
instances.add(new ParameterViewItem(voteItem, vBox, labelWidth, votingDefaultValues, removeHandler));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cleanupAllInstances() {
|
|
||||||
instances.stream().forEach(ParameterViewItem::cleanupInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean contains(VoteItem selectedItem) {
|
|
||||||
return instances.stream().filter(e -> e.voteItem.getVotingType() == selectedItem.getVotingType()).findAny().isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
|
||||||
public static boolean isEmpty() {
|
|
||||||
return instances.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParameterViewItem(VoteItem voteItem, VBox vBox, DoubleProperty labelWidth, VotingDefaultValues votingDefaultValues, Runnable removeHandler) {
|
|
||||||
this.voteItem = voteItem;
|
|
||||||
originalValue = votingDefaultValues.getValueByVotingType(voteItem.getVotingType());
|
|
||||||
HBox hBox = new HBox();
|
|
||||||
hBox.setSpacing(5);
|
|
||||||
vBox.getChildren().add(hBox);
|
|
||||||
|
|
||||||
label = new AutoTooltipLabel(voteItem.getName() + ":");
|
|
||||||
HBox.setMargin(label, new Insets(4, 0, 0, 0));
|
|
||||||
numberChangeListener = (observable, oldValue, newValue) -> {
|
|
||||||
if ((double) newValue > 0) {
|
|
||||||
labelWidth.set(Math.max(labelWidth.get(), (double) newValue));
|
|
||||||
UserThread.execute(() -> label.prefWidthProperty().bind(labelWidth));
|
|
||||||
label.widthProperty().removeListener(numberChangeListener);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
label.widthProperty().addListener(numberChangeListener);
|
|
||||||
|
|
||||||
inputTextField = new InputTextField();
|
|
||||||
inputTextField.setPrefWidth(100);
|
|
||||||
inputTextField.setText(String.valueOf(originalValue));
|
|
||||||
slider = new Slider();
|
|
||||||
inputTextFieldChangeListener = (observable, oldValue, newValue) -> {
|
|
||||||
if (!slider.isFocused()) {
|
|
||||||
try {
|
|
||||||
long change = votingDefaultValues.getChange(originalValue, Long.valueOf(inputTextField.getText()));
|
|
||||||
slider.setValue(change);
|
|
||||||
voteItem.setValue((byte) change);
|
|
||||||
} catch (Throwable ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputTextField.textProperty().addListener(inputTextFieldChangeListener);
|
|
||||||
inputTextFieldFocusListener = (observable, oldValue, newValue) -> {
|
|
||||||
if (oldValue && !newValue) {
|
|
||||||
// focus out
|
|
||||||
// We adjust value to our 255 value grid
|
|
||||||
int change = (int) Math.round(slider.getValue());
|
|
||||||
long dataValue = votingDefaultValues.getAdjustedValue(originalValue, change);
|
|
||||||
inputTextField.setText(String.valueOf(dataValue));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputTextField.focusedProperty().addListener(inputTextFieldFocusListener);
|
|
||||||
|
|
||||||
slider.setPrefWidth(300);
|
|
||||||
slider.setMin(0);
|
|
||||||
slider.setMax(254);
|
|
||||||
slider.setValue(127);
|
|
||||||
slider.setShowTickLabels(true);
|
|
||||||
HBox.setMargin(slider, new Insets(-1, 20, 0, 20));
|
|
||||||
HBox.setHgrow(slider, Priority.ALWAYS);
|
|
||||||
|
|
||||||
slider.setLabelFormatter(new StringConverter<Double>() {
|
|
||||||
@Override
|
|
||||||
public String toString(Double object) {
|
|
||||||
return String.valueOf(votingDefaultValues.getAdjustedValue(originalValue, object.intValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Double fromString(String string) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sliderListener = (observable, oldValue, newValue) -> {
|
|
||||||
if (!inputTextField.isFocused()) {
|
|
||||||
int change = (int) Math.round(slider.getValue());
|
|
||||||
long dataValue = votingDefaultValues.getAdjustedValue(originalValue, change);
|
|
||||||
inputTextField.setText(String.valueOf(dataValue));
|
|
||||||
voteItem.setValue((byte) change);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
slider.valueProperty().addListener(sliderListener);
|
|
||||||
|
|
||||||
resetButton = new AutoTooltipButton(Res.get("shared.reset"));
|
|
||||||
resetButton.setOnAction(event -> inputTextField.setText(String.valueOf(originalValue)));
|
|
||||||
|
|
||||||
removeButton = new AutoTooltipButton(Res.get("shared.remove"));
|
|
||||||
removeButton.setOnAction(event -> {
|
|
||||||
vBox.getChildren().remove(hBox);
|
|
||||||
cleanupInstance();
|
|
||||||
instances.remove(this);
|
|
||||||
removeHandler.run();
|
|
||||||
});
|
|
||||||
|
|
||||||
hBox.getChildren().addAll(label, inputTextField, slider, resetButton, removeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanupInstance() {
|
|
||||||
label.widthProperty().removeListener(numberChangeListener);
|
|
||||||
inputTextField.focusedProperty().removeListener(inputTextFieldFocusListener);
|
|
||||||
inputTextField.textProperty().removeListener(inputTextFieldChangeListener);
|
|
||||||
slider.valueProperty().removeListener(sliderListener);
|
|
||||||
resetButton.setOnAction(null);
|
|
||||||
removeButton.setOnAction(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,316 +19,32 @@ package bisq.desktop.main.dao.voting.vote;
|
|||||||
|
|
||||||
import bisq.desktop.common.view.ActivatableView;
|
import bisq.desktop.common.view.ActivatableView;
|
||||||
import bisq.desktop.common.view.FxmlView;
|
import bisq.desktop.common.view.FxmlView;
|
||||||
import bisq.desktop.components.TitledGroupBg;
|
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
|
||||||
import bisq.desktop.util.BSFormatter;
|
|
||||||
import bisq.desktop.util.BsqFormatter;
|
|
||||||
import bisq.desktop.util.GUIUtil;
|
|
||||||
import bisq.desktop.util.Layout;
|
|
||||||
|
|
||||||
import bisq.core.btc.exceptions.TransactionVerificationException;
|
|
||||||
import bisq.core.btc.exceptions.WalletException;
|
|
||||||
import bisq.core.btc.wallet.BsqWalletService;
|
|
||||||
import bisq.core.btc.wallet.BtcWalletService;
|
|
||||||
import bisq.core.btc.wallet.WalletsSetup;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequest;
|
|
||||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
|
||||||
import bisq.core.dao.vote.CompensationRequestVoteItem;
|
|
||||||
import bisq.core.dao.vote.CompensationRequestVoteItemCollection;
|
|
||||||
import bisq.core.dao.vote.VoteItem;
|
|
||||||
import bisq.core.dao.vote.VoteItemsList;
|
|
||||||
import bisq.core.dao.vote.VotingManager;
|
|
||||||
import bisq.core.provider.fee.FeeService;
|
|
||||||
import bisq.core.util.CoinUtil;
|
|
||||||
|
|
||||||
import bisq.network.p2p.P2PService;
|
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
|
||||||
import bisq.common.locale.Res;
|
|
||||||
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
import org.bitcoinj.core.InsufficientMoneyException;
|
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.ComboBox;
|
|
||||||
import javafx.scene.control.SingleSelectionModel;
|
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
|
|
||||||
import javafx.beans.property.DoubleProperty;
|
|
||||||
import javafx.beans.property.SimpleDoubleProperty;
|
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
|
|
||||||
import javafx.util.StringConverter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addLabelComboBox;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
import static javafx.beans.binding.Bindings.createBooleanBinding;
|
|
||||||
|
|
||||||
@FxmlView
|
@FxmlView
|
||||||
public class VoteView extends ActivatableView<GridPane, Void> {
|
public class VoteView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
private ComboBox<VoteItem> parametersComboBox;
|
|
||||||
private ComboBox<CompensationRequestVoteItem> compensationRequestsComboBox;
|
|
||||||
|
|
||||||
private int gridRow = 0;
|
|
||||||
private final CompensationRequestManager compensationRequestManager;
|
|
||||||
private final BsqWalletService bsqWalletService;
|
|
||||||
private final BtcWalletService btcWalletService;
|
|
||||||
private final WalletsSetup walletsSetup;
|
|
||||||
private final P2PService p2PService;
|
|
||||||
private final FeeService feeService;
|
|
||||||
private final BsqFormatter bsqFormatter;
|
|
||||||
private final BSFormatter btcFormatter;
|
|
||||||
private final VotingManager voteManager;
|
|
||||||
private Button voteButton;
|
|
||||||
private List<CompensationRequest> compensationRequests;
|
|
||||||
private TitledGroupBg compensationRequestsTitledGroupBg, parametersTitledGroupBg;
|
|
||||||
private VoteItemsList voteItemsList;
|
|
||||||
private VBox parametersVBox, compensationRequestsVBox;
|
|
||||||
private final DoubleProperty parametersLabelWidth = new SimpleDoubleProperty();
|
|
||||||
private final DoubleProperty compensationRequestsLabelWidth = new SimpleDoubleProperty();
|
|
||||||
private ChangeListener<Number> numberChangeListener;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor, lifecycle
|
// Constructor, lifecycle
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private VoteView(CompensationRequestManager compensationRequestManager,
|
private VoteView() {
|
||||||
BsqWalletService bsqWalletService,
|
|
||||||
BtcWalletService btcWalletService,
|
|
||||||
WalletsSetup walletsSetup,
|
|
||||||
P2PService p2PService,
|
|
||||||
FeeService feeService,
|
|
||||||
BsqFormatter bsqFormatter,
|
|
||||||
BSFormatter btcFormatter,
|
|
||||||
VotingManager voteManager) {
|
|
||||||
this.compensationRequestManager = compensationRequestManager;
|
|
||||||
this.bsqWalletService = bsqWalletService;
|
|
||||||
this.btcWalletService = btcWalletService;
|
|
||||||
this.walletsSetup = walletsSetup;
|
|
||||||
this.p2PService = p2PService;
|
|
||||||
this.feeService = feeService;
|
|
||||||
this.bsqFormatter = bsqFormatter;
|
|
||||||
this.btcFormatter = btcFormatter;
|
|
||||||
this.voteManager = voteManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
addTitledGroupBg(root, gridRow, 2, Res.get("dao.voting.addItems"));
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
compensationRequestsComboBox = addLabelComboBox(root, gridRow, "", Layout.FIRST_ROW_DISTANCE).second;
|
|
||||||
compensationRequestsComboBox.setPromptText(Res.get("dao.voting.addRequest"));
|
|
||||||
compensationRequestsComboBox.setConverter(new StringConverter<CompensationRequestVoteItem>() {
|
|
||||||
@Override
|
|
||||||
public String toString(CompensationRequestVoteItem item) {
|
|
||||||
return item.compensationRequest.getPayload().getUid();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompensationRequestVoteItem fromString(String s) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
compensationRequestsComboBox.setOnAction(event -> {
|
|
||||||
SingleSelectionModel<CompensationRequestVoteItem> selectionModel = compensationRequestsComboBox.getSelectionModel();
|
|
||||||
CompensationRequestVoteItem selectedItem = selectionModel.getSelectedItem();
|
|
||||||
if (selectedItem != null) {
|
|
||||||
if (!CompensationViewItem.contains(selectedItem)) {
|
|
||||||
CompensationViewItem.attach(selectedItem,
|
|
||||||
bsqWalletService,
|
|
||||||
compensationRequestsVBox,
|
|
||||||
compensationRequestsLabelWidth,
|
|
||||||
bsqFormatter,
|
|
||||||
() -> compensationRequestsTitledGroupBg.setManaged(!CompensationViewItem.isEmpty()));
|
|
||||||
UserThread.execute(selectionModel::clearSelection);
|
|
||||||
} else {
|
|
||||||
new Popup<>().warning(Res.get("dao.voting.requestAlreadyAdded")).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compensationRequestsTitledGroupBg.setManaged(!CompensationViewItem.isEmpty());
|
|
||||||
});
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
parametersComboBox = addLabelComboBox(root, ++gridRow, "").second;
|
|
||||||
parametersComboBox.setPromptText(Res.get("dao.voting.addParameter"));
|
|
||||||
parametersComboBox.setConverter(new StringConverter<VoteItem>() {
|
|
||||||
@Override
|
|
||||||
public String toString(VoteItem item) {
|
|
||||||
return item.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoteItem fromString(String s) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
parametersComboBox.setOnAction(event -> {
|
|
||||||
SingleSelectionModel<VoteItem> selectionModel = parametersComboBox.getSelectionModel();
|
|
||||||
VoteItem selectedItem = selectionModel.getSelectedItem();
|
|
||||||
if (selectedItem != null) {
|
|
||||||
if (!ParameterViewItem.contains(selectedItem)) {
|
|
||||||
ParameterViewItem.attach(selectedItem, parametersVBox, parametersLabelWidth, voteManager.getVotingDefaultValues(),
|
|
||||||
() -> parametersTitledGroupBg.setManaged(!ParameterViewItem.isEmpty()));
|
|
||||||
UserThread.execute(selectionModel::clearSelection);
|
|
||||||
} else {
|
|
||||||
new Popup<>().warning(Res.get("dao.voting.parameterAlreadyAdded")).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parametersTitledGroupBg.setManaged(!ParameterViewItem.isEmpty());
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
compensationRequestsTitledGroupBg = addTitledGroupBg(root, ++gridRow, 1, Res.get("dao.voting.compensationRequests"), Layout.GROUP_DISTANCE);
|
|
||||||
compensationRequestsTitledGroupBg.setManaged(false);
|
|
||||||
compensationRequestsTitledGroupBg.visibleProperty().bind(compensationRequestsTitledGroupBg.managedProperty());
|
|
||||||
|
|
||||||
compensationRequestsVBox = new VBox();
|
|
||||||
compensationRequestsVBox.setSpacing(5);
|
|
||||||
GridPane.setRowIndex(compensationRequestsVBox, gridRow);
|
|
||||||
GridPane.setColumnSpan(compensationRequestsVBox, 2);
|
|
||||||
GridPane.setMargin(compensationRequestsVBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
|
|
||||||
root.getChildren().add(compensationRequestsVBox);
|
|
||||||
compensationRequestsVBox.managedProperty().bind(compensationRequestsTitledGroupBg.managedProperty());
|
|
||||||
compensationRequestsVBox.visibleProperty().bind(compensationRequestsVBox.managedProperty());
|
|
||||||
|
|
||||||
|
|
||||||
parametersTitledGroupBg = addTitledGroupBg(root, ++gridRow, 1, Res.get("shared.parameters"), Layout.GROUP_DISTANCE);
|
|
||||||
parametersTitledGroupBg.setManaged(false);
|
|
||||||
parametersTitledGroupBg.visibleProperty().bind(parametersTitledGroupBg.managedProperty());
|
|
||||||
|
|
||||||
parametersVBox = new VBox();
|
|
||||||
parametersVBox.setSpacing(5);
|
|
||||||
GridPane.setRowIndex(parametersVBox, gridRow);
|
|
||||||
GridPane.setColumnSpan(parametersVBox, 2);
|
|
||||||
GridPane.setMargin(parametersVBox, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
|
|
||||||
root.getChildren().add(parametersVBox);
|
|
||||||
parametersVBox.managedProperty().bind(parametersTitledGroupBg.managedProperty());
|
|
||||||
parametersVBox.visibleProperty().bind(parametersVBox.managedProperty());
|
|
||||||
|
|
||||||
voteButton = addButtonAfterGroup(root, ++gridRow, Res.get("shared.vote"));
|
|
||||||
voteButton.managedProperty().bind(createBooleanBinding(() -> compensationRequestsTitledGroupBg.isManaged() || parametersTitledGroupBg.isManaged(),
|
|
||||||
compensationRequestsTitledGroupBg.managedProperty(), parametersTitledGroupBg.managedProperty()));
|
|
||||||
voteButton.visibleProperty().bind(voteButton.managedProperty());
|
|
||||||
|
|
||||||
voteButton.setOnAction(event -> {
|
|
||||||
// TODO break up in methods
|
|
||||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
|
||||||
log.info(voteItemsList.toString());
|
|
||||||
//TODO
|
|
||||||
if (voteItemsList.isMyVote()) {
|
|
||||||
new Popup<>().warning(Res.get("dao.voting.votedAlready")).show();
|
|
||||||
} else if (!voteItemsList.getAllVoteItemList().stream().filter(VoteItem::isHasVoted).findAny().isPresent() &&
|
|
||||||
!voteItemsList.getAllVoteItemList().stream().filter(e -> e instanceof CompensationRequestVoteItemCollection)
|
|
||||||
.filter(e -> ((CompensationRequestVoteItemCollection) e).hasVotedOnAnyItem()).findAny().isPresent()) {
|
|
||||||
new Popup<>().warning(Res.get("dao.voting.notVotedOnAnyEntry")).show();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
byte[] opReturnData = voteManager.calculateOpReturnData(voteItemsList);
|
|
||||||
try {
|
|
||||||
Coin votingTxFee = feeService.getVotingTxFee();
|
|
||||||
Transaction preparedVotingTx = bsqWalletService.getPreparedBurnFeeTx(votingTxFee);
|
|
||||||
Transaction txWithBtcFee = btcWalletService.completePreparedBsqTx(preparedVotingTx, false, opReturnData);
|
|
||||||
Transaction signedTx = bsqWalletService.signTx(txWithBtcFee);
|
|
||||||
Coin miningFee = signedTx.getFee();
|
|
||||||
int txSize = signedTx.bitcoinSerialize().length;
|
|
||||||
new Popup<>().headLine(Res.get("dao.voting.confirmTx"))
|
|
||||||
.confirmation(Res.get("dao.tx.summary",
|
|
||||||
btcFormatter.formatCoinWithCode(votingTxFee),
|
|
||||||
btcFormatter.formatCoinWithCode(miningFee),
|
|
||||||
CoinUtil.getFeePerByte(miningFee, txSize),
|
|
||||||
(txSize / 1000d)))
|
|
||||||
.actionButtonText(Res.get("shared.yes"))
|
|
||||||
.onAction(() -> {
|
|
||||||
bsqWalletService.commitTx(txWithBtcFee);
|
|
||||||
// We need to create another instance, otherwise the tx would trigger an invalid state exception
|
|
||||||
// if it gets committed 2 times
|
|
||||||
btcWalletService.commitTx(btcWalletService.getClonedTransaction(txWithBtcFee));
|
|
||||||
|
|
||||||
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable Transaction transaction) {
|
|
||||||
checkNotNull(transaction, "Transaction must not be null at doSend callback.");
|
|
||||||
log.error("tx successful published" + transaction.getHashAsString());
|
|
||||||
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
|
||||||
voteItemsList.setIsMyVote(true);
|
|
||||||
|
|
||||||
//TODO send to P2P network
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NotNull Throwable t) {
|
|
||||||
new Popup<>().warning(t.toString()).show();
|
|
||||||
}
|
|
||||||
}, 15);
|
|
||||||
})
|
|
||||||
.closeButtonText(Res.get("shared.cancel"))
|
|
||||||
.show();
|
|
||||||
} catch (InsufficientMoneyException | WalletException | TransactionVerificationException e) {
|
|
||||||
log.error(e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
new Popup<>().warning(e.toString()).show();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
new Popup<>().error(e.toString()).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
//TODO rename
|
|
||||||
voteItemsList = voteManager.getActiveVoteItemsList();
|
|
||||||
//noinspection StatementWithEmptyBody
|
|
||||||
if (voteItemsList != null) {
|
|
||||||
CompensationRequestVoteItemCollection compensationRequestVoteItemCollection = voteItemsList.getCompensationRequestVoteItemCollection();
|
|
||||||
ObservableList<CompensationRequestVoteItem> compensationRequestVoteItems = FXCollections.observableArrayList(compensationRequestVoteItemCollection.getCompensationRequestVoteItems());
|
|
||||||
compensationRequestsComboBox.setItems(compensationRequestVoteItems);
|
|
||||||
|
|
||||||
//TODO move to voteManager.getCurrentVoteItemsList()?
|
|
||||||
compensationRequestManager.getActiveRequests().stream().forEach(e -> compensationRequestVoteItems.add(new CompensationRequestVoteItem(e)));
|
|
||||||
|
|
||||||
parametersComboBox.setItems(FXCollections.observableArrayList(voteItemsList.getVoteItemList()));
|
|
||||||
} else {
|
|
||||||
//TODO add listener
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
compensationRequestsComboBox.setOnAction(null);
|
|
||||||
parametersComboBox.setOnAction(null);
|
|
||||||
voteButton.setOnAction(null);
|
|
||||||
ParameterViewItem.cleanupAllInstances();
|
|
||||||
CompensationViewItem.cleanupAllInstances();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ class TransactionsListItem {
|
|||||||
//
|
//
|
||||||
final Optional<TxType> txTypeOptional = bsqBlockChain.getTxType(txId);
|
final Optional<TxType> txTypeOptional = bsqBlockChain.getTxType(txId);
|
||||||
if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST))
|
if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST))
|
||||||
details = Res.get("funds.tx.compRequest");
|
details = Res.get("funds.tx.proposal");
|
||||||
} else {
|
} else {
|
||||||
outgoing = true;
|
outgoing = true;
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of Bisq.
|
* This file is part of Bisq.
|
||||||
*
|
*
|
||||||
* bisq is free software: you can redistribute it and/or modify it
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
* your option) any later version.
|
* your option) any later version.
|
||||||
*
|
*
|
||||||
* bisq is distributed in the hope that it will be useful, but WITHOUT
|
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
* License for more details.
|
* License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with bisq. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import bisq.desktop.components.AutoTooltipLabel;
|
|||||||
import bisq.desktop.components.BusyAnimation;
|
import bisq.desktop.components.BusyAnimation;
|
||||||
import bisq.desktop.main.overlays.Overlay;
|
import bisq.desktop.main.overlays.Overlay;
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.VerifyDescriptor;
|
|
||||||
|
|
||||||
import bisq.core.alert.Alert;
|
import bisq.core.alert.Alert;
|
||||||
|
|
||||||
@ -237,9 +236,9 @@ public class DisplayUpdateDownloadWindow extends Overlay<DisplayUpdateDownloadWi
|
|||||||
statusLabel.setText("");
|
statusLabel.setText("");
|
||||||
stopAnimations();
|
stopAnimations();
|
||||||
|
|
||||||
List<VerifyDescriptor> verifyResults = verifyTask.getValue();
|
List<BisqInstaller.VerifyDescriptor> verifyResults = verifyTask.getValue();
|
||||||
// check that there are no failed verifications
|
// check that there are no failed verifications
|
||||||
Optional<VerifyDescriptor> verifyFailed = verifyResults.stream()
|
Optional<BisqInstaller.VerifyDescriptor> verifyFailed = verifyResults.stream()
|
||||||
.filter(verifyDescriptor -> !BisqInstaller.VerifyStatusEnum.OK.equals(verifyDescriptor.getVerifyStatusEnum())).findFirst();
|
.filter(verifyDescriptor -> !BisqInstaller.VerifyStatusEnum.OK.equals(verifyDescriptor.getVerifyStatusEnum())).findFirst();
|
||||||
if (verifyResults == null || verifyResults.isEmpty() || verifyFailed.isPresent()) {
|
if (verifyResults == null || verifyResults.isEmpty() || verifyFailed.isPresent()) {
|
||||||
showErrorMessage(downloadButton, statusLabel, Res.get("displayUpdateDownloadWindow.verify.failed"));
|
showErrorMessage(downloadButton, statusLabel, Res.get("displayUpdateDownloadWindow.verify.failed"));
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
package bisq.desktop.main.overlays.windows.downloadupdate;
|
package bisq.desktop.main.overlays.windows.downloadupdate;
|
||||||
|
|
||||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.FileDescriptor;
|
|
||||||
|
|
||||||
import bisq.common.storage.FileUtil;
|
import bisq.common.storage.FileUtil;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
@ -46,25 +44,25 @@ import javafx.concurrent.Task;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Getter
|
@Getter
|
||||||
public class DownloadTask extends Task<List<FileDescriptor>> {
|
public class DownloadTask extends Task<List<BisqInstaller.FileDescriptor>> {
|
||||||
private static final int EOF = -1;
|
private static final int EOF = -1;
|
||||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||||
private String fileName = null;
|
private String fileName = null;
|
||||||
private final List<FileDescriptor> fileDescriptors;
|
private final List<BisqInstaller.FileDescriptor> fileDescriptors;
|
||||||
private final String saveDir;
|
private final String saveDir;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares a task to download a file from {@code fileDescriptors} to the system's download dir.
|
* Prepares a task to download a file from {@code fileDescriptors} to the system's download dir.
|
||||||
*/
|
*/
|
||||||
public DownloadTask(final FileDescriptor fileDescriptor) {
|
public DownloadTask(final BisqInstaller.FileDescriptor fileDescriptor) {
|
||||||
this(Lists.newArrayList(fileDescriptor));
|
this(Lists.newArrayList(fileDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadTask(final FileDescriptor fileDescriptor, final String saveDir) {
|
public DownloadTask(final BisqInstaller.FileDescriptor fileDescriptor, final String saveDir) {
|
||||||
this(Lists.newArrayList(fileDescriptor), saveDir);
|
this(Lists.newArrayList(fileDescriptor), saveDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadTask(final List<FileDescriptor> fileDescriptors) {
|
public DownloadTask(final List<BisqInstaller.FileDescriptor> fileDescriptors) {
|
||||||
this(Lists.newArrayList(fileDescriptors), System.getProperty("java.io.tmpdir"));
|
this(Lists.newArrayList(fileDescriptors), System.getProperty("java.io.tmpdir"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +72,7 @@ public class DownloadTask extends Task<List<FileDescriptor>> {
|
|||||||
* @param fileDescriptors HTTP URL of the file to be downloaded
|
* @param fileDescriptors HTTP URL of the file to be downloaded
|
||||||
* @param saveDir path of the directory to save the file
|
* @param saveDir path of the directory to save the file
|
||||||
*/
|
*/
|
||||||
public DownloadTask(final List<FileDescriptor> fileDescriptors, final String saveDir) {
|
public DownloadTask(final List<BisqInstaller.FileDescriptor> fileDescriptors, final String saveDir) {
|
||||||
super();
|
super();
|
||||||
this.fileDescriptors = fileDescriptors;
|
this.fileDescriptors = fileDescriptors;
|
||||||
this.saveDir = saveDir;
|
this.saveDir = saveDir;
|
||||||
@ -88,7 +86,7 @@ public class DownloadTask extends Task<List<FileDescriptor>> {
|
|||||||
* @throws IOException Forwarded exceotions from HttpURLConnection and file handling methods
|
* @throws IOException Forwarded exceotions from HttpURLConnection and file handling methods
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<FileDescriptor> call() throws IOException {
|
protected List<BisqInstaller.FileDescriptor> call() throws IOException {
|
||||||
log.debug("DownloadTask started...");
|
log.debug("DownloadTask started...");
|
||||||
|
|
||||||
String partialSaveFilePath = saveDir + (saveDir.endsWith(File.separator) ? "" : File.separator);
|
String partialSaveFilePath = saveDir + (saveDir.endsWith(File.separator) ? "" : File.separator);
|
||||||
|
@ -21,10 +21,6 @@ package bisq.desktop.main.overlays.windows.downloadupdate;
|
|||||||
* A Task to verify the downloaded bisq installer against the available keys/signatures.
|
* A Task to verify the downloaded bisq installer against the available keys/signatures.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.DownloadType;
|
|
||||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.FileDescriptor;
|
|
||||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.VerifyDescriptor;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
@ -44,15 +40,15 @@ import javafx.concurrent.Task;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Getter
|
@Getter
|
||||||
public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
public class VerifyTask extends Task<List<BisqInstaller.VerifyDescriptor>> {
|
||||||
private final List<FileDescriptor> fileDescriptors;
|
private final List<BisqInstaller.FileDescriptor> fileDescriptors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares a task to download a file from {@code fileDescriptors} to {@code saveDir}.
|
* Prepares a task to download a file from {@code fileDescriptors} to {@code saveDir}.
|
||||||
*
|
*
|
||||||
* @param fileDescriptors HTTP URL of the file to be downloaded
|
* @param fileDescriptors HTTP URL of the file to be downloaded
|
||||||
*/
|
*/
|
||||||
public VerifyTask(final List<FileDescriptor> fileDescriptors) {
|
public VerifyTask(final List<BisqInstaller.FileDescriptor> fileDescriptors) {
|
||||||
super();
|
super();
|
||||||
this.fileDescriptors = fileDescriptors;
|
this.fileDescriptors = fileDescriptors;
|
||||||
log.info("Starting VerifyTask with files:{}", fileDescriptors);
|
log.info("Starting VerifyTask with files:{}", fileDescriptors);
|
||||||
@ -65,23 +61,23 @@ public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
|||||||
* @throws IOException Forwarded exceotions from HttpURLConnection and file handling methods
|
* @throws IOException Forwarded exceotions from HttpURLConnection and file handling methods
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<VerifyDescriptor> call() throws IOException {
|
protected List<BisqInstaller.VerifyDescriptor> call() throws IOException {
|
||||||
log.debug("VerifyTask started...");
|
log.debug("VerifyTask started...");
|
||||||
Optional<FileDescriptor> installer = fileDescriptors.stream()
|
Optional<BisqInstaller.FileDescriptor> installer = fileDescriptors.stream()
|
||||||
.filter(fileDescriptor -> DownloadType.INSTALLER.equals(fileDescriptor.getType()))
|
.filter(fileDescriptor -> BisqInstaller.DownloadType.INSTALLER.equals(fileDescriptor.getType()))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (!installer.isPresent()) {
|
if (!installer.isPresent()) {
|
||||||
log.error("No installer file found.");
|
log.error("No installer file found.");
|
||||||
return Lists.newArrayList();
|
return Lists.newArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<FileDescriptor> signingKeyOptional = fileDescriptors.stream()
|
Optional<BisqInstaller.FileDescriptor> signingKeyOptional = fileDescriptors.stream()
|
||||||
.filter(fileDescriptor -> DownloadType.SIGNING_KEY.equals(fileDescriptor.getType()))
|
.filter(fileDescriptor -> BisqInstaller.DownloadType.SIGNING_KEY.equals(fileDescriptor.getType()))
|
||||||
.findAny();
|
.findAny();
|
||||||
|
|
||||||
List<VerifyDescriptor> verifyDescriptors = Lists.newArrayList();
|
List<BisqInstaller.VerifyDescriptor> verifyDescriptors = Lists.newArrayList();
|
||||||
if (signingKeyOptional.isPresent()) {
|
if (signingKeyOptional.isPresent()) {
|
||||||
final FileDescriptor signingKeyFD = signingKeyOptional.get();
|
final BisqInstaller.FileDescriptor signingKeyFD = signingKeyOptional.get();
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
Scanner scanner = new Scanner(new FileReader(signingKeyFD.getSaveFile()));
|
Scanner scanner = new Scanner(new FileReader(signingKeyFD.getSaveFile()));
|
||||||
@ -92,27 +88,27 @@ public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error(e.toString());
|
log.error(e.toString());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder();
|
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder();
|
||||||
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
||||||
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
||||||
return verifyDescriptors;
|
return verifyDescriptors;
|
||||||
}
|
}
|
||||||
String signingKey = sb.toString();
|
String signingKey = sb.toString();
|
||||||
|
|
||||||
List<FileDescriptor> sigs = fileDescriptors.stream()
|
List<BisqInstaller.FileDescriptor> sigs = fileDescriptors.stream()
|
||||||
.filter(fileDescriptor -> DownloadType.SIG.equals(fileDescriptor.getType()))
|
.filter(fileDescriptor -> BisqInstaller.DownloadType.SIG.equals(fileDescriptor.getType()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// iterate all signatures available to us
|
// iterate all signatures available to us
|
||||||
for (FileDescriptor sig : sigs) {
|
for (BisqInstaller.FileDescriptor sig : sigs) {
|
||||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder().sigFile(sig.getSaveFile());
|
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder().sigFile(sig.getSaveFile());
|
||||||
// Sigs are linked to keys, extract all keys which have the same id
|
// Sigs are linked to keys, extract all keys which have the same id
|
||||||
List<FileDescriptor> keys = fileDescriptors.stream()
|
List<BisqInstaller.FileDescriptor> keys = fileDescriptors.stream()
|
||||||
.filter(keyDescriptor -> DownloadType.KEY.equals(keyDescriptor.getType()))
|
.filter(keyDescriptor -> BisqInstaller.DownloadType.KEY.equals(keyDescriptor.getType()))
|
||||||
.filter(keyDescriptor -> sig.getId().equals(keyDescriptor.getId()))
|
.filter(keyDescriptor -> sig.getId().equals(keyDescriptor.getId()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// iterate all keys which have the same id
|
// iterate all keys which have the same id
|
||||||
for (FileDescriptor key : keys) {
|
for (BisqInstaller.FileDescriptor key : keys) {
|
||||||
if (signingKey.equals(key.getId())) {
|
if (signingKey.equals(key.getId())) {
|
||||||
verifyDescriptorBuilder.keyFile(key.getSaveFile());
|
verifyDescriptorBuilder.keyFile(key.getSaveFile());
|
||||||
try {
|
try {
|
||||||
@ -133,7 +129,7 @@ public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("signingKey is not found");
|
log.error("signingKey is not found");
|
||||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder();
|
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder();
|
||||||
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
||||||
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
|
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
if (button == null) {
|
if (button == null) {
|
||||||
iconView.setId("image-remove");
|
|
||||||
button = new AutoTooltipButton(Res.get("shared.remove"));
|
button = new AutoTooltipButton(Res.get("shared.remove"));
|
||||||
button.setMinWidth(70);
|
button.setMinWidth(70);
|
||||||
iconView.setId("image-remove");
|
iconView.setId("image-remove");
|
||||||
|
@ -20,9 +20,11 @@ package bisq.desktop.main.portfolio.pendingtrades.steps;
|
|||||||
import bisq.desktop.components.InfoTextField;
|
import bisq.desktop.components.InfoTextField;
|
||||||
import bisq.desktop.components.TitledGroupBg;
|
import bisq.desktop.components.TitledGroupBg;
|
||||||
import bisq.desktop.components.TxIdTextField;
|
import bisq.desktop.components.TxIdTextField;
|
||||||
|
import bisq.desktop.components.paymentmethods.PaymentMethodForm;
|
||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.TradeSubView;
|
import bisq.desktop.main.portfolio.pendingtrades.TradeSubView;
|
||||||
|
import bisq.desktop.util.FormBuilder;
|
||||||
import bisq.desktop.util.Layout;
|
import bisq.desktop.util.Layout;
|
||||||
|
|
||||||
import bisq.core.arbitration.Dispute;
|
import bisq.core.arbitration.Dispute;
|
||||||
@ -55,8 +57,6 @@ import java.util.Optional;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static bisq.desktop.components.paymentmethods.PaymentMethodForm.addOpenTradeDuration;
|
|
||||||
import static bisq.desktop.util.FormBuilder.*;
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
public abstract class TradeStepView extends AnchorPane {
|
public abstract class TradeStepView extends AnchorPane {
|
||||||
@ -89,7 +89,7 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
trade = model.dataModel.getTrade();
|
trade = model.dataModel.getTrade();
|
||||||
checkNotNull(trade, "trade must not be null at TradeStepView");
|
checkNotNull(trade, "trade must not be null at TradeStepView");
|
||||||
|
|
||||||
gridPane = addGridPane(this);
|
gridPane = FormBuilder.addGridPane(this);
|
||||||
|
|
||||||
AnchorPane.setLeftAnchor(this, 0d);
|
AnchorPane.setLeftAnchor(this, 0d);
|
||||||
AnchorPane.setRightAnchor(this, 0d);
|
AnchorPane.setRightAnchor(this, 0d);
|
||||||
@ -180,8 +180,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addTradeInfoBlock() {
|
protected void addTradeInfoBlock() {
|
||||||
tradeInfoTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, Res.get("portfolio.pending.tradeInformation"));
|
tradeInfoTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, gridRow, 4, Res.get("portfolio.pending.tradeInformation"));
|
||||||
txIdTextField = addLabelTxIdTextField(gridPane, gridRow, Res.getWithCol("shared.depositTransactionId"), Layout.FIRST_ROW_DISTANCE).second;
|
txIdTextField = FormBuilder.addLabelTxIdTextField(gridPane, gridRow, Res.getWithCol("shared.depositTransactionId"), Layout.FIRST_ROW_DISTANCE).second;
|
||||||
String id = model.dataModel.txId.get();
|
String id = model.dataModel.txId.get();
|
||||||
if (!id.isEmpty())
|
if (!id.isEmpty())
|
||||||
txIdTextField.setup(id);
|
txIdTextField.setup(id);
|
||||||
@ -189,11 +189,11 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
txIdTextField.cleanup();
|
txIdTextField.cleanup();
|
||||||
|
|
||||||
if (model.dataModel.getTrade() != null) {
|
if (model.dataModel.getTrade() != null) {
|
||||||
InfoTextField infoTextField = addOpenTradeDuration(gridPane, ++gridRow, model.dataModel.getTrade().getOffer());
|
InfoTextField infoTextField = PaymentMethodForm.addOpenTradeDuration(gridPane, ++gridRow, model.dataModel.getTrade().getOffer());
|
||||||
infoTextField.setContentForInfoPopOver(createInfoPopover());
|
infoTextField.setContentForInfoPopOver(createInfoPopover());
|
||||||
}
|
}
|
||||||
|
|
||||||
timeLeftTextField = addLabelTextField(gridPane, ++gridRow, Res.getWithCol("portfolio.pending.remainingTime")).second;
|
timeLeftTextField = FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.getWithCol("portfolio.pending.remainingTime")).second;
|
||||||
|
|
||||||
timeLeftProgressBar = new ProgressBar(0);
|
timeLeftProgressBar = new ProgressBar(0);
|
||||||
timeLeftProgressBar.setOpacity(0.7);
|
timeLeftProgressBar.setOpacity(0.7);
|
||||||
@ -210,8 +210,8 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addInfoBlock() {
|
protected void addInfoBlock() {
|
||||||
addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE);
|
FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE);
|
||||||
addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
FormBuilder.addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getInfoText() {
|
protected String getInfoText() {
|
||||||
@ -446,7 +446,7 @@ public abstract class TradeStepView extends AnchorPane {
|
|||||||
infoGridPane.setHgap(5);
|
infoGridPane.setHgap(5);
|
||||||
infoGridPane.setVgap(10);
|
infoGridPane.setVgap(10);
|
||||||
infoGridPane.setPadding(new Insets(10, 10, 10, 10));
|
infoGridPane.setPadding(new Insets(10, 10, 10, 10));
|
||||||
Label label = addMultilineLabel(infoGridPane, rowIndex++, Res.get("portfolio.pending.tradePeriodInfo"));
|
Label label = FormBuilder.addMultilineLabel(infoGridPane, rowIndex++, Res.get("portfolio.pending.tradePeriodInfo"));
|
||||||
label.setMaxWidth(450);
|
label.setMaxWidth(450);
|
||||||
|
|
||||||
HBox warningBox = new HBox();
|
HBox warningBox = new HBox();
|
||||||
|
@ -45,6 +45,7 @@ import bisq.desktop.components.paymentmethods.WesternUnionForm;
|
|||||||
import bisq.desktop.main.overlays.popups.Popup;
|
import bisq.desktop.main.overlays.popups.Popup;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
|
import bisq.desktop.util.FormBuilder;
|
||||||
import bisq.desktop.util.Layout;
|
import bisq.desktop.util.Layout;
|
||||||
|
|
||||||
import bisq.core.payment.payload.CashDepositAccountPayload;
|
import bisq.core.payment.payload.CashDepositAccountPayload;
|
||||||
@ -70,10 +71,6 @@ import javafx.scene.layout.GridPane;
|
|||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addLabelTextFieldWithCopyIcon;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|
||||||
|
|
||||||
public class BuyerStep2View extends TradeStepView {
|
public class BuyerStep2View extends TradeStepView {
|
||||||
|
|
||||||
private Button confirmButton;
|
private Button confirmButton;
|
||||||
@ -175,10 +172,10 @@ public class BuyerStep2View extends TradeStepView {
|
|||||||
|
|
||||||
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
|
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
|
||||||
String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "";
|
String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "";
|
||||||
TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1,
|
TitledGroupBg accountTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1,
|
||||||
Res.get("portfolio.pending.step2_buyer.startPaymentUsing", Res.get(paymentMethodId)),
|
Res.get("portfolio.pending.step2_buyer.startPaymentUsing", Res.get(paymentMethodId)),
|
||||||
Layout.GROUP_DISTANCE);
|
Layout.GROUP_DISTANCE);
|
||||||
TextFieldWithCopyIcon field = addLabelTextFieldWithCopyIcon(gridPane, gridRow, Res.get("portfolio.pending.step2_buyer.amountToTransfer"),
|
TextFieldWithCopyIcon field = FormBuilder.addLabelTextFieldWithCopyIcon(gridPane, gridRow, Res.get("portfolio.pending.step2_buyer.amountToTransfer"),
|
||||||
model.getFiatVolume(),
|
model.getFiatVolume(),
|
||||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||||
field.setCopyWithoutCurrencyPostFix(true);
|
field.setCopyWithoutCurrencyPostFix(true);
|
||||||
@ -257,12 +254,12 @@ public class BuyerStep2View extends TradeStepView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload))
|
if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload))
|
||||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
FormBuilder.addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
||||||
Res.getWithCol("shared.reasonForPayment"), model.dataModel.getReference());
|
Res.getWithCol("shared.reasonForPayment"), model.dataModel.getReference());
|
||||||
|
|
||||||
GridPane.setRowSpan(accountTitledGroupBg, gridRow - 3);
|
GridPane.setRowSpan(accountTitledGroupBg, gridRow - 3);
|
||||||
|
|
||||||
Tuple3<Button, BusyAnimation, Label> tuple3 = addButtonBusyAnimationLabelAfterGroup(gridPane, ++gridRow,
|
Tuple3<Button, BusyAnimation, Label> tuple3 = FormBuilder.addButtonBusyAnimationLabelAfterGroup(gridPane, ++gridRow,
|
||||||
Res.get("portfolio.pending.step2_buyer.paymentStarted"));
|
Res.get("portfolio.pending.step2_buyer.paymentStarted"));
|
||||||
confirmButton = tuple3.first;
|
confirmButton = tuple3.first;
|
||||||
confirmButton.setOnAction(e -> onPaymentStarted());
|
confirmButton.setOnAction(e -> onPaymentStarted());
|
||||||
|
@ -29,6 +29,7 @@ import bisq.desktop.main.portfolio.closedtrades.ClosedTradesView;
|
|||||||
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||||
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||||
import bisq.desktop.util.BSFormatter;
|
import bisq.desktop.util.BSFormatter;
|
||||||
|
import bisq.desktop.util.FormBuilder;
|
||||||
import bisq.desktop.util.Layout;
|
import bisq.desktop.util.Layout;
|
||||||
import bisq.desktop.util.validation.BtcAddressValidator;
|
import bisq.desktop.util.validation.BtcAddressValidator;
|
||||||
|
|
||||||
@ -63,10 +64,6 @@ import org.spongycastle.crypto.params.KeyParameter;
|
|||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static bisq.desktop.util.FormBuilder.addLabelInputTextField;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addLabelTextField;
|
|
||||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
|
||||||
|
|
||||||
public class BuyerStep4View extends TradeStepView {
|
public class BuyerStep4View extends TradeStepView {
|
||||||
// private final ChangeListener<Boolean> focusedPropertyListener;
|
// private final ChangeListener<Boolean> focusedPropertyListener;
|
||||||
|
|
||||||
@ -126,19 +123,19 @@ public class BuyerStep4View extends TradeStepView {
|
|||||||
@SuppressWarnings("PointlessBooleanExpression")
|
@SuppressWarnings("PointlessBooleanExpression")
|
||||||
@Override
|
@Override
|
||||||
protected void addContent() {
|
protected void addContent() {
|
||||||
addTitledGroupBg(gridPane, gridRow, 5, Res.get("portfolio.pending.step5_buyer.groupTitle"), 0);
|
FormBuilder.addTitledGroupBg(gridPane, gridRow, 5, Res.get("portfolio.pending.step5_buyer.groupTitle"), 0);
|
||||||
addLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.FIRST_ROW_DISTANCE);
|
FormBuilder.addLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.FIRST_ROW_DISTANCE);
|
||||||
|
|
||||||
addLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
|
FormBuilder.addLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
|
||||||
addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
|
FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
|
||||||
addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.tradeFee"), model.getTradeFee());
|
FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.tradeFee"), model.getTradeFee());
|
||||||
final String miningFee = model.dataModel.isMaker() ?
|
final String miningFee = model.dataModel.isMaker() ?
|
||||||
Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
|
Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
|
||||||
Res.get("portfolio.pending.step5_buyer.takersMiningFee");
|
Res.get("portfolio.pending.step5_buyer.takersMiningFee");
|
||||||
addLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
FormBuilder.addLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
||||||
withdrawTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("portfolio.pending.step5_buyer.withdrawBTC"), Layout.GROUP_DISTANCE);
|
withdrawTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("portfolio.pending.step5_buyer.withdrawBTC"), Layout.GROUP_DISTANCE);
|
||||||
addLabelTextField(gridPane, gridRow, Res.get("portfolio.pending.step5_buyer.amount"), model.getPayoutAmount(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
FormBuilder.addLabelTextField(gridPane, gridRow, Res.get("portfolio.pending.step5_buyer.amount"), model.getPayoutAmount(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||||
final Tuple2<Label, InputTextField> tuple2 = addLabelInputTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.withdrawToAddress"));
|
final Tuple2<Label, InputTextField> tuple2 = FormBuilder.addLabelInputTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.withdrawToAddress"));
|
||||||
withdrawAddressLabel = tuple2.first;
|
withdrawAddressLabel = tuple2.first;
|
||||||
withdrawAddressLabel.setManaged(false);
|
withdrawAddressLabel.setManaged(false);
|
||||||
withdrawAddressLabel.setVisible(false);
|
withdrawAddressLabel.setVisible(false);
|
||||||
|
@ -42,7 +42,6 @@ import static bisq.common.locale.TradeCurrencyMakers.usd;
|
|||||||
import static bisq.core.user.PreferenceMakers.empty;
|
import static bisq.core.user.PreferenceMakers.empty;
|
||||||
import static bisq.desktop.main.offer.offerbook.OfferBookListItemMaker.btcItem;
|
import static bisq.desktop.main.offer.offerbook.OfferBookListItemMaker.btcItem;
|
||||||
import static bisq.desktop.main.offer.offerbook.OfferBookListItemMaker.btcSellItem;
|
import static bisq.desktop.main.offer.offerbook.OfferBookListItemMaker.btcSellItem;
|
||||||
import static bisq.desktop.main.offer.offerbook.OfferBookListItemMaker.useMarketBasedPrice;
|
|
||||||
import static com.natpryce.makeiteasy.MakeItEasy.make;
|
import static com.natpryce.makeiteasy.MakeItEasy.make;
|
||||||
import static com.natpryce.makeiteasy.MakeItEasy.with;
|
import static com.natpryce.makeiteasy.MakeItEasy.with;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -77,7 +76,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
|
|
||||||
|
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
final OfferBookListItem item = make(btcItem.but(with(useMarketBasedPrice, true)));
|
final OfferBookListItem item = make(OfferBookListItemMaker.btcItem.but(with(OfferBookListItemMaker.useMarketBasedPrice, true)));
|
||||||
item.getOffer().setPriceFeedService(priceFeedService);
|
item.getOffer().setPriceFeedService(priceFeedService);
|
||||||
offerBookListItems.addAll(item);
|
offerBookListItems.addAll(item);
|
||||||
|
|
||||||
@ -95,7 +94,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
PriceFeedService service = mock(PriceFeedService.class);
|
PriceFeedService service = mock(PriceFeedService.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -124,7 +123,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
PriceFeedService service = mock(PriceFeedService.class);
|
PriceFeedService service = mock(PriceFeedService.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
|
|
||||||
|
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
final OfferBookListItem item = make(btcSellItem.but(with(useMarketBasedPrice, true)));
|
final OfferBookListItem item = make(OfferBookListItemMaker.btcSellItem.but(with(OfferBookListItemMaker.useMarketBasedPrice, true)));
|
||||||
item.getOffer().setPriceFeedService(priceFeedService);
|
item.getOffer().setPriceFeedService(priceFeedService);
|
||||||
offerBookListItems.addAll(item);
|
offerBookListItems.addAll(item);
|
||||||
|
|
||||||
@ -173,7 +172,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
PriceFeedService service = mock(PriceFeedService.class);
|
PriceFeedService service = mock(PriceFeedService.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcSellItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcSellItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -202,7 +201,7 @@ public class OfferBookChartViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
PriceFeedService service = mock(PriceFeedService.class);
|
PriceFeedService service = mock(PriceFeedService.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcSellItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcSellItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class SpreadViewModelTest {
|
|||||||
public void testMaxCharactersForAmount() {
|
public void testMaxCharactersForAmount() {
|
||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import bisq.core.offer.OfferMaker;
|
|||||||
import bisq.core.offer.OfferPayload;
|
import bisq.core.offer.OfferPayload;
|
||||||
|
|
||||||
import com.natpryce.makeiteasy.Instantiator;
|
import com.natpryce.makeiteasy.Instantiator;
|
||||||
|
import com.natpryce.makeiteasy.MakeItEasy;
|
||||||
import com.natpryce.makeiteasy.Maker;
|
import com.natpryce.makeiteasy.Maker;
|
||||||
import com.natpryce.makeiteasy.Property;
|
import com.natpryce.makeiteasy.Property;
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ public class OfferBookListItemMaker {
|
|||||||
|
|
||||||
public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup ->
|
public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup ->
|
||||||
new OfferBookListItem(make(btcUsdOffer.but(
|
new OfferBookListItem(make(btcUsdOffer.but(
|
||||||
with(OfferMaker.price, lookup.valueOf(price, 100000L)),
|
MakeItEasy.with(OfferMaker.price, lookup.valueOf(price, 100000L)),
|
||||||
with(OfferMaker.amount, lookup.valueOf(amount, 100000L)),
|
with(OfferMaker.amount, lookup.valueOf(amount, 100000L)),
|
||||||
with(OfferMaker.minAmount, lookup.valueOf(amount, 100000L)),
|
with(OfferMaker.minAmount, lookup.valueOf(amount, 100000L)),
|
||||||
with(OfferMaker.direction, lookup.valueOf(direction, OfferPayload.Direction.BUY)),
|
with(OfferMaker.direction, lookup.valueOf(direction, OfferPayload.Direction.BUY)),
|
||||||
@ -49,7 +50,7 @@ public class OfferBookListItemMaker {
|
|||||||
|
|
||||||
public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup ->
|
public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup ->
|
||||||
new OfferBookListItem(make(btcUsdOffer.but(
|
new OfferBookListItem(make(btcUsdOffer.but(
|
||||||
with(OfferMaker.price, lookup.valueOf(price, 100000L)),
|
MakeItEasy.with(OfferMaker.price, lookup.valueOf(price, 100000L)),
|
||||||
with(OfferMaker.minAmount, lookup.valueOf(minAmount, 100000L)),
|
with(OfferMaker.minAmount, lookup.valueOf(minAmount, 100000L)),
|
||||||
with(OfferMaker.amount, lookup.valueOf(amount, 200000L)))));
|
with(OfferMaker.amount, lookup.valueOf(amount, 200000L)))));
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ public class OfferBookViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ public class OfferBookViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItemWithRange));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItemWithRange));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ public class OfferBookViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ public class OfferBookViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItemWithRange));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItemWithRange));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ public class OfferBookViewModelTest {
|
|||||||
OfferBook offerBook = mock(OfferBook.class);
|
OfferBook offerBook = mock(OfferBook.class);
|
||||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||||
offerBookListItems.addAll(make(btcItem));
|
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||||
|
|
||||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user