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.WalletsSetup;
|
||||
import bisq.core.dao.DaoManager;
|
||||
import bisq.core.dao.request.compensation.CompensationRequestManager;
|
||||
import bisq.core.dao.vote.VotingManager;
|
||||
import bisq.core.dao.proposal.ProposalCollectionsManager;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.trade.TradeManager;
|
||||
@ -228,8 +227,7 @@ public class BisqApp extends Application {
|
||||
persistedDataHosts.add(injector.getInstance(FailedTradesManager.class));
|
||||
persistedDataHosts.add(injector.getInstance(DisputeManager.class));
|
||||
persistedDataHosts.add(injector.getInstance(P2PService.class));
|
||||
persistedDataHosts.add(injector.getInstance(VotingManager.class));
|
||||
persistedDataHosts.add(injector.getInstance(CompensationRequestManager.class));
|
||||
persistedDataHosts.add(injector.getInstance(ProposalCollectionsManager.class));
|
||||
|
||||
// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
|
||||
persistedDataHosts.forEach(e -> {
|
||||
|
@ -25,7 +25,6 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
@ -68,9 +67,9 @@ public class FundsTextField extends InfoTextField {
|
||||
}
|
||||
});
|
||||
|
||||
AnchorPane.setRightAnchor(copyIcon, 30.0);
|
||||
AnchorPane.setRightAnchor(infoIcon, 62.0);
|
||||
AnchorPane.setRightAnchor(textField, 55.0);
|
||||
setRightAnchor(copyIcon, 30.0);
|
||||
setRightAnchor(infoIcon, 62.0);
|
||||
setRightAnchor(textField, 55.0);
|
||||
|
||||
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() {
|
||||
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.setLeftAnchor(startLabel, 0d);
|
||||
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.setRightAnchor(endLabel, 0d);
|
||||
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.ViewLoader;
|
||||
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.wallet.BsqWalletView;
|
||||
import bisq.desktop.main.dao.wallet.dashboard.BsqDashboardView;
|
||||
@ -67,7 +67,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
||||
|
||||
@Override
|
||||
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"));
|
||||
compensationTab.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);
|
||||
} else if (newValue == compensationTab) {
|
||||
//noinspection unchecked
|
||||
navigation.navigateTo(MainView.class, DaoView.class, CompensationView.class);
|
||||
navigation.navigateTo(MainView.class, DaoView.class, ProposalView.class);
|
||||
} else if (newValue == votingTab) {
|
||||
//noinspection unchecked
|
||||
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);
|
||||
else if (selectedItem == compensationTab)
|
||||
//noinspection unchecked
|
||||
navigation.navigateTo(MainView.class, DaoView.class, CompensationView.class);
|
||||
navigation.navigateTo(MainView.class, DaoView.class, ProposalView.class);
|
||||
else if (selectedItem == votingTab)
|
||||
//noinspection unchecked
|
||||
navigation.navigateTo(MainView.class, DaoView.class, VotingView.class);
|
||||
@ -139,7 +139,7 @@ public class DaoView extends ActivatableViewAndModel<TabPane, Activatable> {
|
||||
if (view instanceof BsqWalletView) {
|
||||
selectedTab = bsqWalletTab;
|
||||
bsqWalletView = (BsqWalletView) view;
|
||||
} else if (view instanceof CompensationView) {
|
||||
} else if (view instanceof ProposalView) {
|
||||
selectedTab = compensationTab;
|
||||
} else if (view instanceof VotingView) {
|
||||
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.ColumnConstraints?>
|
||||
<?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"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.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.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 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.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
|
||||
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
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private VoteView(CompensationRequestManager compensationRequestManager,
|
||||
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;
|
||||
private VoteView() {
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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);
|
||||
if (txTypeOptional.isPresent() && txTypeOptional.get().equals(TxType.COMPENSATION_REQUEST))
|
||||
details = Res.get("funds.tx.compRequest");
|
||||
details = Res.get("funds.tx.proposal");
|
||||
} else {
|
||||
outgoing = true;
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* 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/>.
|
||||
* 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.main.overlays.Overlay;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.VerifyDescriptor;
|
||||
|
||||
import bisq.core.alert.Alert;
|
||||
|
||||
@ -237,9 +236,9 @@ public class DisplayUpdateDownloadWindow extends Overlay<DisplayUpdateDownloadWi
|
||||
statusLabel.setText("");
|
||||
stopAnimations();
|
||||
|
||||
List<VerifyDescriptor> verifyResults = verifyTask.getValue();
|
||||
List<BisqInstaller.VerifyDescriptor> verifyResults = verifyTask.getValue();
|
||||
// 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();
|
||||
if (verifyResults == null || verifyResults.isEmpty() || verifyFailed.isPresent()) {
|
||||
showErrorMessage(downloadButton, statusLabel, Res.get("displayUpdateDownloadWindow.verify.failed"));
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
package bisq.desktop.main.overlays.windows.downloadupdate;
|
||||
|
||||
import bisq.desktop.main.overlays.windows.downloadupdate.BisqInstaller.FileDescriptor;
|
||||
|
||||
import bisq.common.storage.FileUtil;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@ -46,25 +44,25 @@ import javafx.concurrent.Task;
|
||||
|
||||
@Slf4j
|
||||
@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 DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||
private String fileName = null;
|
||||
private final List<FileDescriptor> fileDescriptors;
|
||||
private final List<BisqInstaller.FileDescriptor> fileDescriptors;
|
||||
private final String saveDir;
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
public DownloadTask(final FileDescriptor fileDescriptor, final String saveDir) {
|
||||
public DownloadTask(final BisqInstaller.FileDescriptor fileDescriptor, final String 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"));
|
||||
}
|
||||
|
||||
@ -74,7 +72,7 @@ public class DownloadTask extends Task<List<FileDescriptor>> {
|
||||
* @param fileDescriptors HTTP URL of the file to be downloaded
|
||||
* @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();
|
||||
this.fileDescriptors = fileDescriptors;
|
||||
this.saveDir = saveDir;
|
||||
@ -88,7 +86,7 @@ public class DownloadTask extends Task<List<FileDescriptor>> {
|
||||
* @throws IOException Forwarded exceotions from HttpURLConnection and file handling methods
|
||||
*/
|
||||
@Override
|
||||
protected List<FileDescriptor> call() throws IOException {
|
||||
protected List<BisqInstaller.FileDescriptor> call() throws IOException {
|
||||
log.debug("DownloadTask started...");
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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 java.io.FileReader;
|
||||
@ -44,15 +40,15 @@ import javafx.concurrent.Task;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
||||
private final List<FileDescriptor> fileDescriptors;
|
||||
public class VerifyTask extends Task<List<BisqInstaller.VerifyDescriptor>> {
|
||||
private final List<BisqInstaller.FileDescriptor> fileDescriptors;
|
||||
|
||||
/**
|
||||
* Prepares a task to download a file from {@code fileDescriptors} to {@code saveDir}.
|
||||
*
|
||||
* @param fileDescriptors HTTP URL of the file to be downloaded
|
||||
*/
|
||||
public VerifyTask(final List<FileDescriptor> fileDescriptors) {
|
||||
public VerifyTask(final List<BisqInstaller.FileDescriptor> fileDescriptors) {
|
||||
super();
|
||||
this.fileDescriptors = 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
|
||||
*/
|
||||
@Override
|
||||
protected List<VerifyDescriptor> call() throws IOException {
|
||||
protected List<BisqInstaller.VerifyDescriptor> call() throws IOException {
|
||||
log.debug("VerifyTask started...");
|
||||
Optional<FileDescriptor> installer = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> DownloadType.INSTALLER.equals(fileDescriptor.getType()))
|
||||
Optional<BisqInstaller.FileDescriptor> installer = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> BisqInstaller.DownloadType.INSTALLER.equals(fileDescriptor.getType()))
|
||||
.findFirst();
|
||||
if (!installer.isPresent()) {
|
||||
log.error("No installer file found.");
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
Optional<FileDescriptor> signingKeyOptional = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> DownloadType.SIGNING_KEY.equals(fileDescriptor.getType()))
|
||||
Optional<BisqInstaller.FileDescriptor> signingKeyOptional = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> BisqInstaller.DownloadType.SIGNING_KEY.equals(fileDescriptor.getType()))
|
||||
.findAny();
|
||||
|
||||
List<VerifyDescriptor> verifyDescriptors = Lists.newArrayList();
|
||||
List<BisqInstaller.VerifyDescriptor> verifyDescriptors = Lists.newArrayList();
|
||||
if (signingKeyOptional.isPresent()) {
|
||||
final FileDescriptor signingKeyFD = signingKeyOptional.get();
|
||||
final BisqInstaller.FileDescriptor signingKeyFD = signingKeyOptional.get();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
Scanner scanner = new Scanner(new FileReader(signingKeyFD.getSaveFile()));
|
||||
@ -92,27 +88,27 @@ public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
||||
} catch (Exception e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder();
|
||||
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder();
|
||||
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
||||
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
||||
return verifyDescriptors;
|
||||
}
|
||||
String signingKey = sb.toString();
|
||||
|
||||
List<FileDescriptor> sigs = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> DownloadType.SIG.equals(fileDescriptor.getType()))
|
||||
List<BisqInstaller.FileDescriptor> sigs = fileDescriptors.stream()
|
||||
.filter(fileDescriptor -> BisqInstaller.DownloadType.SIG.equals(fileDescriptor.getType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// iterate all signatures available to us
|
||||
for (FileDescriptor sig : sigs) {
|
||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder().sigFile(sig.getSaveFile());
|
||||
for (BisqInstaller.FileDescriptor sig : sigs) {
|
||||
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder().sigFile(sig.getSaveFile());
|
||||
// Sigs are linked to keys, extract all keys which have the same id
|
||||
List<FileDescriptor> keys = fileDescriptors.stream()
|
||||
.filter(keyDescriptor -> DownloadType.KEY.equals(keyDescriptor.getType()))
|
||||
List<BisqInstaller.FileDescriptor> keys = fileDescriptors.stream()
|
||||
.filter(keyDescriptor -> BisqInstaller.DownloadType.KEY.equals(keyDescriptor.getType()))
|
||||
.filter(keyDescriptor -> sig.getId().equals(keyDescriptor.getId()))
|
||||
.collect(Collectors.toList());
|
||||
// iterate all keys which have the same id
|
||||
for (FileDescriptor key : keys) {
|
||||
for (BisqInstaller.FileDescriptor key : keys) {
|
||||
if (signingKey.equals(key.getId())) {
|
||||
verifyDescriptorBuilder.keyFile(key.getSaveFile());
|
||||
try {
|
||||
@ -133,7 +129,7 @@ public class VerifyTask extends Task<List<VerifyDescriptor>> {
|
||||
}
|
||||
} else {
|
||||
log.error("signingKey is not found");
|
||||
VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = VerifyDescriptor.builder();
|
||||
BisqInstaller.VerifyDescriptor.VerifyDescriptorBuilder verifyDescriptorBuilder = BisqInstaller.VerifyDescriptor.builder();
|
||||
verifyDescriptorBuilder.verifyStatusEnum(BisqInstaller.VerifyStatusEnum.FAIL);
|
||||
verifyDescriptors.add(verifyDescriptorBuilder.build());
|
||||
}
|
||||
|
@ -432,7 +432,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
|
||||
if (item != null && !empty) {
|
||||
if (button == null) {
|
||||
iconView.setId("image-remove");
|
||||
button = new AutoTooltipButton(Res.get("shared.remove"));
|
||||
button.setMinWidth(70);
|
||||
iconView.setId("image-remove");
|
||||
|
@ -20,9 +20,11 @@ package bisq.desktop.main.portfolio.pendingtrades.steps;
|
||||
import bisq.desktop.components.InfoTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.components.TxIdTextField;
|
||||
import bisq.desktop.components.paymentmethods.PaymentMethodForm;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
|
||||
import bisq.desktop.main.portfolio.pendingtrades.TradeSubView;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.arbitration.Dispute;
|
||||
@ -55,8 +57,6 @@ import java.util.Optional;
|
||||
import org.slf4j.Logger;
|
||||
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;
|
||||
|
||||
public abstract class TradeStepView extends AnchorPane {
|
||||
@ -89,7 +89,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
trade = model.dataModel.getTrade();
|
||||
checkNotNull(trade, "trade must not be null at TradeStepView");
|
||||
|
||||
gridPane = addGridPane(this);
|
||||
gridPane = FormBuilder.addGridPane(this);
|
||||
|
||||
AnchorPane.setLeftAnchor(this, 0d);
|
||||
AnchorPane.setRightAnchor(this, 0d);
|
||||
@ -180,8 +180,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
}
|
||||
|
||||
protected void addTradeInfoBlock() {
|
||||
tradeInfoTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, Res.get("portfolio.pending.tradeInformation"));
|
||||
txIdTextField = addLabelTxIdTextField(gridPane, gridRow, Res.getWithCol("shared.depositTransactionId"), Layout.FIRST_ROW_DISTANCE).second;
|
||||
tradeInfoTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, gridRow, 4, Res.get("portfolio.pending.tradeInformation"));
|
||||
txIdTextField = FormBuilder.addLabelTxIdTextField(gridPane, gridRow, Res.getWithCol("shared.depositTransactionId"), Layout.FIRST_ROW_DISTANCE).second;
|
||||
String id = model.dataModel.txId.get();
|
||||
if (!id.isEmpty())
|
||||
txIdTextField.setup(id);
|
||||
@ -189,11 +189,11 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
txIdTextField.cleanup();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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.setOpacity(0.7);
|
||||
@ -210,8 +210,8 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
}
|
||||
|
||||
protected void addInfoBlock() {
|
||||
addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE);
|
||||
addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, getInfoBlockTitle(), Layout.GROUP_DISTANCE);
|
||||
FormBuilder.addMultilineLabel(gridPane, gridRow, getInfoText(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
}
|
||||
|
||||
protected String getInfoText() {
|
||||
@ -446,7 +446,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
infoGridPane.setHgap(5);
|
||||
infoGridPane.setVgap(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);
|
||||
|
||||
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.portfolio.pendingtrades.PendingTradesViewModel;
|
||||
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.payment.payload.CashDepositAccountPayload;
|
||||
@ -70,10 +71,6 @@ import javafx.scene.layout.GridPane;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
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 {
|
||||
|
||||
private Button confirmButton;
|
||||
@ -175,10 +172,10 @@ public class BuyerStep2View extends TradeStepView {
|
||||
|
||||
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
|
||||
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)),
|
||||
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(),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
field.setCopyWithoutCurrencyPostFix(true);
|
||||
@ -257,12 +254,12 @@ public class BuyerStep2View extends TradeStepView {
|
||||
}
|
||||
|
||||
if (!(paymentAccountPayload instanceof CryptoCurrencyAccountPayload))
|
||||
addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
||||
FormBuilder.addLabelTextFieldWithCopyIcon(gridPane, ++gridRow,
|
||||
Res.getWithCol("shared.reasonForPayment"), model.dataModel.getReference());
|
||||
|
||||
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"));
|
||||
confirmButton = tuple3.first;
|
||||
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.steps.TradeStepView;
|
||||
import bisq.desktop.util.BSFormatter;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.Layout;
|
||||
import bisq.desktop.util.validation.BtcAddressValidator;
|
||||
|
||||
@ -63,10 +64,6 @@ import org.spongycastle.crypto.params.KeyParameter;
|
||||
|
||||
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 {
|
||||
// private final ChangeListener<Boolean> focusedPropertyListener;
|
||||
|
||||
@ -126,19 +123,19 @@ public class BuyerStep4View extends TradeStepView {
|
||||
@SuppressWarnings("PointlessBooleanExpression")
|
||||
@Override
|
||||
protected void addContent() {
|
||||
addTitledGroupBg(gridPane, gridRow, 5, Res.get("portfolio.pending.step5_buyer.groupTitle"), 0);
|
||||
addLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.FIRST_ROW_DISTANCE);
|
||||
FormBuilder.addTitledGroupBg(gridPane, gridRow, 5, Res.get("portfolio.pending.step5_buyer.groupTitle"), 0);
|
||||
FormBuilder.addLabelTextField(gridPane, gridRow, getBtcTradeAmountLabel(), model.getTradeVolume(), Layout.FIRST_ROW_DISTANCE);
|
||||
|
||||
addLabelTextField(gridPane, ++gridRow, getFiatTradeAmountLabel(), model.getFiatVolume());
|
||||
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, getFiatTradeAmountLabel(), model.getFiatVolume());
|
||||
FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.refunded"), model.getSecurityDeposit());
|
||||
FormBuilder.addLabelTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.tradeFee"), model.getTradeFee());
|
||||
final String miningFee = model.dataModel.isMaker() ?
|
||||
Res.get("portfolio.pending.step5_buyer.makersMiningFee") :
|
||||
Res.get("portfolio.pending.step5_buyer.takersMiningFee");
|
||||
addLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
||||
withdrawTitledGroupBg = 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);
|
||||
final Tuple2<Label, InputTextField> tuple2 = addLabelInputTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.withdrawToAddress"));
|
||||
FormBuilder.addLabelTextField(gridPane, ++gridRow, miningFee, model.getTxFee());
|
||||
withdrawTitledGroupBg = FormBuilder.addTitledGroupBg(gridPane, ++gridRow, 1, Res.get("portfolio.pending.step5_buyer.withdrawBTC"), Layout.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 = FormBuilder.addLabelInputTextField(gridPane, ++gridRow, Res.get("portfolio.pending.step5_buyer.withdrawToAddress"));
|
||||
withdrawAddressLabel = tuple2.first;
|
||||
withdrawAddressLabel.setManaged(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.desktop.main.offer.offerbook.OfferBookListItemMaker.btcItem;
|
||||
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.with;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -77,7 +76,7 @@ public class OfferBookChartViewModelTest {
|
||||
|
||||
|
||||
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);
|
||||
offerBookListItems.addAll(item);
|
||||
|
||||
@ -95,7 +94,7 @@ public class OfferBookChartViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
PriceFeedService service = mock(PriceFeedService.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -124,7 +123,7 @@ public class OfferBookChartViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
PriceFeedService service = mock(PriceFeedService.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -155,7 +154,7 @@ public class OfferBookChartViewModelTest {
|
||||
|
||||
|
||||
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);
|
||||
offerBookListItems.addAll(item);
|
||||
|
||||
@ -173,7 +172,7 @@ public class OfferBookChartViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
PriceFeedService service = mock(PriceFeedService.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcSellItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcSellItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -202,7 +201,7 @@ public class OfferBookChartViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
PriceFeedService service = mock(PriceFeedService.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcSellItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcSellItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class SpreadViewModelTest {
|
||||
public void testMaxCharactersForAmount() {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
|
@ -21,6 +21,7 @@ import bisq.core.offer.OfferMaker;
|
||||
import bisq.core.offer.OfferPayload;
|
||||
|
||||
import com.natpryce.makeiteasy.Instantiator;
|
||||
import com.natpryce.makeiteasy.MakeItEasy;
|
||||
import com.natpryce.makeiteasy.Maker;
|
||||
import com.natpryce.makeiteasy.Property;
|
||||
|
||||
@ -40,7 +41,7 @@ public class OfferBookListItemMaker {
|
||||
|
||||
public static final Instantiator<OfferBookListItem> OfferBookListItem = lookup ->
|
||||
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.minAmount, lookup.valueOf(amount, 100000L)),
|
||||
with(OfferMaker.direction, lookup.valueOf(direction, OfferPayload.Direction.BUY)),
|
||||
@ -49,7 +50,7 @@ public class OfferBookListItemMaker {
|
||||
|
||||
public static final Instantiator<OfferBookListItem> OfferBookListItemWithRange = lookup ->
|
||||
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.amount, lookup.valueOf(amount, 200000L)))));
|
||||
|
||||
|
@ -243,7 +243,7 @@ public class OfferBookViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -262,7 +262,7 @@ public class OfferBookViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItemWithRange));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItemWithRange));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -297,7 +297,7 @@ public class OfferBookViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -316,7 +316,7 @@ public class OfferBookViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItemWithRange));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItemWithRange));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
@ -351,7 +351,7 @@ public class OfferBookViewModelTest {
|
||||
OfferBook offerBook = mock(OfferBook.class);
|
||||
OpenOfferManager openOfferManager = mock(OpenOfferManager.class);
|
||||
final ObservableList<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
offerBookListItems.addAll(make(btcItem));
|
||||
offerBookListItems.addAll(make(OfferBookListItemMaker.btcItem));
|
||||
|
||||
when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user