mirror of
https://github.com/haveno-dex/haveno.git
synced 2026-01-08 11:05:28 -05:00
show trade wallet sync progress with fixes
This commit is contained in:
parent
1f62ca3970
commit
a3c38ff678
26 changed files with 160 additions and 65 deletions
|
|
@ -69,7 +69,7 @@ public class AppStartupState {
|
|||
});
|
||||
|
||||
xmrWalletService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (xmrWalletService.isDownloadComplete())
|
||||
if (xmrWalletService.wasWalletSynced())
|
||||
isWalletSynced.set(true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ public abstract class SupportManager {
|
|||
p2PService.isBootstrapped() &&
|
||||
xmrConnectionService.isDownloadComplete() &&
|
||||
xmrConnectionService.hasSufficientPeersForBroadcast() &&
|
||||
xmrWalletService.isDownloadComplete();
|
||||
xmrWalletService.wasWalletSynced();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import java.util.Date;
|
|||
public class DownloadListener {
|
||||
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
|
||||
|
||||
// TODO: remove redundant execute?
|
||||
public void progress(double percentage, long blocksLeft, Date date) {
|
||||
UserThread.execute(() -> {
|
||||
UserThread.await(() -> this.percentage.set(percentage)); // TODO: these awaits are jenky
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import haveno.core.api.XmrConnectionService;
|
|||
import haveno.core.trade.HavenoUtils;
|
||||
import haveno.core.xmr.setup.DownloadListener;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -50,13 +51,14 @@ public abstract class XmrWalletBase {
|
|||
protected boolean wasWalletSynced;
|
||||
protected final Map<String, Optional<MoneroTx>> txCache = new HashMap<String, Optional<MoneroTx>>();
|
||||
protected boolean isClosingWallet;
|
||||
protected boolean isSyncingWithoutProgress;
|
||||
protected boolean isSyncingWithProgress;
|
||||
protected Long syncStartHeight;
|
||||
protected TaskLooper syncProgressLooper;
|
||||
protected CountDownLatch syncProgressLatch;
|
||||
protected Exception syncProgressError;
|
||||
protected Timer syncProgressTimeout;
|
||||
protected final DownloadListener downloadListener = new DownloadListener();
|
||||
protected final DownloadListener walletSyncListener = new DownloadListener();
|
||||
protected final LongProperty walletHeight = new SimpleLongProperty(0);
|
||||
@Getter
|
||||
protected boolean isShutDownStarted;
|
||||
|
|
@ -82,9 +84,12 @@ public abstract class XmrWalletBase {
|
|||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
Callable<MoneroSyncResult> task = () -> {
|
||||
MoneroSyncResult result = wallet.sync();
|
||||
saveWalletIfElapsedTime();
|
||||
if (isSyncing()) log.warn("Syncing without progress while already syncing. That should never happen.");
|
||||
isSyncingWithoutProgress = true;
|
||||
walletHeight.set(wallet.getHeight());
|
||||
MoneroSyncResult result = wallet.sync();
|
||||
walletHeight.set(wallet.getHeight());
|
||||
wasWalletSynced = true;
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
@ -101,6 +106,8 @@ public abstract class XmrWalletBase {
|
|||
Thread.currentThread().interrupt(); // restore interrupt status
|
||||
throw new RuntimeException("Sync was interrupted", e);
|
||||
} finally {
|
||||
isSyncingWithoutProgress = false;
|
||||
saveWalletIfElapsedTime();
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
|
@ -116,13 +123,13 @@ public abstract class XmrWalletBase {
|
|||
try {
|
||||
|
||||
// set initial state
|
||||
if (isSyncingWithProgress) log.warn("Syncing with progress while already syncing with progress. That should never happen");
|
||||
if (isSyncing()) log.warn("Syncing with progress while already syncing. That should never happen.");
|
||||
resetSyncProgressTimeout();
|
||||
isSyncingWithProgress = true;
|
||||
walletSyncListener.progress(0, -1, null); // reset progress
|
||||
syncProgressError = null;
|
||||
long targetHeightAtStart = xmrConnectionService.getTargetHeight();
|
||||
syncStartHeight = walletHeight.get();
|
||||
updateSyncProgress(syncStartHeight, targetHeightAtStart);
|
||||
updateSyncProgress(walletHeight.get(), targetHeightAtStart);
|
||||
|
||||
// test connection changing on startup before wallet synced
|
||||
if (testReconnectOnStartup) {
|
||||
|
|
@ -144,7 +151,7 @@ public abstract class XmrWalletBase {
|
|||
updateSyncProgress(height, appliedTargetHeight);
|
||||
}
|
||||
});
|
||||
setWalletSyncedWithProgress();
|
||||
onDoneSyncWithProgress();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -189,11 +196,8 @@ public abstract class XmrWalletBase {
|
|||
syncProgressLooper.stop();
|
||||
|
||||
// set synced or throw error
|
||||
if (syncProgressError == null) {
|
||||
setWalletSyncedWithProgress();
|
||||
} else {
|
||||
throw new RuntimeException(syncProgressError);
|
||||
}
|
||||
if (syncProgressError == null) onDoneSyncWithProgress();
|
||||
else throw new RuntimeException(syncProgressError);
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
@ -203,6 +207,10 @@ public abstract class XmrWalletBase {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean wasWalletSynced() {
|
||||
return wasWalletSynced;
|
||||
}
|
||||
|
||||
public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) {
|
||||
if (xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection)) {
|
||||
onConnectionChanged(xmrConnectionService.getConnection()); // change connection on same thread
|
||||
|
|
@ -224,6 +232,14 @@ public abstract class XmrWalletBase {
|
|||
ThreadUtils.submitToPool(() -> saveWalletIfElapsedTime());
|
||||
}
|
||||
|
||||
public boolean isSyncing() {
|
||||
return isSyncingWithProgress || isSyncingWithoutProgress;
|
||||
}
|
||||
|
||||
public ReadOnlyDoubleProperty downloadPercentageProperty() {
|
||||
return walletSyncListener.percentageProperty();
|
||||
}
|
||||
|
||||
public static boolean isSyncWithProgressTimeout(Throwable e) {
|
||||
return e.getMessage() != null && e.getMessage().contains(SYNC_TIMEOUT_MSG);
|
||||
}
|
||||
|
|
@ -246,17 +262,15 @@ public abstract class XmrWalletBase {
|
|||
// set wallet height
|
||||
walletHeight.set(height);
|
||||
|
||||
// new wallet reports height 1 before synced
|
||||
if (height == 1) {
|
||||
downloadListener.progress(0, targetHeight - height, null);
|
||||
return;
|
||||
}
|
||||
// new wallet reports height 0 or 1 before synced
|
||||
if (height <= 1) return;
|
||||
|
||||
// set progress
|
||||
long blocksLeft = targetHeight - height;
|
||||
if (syncStartHeight == null) syncStartHeight = height;
|
||||
double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) height - syncStartHeight) / (double) (targetHeight - syncStartHeight));
|
||||
downloadListener.progress(percent, blocksLeft, null);
|
||||
if (percent >= 1.0) wasWalletSynced = true; // set synced state before announcing progress
|
||||
walletSyncListener.progress(percent, blocksLeft, null);
|
||||
}
|
||||
|
||||
private synchronized void resetSyncProgressTimeout() {
|
||||
|
|
@ -268,7 +282,7 @@ public abstract class XmrWalletBase {
|
|||
}, SYNC_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void setWalletSyncedWithProgress() {
|
||||
private void onDoneSyncWithProgress() {
|
||||
|
||||
// stop syncing and save wallet if elapsed time
|
||||
if (wallet != null) { // can become null if interrupted by force close
|
||||
|
|
@ -277,8 +291,5 @@ public abstract class XmrWalletBase {
|
|||
saveWalletIfElapsedTime();
|
||||
}
|
||||
}
|
||||
|
||||
// update state
|
||||
wasWalletSynced = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import monero.common.MoneroError;
|
||||
import monero.common.MoneroRpcConnection;
|
||||
|
|
@ -266,18 +265,6 @@ public class XmrWalletService extends XmrWalletBase {
|
|||
return accountService.getPassword() != null;
|
||||
}
|
||||
|
||||
public ReadOnlyDoubleProperty downloadPercentageProperty() {
|
||||
return downloadListener.percentageProperty();
|
||||
}
|
||||
|
||||
private void doneDownload() {
|
||||
downloadListener.doneDownload();
|
||||
}
|
||||
|
||||
public boolean isDownloadComplete() {
|
||||
return downloadPercentageProperty().get() == 1d;
|
||||
}
|
||||
|
||||
public LongProperty walletHeightProperty() {
|
||||
return walletHeight;
|
||||
}
|
||||
|
|
@ -1494,7 +1481,7 @@ public class XmrWalletService extends XmrWalletBase {
|
|||
resetIfWalletChanged();
|
||||
|
||||
// signal that main wallet is synced
|
||||
doneDownload();
|
||||
walletSyncListener.doneDownload();
|
||||
|
||||
// notify setup that main wallet is initialized
|
||||
// TODO: app fully initializes after this is set to true, even though wallet might not be initialized if unconnected. wallet will be created when connection detected
|
||||
|
|
|
|||
|
|
@ -660,6 +660,7 @@ portfolio.pending.unconfirmedTooLong=Deposit transactions on trade {0} are still
|
|||
confirmed in Haveno, try restarting Haveno.\n\n\
|
||||
If the problem persists, contact Haveno support [HYPERLINK:https://matrix.to/#/#haveno:monero.social].
|
||||
|
||||
portfolio.pending.syncing=Syncing trade wallet — {0}% ({1} blocks remaining)
|
||||
portfolio.pending.step1.waitForConf=Wait for blockchain confirmations
|
||||
portfolio.pending.step2_buyer.additionalConf=Deposits have reached 10 confirmations.\nFor extra security, we recommend waiting {0} confirmations before sending payment.\nProceed early at your own risk.
|
||||
portfolio.pending.step2_buyer.startPayment=Start payment
|
||||
|
|
|
|||
|
|
@ -660,6 +660,7 @@ portfolio.pending.unconfirmedTooLong=Vkladové transakce obchodu {0} jsou stále
|
|||
potvrzené v Haveno, zkuste Haveno restartovat.\n\n\
|
||||
Pokud problém přetrvává, kontaktujte podporu Haveno [HYPERLINK:https://matrix.to/#/#haveno:monero.social].
|
||||
|
||||
portfolio.pending.syncing=Synchronizuji obchodní peněženku — {0}% ({1} bloků zbývá)
|
||||
portfolio.pending.step1.waitForConf=Počkejte na potvrzení na blockchainu
|
||||
portfolio.pending.step2_buyer.additionalConf=Vklady dosáhly 10 potvrzení.\nPro vyšší bezpečnost doporučujeme počkat na {0} potvrzení před odesláním platby.\nPokračujte dříve na vlastní riziko.
|
||||
portfolio.pending.step2_buyer.startPayment=Zahajte platbu
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=Prozentuale Preisabweichung vom Markt
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Handelwallet wird synchronisiert — {0}% ({1} Blöcke verbleibend)
|
||||
portfolio.pending.step1.waitForConf=Auf Blockchain-Bestätigung warten
|
||||
portfolio.pending.step2_buyer.additionalConf=Einzahlungen haben 10 Bestätigungen erreicht.\nFür zusätzliche Sicherheit empfehlen wir, {0} Bestätigungen abzuwarten, bevor Sie die Zahlung senden.\nEin früheres Vorgehen erfolgt auf eigenes Risiko.
|
||||
portfolio.pending.step2_buyer.startPayment=Zahlung beginnen
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=Desviación porcentual de precio de mercad
|
|||
|
||||
portfolio.pending.invalidTx=Hay un problema con una transacción inválida o no encontrada.\n\nPor faovr NO envíe el pago de traditional o cryptos.\n\nAbra un ticket de soporte para obtener asistencia de un mediador.\n\nMensaje de error: {0}
|
||||
|
||||
portfolio.pending.syncing=Sincronizando la billetera de comercio — {0}% ({1} bloques restantes)
|
||||
portfolio.pending.step1.waitForConf=Esperar a la confirmación en la cadena de bloques
|
||||
portfolio.pending.step2_buyer.additionalConf=Los depósitos han alcanzado 10 confirmaciones.\nPara mayor seguridad, recomendamos esperar {0} confirmaciones antes de enviar el pago.\nProceda antes bajo su propio riesgo.
|
||||
portfolio.pending.step2_buyer.startPayment=Comenzar pago
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=همگامسازی کیفپول معامله — {0}% ({1} بلاک باقیمانده)
|
||||
portfolio.pending.step1.waitForConf=برای تأییدیه بلاک چین منتظر باشید
|
||||
portfolio.pending.step2_buyer.additionalConf=واریزها به ۱۰ تأیید رسیدهاند.\nبرای امنیت بیشتر، توصیه میکنیم قبل از ارسال پرداخت، {0} تأیید صبر کنید.\nاقدام زودهنگام با مسئولیت خودتان است.
|
||||
portfolio.pending.step2_buyer.startPayment=آغاز پرداخت
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=Pourcentage de déviation du prix par rapp
|
|||
|
||||
portfolio.pending.invalidTx=Il y'a un problème avec une transaction manquante ou invalide.\n\nVeuillez NE PAS envoyer le payement Traditional ou crypto.\n\nOuvrez un ticket de support pour avoir l'aide d'un médiateur.\n\nMessage d'erreur: {0}
|
||||
|
||||
portfolio.pending.syncing=Synchronisation du portefeuille de trading — {0}% ({1} blocs restants)
|
||||
portfolio.pending.step1.waitForConf=Attendre la confirmation de la blockchain
|
||||
portfolio.pending.step2_buyer.additionalConf=Les dépôts ont atteint 10 confirmations.\nPour plus de sécurité, nous recommandons d’attendre {0} confirmations avant d’envoyer le paiement.\nProcédez plus tôt à vos propres risques.
|
||||
portfolio.pending.step2_buyer.startPayment=Initier le paiement
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Sincronizzazione del portafoglio trade — {0}% ({1} blocchi rimanenti)
|
||||
portfolio.pending.step1.waitForConf=Attendi la conferma della blockchain
|
||||
portfolio.pending.step2_buyer.additionalConf=I depositi hanno raggiunto 10 conferme.\nPer maggiore sicurezza, consigliamo di attendere {0} conferme prima di inviare il pagamento.\nProcedi in anticipo a tuo rischio.
|
||||
portfolio.pending.step2_buyer.startPayment=Inizia il pagamento
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=市場からの割合価格偏差
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=取引ウォレットを同期中 — {0}%(残り {1} ブロック)
|
||||
portfolio.pending.step1.waitForConf=ブロックチェーンの承認をお待ち下さい
|
||||
portfolio.pending.step2_buyer.additionalConf=入金は10承認に達しました。\n追加の安全のため、支払いを送信する前に{0}承認を待つことをお勧めします。\n早めに進める場合は自己責任となります。
|
||||
portfolio.pending.step2_buyer.startPayment=支払い開始
|
||||
|
|
|
|||
|
|
@ -579,6 +579,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Sincronizando a carteira de negociação — {0}% ({1} blocos restantes)
|
||||
portfolio.pending.step1.waitForConf=Aguardar confirmação da blockchain
|
||||
portfolio.pending.step2_buyer.additionalConf=Depósitos alcançaram 10 confirmações.\nPara maior segurança, recomendamos aguardar {0} confirmações antes de enviar o pagamento.\nProssiga antecipadamente por sua própria conta e risco.
|
||||
portfolio.pending.step2_buyer.startPayment=Iniciar pagamento
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Sincronizando a carteira de negociação — {0}% ({1} blocos restantes)
|
||||
portfolio.pending.step1.waitForConf=Esperando confirmação da blockchain
|
||||
portfolio.pending.step2_buyer.additionalConf=Os depósitos alcançaram 10 confirmações.\nPara maior segurança, recomendamos aguardar {0} confirmações antes de enviar o pagamento.\nProceda antecipadamente por sua própria conta e risco.
|
||||
portfolio.pending.step2_buyer.startPayment=Iniciar pagamento
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Синхронизация торгового кошелька — {0}% (осталось блоков: {1})
|
||||
portfolio.pending.step1.waitForConf=Ожидание подтверждения в блокчейне
|
||||
portfolio.pending.step2_buyer.additionalConf=Депозиты достигли 10 подтверждений.\nДля дополнительной безопасности мы рекомендуем дождаться {0} подтверждений перед отправкой платежа.\nРанее действия осуществляются на ваш страх и риск.
|
||||
portfolio.pending.step2_buyer.startPayment=Сделать платеж
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=กำลังซิงค์กระเป๋าเงินสำหรับการซื้อขาย — {0}% (เหลืออีก {1} บล็อก)
|
||||
portfolio.pending.step1.waitForConf=รอการยืนยันของบล็อกเชน
|
||||
portfolio.pending.step2_buyer.additionalConf=ยอดฝากถึง 10 การยืนยันแล้ว\nเพื่อความปลอดภัยเพิ่มเติม เราแนะนำให้รอ {0} การยืนยันก่อนทำการชำระเงิน\nดำเนินการล่วงหน้าตามความเสี่ยงของคุณเอง
|
||||
portfolio.pending.step2_buyer.startPayment=เริ่มการชำระเงิน
|
||||
|
|
|
|||
|
|
@ -623,6 +623,7 @@ portfolio.pending.unconfirmedTooLong=İşlem {0} üzerindeki güvence işlemleri
|
|||
onaylanmış olarak gösterilmiyorlarsa, Haveno'yu yeniden başlatmayı deneyin.\n\n\
|
||||
Sorun devam ederse, Haveno desteğiyle iletişime geçin [HYPERLINK:https://matrix.to/#/#haveno:monero.social].
|
||||
|
||||
portfolio.pending.syncing=Ticaret cüzdanı senkronize ediliyor — %{0} ({1} blok kaldı)
|
||||
portfolio.pending.step1.waitForConf=Blok zinciri onaylarını bekleyin
|
||||
portfolio.pending.step2_buyer.additionalConf=Mevduatlar 10 onayı ulaştı.\nEkstra güvenlik için, ödeme göndermeden önce {0} onayı beklemenizi öneririz.\nErken ilerlemek kendi riskinizdedir.
|
||||
portfolio.pending.step2_buyer.startPayment=Ödemeyi başlat
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=Đang đồng bộ ví giao dịch — {0}% (còn lại {1} khối)
|
||||
portfolio.pending.step1.waitForConf=Đợi xác nhận blockchain
|
||||
portfolio.pending.step2_buyer.additionalConf=Tiền gửi đã đạt 10 xác nhận.\nĐể tăng cường bảo mật, chúng tôi khuyên bạn chờ {0} xác nhận trước khi gửi thanh toán.\nTiến hành sớm là rủi ro của bạn.
|
||||
portfolio.pending.step2_buyer.startPayment=Bắt đầu thanh toán
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=与市场价格偏差百分比
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=正在同步交易钱包 — {0}%(剩余 {1} 个区块)
|
||||
portfolio.pending.step1.waitForConf=等待区块链确认
|
||||
portfolio.pending.step2_buyer.additionalConf=存款已达到 10 个确认。\n为了额外安全,我们建议在发送付款前等待 {0} 个确认。\n提前操作风险自负。
|
||||
portfolio.pending.step2_buyer.startPayment=开始付款
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ portfolio.closedTrades.deviation.help=Percentage price deviation from market
|
|||
|
||||
portfolio.pending.invalidTx=There is an issue with a missing or invalid transaction.\n\nPlease do NOT send the traditional or crypto payment.\n\nOpen a support ticket to get assistance from a Mediator.\n\nError message: {0}
|
||||
|
||||
portfolio.pending.syncing=正在同步交易錢包 — {0}%(剩餘 {1} 個區塊)
|
||||
portfolio.pending.step1.waitForConf=等待區塊鏈確認
|
||||
portfolio.pending.step2_buyer.additionalConf=存款已達 10 次確認。\n為了額外安全,我們建議在發送付款前等待 {0} 次確認。\n提前操作風險自負。
|
||||
portfolio.pending.step2_buyer.startPayment=開始付款
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
protected final Preferences preferences;
|
||||
protected final GridPane gridPane;
|
||||
|
||||
private Subscription tradePeriodStateSubscription, tradeStateSubscription, disputeStateSubscription, mediationResultStateSubscription;
|
||||
private Subscription tradePeriodStateSubscription, tradeStateSubscription, disputeStateSubscription, mediationResultStateSubscription, syncProgressSubscription;
|
||||
protected int gridRow = 0;
|
||||
private TextField timeLeftTextField;
|
||||
private ProgressBar timeLeftProgressBar;
|
||||
|
|
@ -93,6 +93,9 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
private BootstrapListener bootstrapListener;
|
||||
private TradeSubView.ChatCallback chatCallback;
|
||||
private ChangeListener<Boolean> pendingTradesInitializedListener;
|
||||
protected Label statusLabel;
|
||||
protected String syncStatus;
|
||||
protected String tradeStatus;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -258,9 +261,21 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
if (newValue) addTradeStateSubscription();
|
||||
});
|
||||
|
||||
syncProgressSubscription = EasyBind.subscribe(trade.downloadPercentageProperty(), newValue -> {
|
||||
if (newValue != null) onSyncProgress((double) newValue);
|
||||
});
|
||||
|
||||
UserThread.execute(() -> model.p2PService.removeP2PServiceListener(bootstrapListener));
|
||||
}
|
||||
|
||||
protected void onSyncProgress(double percent) {
|
||||
if (percent < 0.0 || percent >= 1.0) setSyncStatus("");
|
||||
else {
|
||||
long blocksRemaining = HavenoUtils.xmrConnectionService.getTargetHeight() - trade.getHeight();
|
||||
setSyncStatus(Res.get("portfolio.pending.syncing", ((int) Math.round(percent * 100)), blocksRemaining));
|
||||
}
|
||||
}
|
||||
|
||||
private void addTradeStateSubscription() {
|
||||
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
|
||||
if (newValue != null) {
|
||||
|
|
@ -301,6 +316,9 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
if (mediationResultStateSubscription != null)
|
||||
mediationResultStateSubscription.unsubscribe();
|
||||
|
||||
if (syncProgressSubscription != null)
|
||||
syncProgressSubscription.unsubscribe();
|
||||
|
||||
if (tradePeriodStateSubscription != null)
|
||||
tradePeriodStateSubscription.unsubscribe();
|
||||
|
||||
|
|
@ -402,6 +420,9 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
|
||||
infoLabel = addMultilineLabel(gridPane, gridRow, "", Layout.COMPACT_FIRST_ROW_AND_COMPACT_GROUP_DISTANCE);
|
||||
GridPane.setColumnSpan(infoLabel, 2);
|
||||
|
||||
statusLabel = new Label();
|
||||
gridPane.add(statusLabel, 0, ++gridRow, 2, 1);
|
||||
}
|
||||
|
||||
protected String getInfoText() {
|
||||
|
|
@ -869,4 +890,24 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
public void setChatCallback(TradeSubView.ChatCallback chatCallback) {
|
||||
this.chatCallback = chatCallback;
|
||||
}
|
||||
|
||||
protected void setSyncStatus(String text) {
|
||||
syncStatus = text;
|
||||
if (syncStatus == null || syncStatus.isEmpty()) {
|
||||
setStatus(tradeStatus);
|
||||
} else {
|
||||
setStatus(syncStatus);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setTradeStatus(String text) {
|
||||
tradeStatus = text;
|
||||
if (syncStatus == null || syncStatus.isEmpty()) {
|
||||
setStatus(tradeStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatus(String text) {
|
||||
if (statusLabel != null) statusLabel.setText(text == null ? "" : text);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@ import static haveno.desktop.util.FormBuilder.addTopLabelTextFieldWithCopyIcon;
|
|||
public class BuyerStep2View extends TradeStepView {
|
||||
|
||||
private Button confirmButton;
|
||||
private Label statusLabel;
|
||||
private BusyAnimation busyAnimation;
|
||||
private Subscription tradeStatePropertySubscription;
|
||||
private Timer timeoutTimer;
|
||||
|
|
@ -159,40 +158,40 @@ public class BuyerStep2View extends TradeStepView {
|
|||
|
||||
if (trade.isDepositsUnlocked() && !trade.isPaymentSent()) {
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText("");
|
||||
setTradeStatus("");
|
||||
showPopup();
|
||||
} else if (state.ordinal() <= Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) {
|
||||
switch (state) {
|
||||
case BUYER_CONFIRMED_PAYMENT_SENT:
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.preparingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.preparingConfirmation"));
|
||||
break;
|
||||
case BUYER_SENT_PAYMENT_SENT_MSG:
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmation"));
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmationAgain"));
|
||||
}, 30);
|
||||
break;
|
||||
case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG:
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
|
||||
setTradeStatus(Res.get("shared.messageStoredInMailbox"));
|
||||
break;
|
||||
case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG:
|
||||
case SELLER_RECEIVED_PAYMENT_SENT_MSG:
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.messageArrived"));
|
||||
setTradeStatus(Res.get("shared.messageArrived"));
|
||||
break;
|
||||
case BUYER_SEND_FAILED_PAYMENT_SENT_MSG:
|
||||
// We get a popup and the trade closed, so we dont need to show anything here
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText("");
|
||||
setTradeStatus("");
|
||||
break;
|
||||
default:
|
||||
log.warn("Unexpected case: State={}, tradeId={} ", state.name(), trade.getId());
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmationAgain"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -676,7 +675,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
|
||||
private void confirmPaymentSent() {
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.preparingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.preparingConfirmation"));
|
||||
confirmButton.setDisable(true);
|
||||
|
||||
model.dataModel.onPaymentSent(() -> {
|
||||
|
|
@ -684,7 +683,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
busyAnimation.stop();
|
||||
new Popup().warning(Res.get("popup.warning.sendMsgFailed") + "\n\n" + errorMessage).show();
|
||||
confirmButton.setDisable(!confirmPaymentSentPermitted());
|
||||
UserThread.execute(() -> statusLabel.setText("Error confirming payment sent."));
|
||||
UserThread.execute(() -> setTradeStatus("Error confirming payment sent."));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package haveno.desktop.main.portfolio.pendingtrades.steps.buyer;
|
||||
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import haveno.common.util.Tuple4;
|
||||
import haveno.core.locale.Res;
|
||||
import haveno.core.network.MessageState;
|
||||
import haveno.desktop.components.TextFieldWithIcon;
|
||||
|
|
@ -27,10 +28,11 @@ import haveno.desktop.util.Layout;
|
|||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import static haveno.desktop.util.FormBuilder.addMultilineLabel;
|
||||
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
import static haveno.desktop.util.FormBuilder.addTopLabelTextFieldWithIcon;
|
||||
import static haveno.desktop.util.FormBuilder.addTopLabelTextFieldWithIconLabel;
|
||||
|
||||
public class BuyerStep3View extends TradeStepView {
|
||||
private final ChangeListener<MessageState> messageStateChangeListener;
|
||||
|
|
@ -74,8 +76,11 @@ public class BuyerStep3View extends TradeStepView {
|
|||
addTitledGroupBg(gridPane, ++gridRow, 2, getInfoBlockTitle(), Layout.GROUP_DISTANCE);
|
||||
infoLabel = addMultilineLabel(gridPane, gridRow, "", Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
GridPane.setColumnSpan(infoLabel, 2);
|
||||
textFieldWithIcon = addTopLabelTextFieldWithIcon(gridPane, ++gridRow,
|
||||
Res.get("portfolio.pending.step3_buyer.wait.msgStateInfo.label"), 0).second;
|
||||
Tuple4<VBox, Label, TextFieldWithIcon, Label> tuple = addTopLabelTextFieldWithIconLabel(gridPane, ++gridRow,
|
||||
Res.get("portfolio.pending.step3_buyer.wait.msgStateInfo.label"), 0);
|
||||
GridPane.setColumnSpan(tuple.first, 2);
|
||||
textFieldWithIcon = tuple.third;
|
||||
statusLabel = tuple.fourth;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ import static haveno.desktop.util.Layout.FLOATING_LABEL_DISTANCE;
|
|||
public class SellerStep3View extends TradeStepView {
|
||||
|
||||
private Button confirmButton;
|
||||
private Label statusLabel;
|
||||
private BusyAnimation busyAnimation;
|
||||
private Subscription tradeStatePropertySubscription;
|
||||
private Timer timeoutTimer;
|
||||
|
|
@ -110,44 +109,44 @@ public class SellerStep3View extends TradeStepView {
|
|||
|
||||
if (trade.isPaymentSent() && !trade.isPaymentReceived()) {
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText("");
|
||||
setTradeStatus("");
|
||||
showPopup();
|
||||
} else if (trade.isPaymentReceived()) {
|
||||
if (trade.isCompleted()) {
|
||||
if (!trade.isPayoutPublished()) log.warn("Payout is expected to be published for {} {} state {}", trade.getClass().getSimpleName(), trade.getId(), trade.getState());
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText("");
|
||||
setTradeStatus("");
|
||||
} else switch (state) {
|
||||
case SELLER_CONFIRMED_PAYMENT_RECEIPT:
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.preparingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.preparingConfirmation"));
|
||||
break;
|
||||
case SELLER_SENT_PAYMENT_RECEIVED_MSG:
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmation"));
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmationAgain"));
|
||||
}, 30);
|
||||
break;
|
||||
case SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG:
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
|
||||
setTradeStatus(Res.get("shared.messageStoredInMailbox"));
|
||||
break;
|
||||
case SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG:
|
||||
case BUYER_RECEIVED_PAYMENT_RECEIVED_MSG:
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.messageArrived"));
|
||||
setTradeStatus(Res.get("shared.messageArrived"));
|
||||
break;
|
||||
case SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG:
|
||||
// We get a popup and the trade closed, so we dont need to show anything here
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText("");
|
||||
setTradeStatus("");
|
||||
break;
|
||||
default:
|
||||
log.warn("Unexpected case: State={}, tradeId={} " + state.name(), trade.getId());
|
||||
busyAnimation.stop();
|
||||
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
|
||||
setTradeStatus(Res.get("shared.sendingConfirmationAgain"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -446,7 +445,7 @@ public class SellerStep3View extends TradeStepView {
|
|||
private void confirmPaymentReceived() {
|
||||
log.info("User pressed the [Confirm payment receipt] button for Trade {}", trade.getShortId());
|
||||
busyAnimation.play();
|
||||
statusLabel.setText(Res.get("shared.preparingConfirmation"));
|
||||
setTradeStatus(Res.get("shared.preparingConfirmation"));
|
||||
confirmButton.setDisable(true);
|
||||
|
||||
model.dataModel.onPaymentReceived(() -> {
|
||||
|
|
@ -454,7 +453,7 @@ public class SellerStep3View extends TradeStepView {
|
|||
busyAnimation.stop();
|
||||
new Popup().warning(Res.get("popup.warning.sendMsgFailed") + "\n\n" + errorMessage).show();
|
||||
confirmButton.setDisable(!confirmPaymentReceivedPermitted());
|
||||
UserThread.execute(() -> statusLabel.setText("Error confirming payment received."));
|
||||
UserThread.execute(() -> setTradeStatus("Error confirming payment received."));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -540,6 +540,42 @@ public class FormBuilder {
|
|||
return new Tuple2<>(addTopLabelWithVBox(gridPane, rowIndex, columnIndex, title, textFieldWithIcon, top).first, textFieldWithIcon);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Label + TextFieldWithIcon + Label
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static Tuple4<VBox, Label, TextFieldWithIcon, Label> addTopLabelTextFieldWithIconLabel(GridPane gridPane,
|
||||
int rowIndex,
|
||||
String title,
|
||||
double top) {
|
||||
return addTopLabelTextFieldWithIconLabel(gridPane, rowIndex, 0, title, top);
|
||||
}
|
||||
|
||||
public static Tuple4<VBox, Label, TextFieldWithIcon, Label> addTopLabelTextFieldWithIconLabel(GridPane gridPane,
|
||||
int rowIndex,
|
||||
int columnIndex,
|
||||
String title,
|
||||
double top) {
|
||||
HBox hBox = new HBox();
|
||||
hBox.setSpacing(10);
|
||||
|
||||
TextFieldWithIcon textFieldWithIcon = new TextFieldWithIcon();
|
||||
textFieldWithIcon.setFocusTraversable(false);
|
||||
|
||||
Label label = new AutoTooltipLabel();
|
||||
hBox.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
hBox.getChildren().addAll(textFieldWithIcon, label);
|
||||
GridPane.setRowIndex(hBox, rowIndex);
|
||||
GridPane.setColumnIndex(hBox, columnIndex);
|
||||
GridPane.setMargin(hBox, new Insets(top, 0, 0, 0));
|
||||
gridPane.getChildren().add(hBox);
|
||||
|
||||
Tuple2<Label, VBox> topLabelWithVBox = addTopLabelWithVBox(gridPane, rowIndex, columnIndex, title, hBox, top);
|
||||
|
||||
return new Tuple4<>(topLabelWithVBox.second, topLabelWithVBox.first, textFieldWithIcon, label);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// HyperlinkWithIcon
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue