package lighthouse.subwindows;
import com.vinumeris.crashfx.*;
import javafx.application.*;
import javafx.fxml.*;
import javafx.scene.control.*;
import javafx.scene.input.*;
import lighthouse.*;
import lighthouse.protocol.*;
import lighthouse.utils.*;
import lighthouse.wallet.*;
import org.bitcoinj.core.*;
import org.slf4j.*;
import org.spongycastle.crypto.params.*;
import javax.annotation.*;
import static com.google.common.base.Preconditions.*;
import static lighthouse.utils.GuiUtils.*;
import static lighthouse.utils.I18nUtil.*;
/**
* Window which asks user to specify the amount they want to pledge.
*/
public class PledgeWindow extends InnerWindow {
private static final Logger log = LoggerFactory.getLogger(PledgeWindow.class);
@FXML TextField amountEdit;
@FXML Button confirmButton;
@FXML Label minersFeeLabel;
@FXML Label pubPrivLabel;
@FXML TextArea messageEdit;
@FXML TextField emailEdit;
@FXML TextField nameEdit;
// Will be initialised by the ProjectView.
public Project project;
private Coin max, min;
public Runnable onSuccess;
public void initialize() {
ValidationLink amountLink = new ValidationLink(amountEdit, str -> {
// Can't pledge more than our balance or more than the project is trying to actually raise
// as excess would go to miners fees.
Coin coin = valueOrNull(str);
boolean valid = coin != null && coin.compareTo(max) <= 0 && coin.compareTo(min) >= 0;
minersFeeLabel.setVisible(valid && !coin.equals(Main.wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE)));
return valid;
});
ValidationLink emailLink = new ValidationLink(emailEdit, str -> str.matches("^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$"));
ValidationLink.autoDisableButton(confirmButton, amountLink, emailLink);
String savedContact = Main.instance.prefs.getContactAddress();
if (savedContact != null)
emailEdit.setText(savedContact);
minersFeeLabel.setText(String.format(minersFeeLabel.getText(), Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.toFriendlyString()));
}
public void setProject(Project project) {
this.project = project;
// Until we do encryption of data in pledges, serverless projects are different to server assisted.
if (project.getPaymentURL() != null) {
pubPrivLabel.setText(tr("Name and message will be public."));
} else {
pubPrivLabel.setText(tr("Name, email and message will be public."));
}
}
public void setLimits(Coin limit, Coin min) {
// Note that we don't subtract the fee here because if the user pledges their entire balance, we should not
// require a dependency tx as all outputs can be included in the pledge.
// TODO: Make sure that it actually works this way when we sent multiple payments to the app.
this.max = Coin.valueOf(Math.min(limit.value, Main.wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE).value));
checkState(!max.isNegative());
this.min = min;
log.info("Max {} Min {}", max, min);
// TRANS: %s = example BTC amount limit
amountEdit.setPromptText(String.format(tr("e.g. %s"), max.toPlainString()));
}
@FXML
public void confirmClicked() {
log.info("Confirm pledge clicked: {}", amountEdit.getText());
// runLater: shitty hack around RT-37821 (consider upgrading to 8u40 when available and/or applying fix locally)
// otherwise pressing enter can cause a crash here when we open a new window with a default button
Platform.runLater(() -> {
if (Main.wallet.isEncrypted()) {
log.info("Wallet is encrypted, requesting password");
WalletPasswordController.requestPasswordWithNextWindow(this::tryMakePledge);
} else {
tryMakePledge(null);
}
});
}
private void tryMakePledge(@Nullable KeyParameter aesKey) {
try {
LHProtos.PledgeDetails.Builder details = LHProtos.PledgeDetails.newBuilder();
details.setContactAddress(emailEdit.getText());
Main.instance.prefs.setContactAddress(emailEdit.getText());
if (!messageEdit.getText().isEmpty())
details.setMemo(messageEdit.getText());
if (!nameEdit.getText().isEmpty())
details.setName(nameEdit.getText());
PledgingWallet.PendingPledge pledge = Main.wallet.createPledge(project, valueOrThrow(amountEdit.getText()), aesKey, details.buildPartial());
log.info("Created pledge is {}", pledge);
if (project.getPaymentURL() == null) {
// Show drag/drop icon and file save button. This will automatically finish this overlay UI too.
ExportWindow.openForPledge(project, pledge);
} else {
PledgeUploadWindow.open(project, pledge, onSuccess);
}
} catch (InsufficientMoneyException e) {
// This should not be possible because we disable the confirm button if the amount doesn't validate.
CrashWindow.open(e);
}
}
@FXML
public void allMoneyClicked(MouseEvent event) {
log.info("Maximum amount possible clicked");
amountEdit.setText(max.toPlainString());
}
@FXML
public void minMoneyClicked(MouseEvent event) {
log.info("Minimum amount possible clicked");
amountEdit.setText(min.toPlainString());
}
}