diff --git a/common/src/main/resources/i18n/displayStrings.properties b/common/src/main/resources/i18n/displayStrings.properties index 2ba3934295..7a1c8c0a65 100644 --- a/common/src/main/resources/i18n/displayStrings.properties +++ b/common/src/main/resources/i18n/displayStrings.properties @@ -1014,9 +1014,9 @@ dao.phase.short.BREAK2= dao.phase.short.VOTE_CONFIRMATION=Result dao.phase.short.BREAK3= +dao.compensation.selectedRequest=Selected compensation request dao.compensation.active.header=Active compensation request -dao.compensation.active.selectedRequest=Selected compensation request dao.compensation.active.notOpenAnymore=This compensation request is not open anymore for funding. Please wait until the next funding period starts. dao.compensation.active.remove=Remove compensation request dao.compensation.active.remove.failed=Could not remove compensation request. @@ -1024,6 +1024,8 @@ dao.compensation.active.vote=Vote on compensation request dao.compensation.active.fund=Fund compensation request dao.compensation.active.successfullyFunded=Compensation request successfully funded. +dao.compensation.past.header=Past compensation request + dao.compensation.create.createNew=Create new compensation request dao.compensation.create.create.button=Create compensation request dao.compensation.create.confirm=Confirm compensation request diff --git a/common/src/main/resources/i18n/displayStrings_de.properties b/common/src/main/resources/i18n/displayStrings_de.properties index 36d7a2eb11..ba344365db 100644 --- a/common/src/main/resources/i18n/displayStrings_de.properties +++ b/common/src/main/resources/i18n/displayStrings_de.properties @@ -876,7 +876,7 @@ dao.compensation.menuItem.activeRequests=Aktive Anfragen dao.compensation.menuItem.pastRequests=Erledigte Anfragen dao.compensation.active.header=Aktive Entschädigungsanfrage -dao.compensation.active.selectedRequest=Ausgewählte Entschädigungsanfrage +dao.compensation.selectedRequest=Ausgewählte Entschädigungsanfrage dao.compensation.active.notOpenAnymore=Diese Entschädigung ist nicht zur Finanzierung verfügbar. Bitte warten Sie bis die nächste Finanzierungsperiode beginnt. dao.compensation.active.vote=Für Entschädigung stimmen dao.compensation.active.fund=Entschädigungsanfrage finanzieren diff --git a/common/src/main/resources/i18n/displayStrings_el.properties b/common/src/main/resources/i18n/displayStrings_el.properties index 6162fc07b1..9f0c7aba7d 100644 --- a/common/src/main/resources/i18n/displayStrings_el.properties +++ b/common/src/main/resources/i18n/displayStrings_el.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=Ενεργά αιτήματα dao.compensation.menuItem.pastRequests=Προηγούμενα αιτήματα dao.compensation.active.header=Ενεργό αίτημα αποζημίωσης -dao.compensation.active.selectedRequest=Επιλεγμένο αίτημα αποζημίωσης +dao.compensation.selectedRequest=Επιλεγμένο αίτημα αποζημίωσης dao.compensation.active.notOpenAnymore=Το αίτημα αποζημίωσης δεν είναι πλέον ανοιχτό προς χρηματοδότηση. Περίμενε μέχρι την έναρξη της επόμενης περιόδου χρηματοδότησης. dao.compensation.active.vote=Ψήφισμα περί αιτήματος αποζημίωσης dao.compensation.active.fund=Χρηματοδότηση αιτήματος αποζημίωσης diff --git a/common/src/main/resources/i18n/displayStrings_es.properties b/common/src/main/resources/i18n/displayStrings_es.properties index 44ba87502a..0aa9d1796d 100644 --- a/common/src/main/resources/i18n/displayStrings_es.properties +++ b/common/src/main/resources/i18n/displayStrings_es.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=Activar solicitudes dao.compensation.menuItem.pastRequests=Solicitudes pasadas dao.compensation.active.header=Activar solicitud de compensación -dao.compensation.active.selectedRequest=Solicitud de compensación seleccionada +dao.compensation.selectedRequest=Solicitud de compensación seleccionada dao.compensation.active.notOpenAnymore=Esta solicitud de compensación ya no está abierta para añadir fondos. Por favor, espere a que comience el siguiente periodo de financiación. dao.compensation.active.vote=Votar solicitud de compensación dao.compensation.active.fund=Financiar solicitud de compensación diff --git a/common/src/main/resources/i18n/displayStrings_hu.properties b/common/src/main/resources/i18n/displayStrings_hu.properties index 4d716770d6..1c62b995d3 100644 --- a/common/src/main/resources/i18n/displayStrings_hu.properties +++ b/common/src/main/resources/i18n/displayStrings_hu.properties @@ -915,7 +915,7 @@ dao.phase.short.BREAK3= dao.compensation.active.header=Aktív kártérítési kérelmek -dao.compensation.active.selectedRequest=Kiválasztott kártérítési kérelmek +dao.compensation.selectedRequest=Kiválasztott kártérítési kérelmek dao.compensation.active.notOpenAnymore=Ez a Kártérítési kérelem többé nem nyílt finanszírozáshoz. Kérjük várjon, amíg megkezdődik a következő finanszírozási időszak. dao.compensation.active.remove=Töröld a kártérítési kérelmet dao.compensation.active.remove.failed=A kártérítési kérelmet nem sikerült eltávolítani. diff --git a/common/src/main/resources/i18n/displayStrings_pt.properties b/common/src/main/resources/i18n/displayStrings_pt.properties index 0c09adeb0a..d5bf44a0f5 100644 --- a/common/src/main/resources/i18n/displayStrings_pt.properties +++ b/common/src/main/resources/i18n/displayStrings_pt.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=Solicitações ativas dao.compensation.menuItem.pastRequests=Solicitações anteriores dao.compensation.active.header=Pedido de compensação ativo -dao.compensation.active.selectedRequest=Pedido de compensação selecionado +dao.compensation.selectedRequest=Pedido de compensação selecionado dao.compensation.active.notOpenAnymore=Este pedido de compensação não está mais aberto para financiamento. Favor aguardar até o próximo período de financiamento iniciar. dao.compensation.active.vote=Votar em pedido de compensação dao.compensation.active.fund=Financiar pedido de compensação diff --git a/common/src/main/resources/i18n/displayStrings_ro.properties b/common/src/main/resources/i18n/displayStrings_ro.properties index 23f1c36843..5d74d60d2c 100644 --- a/common/src/main/resources/i18n/displayStrings_ro.properties +++ b/common/src/main/resources/i18n/displayStrings_ro.properties @@ -915,7 +915,7 @@ dao.phase.short.BREAK3= dao.compensation.active.header=Solicitare de despăgubire activă -dao.compensation.active.selectedRequest=Solicitare de despăgubire selectată +dao.compensation.selectedRequest=Solicitare de despăgubire selectată dao.compensation.active.notOpenAnymore=Această solicitare de despăgubire nu mai este deschisă spre finanțare. Așteaptă până începe următoarea perioadă de finanțare. dao.compensation.active.remove=Înlătură solicitarea de despăgubire dao.compensation.active.remove.failed=Solicitarea de despăgubire nu a putut fi înlăturată. diff --git a/common/src/main/resources/i18n/displayStrings_ru.properties b/common/src/main/resources/i18n/displayStrings_ru.properties index d89cc6b885..b0d0feec22 100644 --- a/common/src/main/resources/i18n/displayStrings_ru.properties +++ b/common/src/main/resources/i18n/displayStrings_ru.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=Текущие запросы dao.compensation.menuItem.pastRequests=Прошлые запросы dao.compensation.active.header=Запрос активной компенсации -dao.compensation.active.selectedRequest=Запрос выбранной компенсации +dao.compensation.selectedRequest=Запрос выбранной компенсации dao.compensation.active.notOpenAnymore=Этот запрос компенсации более не открыт для оплаты. Пожалуйста подождите до начала следующего периода оплаты. dao.compensation.active.vote=Голосование по запросу компенсации dao.compensation.active.fund=Найти запрос компенсации diff --git a/common/src/main/resources/i18n/displayStrings_sr.properties b/common/src/main/resources/i18n/displayStrings_sr.properties index a9d592ede7..5204d6089d 100644 --- a/common/src/main/resources/i18n/displayStrings_sr.properties +++ b/common/src/main/resources/i18n/displayStrings_sr.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=Aktivni zahtevi dao.compensation.menuItem.pastRequests=Raniji zahtevi dao.compensation.active.header=Aktivni zahtevi za nadoknadu -dao.compensation.active.selectedRequest=Izabrani zahtevi za nadoknadu +dao.compensation.selectedRequest=Izabrani zahtevi za nadoknadu dao.compensation.active.notOpenAnymore=Ovaj zahtev za nadoknadu nije više otvoren za finansiranje. Molimo sačekajte do početka sledećeg perioda finansiranja. dao.compensation.active.vote=Glasaj na zahtev za nadoknadu dao.compensation.active.fund=Finansiraj zahtev za nadoknadu diff --git a/common/src/main/resources/i18n/displayStrings_zh.properties b/common/src/main/resources/i18n/displayStrings_zh.properties index 54db2683af..072534566e 100644 --- a/common/src/main/resources/i18n/displayStrings_zh.properties +++ b/common/src/main/resources/i18n/displayStrings_zh.properties @@ -849,7 +849,7 @@ dao.compensation.menuItem.activeRequests=活动要求 dao.compensation.menuItem.pastRequests=过期要求 dao.compensation.active.header=活动赔偿要求 -dao.compensation.active.selectedRequest=选定赔偿要求 +dao.compensation.selectedRequest=选定赔偿要求 dao.compensation.active.notOpenAnymore=这笔补偿申请不再对资金开放。 请等到下一个资助期开始。 dao.compensation.active.vote=在赔偿要求上投票 dao.compensation.active.fund=为赔偿要求充值 diff --git a/core/src/main/java/io/bisq/core/app/AppSetupWithP2P.java b/core/src/main/java/io/bisq/core/app/AppSetupWithP2P.java index f631ed7c8e..10e7b954b2 100644 --- a/core/src/main/java/io/bisq/core/app/AppSetupWithP2P.java +++ b/core/src/main/java/io/bisq/core/app/AppSetupWithP2P.java @@ -42,6 +42,7 @@ public class AppSetupWithP2P extends AppSetup { protected final FilterManager filterManager; protected BooleanProperty p2pNetWorkReady; protected final TradeStatisticsManager tradeStatisticsManager; + protected ArrayList persistedDataHosts; @Inject public AppSetupWithP2P(EncryptionService encryptionService, @@ -50,16 +51,16 @@ public class AppSetupWithP2P extends AppSetup { TradeStatisticsManager tradeStatisticsManager, AccountAgeWitnessService accountAgeWitnessService, FilterManager filterManager) { - super(encryptionService,keyRing); + super(encryptionService, keyRing); this.p2PService = p2PService; this.tradeStatisticsManager = tradeStatisticsManager; this.accountAgeWitnessService = accountAgeWitnessService; this.filterManager = filterManager; + this.persistedDataHosts = new ArrayList<>(); } @Override public void initPersistedDataHosts() { - ArrayList persistedDataHosts = new ArrayList<>(); persistedDataHosts.add(p2PService); // we apply at startup the reading of persisted data but don't want to get it triggered in the constructor diff --git a/core/src/main/java/io/bisq/core/app/AppSetupWithP2PAndDAO.java b/core/src/main/java/io/bisq/core/app/AppSetupWithP2PAndDAO.java index 9ded9ef300..a95e2bd8d5 100644 --- a/core/src/main/java/io/bisq/core/app/AppSetupWithP2PAndDAO.java +++ b/core/src/main/java/io/bisq/core/app/AppSetupWithP2PAndDAO.java @@ -18,6 +18,7 @@ package io.bisq.core.app; import io.bisq.common.crypto.KeyRing; +import io.bisq.common.proto.persistable.PersistedDataHost; import io.bisq.core.dao.DaoManager; import io.bisq.core.filter.FilterManager; import io.bisq.core.payment.AccountAgeWitnessService; @@ -47,6 +48,7 @@ public class AppSetupWithP2PAndDAO extends AppSetupWithP2P { accountAgeWitnessService, filterManager); this.daoManager = daoManager; + this.persistedDataHosts.add(daoManager.getCompensationRequestManager()); } @Override diff --git a/core/src/main/java/io/bisq/core/dao/DaoManager.java b/core/src/main/java/io/bisq/core/dao/DaoManager.java index d51ba1182d..25ec9eaa88 100644 --- a/core/src/main/java/io/bisq/core/dao/DaoManager.java +++ b/core/src/main/java/io/bisq/core/dao/DaoManager.java @@ -24,6 +24,7 @@ import io.bisq.core.dao.blockchain.BsqNode; import io.bisq.core.dao.blockchain.BsqNodeProvider; import io.bisq.core.dao.compensation.CompensationRequestManager; import io.bisq.core.dao.vote.VotingManager; +import lombok.Getter; /** * High level entry point for Dao domain @@ -31,6 +32,7 @@ import io.bisq.core.dao.vote.VotingManager; public class DaoManager { private final DaoPeriodService daoPeriodService; private final VotingManager voteManager; + @Getter private final CompensationRequestManager compensationRequestManager; private final BsqNode bsqNode; diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestDisplay.java b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestDisplay.java index be5c0de1a2..366bf9cd74 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestDisplay.java +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestDisplay.java @@ -22,16 +22,19 @@ import io.bisq.core.btc.wallet.BsqWalletService; import io.bisq.core.dao.compensation.CompensationRequestPayload; import io.bisq.core.dao.compensation.Restrictions; import io.bisq.core.provider.fee.FeeService; -import io.bisq.gui.components.HyperlinkWithIcon; -import io.bisq.gui.components.InputTextField; -import io.bisq.gui.components.TxIdTextField; +import io.bisq.gui.components.*; import io.bisq.gui.util.BsqFormatter; import io.bisq.gui.util.GUIUtil; import io.bisq.gui.util.Layout; import io.bisq.gui.util.validation.BsqAddressValidator; import io.bisq.gui.util.validation.BsqValidator; -import javafx.scene.control.TextArea; -import javafx.scene.layout.GridPane; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.geometry.HPos; +import javafx.geometry.Insets; +import javafx.geometry.Orientation; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.util.Callback; import javax.annotation.Nullable; import java.util.UUID; @@ -150,4 +153,177 @@ public class CompensationRequestDisplay { public int incrementAndGetGridRow() { return ++gridRow; } + + public GridPane createCompensationList(TableView 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 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 tableView) { + TableColumn dateColumn = new AutoTooltipTableColumn(Res.get("shared.dateTime")) { + { + setMinWidth(190); + setMaxWidth(190); + } + }; + dateColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); + dateColumn.setCellFactory( + new Callback, TableCell>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell() { + @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 nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.name")); + nameColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); + nameColumn.setCellFactory( + new Callback, TableCell>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell() { + @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 uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id")); + uidColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); + uidColumn.setCellFactory( + new Callback, TableCell>() { + @Override + public TableCell call( + TableColumn column) { + return new TableCell() { + @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 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, + TableCell>() { + + @Override + public TableCell call(TableColumn column) { + return new TableCell() { + + @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); + } } diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/CompensationRequestListItem.java b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestListItem.java similarity index 98% rename from gui/src/main/java/io/bisq/gui/main/dao/compensation/active/CompensationRequestListItem.java rename to gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestListItem.java index 97d2034289..a4c2e21d4b 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/CompensationRequestListItem.java +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestListItem.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package io.bisq.gui.main.dao.compensation.active; +package io.bisq.gui.main.dao.compensation; import io.bisq.common.locale.Res; import io.bisq.core.btc.listeners.TxConfidenceListener; @@ -42,7 +42,7 @@ import java.util.Optional; @ToString @Slf4j @EqualsAndHashCode -class CompensationRequestListItem implements BsqBlockChainListener { +public class CompensationRequestListItem implements BsqBlockChainListener { @Getter private final CompensationRequest compensationRequest; private final BsqWalletService bsqWalletService; diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestView.java b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestView.java new file mode 100644 index 0000000000..9c251d9adb --- /dev/null +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/CompensationRequestView.java @@ -0,0 +1,138 @@ +/* + * 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 . + */ + +package io.bisq.gui.main.dao.compensation; + +import io.bisq.common.UserThread; +import io.bisq.common.locale.Res; +import io.bisq.core.btc.wallet.BsqWalletService; +import io.bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher; +import io.bisq.core.dao.blockchain.BsqBlockChainListener; +import io.bisq.core.dao.blockchain.parse.BsqBlockChain; +import io.bisq.core.dao.compensation.CompensationRequest; +import io.bisq.core.dao.compensation.CompensationRequestManager; +import io.bisq.gui.common.view.ActivatableView; +import io.bisq.gui.common.view.FxmlView; +import io.bisq.gui.util.BsqFormatter; +import io.bisq.gui.util.Layout; +import javafx.beans.value.ChangeListener; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; +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 javax.inject.Inject; + +@FxmlView +public class CompensationRequestView extends ActivatableView implements BsqBlockChainListener { + + protected final CompensationRequestManager compensationRequestManger; + protected final BsqBlockChain bsqBlockChain; + protected final ObservableList observableList = FXCollections.observableArrayList(); + protected TableView tableView; + protected final BsqWalletService bsqWalletService; + protected final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher; + protected final BsqFormatter bsqFormatter; + protected SortedList 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 chainHeightChangeListener; + protected ListChangeListener 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); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Protected + /////////////////////////////////////////////////////////////////////////////////////////// + + protected void updateList() { + } + + 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()); + } + } +} + diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.fxml b/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.fxml index 0423b155c8..1efbc3e80f 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.fxml +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.fxml @@ -18,11 +18,10 @@ --> - - - + + + diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.java b/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.java index fc24f502cc..b571e67ad8 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.java +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/active/ActiveCompensationRequestView.java @@ -17,7 +17,6 @@ package io.bisq.gui.main.dao.compensation.active; -import io.bisq.common.UserThread; import io.bisq.common.locale.Res; import io.bisq.core.btc.wallet.BsqWalletService; import io.bisq.core.dao.DaoPeriodService; @@ -28,35 +27,23 @@ import io.bisq.core.dao.compensation.CompensationRequest; import io.bisq.core.dao.compensation.CompensationRequestManager; import io.bisq.core.provider.fee.FeeService; import io.bisq.gui.Navigation; -import io.bisq.gui.common.view.ActivatableView; import io.bisq.gui.common.view.FxmlView; -import io.bisq.gui.components.AutoTooltipLabel; -import io.bisq.gui.components.AutoTooltipTableColumn; import io.bisq.gui.components.SeparatedPhaseBars; -import io.bisq.gui.components.TableGroupHeadline; import io.bisq.gui.main.MainView; import io.bisq.gui.main.dao.DaoView; import io.bisq.gui.main.dao.compensation.CompensationRequestDisplay; +import io.bisq.gui.main.dao.compensation.CompensationRequestListItem; +import io.bisq.gui.main.dao.compensation.CompensationRequestView; import io.bisq.gui.main.dao.voting.VotingView; import io.bisq.gui.main.dao.voting.vote.VoteView; import io.bisq.gui.main.overlays.popups.Popup; import io.bisq.gui.util.BsqFormatter; import io.bisq.gui.util.Layout; -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.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.control.*; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.Priority; -import javafx.util.Callback; +import javafx.scene.layout.*; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -69,32 +56,15 @@ import static io.bisq.gui.util.FormBuilder.addButtonAfterGroup; import static io.bisq.gui.util.FormBuilder.addTitledGroupBg; @FxmlView -public class ActiveCompensationRequestView extends ActivatableView implements BsqBlockChainListener { +public class ActiveCompensationRequestView extends CompensationRequestView implements BsqBlockChainListener { - TableView tableView; - private final CompensationRequestManager compensationRequestManger; - private final DaoPeriodService daoPeriodService; - private final BsqWalletService bsqWalletService; - private final BsqBlockChain bsqBlockChain; - private final FeeService feeService; - private final BsqBlockChainChangeDispatcher bsqBlockChainChangeDispatcher; - private final Navigation navigation; - private final BsqFormatter bsqFormatter; - private final ObservableList observableList = FXCollections.observableArrayList(); - private SortedList sortedList = new SortedList<>(observableList); - private Subscription selectedCompensationRequestSubscription, phaseSubscription; - private CompensationRequestDisplay compensationRequestDisplay; - private int gridRow = 0; - private GridPane detailsGridPane, gridPane; - private DaoPeriodService.Phase currentPhase; - private CompensationRequestListItem selectedCompensationRequest; - private Button removeButton, voteButton; - private TextField cycleTextField; private List phaseBarsItems; - private ChangeListener chainHeightChangeListener; - private ListChangeListener compensationRequestListChangeListener; + private Button removeButton, voteButton; + private final Navigation navigation; + private final DaoPeriodService daoPeriodService; + private DaoPeriodService.Phase currentPhase; private ChangeListener phaseChangeListener; - + private Subscription phaseSubscription; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -109,22 +79,16 @@ public class ActiveCompensationRequestView extends ActivatableView tuple2 = addLabelTextField(gridPane, ++gridRow, Res.get("dao.compensation.active.cycle")); @@ -155,25 +113,15 @@ public class ActiveCompensationRequestView extends ActivatableView(); - tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); - tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData"))); - tableView.setMinHeight(90); - GridPane.setRowIndex(tableView, ++gridRow); - GridPane.setColumnSpan(tableView, 2); - GridPane.setMargin(tableView, new Insets(5, -15, -10, -10)); - GridPane.setVgrow(tableView, Priority.ALWAYS); - GridPane.setHgrow(tableView, Priority.ALWAYS); - gridPane.getChildren().add(tableView); - - createColumns(); + 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); @@ -186,17 +134,27 @@ public class ActiveCompensationRequestView extends ActivatableView 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() { - sortedList.comparatorProperty().bind(tableView.comparatorProperty()); - - selectedCompensationRequestSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), this::onSelectCompensationRequest); + 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(); @@ -206,46 +164,19 @@ public class ActiveCompensationRequestView extends ActivatableView activeRequests = compensationRequestManger.getActiveRequests(); @@ -258,8 +189,6 @@ public class ActiveCompensationRequestView extends ActivatableView { int startBlock = daoPeriodService.getAbsoluteStartBlockOfPhase(height, item.getPhase()); int endBlock = daoPeriodService.getAbsoluteEndBlockOfPhase(height, item.getPhase()); @@ -274,48 +203,11 @@ public class ActiveCompensationRequestView extends ActivatableView dateColumn = new AutoTooltipTableColumn(Res.get("shared.dateTime")) { - { - setMinWidth(190); - setMaxWidth(190); - } - }; - dateColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); - dateColumn.setCellFactory( - new Callback, TableCell>() { - @Override - public TableCell call( - TableColumn column) { - return new TableCell() { - @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 nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.name")); - nameColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); - nameColumn.setCellFactory( - new Callback, TableCell>() { - @Override - public TableCell call( - TableColumn column) { - return new TableCell() { - @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 uidColumn = new AutoTooltipTableColumn<>(Res.get("shared.id")); - uidColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue())); - uidColumn.setCellFactory( - new Callback, TableCell>() { - @Override - public TableCell call( - TableColumn column) { - return new TableCell() { - @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 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, - TableCell>() { - - @Override - public TableCell call(TableColumn column) { - return new TableCell() { - - @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); - } } diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.fxml b/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.fxml index 568fc757d1..0829268708 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.fxml +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.fxml @@ -17,15 +17,10 @@ ~ along with Bisq. If not, see . --> - - + + - - - - diff --git a/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.java b/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.java index f1d319dfd5..7dc9110ed0 100644 --- a/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.java +++ b/gui/src/main/java/io/bisq/gui/main/dao/compensation/past/PastCompensationRequestView.java @@ -17,14 +17,34 @@ package io.bisq.gui.main.dao.compensation.past; -import io.bisq.gui.common.view.ActivatableView; +import io.bisq.common.locale.Res; +import io.bisq.core.btc.wallet.BsqWalletService; +import io.bisq.core.dao.DaoPeriodService; +import io.bisq.core.dao.blockchain.BsqBlockChainChangeDispatcher; +import io.bisq.core.dao.blockchain.BsqBlockChainListener; +import io.bisq.core.dao.blockchain.parse.BsqBlockChain; +import io.bisq.core.dao.compensation.CompensationRequest; +import io.bisq.core.dao.compensation.CompensationRequestManager; +import io.bisq.gui.Navigation; import io.bisq.gui.common.view.FxmlView; -import javafx.scene.layout.GridPane; +import io.bisq.gui.components.SeparatedPhaseBars; +import io.bisq.gui.main.dao.compensation.CompensationRequestDisplay; +import io.bisq.gui.main.dao.compensation.CompensationRequestListItem; +import io.bisq.gui.main.dao.compensation.CompensationRequestView; +import io.bisq.gui.util.BsqFormatter; +import javafx.collections.transformation.FilteredList; +import javafx.geometry.Insets; +import javafx.scene.control.*; +import javafx.scene.layout.*; import javax.inject.Inject; +import java.util.List; +import java.util.stream.Collectors; @FxmlView -public class PastCompensationRequestView extends ActivatableView { +public class PastCompensationRequestView extends CompensationRequestView implements BsqBlockChainListener { + + private List phaseBarsItems; /////////////////////////////////////////////////////////////////////////////////////////// @@ -32,19 +52,63 @@ public class PastCompensationRequestView extends ActivatableView /////////////////////////////////////////////////////////////////////////////////////////// @Inject - private PastCompensationRequestView() { + 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 activate() { - } + protected void updateList() { + observableList.forEach(CompensationRequestListItem::cleanup); - @Override - protected void deactivate() { + final FilteredList pastRequests = compensationRequestManger.getPastRequests(); + observableList.setAll(pastRequests.stream() + .map(e -> new CompensationRequestListItem(e, bsqWalletService, bsqBlockChain, bsqBlockChainChangeDispatcher, bsqFormatter)) + .collect(Collectors.toSet())); + + if (pastRequests.isEmpty() && compensationRequestDisplay != null) + compensationRequestDisplay.removeAllFields(); } }