mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Merge pull request #2372 from ripcurlx/add-wait-until-next-proposal-phase-state
Show info if not in proposal phase
This commit is contained in:
commit
a4428ffc06
@ -444,7 +444,7 @@ public class DaoFacade implements DaoSetupService {
|
||||
return lastBlock;
|
||||
}
|
||||
|
||||
// Because last block in request and voting phases must not be used fo making a tx as it will get confirmed in the
|
||||
// Because last block in request and voting phases must not be used for making a tx as it will get confirmed in the
|
||||
// next block which would be already the next phase we hide that last block to the user and add it to the break.
|
||||
public int getDurationForPhaseForDisplay(DaoPhase.Phase phase) {
|
||||
int duration = periodService.getDurationForPhase(phase, daoStateService.getChainHeight());
|
||||
@ -475,6 +475,10 @@ public class DaoFacade implements DaoSetupService {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public int getCurrentCycleDuration() {
|
||||
return periodService.getCurrentCycle().getDuration();
|
||||
}
|
||||
|
||||
// listeners for phase change
|
||||
public ReadOnlyObjectProperty<DaoPhase.Phase> phaseProperty() {
|
||||
return phaseProperty;
|
||||
|
57
core/src/main/java/bisq/core/dao/DaoUtil.java
Normal file
57
core/src/main/java/bisq/core/dao/DaoUtil.java
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.core.dao;
|
||||
|
||||
import bisq.core.dao.state.model.governance.DaoPhase;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.util.BSFormatter;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DaoUtil {
|
||||
|
||||
public static String getNextPhaseDuration(int height, DaoPhase.Phase phase, DaoFacade daoFacade, BSFormatter formatter) {
|
||||
final int currentCycleDuration = daoFacade.getCurrentCycleDuration();
|
||||
long start = daoFacade.getFirstBlockOfPhaseForDisplay(height, phase) + currentCycleDuration;
|
||||
long end = daoFacade.getLastBlockOfPhaseForDisplay(height, phase) + currentCycleDuration;
|
||||
|
||||
long now = new Date().getTime();
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM", Locale.getDefault());
|
||||
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
String startDateTime = formatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
String endDateTime = formatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
|
||||
return Res.get("dao.cycle.phaseDurationWithoutBlocks", start, end, startDateTime, endDateTime);
|
||||
}
|
||||
|
||||
public static String getPhaseDuration(int height, DaoPhase.Phase phase, DaoFacade daoFacade, BSFormatter formatter) {
|
||||
long start = daoFacade.getFirstBlockOfPhaseForDisplay(height, phase);
|
||||
long end = daoFacade.getLastBlockOfPhaseForDisplay(height, phase);
|
||||
long duration = daoFacade.getDurationForPhaseForDisplay(phase);
|
||||
long now = new Date().getTime();
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM", Locale.getDefault());
|
||||
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
String startDateTime = formatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
String endDateTime = formatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
String durationTime = formatter.formatDurationAsWords(duration * 10 * 60 * 1000, false, false);
|
||||
return Res.get("dao.cycle.phaseDuration", duration, durationTime, start, end, startDateTime, endDateTime);
|
||||
}
|
||||
}
|
@ -1205,10 +1205,12 @@ dao.cycle.overview.headline=Voting cycle overview
|
||||
dao.cycle.currentPhase=Current phase
|
||||
dao.cycle.currentBlockHeight=Current block height
|
||||
dao.cycle.proposal=Proposal phase
|
||||
dao.cycle.proposal.next=Next proposal phase
|
||||
dao.cycle.blindVote=Blind vote phase
|
||||
dao.cycle.voteReveal=Vote reveal phase
|
||||
dao.cycle.voteResult=Vote result
|
||||
dao.cycle.phaseDuration={0} blocks (≈{1}); Block {2} - {3} (≈{4} - ≈{5})
|
||||
dao.cycle.phaseDurationWithoutBlocks=Block {0} - {1} (≈{2} - ≈{3})
|
||||
|
||||
dao.voteReveal.txPublished.headLine=Vote reveal transaction published
|
||||
dao.voteReveal.txPublished=Your vote reveal transaction with transaction ID {0} was successfully published.\n\n\
|
||||
@ -1575,6 +1577,7 @@ dao.proposal.votes.header=Vote on all proposals
|
||||
dao.proposal.votes.header.voted=My vote
|
||||
dao.proposal.myVote.button=Vote on all proposals
|
||||
dao.proposal.create.selectProposalType=Select proposal type
|
||||
dao.proposal.create.phase.inactive=Please wait until the next proposal phase
|
||||
dao.proposal.create.proposalType=Proposal type
|
||||
dao.proposal.create.createNew=Make new proposal
|
||||
dao.proposal.create.create.button=Make proposal
|
||||
|
@ -20,10 +20,10 @@ package bisq.desktop.main.dao.governance.dashboard;
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.main.dao.governance.PhasesView;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.DaoUtil;
|
||||
import bisq.core.dao.governance.period.PeriodService;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.model.governance.DaoPhase;
|
||||
@ -35,11 +35,6 @@ import javax.inject.Inject;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
|
||||
@ -76,11 +71,11 @@ public class GovernanceDashboardView extends ActivatableView<GridPane, Void> imp
|
||||
addTitledGroupBg(root, ++gridRow, 6, Res.get("dao.cycle.overview.headline"), Layout.GROUP_DISTANCE);
|
||||
currentBlockHeightTextField = addTopLabelReadOnlyTextField(root, gridRow, Res.get("dao.cycle.currentBlockHeight"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE).second;
|
||||
currentPhaseTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.currentPhase")).second;
|
||||
proposalTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.proposal")).second;
|
||||
blindVoteTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.blindVote")).second;
|
||||
voteRevealTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.voteReveal")).second;
|
||||
voteResultTextField = FormBuilder.addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.voteResult")).second;
|
||||
currentPhaseTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.currentPhase")).second;
|
||||
proposalTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.proposal")).second;
|
||||
blindVoteTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.blindVote")).second;
|
||||
voteRevealTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.voteReveal")).second;
|
||||
voteResultTextField = addTopLabelReadOnlyTextField(root, ++gridRow, Res.get("dao.cycle.voteResult")).second;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -131,22 +126,9 @@ public class GovernanceDashboardView extends ActivatableView<GridPane, Void> imp
|
||||
phase = periodService.getPhaseForHeight(height + 1);
|
||||
}
|
||||
currentPhaseTextField.setText(Res.get("dao.phase." + phase.name()));
|
||||
proposalTextField.setText(getPhaseDuration(height, DaoPhase.Phase.PROPOSAL));
|
||||
blindVoteTextField.setText(getPhaseDuration(height, DaoPhase.Phase.BLIND_VOTE));
|
||||
voteRevealTextField.setText(getPhaseDuration(height, DaoPhase.Phase.VOTE_REVEAL));
|
||||
voteResultTextField.setText(getPhaseDuration(height, DaoPhase.Phase.RESULT));
|
||||
}
|
||||
|
||||
private String getPhaseDuration(int height, DaoPhase.Phase phase) {
|
||||
long start = daoFacade.getFirstBlockOfPhaseForDisplay(height, phase);
|
||||
long end = daoFacade.getLastBlockOfPhaseForDisplay(height, phase);
|
||||
long duration = daoFacade.getDurationForPhaseForDisplay(phase);
|
||||
long now = new Date().getTime();
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMM", Locale.getDefault());
|
||||
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
String startDateTime = formatter.formatDateTime(new Date(now + (start - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
String endDateTime = formatter.formatDateTime(new Date(now + (end - height) * 10 * 60 * 1000L), dateFormatter, timeFormatter);
|
||||
String durationTime = formatter.formatDurationAsWords(duration * 10 * 60 * 1000, false, false);
|
||||
return Res.get("dao.cycle.phaseDuration", duration, durationTime, start, end, startDateTime, endDateTime);
|
||||
proposalTextField.setText(DaoUtil.getPhaseDuration(height, DaoPhase.Phase.PROPOSAL, daoFacade, formatter));
|
||||
blindVoteTextField.setText(DaoUtil.getPhaseDuration(height, DaoPhase.Phase.BLIND_VOTE, daoFacade, formatter));
|
||||
voteRevealTextField.setText(DaoUtil.getPhaseDuration(height, DaoPhase.Phase.VOTE_REVEAL, daoFacade, formatter));
|
||||
voteResultTextField.setText(DaoUtil.getPhaseDuration(height, DaoPhase.Phase.RESULT, daoFacade, formatter));
|
||||
}
|
||||
}
|
||||
|
@ -21,16 +21,17 @@ import bisq.desktop.Navigation;
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.main.dao.governance.PhasesView;
|
||||
import bisq.desktop.main.dao.governance.ProposalDisplay;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.btc.exceptions.InsufficientBsqException;
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.DaoUtil;
|
||||
import bisq.core.dao.exceptions.ValidationException;
|
||||
import bisq.core.dao.governance.bond.Bond;
|
||||
import bisq.core.dao.governance.param.Param;
|
||||
@ -51,6 +52,7 @@ import bisq.asset.Asset;
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.app.DevEnv;
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.InsufficientMoneyException;
|
||||
@ -60,8 +62,15 @@ import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
@ -76,7 +85,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
|
||||
import static bisq.desktop.util.FormBuilder.addComboBox;
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@FxmlView
|
||||
@ -95,6 +106,13 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
private Button makeProposalButton;
|
||||
private ComboBox<ProposalType> proposalTypeComboBox;
|
||||
private ChangeListener<ProposalType> proposalTypeChangeListener;
|
||||
private TextField nextProposalTextField;
|
||||
private TitledGroupBg proposalTitledGroup;
|
||||
private VBox nextProposalBox;
|
||||
|
||||
private BooleanProperty isProposalPhase = new SimpleBooleanProperty(false);
|
||||
private StringProperty proposalGroupTitle = new SimpleStringProperty(Res.get("dao.proposal.create.phase.inactive"));
|
||||
|
||||
@Nullable
|
||||
private ProposalType selectedProposalType;
|
||||
private int gridRow;
|
||||
@ -128,8 +146,13 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
public void initialize() {
|
||||
gridRow = phasesView.addGroup(root, gridRow);
|
||||
|
||||
addTitledGroupBg(root, ++gridRow, 1, Res.get("dao.proposal.create.selectProposalType"), Layout.GROUP_DISTANCE);
|
||||
proposalTypeComboBox = FormBuilder.addComboBox(root, gridRow,
|
||||
proposalTitledGroup = addTitledGroupBg(root, ++gridRow, 2, proposalGroupTitle.get(), Layout.GROUP_DISTANCE);
|
||||
final Tuple3<Label, TextField, VBox> nextProposalPhaseTuple = addTopLabelReadOnlyTextField(root, gridRow,
|
||||
Res.get("dao.cycle.proposal.next"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
nextProposalBox = nextProposalPhaseTuple.third;
|
||||
nextProposalTextField = nextProposalPhaseTuple.second;
|
||||
proposalTypeComboBox = addComboBox(root, gridRow,
|
||||
Res.get("dao.proposal.create.proposalType"), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
proposalTypeComboBox.setMaxWidth(300);
|
||||
proposalTypeComboBox.setConverter(new StringConverter<>() {
|
||||
@ -156,6 +179,8 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
addBindings();
|
||||
|
||||
phasesView.activate();
|
||||
|
||||
daoFacade.addBsqStateListener(this);
|
||||
@ -169,6 +194,8 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
removeBindings();
|
||||
|
||||
phasesView.deactivate();
|
||||
|
||||
daoFacade.removeBsqStateListener(this);
|
||||
@ -178,6 +205,25 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
makeProposalButton.setOnAction(null);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Bindings, Listeners
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void addBindings() {
|
||||
proposalTypeComboBox.managedProperty().bind(isProposalPhase);
|
||||
proposalTypeComboBox.visibleProperty().bind(isProposalPhase);
|
||||
nextProposalBox.managedProperty().bind(isProposalPhase.not());
|
||||
nextProposalBox.visibleProperty().bind(isProposalPhase.not());
|
||||
proposalTitledGroup.textProperty().bind(proposalGroupTitle);
|
||||
}
|
||||
|
||||
private void removeBindings() {
|
||||
proposalTypeComboBox.managedProperty().unbind();
|
||||
proposalTypeComboBox.visibleProperty().unbind();
|
||||
nextProposalBox.managedProperty().unbind();
|
||||
nextProposalBox.visibleProperty().unbind();
|
||||
proposalTitledGroup.textProperty().unbind();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
@ -185,12 +231,18 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
|
||||
@Override
|
||||
public void onNewBlockHeight(int height) {
|
||||
boolean isProposalPhase = daoFacade.isInPhaseButNotLastBlock(DaoPhase.Phase.PROPOSAL);
|
||||
proposalTypeComboBox.setDisable(!isProposalPhase);
|
||||
if (!isProposalPhase)
|
||||
isProposalPhase.set(daoFacade.isInPhaseButNotLastBlock(DaoPhase.Phase.PROPOSAL));
|
||||
if (isProposalPhase.get()) {
|
||||
proposalGroupTitle.set(Res.get("dao.proposal.create.selectProposalType"));
|
||||
} else {
|
||||
proposalGroupTitle.set(Res.get("dao.proposal.create.phase.inactive"));
|
||||
proposalTypeComboBox.getSelectionModel().clearSelection();
|
||||
updateTimeUntilNextProposalPhase(height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onParseBlockChainComplete() {
|
||||
}
|
||||
@ -200,6 +252,10 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void updateTimeUntilNextProposalPhase(int height) {
|
||||
nextProposalTextField.setText(DaoUtil.getNextPhaseDuration(height, DaoPhase.Phase.PROPOSAL, daoFacade, btcFormatter));
|
||||
}
|
||||
|
||||
private void publishMyProposal(ProposalType type) {
|
||||
try {
|
||||
ProposalWithTransaction proposalWithTransaction = getProposalWithTransaction(type);
|
||||
@ -378,9 +434,8 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
|
||||
}
|
||||
});
|
||||
proposalDisplay.getComboBoxes().stream()
|
||||
.filter(Objects::nonNull).forEach(comboBox -> {
|
||||
inputsValid.set(inputsValid.get() && comboBox.getSelectionModel().getSelectedItem() != null);
|
||||
});
|
||||
.filter(Objects::nonNull).forEach(comboBox -> inputsValid.set(inputsValid.get() &&
|
||||
comboBox.getSelectionModel().getSelectedItem() != null));
|
||||
|
||||
InputTextField linkInputTextField = proposalDisplay.linkInputTextField;
|
||||
inputsValid.set(inputsValid.get() &&
|
||||
|
Loading…
Reference in New Issue
Block a user