major update to look and feel of desktop ui (#1733)

This commit is contained in:
woodser 2025-06-06 08:18:51 -04:00 committed by GitHub
parent c239f9aac0
commit aa1eb70d9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
141 changed files with 2395 additions and 995 deletions

View file

@ -51,6 +51,7 @@ import org.bitcoinj.utils.MonetaryFormat;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale;
public class VolumeUtil {
@ -187,4 +188,35 @@ public class VolumeUtil {
private static MonetaryFormat getMonetaryFormat(String currencyCode) {
return CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode) ? VOLUME_FORMAT_UNIT : VOLUME_FORMAT_PRECISE;
}
public static Volume sum(Collection<Volume> volumes) {
if (volumes == null || volumes.isEmpty()) {
return null;
}
Volume sum = null;
for (Volume volume : volumes) {
if (sum == null) {
sum = volume;
} else {
if (!sum.getCurrencyCode().equals(volume.getCurrencyCode())) {
throw new IllegalArgumentException("Cannot sum volumes with different currencies");
}
sum = add(sum, volume);
}
}
return sum;
}
public static Volume add(Volume volume1, Volume volume2) {
if (volume1 == null) return volume2;
if (volume2 == null) return volume1;
if (!volume1.getCurrencyCode().equals(volume2.getCurrencyCode())) {
throw new IllegalArgumentException("Cannot add volumes with different currencies");
}
if (volume1.getMonetary() instanceof CryptoMoney) {
return new Volume(((CryptoMoney) volume1.getMonetary()).add((CryptoMoney) volume2.getMonetary()));
} else {
return new Volume(((TraditionalMoney) volume1.getMonetary()).add((TraditionalMoney) volume2.getMonetary()));
}
}
}

View file

@ -315,9 +315,6 @@ market.tabs.spreadCurrency=Offers by Currency
market.tabs.spreadPayment=Offers by Payment Method
market.tabs.trades=Trades
# OfferBookView
market.offerBook.filterPrompt=Filter
# OfferBookChartView
market.offerBook.sellOffersHeaderLabel=Sell {0} to
market.offerBook.buyOffersHeaderLabel=Buy {0} from
@ -410,8 +407,10 @@ shared.notSigned.noNeedAlts=Cryptocurrency accounts do not feature signing or ag
offerbook.nrOffers=No. of offers: {0}
offerbook.volume={0} (min - max)
offerbook.volumeTotal={0} {1}
offerbook.deposit=Deposit XMR (%)
offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed.
offerbook.XMRTotal=XMR ({0})
offerbook.createNewOffer=Create offer to {0} {1}
offerbook.createOfferDisabled.tooltip=You can only create one offer at a time
@ -1162,8 +1161,6 @@ support.tab.refund.support=Refund
support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Enter trade ID, date, onion address or account data
support.tab.SignedOffers=Signed Offers
support.prompt.signedOffer.penalty.msg=This will charge the maker a penalty fee and return the remaining trade funds to their wallet. Are you sure you want to send?\n\n\
Offer ID: {0}\n\
@ -1337,6 +1334,7 @@ setting.preferences.displayOptions=Display options
setting.preferences.showOwnOffers=Show my own offers in offer book
setting.preferences.useAnimations=Use animations
setting.preferences.useDarkMode=Use dark mode
setting.preferences.useLightMode=Use light mode
setting.preferences.sortWithNumOffers=Sort market lists with no. of offers/trades
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -2012,6 +2010,7 @@ offerDetailsWindow.confirm.takerCrypto=Confirm: Take offer to {0} {1}
offerDetailsWindow.creationDate=Creation date
offerDetailsWindow.makersOnion=Maker's onion address
offerDetailsWindow.challenge=Offer passphrase
offerDetailsWindow.challenge.copy=Copy passphrase to share with your peer
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -315,7 +315,6 @@ market.tabs.spreadPayment=Nabídky podle způsobů platby
market.tabs.trades=Obchody
# OfferBookView
market.offerBook.filterPrompt=Filtr
# OfferBookChartView
market.offerBook.sellOffersHeaderLabel=Prodat {0} kupujícímu
@ -1125,8 +1124,6 @@ support.tab.refund.support=Vrácení peněz
support.tab.arbitration.support=Arbitráž
support.tab.legacyArbitration.support=Starší arbitráž
support.tab.ArbitratorsSupportTickets=Úkoly pro {0}
support.filter=Hledat spory
support.filter.prompt=Zadejte ID obchodu, datum, onion adresu nebo údaje o účtu
support.tab.SignedOffers=Podepsané nabídky
support.prompt.signedOffer.penalty.msg=Tím se tvůrci účtuje sankční poplatek a zbývající prostředky z obchodu se vrátí do jeho peněženky. Jste si jisti, že chcete odeslat?\n\n\
ID nabídky: {0}\n\
@ -1300,6 +1297,7 @@ setting.preferences.displayOptions=Zobrazit možnosti
setting.preferences.showOwnOffers=Zobrazit mé vlastní nabídky v seznamu nabídek
setting.preferences.useAnimations=Použít animace
setting.preferences.useDarkMode=Použít tmavý režim
setting.preferences.useLightMode=Použijte světlý režim
setting.preferences.sortWithNumOffers=Seřadit seznamy trhů s počtem nabídek/obchodů
setting.preferences.onlyShowPaymentMethodsFromAccount=Skrýt nepodporované způsoby platby
setting.preferences.denyApiTaker=Odmítat příjemce, kteří používají API
@ -1975,6 +1973,7 @@ offerDetailsWindow.confirm.takerCrypto=Potvrďte: Přijmout nabídku {0} {1}
offerDetailsWindow.creationDate=Datum vzniku
offerDetailsWindow.makersOnion=Onion adresa tvůrce
offerDetailsWindow.challenge=Passphrase nabídky
offerDetailsWindow.challenge.copy=Zkopírujte přístupovou frázi pro sdílení s protějškem
qRCodeWindow.headline=QR Kód
qRCodeWindow.msg=Použijte tento QR kód k financování vaší peněženky Haveno z vaší externí peněženky.

View file

@ -927,8 +927,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Vermittlung
support.tab.legacyArbitration.support=Legacy-Vermittlung
support.tab.ArbitratorsSupportTickets={0} Tickets
support.filter=Konflikte durchsuchen
support.filter.prompt=Tragen sie Handel ID, Datum, Onion Adresse oder Kontodaten
support.sigCheck.button=Signatur überprüfen
support.sigCheck.popup.info=Fügen Sie die Zusammenfassungsnachricht des Schiedsverfahrens ein. Mit diesem Tool kann jeder Benutzer überprüfen, ob die Unterschrift des Schiedsrichters mit der Zusammenfassungsnachricht übereinstimmt.
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=Darstellungsoptionen
setting.preferences.showOwnOffers=Eigenen Angebote im Angebotsbuch zeigen
setting.preferences.useAnimations=Animationen abspielen
setting.preferences.useDarkMode=Nacht-Modus benutzen
setting.preferences.useLightMode=Leichtmodus verwenden
setting.preferences.sortWithNumOffers=Marktlisten nach Anzahl der Angebote/Trades sortieren
setting.preferences.onlyShowPaymentMethodsFromAccount=Nicht unterstützte Zahlungsmethoden ausblenden
setting.preferences.denyApiTaker=Taker die das API nutzen vermeiden
@ -1477,6 +1476,7 @@ offerDetailsWindow.confirm.taker=Bestätigen: Angebot annehmen monero zu {0}
offerDetailsWindow.creationDate=Erstellungsdatum
offerDetailsWindow.makersOnion=Onion-Adresse des Erstellers
offerDetailsWindow.challenge=Angebots-Passphrase
offerDetailsWindow.challenge.copy=Passphrase kopieren, um sie mit Ihrem Handelspartner zu teilen
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Bitte nutzen Sie diesen QR Code um Ihr Haveno Wallet von Ihrem externen Wallet aufzuladen.

View file

@ -928,8 +928,6 @@ support.tab.mediation.support=Mediación
support.tab.arbitration.support=Arbitraje
support.tab.legacyArbitration.support=Legado de arbitraje
support.tab.ArbitratorsSupportTickets=Tickets de {0}
support.filter=Buscar disputas
support.filter.prompt=Introduzca ID de transacción, fecha, dirección onion o datos de cuenta.
support.sigCheck.button=Comprobar firma
support.sigCheck.popup.info=Pegue el mensaje resumido del proceso de arbitraje. Con esta herramienta, cualquier usuario puede verificar si la firma del árbitro coincide con el mensaje resumido.
@ -1036,6 +1034,7 @@ setting.preferences.displayOptions=Mostrar opciones
setting.preferences.showOwnOffers=Mostrar mis propias ofertas en el libro de ofertas
setting.preferences.useAnimations=Usar animaciones
setting.preferences.useDarkMode=Usar modo oscuro
setting.preferences.useLightMode=Usar modo claro
setting.preferences.sortWithNumOffers=Ordenar listas de mercado por número de ofertas/intercambios
setting.preferences.onlyShowPaymentMethodsFromAccount=Ocultar métodos de pago no soportados
setting.preferences.denyApiTaker=Denegar tomadores usando la misma API
@ -1478,6 +1477,7 @@ offerDetailsWindow.confirm.taker=Confirmar: Tomar oferta {0} monero
offerDetailsWindow.creationDate=Fecha de creación
offerDetailsWindow.makersOnion=Dirección onion del creador
offerDetailsWindow.challenge=Frase de contraseña de la oferta
offerDetailsWindow.challenge.copy=Copiar frase de contraseña para compartir con tu contraparte
qRCodeWindow.headline=Código QR
qRCodeWindow.msg=Por favor, utilice este código QR para fondear su billetera Haveno desde su billetera externa.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=فیلتر
shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Enter trade ID, date, onion address or account data
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=افزودن آلتکوین
setting.preferences.displayOptions=نمایش گزینه‌ها
setting.preferences.showOwnOffers=نمایش پیشنهادهای من در دفتر پیشنهاد
setting.preferences.useAnimations=استفاده از انیمیشن‌ها
setting.preferences.useDarkMode=Use dark mode
setting.preferences.useDarkMode=حالت تاریک را استفاده کنید
setting.preferences.useLightMode=حالت روشن را استفاده کنید
setting.preferences.sortWithNumOffers=مرتب سازی لیست‌ها با تعداد معاملات/پیشنهادها
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1473,6 +1472,7 @@ offerDetailsWindow.confirm.taker=تأیید: پیشنهاد را به {0} بپذ
offerDetailsWindow.creationDate=تاریخ ایجاد
offerDetailsWindow.makersOnion=آدرس Onion سفارش گذار
offerDetailsWindow.challenge=Passphrase de l'offre
offerDetailsWindow.challenge.copy=عبارت عبور را برای به اشتراک‌گذاری با همتا کپی کنید
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -929,8 +929,6 @@ support.tab.mediation.support=Médiation
support.tab.arbitration.support=Arbitrage
support.tab.legacyArbitration.support=Conclusion d'arbitrage
support.tab.ArbitratorsSupportTickets=Tickets de {0}
support.filter=Chercher les litiges
support.filter.prompt=Saisissez l'ID du trade, la date, l'adresse "onion" ou les données du compte.
support.sigCheck.button=Vérifier la signature
support.sigCheck.popup.info=Collez le message récapitulatif du processus d'arbitrage. Avec cet outil, n'importe quel utilisateur peut vérifier si la signature de l'arbitre correspond au message récapitulatif.
@ -1037,6 +1035,7 @@ setting.preferences.displayOptions=Afficher les options
setting.preferences.showOwnOffers=Montrer mes ordres dans le livre des ordres
setting.preferences.useAnimations=Utiliser des animations
setting.preferences.useDarkMode=Utiliser le mode sombre
setting.preferences.useLightMode=Utiliser le mode clair
setting.preferences.sortWithNumOffers=Trier les listes de marché avec le nombre d'ordres/de transactions
setting.preferences.onlyShowPaymentMethodsFromAccount=Masquer les méthodes de paiement non supportées
setting.preferences.denyApiTaker=Refuser les preneurs utilisant l'API
@ -1479,6 +1478,7 @@ offerDetailsWindow.confirm.taker=Confirmer: Acceptez l''ordre de {0} monero
offerDetailsWindow.creationDate=Date de création
offerDetailsWindow.makersOnion=Adresse onion du maker
offerDetailsWindow.challenge=Phrase secrète de l'offre
offerDetailsWindow.challenge.copy=Copier la phrase secrète à partager avec votre pair
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Veuillez utiliser le code QR pour recharger du portefeuille externe au portefeuille Haveno.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=Al momento, hai troppe transazioni non confermate. Per favore riprova più tardi.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=Filtro
shared.enabled=Enabled
@ -927,8 +927,6 @@ support.tab.mediation.support=Mediazione
support.tab.arbitration.support=Arbitrato
support.tab.legacyArbitration.support=Arbitrato Legacy
support.tab.ArbitratorsSupportTickets=I ticket di {0}
support.filter=Search disputes
support.filter.prompt=Inserisci ID commerciale, data, indirizzo onion o dati dell'account
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1034,6 +1032,7 @@ setting.preferences.displayOptions=Mostra opzioni
setting.preferences.showOwnOffers=Mostra le mie offerte nel libro delle offerte
setting.preferences.useAnimations=Usa animazioni
setting.preferences.useDarkMode=Usa modalità notte
setting.preferences.useLightMode=Usa la modalità chiara
setting.preferences.sortWithNumOffers=Ordina le liste di mercato con n. di offerte/scambi
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1476,6 +1475,7 @@ offerDetailsWindow.confirm.taker=Conferma: Accetta l'offerta a {0} monero
offerDetailsWindow.creationDate=Data di creazione
offerDetailsWindow.makersOnion=Indirizzo .onion del maker
offerDetailsWindow.challenge=Passphrase dell'offerta
offerDetailsWindow.challenge.copy=Copia la frase segreta da condividere con il tuo interlocutore
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -927,8 +927,6 @@ support.tab.mediation.support=調停
support.tab.arbitration.support=仲裁
support.tab.legacyArbitration.support=レガシー仲裁
support.tab.ArbitratorsSupportTickets={0} のチケット
support.filter=係争を検索
support.filter.prompt=トレードID、日付、onionアドレスまたはアカウントデータを入力してください
support.sigCheck.button=Check signature
support.sigCheck.popup.info=仲裁プロセスの要約メッセージを貼り付けてください。このツールを使用すると、どんなユーザーでも仲裁者の署名が要約メッセージと一致するかどうかを確認できます。
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=表示設定
setting.preferences.showOwnOffers=オファーブックに自分のオファーを表示
setting.preferences.useAnimations=アニメーションを使用
setting.preferences.useDarkMode=ダークモードを利用
setting.preferences.useLightMode=ライトモードを使用する
setting.preferences.sortWithNumOffers=市場リストをオファー/トレードの数で並び替える
setting.preferences.onlyShowPaymentMethodsFromAccount=サポートされていない支払い方法を非表示にする
setting.preferences.denyApiTaker=APIを使用するテイカーを拒否する
@ -1477,6 +1476,7 @@ offerDetailsWindow.confirm.taker=承認: ビットコインを{0}オファーを
offerDetailsWindow.creationDate=作成日
offerDetailsWindow.makersOnion=メイカーのonionアドレス
offerDetailsWindow.challenge=オファーパスフレーズ
offerDetailsWindow.challenge.copy=ピアと共有するためにパスフレーズをコピーする
qRCodeWindow.headline=QRコード
qRCodeWindow.msg=外部ウォレットからHavenoウォレットへ送金するのに、このQRコードを利用して下さい。

View file

@ -221,7 +221,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=No momento, você possui muitas transações não-confirmadas. Tente novamente mais tarde.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=Filtro
shared.enabled=Enabled
@ -929,8 +929,6 @@ support.tab.mediation.support=Mediação
support.tab.arbitration.support=Arbitragem
support.tab.legacyArbitration.support=Arbitração antiga
support.tab.ArbitratorsSupportTickets=Tickets de {0}
support.filter=Search disputes
support.filter.prompt=Insira ID da negociação. data. endereço onion ou dados da conta
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1036,6 +1034,7 @@ setting.preferences.displayOptions=Opções de exibição
setting.preferences.showOwnOffers=Exibir minhas ofertas no livro de ofertas
setting.preferences.useAnimations=Usar animações
setting.preferences.useDarkMode=Usar modo escuro
setting.preferences.useLightMode=Usar modo claro
setting.preferences.sortWithNumOffers=Ordenar pelo nº de ofertas/negociações
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1480,6 +1479,7 @@ offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero
offerDetailsWindow.creationDate=Criada em
offerDetailsWindow.makersOnion=Endereço onion do ofertante
offerDetailsWindow.challenge=Passphrase da oferta
offerDetailsWindow.challenge.copy=Copiar frase secreta para compartilhar com seu par
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=Filtro
shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediação
support.tab.arbitration.support=Arbitragem
support.tab.legacyArbitration.support=Arbitragem Antiga
support.tab.ArbitratorsSupportTickets=Bilhetes de {0}
support.filter=Search disputes
support.filter.prompt=Insira o ID do negócio, data, endereço onion ou dados da conta
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1033,6 +1031,7 @@ setting.preferences.displayOptions=Mostrar opções
setting.preferences.showOwnOffers=Mostrar as minhas próprias ofertas no livro de ofertas
setting.preferences.useAnimations=Usar animações
setting.preferences.useDarkMode=Usar o modo escuro
setting.preferences.useLightMode=Usar modo claro
setting.preferences.sortWithNumOffers=Ordenar listas de mercado por nº de ofertas/negociações:
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1473,6 +1472,7 @@ offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero
offerDetailsWindow.creationDate=Data de criação
offerDetailsWindow.makersOnion=Endereço onion do ofertante
offerDetailsWindow.challenge=Passphrase da oferta
offerDetailsWindow.challenge.copy=Copiar frase secreta para compartilhar com seu parceiro
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=Фильтр
shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Введите идентификатор сделки, дату, onion-адрес или данные учётной записи
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=Добавить альткойн
setting.preferences.displayOptions=Параметры отображения
setting.preferences.showOwnOffers=Показать мои предложения в списке предложений
setting.preferences.useAnimations=Использовать анимацию
setting.preferences.useDarkMode=Use dark mode
setting.preferences.useDarkMode=Использовать тёмный режим
setting.preferences.useLightMode=Использовать светлый режим
setting.preferences.sortWithNumOffers=Сортировать списки по кол-ву предложений/сделок
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1474,6 +1473,7 @@ offerDetailsWindow.confirm.taker=Подтвердите: принять пред
offerDetailsWindow.creationDate=Дата создания
offerDetailsWindow.makersOnion=Onion-адрес мейкера
offerDetailsWindow.challenge=Пароль предложения
offerDetailsWindow.challenge.copy=Скопируйте кодовую фразу, чтобы поделиться с партнёром
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=ตัวกรอง
shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Enter trade ID, date, onion address or account data
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=เพิ่ม crypto
setting.preferences.displayOptions=แสดงตัวเลือกเพิ่มเติม
setting.preferences.showOwnOffers=แสดงข้อเสนอของฉันเองในสมุดข้อเสนอ
setting.preferences.useAnimations=ใช้ภาพเคลื่อนไหว
setting.preferences.useDarkMode=Use dark mode
setting.preferences.useDarkMode=ใช้โหมดมืด
setting.preferences.useLightMode=ใช้โหมดสว่าง
setting.preferences.sortWithNumOffers=จัดเรียงรายการโดยเลขของข้อเสนอ / การซื้อขาย
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1474,6 +1473,7 @@ offerDetailsWindow.confirm.taker=ยืนยัน: รับข้อเสน
offerDetailsWindow.creationDate=วันที่สร้าง
offerDetailsWindow.makersOnion=ที่อยู่ onion ของผู้สร้าง
offerDetailsWindow.challenge=รหัสผ่านสำหรับข้อเสนอ
offerDetailsWindow.challenge.copy=คัดลอกวลีรหัสเพื่อแชร์กับเพื่อนของคุณ
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -231,7 +231,7 @@ shared.delayedPayoutTxId=Gecikmiş ödeme işlem kimliği
shared.delayedPayoutTxReceiverAddress=Gecikmiş ödeme işlemi gönderildi
shared.unconfirmedTransactionsLimitReached=Şu anda çok fazla onaylanmamış işleminiz var. Lütfen daha sonra tekrar deneyin.
shared.numItemsLabel=Girdi sayısı: {0}
shared.filter=Filtrele
shared.filter=Filtre
shared.enabled=Etkin
shared.pending=Beklemede
shared.me=Ben
@ -1120,8 +1120,6 @@ support.tab.refund.support=Geri Ödeme
support.tab.arbitration.support=Arbitraj
support.tab.legacyArbitration.support=Eski Arbitraj
support.tab.ArbitratorsSupportTickets={0}'nin biletleri
support.filter=Uyuşmazlıkları ara
support.filter.prompt=İşlem ID'si, tarih, onion adresi veya hesap verilerini girin
support.tab.SignedOffers=İmzalı Teklifler
support.prompt.signedOffer.penalty.msg=Bu, üreticiden bir ceza ücreti alacak ve kalan işlem fonlarını cüzdanına iade edecektir. Göndermek istediğinizden emin misiniz?\n\n\
Teklif ID'si: {0}\n\
@ -1295,6 +1293,7 @@ setting.preferences.displayOptions=Görüntüleme seçenekleri
setting.preferences.showOwnOffers=Teklif defterinde kendi tekliflerini göster
setting.preferences.useAnimations=Animasyonları kullan
setting.preferences.useDarkMode=Karanlık modu kullan
setting.preferences.useLightMode=Aydınlık modu kullan
setting.preferences.sortWithNumOffers=Piyasaları teklif sayısına göre sırala
setting.preferences.onlyShowPaymentMethodsFromAccount=Olmayan ödeme yöntemlerini gizle
setting.preferences.denyApiTaker=API kullanan alıcıları reddet
@ -1970,6 +1969,7 @@ offerDetailsWindow.confirm.takerCrypto=Onayla: {0} {1} teklifi al
offerDetailsWindow.creationDate=Oluşturma tarihi
offerDetailsWindow.makersOnion=Yapıcı'nın onion adresi
offerDetailsWindow.challenge=Teklif şifresi
offerDetailsWindow.challenge.copy=Parolanızı eşinizle paylaşmak için kopyalayın
qRCodeWindow.headline=QR Kodu
qRCodeWindow.msg=Harici cüzdanınızdan Haveno cüzdanınızı finanse etmek için bu QR kodunu kullanın.

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=Delayed payout transaction ID
shared.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=Bộ lọc
shared.enabled=Enabled
@ -928,8 +928,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Nhập ID giao dịch, ngày tháng, địa chỉ onion hoặc dữ liệu tài khoản
support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature
@ -1033,7 +1031,8 @@ setting.preferences.addCrypto=Bổ sung crypto
setting.preferences.displayOptions=Hiển thị các phương án
setting.preferences.showOwnOffers=Hiển thị Báo giá của tôi trong danh mục Báo giá
setting.preferences.useAnimations=Sử dụng hoạt ảnh
setting.preferences.useDarkMode=Use dark mode
setting.preferences.useDarkMode=Sử dụng chế độ tối
setting.preferences.useLightMode=Sử dụng chế độ sáng
setting.preferences.sortWithNumOffers=Sắp xếp danh sách thị trường với số chào giá/giao dịch
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1476,6 +1475,7 @@ offerDetailsWindow.confirm.taker=Xác nhận: Nhận chào giáo cho {0} monero
offerDetailsWindow.creationDate=Ngày tạo
offerDetailsWindow.makersOnion=Địa chỉ onion của người tạo
offerDetailsWindow.challenge=Mã bảo vệ giao dịch
offerDetailsWindow.challenge.copy=Sao chép cụm mật khẩu để chia sẻ với đối tác của bạn
qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet.

View file

@ -927,8 +927,6 @@ support.tab.mediation.support=调解
support.tab.arbitration.support=仲裁
support.tab.legacyArbitration.support=历史仲裁
support.tab.ArbitratorsSupportTickets={0} 的工单
support.filter=查找纠纷
support.filter.prompt=输入 交易 ID、日期、洋葱地址或账户信息
support.sigCheck.button=Check signature
support.sigCheck.popup.info=请粘贴仲裁过程的摘要信息。使用这个工具,任何用户都可以检查仲裁者的签名是否与摘要信息相符。
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=显示选项
setting.preferences.showOwnOffers=在报价列表中显示我的报价
setting.preferences.useAnimations=使用动画
setting.preferences.useDarkMode=使用夜间模式
setting.preferences.useLightMode=使用浅色模式
setting.preferences.sortWithNumOffers=使用“报价ID/交易ID”筛选列表
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1478,6 +1477,7 @@ offerDetailsWindow.confirm.taker=确定:下单买入 {0} 比特币
offerDetailsWindow.creationDate=创建时间
offerDetailsWindow.makersOnion=卖家的匿名地址
offerDetailsWindow.challenge=提供密码
offerDetailsWindow.challenge.copy=复制助记词以与您的交易对手共享
qRCodeWindow.headline=二维码
qRCodeWindow.msg=请使用二维码从外部钱包充值至 Haveno 钱包

View file

@ -218,7 +218,7 @@ shared.delayedPayoutTxId=延遲支付交易 ID
shared.delayedPayoutTxReceiverAddress=延遲交易交易已發送至
shared.unconfirmedTransactionsLimitReached=你現在有過多的未確認交易。請稍後嘗試
shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter
shared.filter=篩選
shared.enabled=啟用
@ -927,8 +927,6 @@ support.tab.mediation.support=調解
support.tab.arbitration.support=仲裁
support.tab.legacyArbitration.support=歷史仲裁
support.tab.ArbitratorsSupportTickets={0} 的工單
support.filter=查找糾紛
support.filter.prompt=輸入 交易 ID、日期、洋葱地址或賬户信息
support.sigCheck.button=Check signature
support.sigCheck.popup.info=請貼上仲裁程序的摘要訊息。利用這個工具,任何使用者都可以檢查仲裁者的簽名是否與摘要訊息相符。
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=顯示選項
setting.preferences.showOwnOffers=在報價列表中顯示我的報價
setting.preferences.useAnimations=使用動畫
setting.preferences.useDarkMode=使用夜間模式
setting.preferences.useLightMode=使用淺色模式
setting.preferences.sortWithNumOffers=使用“報價ID/交易ID”篩選列表
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API
@ -1478,6 +1477,7 @@ offerDetailsWindow.confirm.taker=確定:下單買入 {0} 比特幣
offerDetailsWindow.creationDate=創建時間
offerDetailsWindow.makersOnion=賣家的匿名地址
offerDetailsWindow.challenge=提供密碼
offerDetailsWindow.challenge.copy=複製密語以與對方分享
qRCodeWindow.headline=二維碼
qRCodeWindow.msg=請使用二維碼從外部錢包充值至 Haveno 錢包

View file

@ -62,6 +62,8 @@
-demo-bar-fill: -bs-sell;
-fx-background-color: -demo-bar-fill;
-fx-background-insets: 0;
-fx-background-radius: 2px;
-fx-border-radius: 2px;
}
.candlestick-bar.close-above-open {
@ -80,6 +82,8 @@
-fx-padding: 5;
-fx-background-color: -bs-volume-transparent;
-fx-background-insets: 0;
-fx-background-radius: 2px;
-fx-border-radius: 2px;
}
.chart-alternative-row-fill {

View file

@ -74,6 +74,7 @@ import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
@ -224,6 +225,9 @@ public class HavenoApp extends Application implements UncaughtExceptionHandler {
});
CssTheme.loadSceneStyles(scene, preferences.getCssTheme(), config.useDevModeHeader);
// set initial background color
scene.setFill(CssTheme.isDarkTheme() ? Color.BLACK : Color.WHITE);
return scene;
}

View file

@ -216,7 +216,10 @@ public class HavenoAppMain extends HavenoExecutable {
// Set the dialog content
VBox vbox = new VBox(10);
vbox.getChildren().addAll(new ImageView(ImageUtil.getImageByPath("logo_splash.png")), passwordField, errorMessageField, versionField);
ImageView logoImageView = new ImageView(ImageUtil.getImageByPath("logo_splash_light.png"));
logoImageView.setFitWidth(342);
logoImageView.setPreserveRatio(true);
vbox.getChildren().addAll(logoImageView, passwordField, errorMessageField, versionField);
vbox.setAlignment(Pos.TOP_CENTER);
getDialogPane().setContent(vbox);

View file

@ -20,14 +20,17 @@ package haveno.desktop.components;
import com.jfoenix.controls.JFXTextField;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.UserThread;
import haveno.common.util.Utilities;
import haveno.core.locale.Res;
import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.AnchorPane;
@ -55,6 +58,7 @@ public class AddressTextField extends AnchorPane {
textField.setId("address-text-field");
textField.setEditable(false);
textField.setLabelFloat(true);
textField.getStyleClass().add("label-float");
textField.setPromptText(label);
textField.textProperty().bind(address);
@ -70,28 +74,32 @@ public class AddressTextField extends AnchorPane {
textField.focusTraversableProperty().set(focusTraversableProperty().get());
Label extWalletIcon = new Label();
extWalletIcon.setLayoutY(3);
extWalletIcon.setLayoutY(Layout.FLOATING_ICON_Y);
extWalletIcon.getStyleClass().addAll("icon", "highlight");
extWalletIcon.setTooltip(new Tooltip(tooltipText));
AwesomeDude.setIcon(extWalletIcon, AwesomeIcon.SIGNIN);
extWalletIcon.setOnMouseClicked(e -> openWallet());
Label copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().addAll("icon", "highlight");
Tooltip.install(copyIcon, new Tooltip(Res.get("addressTextField.copyToClipboard")));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
copyIcon.setOnMouseClicked(e -> {
Label copyLabel = new Label();
copyLabel.setLayoutY(Layout.FLOATING_ICON_Y);
copyLabel.getStyleClass().addAll("icon", "highlight");
Tooltip.install(copyLabel, new Tooltip(Res.get("addressTextField.copyToClipboard")));
copyLabel.setGraphic(GUIUtil.getCopyIcon());
copyLabel.setOnMouseClicked(e -> {
if (address.get() != null && address.get().length() > 0)
Utilities.copyToClipboard(address.get());
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
Node node = (Node) e.getSource();
UserThread.runAfter(() -> tp.hide(), 1);
tp.show(node, e.getScreenX() + Layout.PADDING, e.getScreenY() + Layout.PADDING);
});
AnchorPane.setRightAnchor(copyIcon, 30.0);
AnchorPane.setRightAnchor(copyLabel, 30.0);
AnchorPane.setRightAnchor(extWalletIcon, 5.0);
AnchorPane.setRightAnchor(textField, 55.0);
AnchorPane.setLeftAnchor(textField, 0.0);
getChildren().addAll(textField, copyIcon, extWalletIcon);
getChildren().addAll(textField, copyLabel, extWalletIcon);
}
private void openWallet() {

View file

@ -31,15 +31,15 @@ public class AutoTooltipButton extends JFXButton {
}
public AutoTooltipButton(String text) {
super(text.toUpperCase());
super(text);
}
public AutoTooltipButton(String text, Node graphic) {
super(text.toUpperCase(), graphic);
super(text, graphic);
}
public void updateText(String text) {
setText(text.toUpperCase());
setText(text);
}
@Override

View file

@ -24,6 +24,7 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.ListView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import org.apache.commons.lang3.StringUtils;
@ -44,6 +45,7 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
private List<? extends T> extendedList;
private List<T> matchingList;
private JFXComboBoxListViewSkin<T> comboBoxListViewSkin;
private boolean selectAllShortcut = false;
public AutocompleteComboBox() {
this(FXCollections.observableArrayList());
@ -153,6 +155,27 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
private void reactToQueryChanges() {
getEditor().addEventHandler(KeyEvent.KEY_RELEASED, (KeyEvent event) -> {
// ignore ctrl and command keys
if (event.getCode() == KeyCode.CONTROL || event.getCode() == KeyCode.COMMAND || event.getCode() == KeyCode.META) {
event.consume();
return;
}
// handle select all
boolean isSelectAll = event.getCode() == KeyCode.A && (event.isControlDown() || event.isMetaDown());
if (isSelectAll) {
getEditor().selectAll();
selectAllShortcut = true;
event.consume();
return;
}
if (event.getCode() == KeyCode.A && selectAllShortcut) { // 'A' can be received after ctrl/cmd
selectAllShortcut = false;
event.consume();
return;
}
UserThread.execute(() -> {
String query = getEditor().getText();
var exactMatch = list.stream().anyMatch(item -> asString(item).equalsIgnoreCase(query));
@ -180,6 +203,10 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
if (matchingListSize() > 0) {
comboBoxListViewSkin.getPopupContent().autosize();
show();
if (comboBoxListViewSkin.getPopupContent() instanceof ListView<?> listView) {
listView.applyCss();
listView.layout();
}
} else {
hide();
}

View file

@ -47,6 +47,7 @@ public class BalanceTextField extends AnchorPane {
public BalanceTextField(String label) {
textField = new HavenoTextField();
textField.setLabelFloat(true);
textField.getStyleClass().add("label-float");
textField.setPromptText(label);
textField.setFocusTraversable(false);
textField.setEditable(false);

View file

@ -23,6 +23,7 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.util.Utilities;
import haveno.core.locale.Res;
import haveno.core.user.Preferences;
import haveno.desktop.util.GUIUtil;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
@ -38,19 +39,19 @@ public class ExplorerAddressTextField extends AnchorPane {
@Getter
private final TextField textField;
private final Label copyIcon, missingAddressWarningIcon;
private final Label copyLabel, missingAddressWarningIcon;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public ExplorerAddressTextField() {
copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().addAll("icon", "highlight");
copyIcon.setTooltip(new Tooltip(Res.get("explorerAddressTextField.copyToClipboard")));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
AnchorPane.setRightAnchor(copyIcon, 30.0);
copyLabel = new Label();
copyLabel.setLayoutY(3);
copyLabel.getStyleClass().addAll("icon", "highlight");
copyLabel.setTooltip(new Tooltip(Res.get("explorerAddressTextField.copyToClipboard")));
copyLabel.setGraphic(GUIUtil.getCopyIcon());
AnchorPane.setRightAnchor(copyLabel, 30.0);
Tooltip tooltip = new Tooltip(Res.get("explorerAddressTextField.blockExplorerIcon.tooltip"));
@ -71,27 +72,27 @@ public class ExplorerAddressTextField extends AnchorPane {
AnchorPane.setRightAnchor(textField, 80.0);
AnchorPane.setLeftAnchor(textField, 0.0);
textField.focusTraversableProperty().set(focusTraversableProperty().get());
getChildren().addAll(textField, missingAddressWarningIcon, copyIcon);
getChildren().addAll(textField, missingAddressWarningIcon, copyLabel);
}
public void setup(@Nullable String address) {
if (address == null) {
textField.setText(Res.get("shared.na"));
textField.setId("address-text-field-error");
copyIcon.setVisible(false);
copyIcon.setManaged(false);
copyLabel.setVisible(false);
copyLabel.setManaged(false);
missingAddressWarningIcon.setVisible(true);
missingAddressWarningIcon.setManaged(true);
return;
}
textField.setText(address);
copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(address));
copyLabel.setOnMouseClicked(e -> Utilities.copyToClipboard(address));
}
public void cleanup() {
textField.setOnMouseClicked(null);
copyIcon.setOnMouseClicked(null);
copyLabel.setOnMouseClicked(null);
textField.setText("");
}
}

View file

@ -17,9 +17,10 @@
package haveno.desktop.components;
import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.util.Utilities;
import haveno.core.locale.Res;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@ -29,8 +30,6 @@ import javafx.scene.layout.AnchorPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static haveno.desktop.util.FormBuilder.getIcon;
public class FundsTextField extends InfoTextField {
public static final Logger log = LoggerFactory.getLogger(FundsTextField.class);
@ -46,11 +45,12 @@ public class FundsTextField extends InfoTextField {
textField.textProperty().unbind();
textField.textProperty().bind(Bindings.concat(textProperty())); // TODO: removed `, " ", fundsStructure` for haveno to fix "Funds needed: .123 XMR (null)" bug
Label copyIcon = getIcon(AwesomeIcon.COPY);
copyIcon.setLayoutY(5);
copyIcon.getStyleClass().addAll("icon", "highlight");
Tooltip.install(copyIcon, new Tooltip(Res.get("shared.copyToClipboard")));
copyIcon.setOnMouseClicked(e -> {
Label copyLabel = new Label();
copyLabel.setLayoutY(Layout.FLOATING_ICON_Y);
copyLabel.getStyleClass().addAll("icon", "highlight");
Tooltip.install(copyLabel, new Tooltip(Res.get("shared.copyToClipboard")));
copyLabel.setGraphic(GUIUtil.getCopyIcon());
copyLabel.setOnMouseClicked(e -> {
String text = getText();
if (text != null && text.length() > 0) {
String copyText;
@ -64,11 +64,11 @@ public class FundsTextField extends InfoTextField {
}
});
AnchorPane.setRightAnchor(copyIcon, 30.0);
AnchorPane.setRightAnchor(copyLabel, 30.0);
AnchorPane.setRightAnchor(infoIcon, 62.0);
AnchorPane.setRightAnchor(textField, 55.0);
getChildren().add(copyIcon);
getChildren().add(copyLabel);
}
///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -1,16 +1,18 @@
package haveno.desktop.components;
import com.jfoenix.controls.JFXTextField;
import haveno.desktop.util.GUIUtil;
import javafx.scene.control.Skin;
public class HavenoTextField extends JFXTextField {
public HavenoTextField(String value) {
super(value);
GUIUtil.applyFilledStyle(this);
}
public HavenoTextField() {
super();
this(null);
}
@Override

View file

@ -21,6 +21,7 @@ import com.jfoenix.controls.JFXTextField;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import haveno.desktop.components.controlsfx.control.PopOver;
import haveno.desktop.util.Layout;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Node;
@ -51,13 +52,14 @@ public class InfoTextField extends AnchorPane {
arrowLocation = PopOver.ArrowLocation.RIGHT_TOP;
textField = new HavenoTextField();
textField.setLabelFloat(true);
textField.getStyleClass().add("label-float");
textField.setEditable(false);
textField.textProperty().bind(text);
textField.setFocusTraversable(false);
textField.setId("info-field");
infoIcon = getIcon(AwesomeIcon.INFO_SIGN);
infoIcon.setLayoutY(5);
infoIcon.setLayoutY(Layout.FLOATING_ICON_Y - 2);
infoIcon.getStyleClass().addAll("icon", "info");
AnchorPane.setRightAnchor(infoIcon, 7.0);

View file

@ -20,6 +20,7 @@ package haveno.desktop.components;
import com.jfoenix.controls.JFXTextField;
import haveno.core.util.validation.InputValidator;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.validation.JFXInputValidator;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
@ -67,6 +68,7 @@ public class InputTextField extends JFXTextField {
public InputTextField() {
super();
GUIUtil.applyFilledStyle(this);
getValidators().add(jfxValidationWrapper);

View file

@ -124,7 +124,8 @@ public class PeerInfoIcon extends Group {
numTradesPane.relocate(scaleFactor * 18, scaleFactor * 14);
numTradesPane.setMouseTransparent(true);
ImageView numTradesCircle = new ImageView();
numTradesCircle.setId("image-green_circle");
numTradesCircle.setId("image-green_circle_solid");
numTradesLabel = new AutoTooltipLabel();
numTradesLabel.relocate(scaleFactor * 5, scaleFactor * 1);
numTradesLabel.setId("ident-num-label");
@ -134,7 +135,7 @@ public class PeerInfoIcon extends Group {
tagPane.relocate(Math.round(scaleFactor * 18), scaleFactor * -2);
tagPane.setMouseTransparent(true);
ImageView tagCircle = new ImageView();
tagCircle.setId("image-blue_circle");
tagCircle.setId("image-blue_circle_solid");
tagLabel = new AutoTooltipLabel();
tagLabel.relocate(Math.round(scaleFactor * 5), scaleFactor * 1);
tagLabel.setId("ident-num-label");

View file

@ -18,12 +18,15 @@
package haveno.desktop.components;
import com.jfoenix.controls.JFXTextField;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.UserThread;
import haveno.common.util.Utilities;
import haveno.core.locale.Res;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
@ -45,12 +48,13 @@ public class TextFieldWithCopyIcon extends AnchorPane {
}
public TextFieldWithCopyIcon(String customStyleClass) {
Label copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().addAll("icon", "highlight");
copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
copyIcon.setOnMouseClicked(e -> {
Label copyLabel = new Label();
copyLabel.setLayoutY(Layout.FLOATING_ICON_Y);
copyLabel.getStyleClass().addAll("icon", "highlight");
if (customStyleClass != null) copyLabel.getStyleClass().add(customStyleClass + "-icon");
copyLabel.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
copyLabel.setGraphic(GUIUtil.getCopyIcon());
copyLabel.setOnMouseClicked(e -> {
String text = getText();
if (text != null && text.length() > 0) {
String copyText;
@ -70,17 +74,25 @@ public class TextFieldWithCopyIcon extends AnchorPane {
copyText = text;
}
Utilities.copyToClipboard(copyText);
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
Node node = (Node) e.getSource();
UserThread.runAfter(() -> tp.hide(), 1);
tp.show(node, e.getScreenX() + Layout.PADDING, e.getScreenY() + Layout.PADDING);
}
});
textField = new JFXTextField();
textField.setEditable(false);
if (customStyleClass != null) textField.getStyleClass().add(customStyleClass);
textField.textProperty().bindBidirectional(text);
AnchorPane.setRightAnchor(copyIcon, 5.0);
AnchorPane.setRightAnchor(copyLabel, 5.0);
AnchorPane.setRightAnchor(textField, 30.0);
AnchorPane.setLeftAnchor(textField, 0.0);
AnchorPane.setTopAnchor(copyLabel, 0.0);
AnchorPane.setBottomAnchor(copyLabel, 0.0);
AnchorPane.setTopAnchor(textField, 0.0);
AnchorPane.setBottomAnchor(textField, 0.0);
textField.focusTraversableProperty().set(focusTraversableProperty().get());
getChildren().addAll(textField, copyIcon);
getChildren().addAll(textField, copyLabel);
}
public void setPromptText(String value) {

View file

@ -21,6 +21,7 @@ import com.jfoenix.controls.JFXTextField;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.UserThread;
import haveno.desktop.util.Layout;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
@ -53,10 +54,10 @@ public class TextFieldWithIcon extends AnchorPane {
iconLabel = new Label();
iconLabel.setLayoutX(0);
iconLabel.setLayoutY(3);
iconLabel.setLayoutY(Layout.FLOATING_ICON_Y);
dummyTextField.widthProperty().addListener((observable, oldValue, newValue) -> {
iconLabel.setLayoutX(dummyTextField.widthProperty().get() + 20);
iconLabel.setLayoutX(dummyTextField.widthProperty().get() + 20 + Layout.FLOATING_ICON_Y);
});
getChildren().addAll(textField, dummyTextField, iconLabel);

View file

@ -29,7 +29,10 @@ import haveno.core.user.Preferences;
import haveno.core.xmr.wallet.XmrWalletService;
import haveno.desktop.components.indicator.TxConfidenceIndicator;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.value.ChangeListener;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
@ -51,7 +54,7 @@ public class TxIdTextField extends AnchorPane {
private final TextField textField;
private final Tooltip progressIndicatorTooltip;
private final TxConfidenceIndicator txConfidenceIndicator;
private final Label copyIcon, blockExplorerIcon, missingTxWarningIcon;
private final Label copyLabel, blockExplorerIcon, missingTxWarningIcon;
private MoneroWalletListener walletListener;
private ChangeListener<Number> tradeListener;
@ -70,16 +73,17 @@ public class TxIdTextField extends AnchorPane {
txConfidenceIndicator.setProgress(0);
txConfidenceIndicator.setVisible(false);
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
AnchorPane.setTopAnchor(txConfidenceIndicator, 3.0);
AnchorPane.setTopAnchor(txConfidenceIndicator, Layout.FLOATING_ICON_Y);
progressIndicatorTooltip = new Tooltip("-");
txConfidenceIndicator.setTooltip(progressIndicatorTooltip);
copyIcon = new Label();
copyIcon.setLayoutY(3);
copyIcon.getStyleClass().addAll("icon", "highlight");
copyIcon.setTooltip(new Tooltip(Res.get("txIdTextField.copyIcon.tooltip")));
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY);
AnchorPane.setRightAnchor(copyIcon, 30.0);
copyLabel = new Label();
copyLabel.setLayoutY(Layout.FLOATING_ICON_Y);
copyLabel.getStyleClass().addAll("icon", "highlight");
copyLabel.setTooltip(new Tooltip(Res.get("txIdTextField.copyIcon.tooltip")));
copyLabel.setGraphic(GUIUtil.getCopyIcon());
copyLabel.setCursor(Cursor.HAND);
AnchorPane.setRightAnchor(copyLabel, 30.0);
Tooltip tooltip = new Tooltip(Res.get("txIdTextField.blockExplorerIcon.tooltip"));
@ -89,7 +93,7 @@ public class TxIdTextField extends AnchorPane {
AwesomeDude.setIcon(blockExplorerIcon, AwesomeIcon.EXTERNAL_LINK);
blockExplorerIcon.setMinWidth(20);
AnchorPane.setRightAnchor(blockExplorerIcon, 52.0);
AnchorPane.setTopAnchor(blockExplorerIcon, 4.0);
AnchorPane.setTopAnchor(blockExplorerIcon, Layout.FLOATING_ICON_Y);
missingTxWarningIcon = new Label();
missingTxWarningIcon.getStyleClass().addAll("icon", "error-icon");
@ -97,7 +101,7 @@ public class TxIdTextField extends AnchorPane {
missingTxWarningIcon.setTooltip(new Tooltip(Res.get("txIdTextField.missingTx.warning.tooltip")));
missingTxWarningIcon.setMinWidth(20);
AnchorPane.setRightAnchor(missingTxWarningIcon, 52.0);
AnchorPane.setTopAnchor(missingTxWarningIcon, 4.0);
AnchorPane.setTopAnchor(missingTxWarningIcon, Layout.FLOATING_ICON_Y);
missingTxWarningIcon.setVisible(false);
missingTxWarningIcon.setManaged(false);
@ -108,7 +112,7 @@ public class TxIdTextField extends AnchorPane {
AnchorPane.setRightAnchor(textField, 80.0);
AnchorPane.setLeftAnchor(textField, 0.0);
textField.focusTraversableProperty().set(focusTraversableProperty().get());
getChildren().addAll(textField, missingTxWarningIcon, blockExplorerIcon, copyIcon, txConfidenceIndicator);
getChildren().addAll(textField, missingTxWarningIcon, blockExplorerIcon, copyLabel, txConfidenceIndicator);
}
public void setup(@Nullable String txId) {
@ -131,8 +135,8 @@ public class TxIdTextField extends AnchorPane {
textField.setId("address-text-field-error");
blockExplorerIcon.setVisible(false);
blockExplorerIcon.setManaged(false);
copyIcon.setVisible(false);
copyIcon.setManaged(false);
copyLabel.setVisible(false);
copyLabel.setManaged(false);
txConfidenceIndicator.setVisible(false);
missingTxWarningIcon.setVisible(true);
missingTxWarningIcon.setManaged(true);
@ -158,7 +162,13 @@ public class TxIdTextField extends AnchorPane {
textField.setText(txId);
textField.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId));
blockExplorerIcon.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId));
copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(txId));
copyLabel.setOnMouseClicked(e -> {
Utilities.copyToClipboard(txId);
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
Node node = (Node) e.getSource();
UserThread.runAfter(() -> tp.hide(), 1);
tp.show(node, e.getScreenX() + Layout.PADDING, e.getScreenY() + Layout.PADDING);
});
txConfidenceIndicator.setVisible(true);
// update off main thread
@ -177,7 +187,7 @@ public class TxIdTextField extends AnchorPane {
trade = null;
textField.setOnMouseClicked(null);
blockExplorerIcon.setOnMouseClicked(null);
copyIcon.setOnMouseClicked(null);
copyLabel.setOnMouseClicked(null);
textField.setText("");
}

View file

@ -494,7 +494,7 @@ public class PopOver extends PopupControl {
* @since 1.0
*/
public final void hide(Duration fadeOutDuration) {
log.info("hide:" + fadeOutDuration.toString());
log.debug("hide:" + fadeOutDuration.toString());
//We must remove EventFilter in order to prevent memory leak.
if (ownerWindow != null) {
ownerWindow.removeEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST,

View file

@ -17,13 +17,10 @@
package haveno.desktop.components.list;
import haveno.core.locale.Res;
import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.components.InputTextField;
import haveno.desktop.util.filtering.FilterableListItem;
import javafx.beans.value.ChangeListener;
import javafx.collections.transformation.FilteredList;
import javafx.geometry.Insets;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
@ -37,13 +34,10 @@ public class FilterBox extends HBox {
super();
setSpacing(5.0);
AutoTooltipLabel label = new AutoTooltipLabel(Res.get("shared.filter"));
HBox.setMargin(label, new Insets(5.0, 0, 0, 10.0));
textField = new InputTextField();
textField.setMinWidth(500);
getChildren().addAll(label, textField);
getChildren().addAll(textField);
}
public void initialize(FilteredList<? extends FilterableListItem> filteredList,
@ -67,4 +61,8 @@ public class FilterBox extends HBox {
private void applyFilteredListPredicate(String filterString) {
filteredList.setPredicate(item -> item.match(filterString));
}
public void setPromptText(String promptText) {
textField.setPromptText(promptText);
}
}

View file

@ -36,6 +36,7 @@ import haveno.desktop.components.AutocompleteComboBox;
import haveno.desktop.components.InputTextField;
import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.FormBuilder;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.geometry.Insets;
import javafx.scene.control.CheckBox;
@ -202,6 +203,8 @@ public class AssetsForm extends PaymentMethodForm {
CurrencyUtil.getActiveSortedCryptoCurrencies(filterManager));
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 10));
currencyComboBox.setCellFactory(GUIUtil.getTradeCurrencyCellFactoryNameAndCode());
currencyComboBox.setConverter(new StringConverter<>() {
@Override
public String toString(TradeCurrency tradeCurrency) {

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,3 @@
/* splash screen */
/*noinspection CssUnknownTarget*/
#image-splash-logo {
-fx-image: url("../../images/logo_splash.png");
}
/* splash screen testnet */
/*noinspection CssUnknownTarget*/
#image-splash-testnet-logo {
-fx-image: url("../../images/logo_splash_testnet.png");
}
/* shared*/
#image-info {
-fx-image: url("../../images/info.png");
}
@ -23,16 +10,29 @@
-fx-image: url("../../images/alert_round.png");
}
#image-red_circle_solid {
-fx-image: url("../../images/red_circle_solid.png");
}
#image-green_circle {
-fx-image: url("../../images/green_circle.png");
}
#image-green_circle_solid {
-fx-image: url("../../images/green_circle_solid.png");
}
#image-yellow_circle {
-fx-image: url("../../images/yellow_circle.png");
}
#image-blue_circle {
-fx-image: url("../../images/blue_circle.png");
#image-yellow_circle_solid {
-fx-image: url("../../images/yellow_circle_solid.png");
}
#image-blue_circle_solid {
-fx-image: url("../../images/blue_circle_solid.png");
}
#image-remove {
@ -300,3 +300,59 @@
#image-new-trade-protocol-screenshot {
-fx-image: url("../../images/new_trade_protocol_screenshot.png");
}
#image-support {
-fx-image: url("../../images/support.png");
}
#image-account {
-fx-image: url("../../images/account.png");
}
#image-settings {
-fx-image: url("../../images/settings.png");
}
#image-btc-logo {
-fx-image: url("../../images/btc_logo.png");
}
#image-bch-logo {
-fx-image: url("../../images/bch_logo.png");
}
#image-dai-erc20-logo {
-fx-image: url("../../images/dai-erc20_logo.png");
}
#image-eth-logo {
-fx-image: url("../../images/eth_logo.png");
}
#image-ltc-logo {
-fx-image: url("../../images/ltc_logo.png");
}
#image-usdc-erc20-logo {
-fx-image: url("../../images/usdc-erc20_logo.png");
}
#image-usdt-erc20-logo {
-fx-image: url("../../images/usdt-erc20_logo.png");
}
#image-usdt-trc20-logo {
-fx-image: url("../../images/usdt-trc20_logo.png");
}
#image-xmr-logo {
-fx-image: url("../../images/xmr_logo.png");
}
#image-dark-mode-toggle {
-fx-image: url("../../images/dark_mode_toggle.png");
}
#image-light-mode-toggle {
-fx-image: url("../../images/light_mode_toggle.png");
}

View file

@ -32,6 +32,7 @@ import haveno.core.locale.GlobalSettings;
import haveno.core.locale.LanguageUtil;
import haveno.core.locale.Res;
import haveno.core.provider.price.MarketPrice;
import haveno.core.user.Preferences;
import haveno.desktop.Navigation;
import haveno.desktop.common.view.CachingViewLoader;
import haveno.desktop.common.view.FxmlView;
@ -73,6 +74,7 @@ import javafx.geometry.Insets;
import javafx.geometry.NodeOrientation;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
@ -92,6 +94,7 @@ import static javafx.scene.layout.AnchorPane.setRightAnchor;
import static javafx.scene.layout.AnchorPane.setTopAnchor;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
@ -125,17 +128,19 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Label xmrSplashInfo;
private Popup p2PNetworkWarnMsgPopup, xmrNetworkWarnMsgPopup;
private final TorNetworkSettingsWindow torNetworkSettingsWindow;
private final Preferences preferences;
private static final int networkIconSize = 20;
public static StackPane getRootContainer() {
return MainView.rootContainer;
}
public static void blurLight() {
transitions.blur(MainView.rootContainer, Transitions.DEFAULT_DURATION, -0.6, false, 5);
transitions.blur(MainView.rootContainer, Transitions.DEFAULT_DURATION, -0.6, false, 15);
}
public static void blurUltraLight() {
transitions.blur(MainView.rootContainer, Transitions.DEFAULT_DURATION, -0.6, false, 2);
transitions.blur(MainView.rootContainer, Transitions.DEFAULT_DURATION, -0.6, false, 15);
}
public static void darken() {
@ -151,12 +156,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
CachingViewLoader viewLoader,
Navigation navigation,
Transitions transitions,
TorNetworkSettingsWindow torNetworkSettingsWindow) {
TorNetworkSettingsWindow torNetworkSettingsWindow,
Preferences preferences) {
super(model);
this.viewLoader = viewLoader;
this.navigation = navigation;
MainView.transitions = transitions;
this.torNetworkSettingsWindow = torNetworkSettingsWindow;
this.preferences = preferences;
}
@Override
@ -165,15 +172,15 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
if (LanguageUtil.isDefaultLanguageRTL())
MainView.rootContainer.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
ToggleButton marketButton = new NavButton(MarketView.class, Res.get("mainView.menu.market").toUpperCase());
ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buyXmr").toUpperCase());
ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sellXmr").toUpperCase());
ToggleButton portfolioButton = new NavButton(PortfolioView.class, Res.get("mainView.menu.portfolio").toUpperCase());
ToggleButton fundsButton = new NavButton(FundsView.class, Res.get("mainView.menu.funds").toUpperCase());
ToggleButton marketButton = new NavButton(MarketView.class, Res.get("mainView.menu.market"));
ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buyXmr"));
ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sellXmr"));
ToggleButton portfolioButton = new NavButton(PortfolioView.class, Res.get("mainView.menu.portfolio"));
ToggleButton fundsButton = new NavButton(FundsView.class, Res.get("mainView.menu.funds"));
ToggleButton supportButton = new NavButton(SupportView.class, Res.get("mainView.menu.support"));
ToggleButton accountButton = new NavButton(AccountView.class, Res.get("mainView.menu.account"));
ToggleButton settingsButton = new NavButton(SettingsView.class, Res.get("mainView.menu.settings"));
ToggleButton supportButton = new SecondaryNavButton(SupportView.class, Res.get("mainView.menu.support"), "image-support");
ToggleButton accountButton = new SecondaryNavButton(AccountView.class, Res.get("mainView.menu.account"), "image-account");
ToggleButton settingsButton = new SecondaryNavButton(SettingsView.class, Res.get("mainView.menu.settings"), "image-settings");
JFXBadge portfolioButtonWithBadge = new JFXBadge(portfolioButton);
JFXBadge supportButtonWithBadge = new JFXBadge(supportButton);
@ -298,47 +305,56 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
});
HBox primaryNav = new HBox(marketButton, getNavigationSeparator(), buyButton, getNavigationSeparator(),
sellButton, getNavigationSeparator(), portfolioButtonWithBadge, getNavigationSeparator(), fundsButton);
HBox primaryNav = new HBox(getLogoPane(), marketButton, getNavigationSpacer(), buyButton, getNavigationSpacer(),
sellButton, getNavigationSpacer(), portfolioButtonWithBadge, getNavigationSpacer(), fundsButton);
primaryNav.setAlignment(Pos.CENTER_LEFT);
primaryNav.getStyleClass().add("nav-primary");
HBox.setHgrow(primaryNav, Priority.SOMETIMES);
HBox secondaryNav = new HBox(supportButtonWithBadge, getNavigationSpacer(), accountButton,
getNavigationSpacer(), settingsButtonWithBadge, getNavigationSpacer());
secondaryNav.getStyleClass().add("nav-secondary");
HBox.setHgrow(secondaryNav, Priority.SOMETIMES);
secondaryNav.setAlignment(Pos.CENTER);
HBox priceAndBalance = new HBox(marketPriceBox.second, getNavigationSeparator(), availableBalanceBox.second,
getNavigationSeparator(), pendingBalanceBox.second, getNavigationSeparator(), reservedBalanceBox.second);
priceAndBalance.setMaxHeight(41);
priceAndBalance.setAlignment(Pos.CENTER);
priceAndBalance.setSpacing(9);
priceAndBalance.setSpacing(12);
priceAndBalance.getStyleClass().add("nav-price-balance");
HBox navPane = new HBox(primaryNav, secondaryNav, getNavigationSpacer(),
priceAndBalance) {{
setLeftAnchor(this, 0d);
setRightAnchor(this, 0d);
setTopAnchor(this, 0d);
HBox navPane = new HBox(primaryNav, priceAndBalance) {{
setLeftAnchor(this, 25d);
setRightAnchor(this, 25d);
setTopAnchor(this, 20d);
setPadding(new Insets(0, 0, 0, 0));
getStyleClass().add("top-navigation");
}};
navPane.setAlignment(Pos.CENTER);
HBox secondaryNav = new HBox(supportButtonWithBadge, accountButton, settingsButtonWithBadge);
secondaryNav.getStyleClass().add("nav-secondary");
secondaryNav.setAlignment(Pos.CENTER_RIGHT);
secondaryNav.setPickOnBounds(false);
HBox.setHgrow(secondaryNav, Priority.ALWAYS);
AnchorPane.setLeftAnchor(secondaryNav, 0.0);
AnchorPane.setRightAnchor(secondaryNav, 0.0);
AnchorPane.setTopAnchor(secondaryNav, 0.0);
AnchorPane secondaryNavContainer = new AnchorPane() {{
setId("nav-secondary-container");
setLeftAnchor(this, 0d);
setRightAnchor(this, 0d);
setTopAnchor(this, 94d);
}};
secondaryNavContainer.setPickOnBounds(false);
secondaryNavContainer.getChildren().add(secondaryNav);
AnchorPane contentContainer = new AnchorPane() {{
getStyleClass().add("content-pane");
setLeftAnchor(this, 0d);
setRightAnchor(this, 0d);
setTopAnchor(this, 57d);
setTopAnchor(this, 95d);
setBottomAnchor(this, 0d);
}};
AnchorPane applicationContainer = new AnchorPane(navPane, contentContainer) {{
AnchorPane applicationContainer = new AnchorPane(navPane, contentContainer, secondaryNavContainer) {{
setId("application-container");
}};
@ -398,15 +414,32 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Separator getNavigationSeparator() {
final Separator separator = new Separator(Orientation.VERTICAL);
HBox.setHgrow(separator, Priority.ALWAYS);
separator.setMaxHeight(22);
separator.setMaxWidth(Double.MAX_VALUE);
separator.getStyleClass().add("nav-separator");
return separator;
}
@NotNull
private Pane getLogoPane() {
ImageView logo = new ImageView();
logo.setId("image-logo-landscape");
logo.setPreserveRatio(true);
logo.setFitHeight(40);
logo.setSmooth(true);
logo.setCache(true);
final Pane pane = new Pane();
HBox.setHgrow(pane, Priority.ALWAYS);
pane.getStyleClass().add("nav-logo");
pane.getChildren().add(logo);
return pane;
}
@NotNull
private Region getNavigationSpacer() {
final Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
spacer.getStyleClass().add("nav-spacer");
return spacer;
}
@ -447,7 +480,6 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
priceComboBox.setVisibleRowCount(12);
priceComboBox.setFocusTraversable(false);
priceComboBox.setId("price-feed-combo");
priceComboBox.setPadding(new Insets(0, -4, -4, 0));
priceComboBox.setCellFactory(p -> getPriceFeedComboBoxListCell());
ListCell<PriceFeedComboBoxItem> buttonCell = getPriceFeedComboBoxListCell();
buttonCell.setId("price-feed-combo");
@ -458,7 +490,6 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
updateMarketPriceLabel(marketPriceLabel);
marketPriceLabel.getStyleClass().add("nav-balance-label");
marketPriceLabel.setPadding(new Insets(-2, 0, 4, 9));
marketPriceBox.getChildren().addAll(priceComboBox, marketPriceLabel);
@ -509,7 +540,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
vBox.setId("splash");
ImageView logo = new ImageView();
logo.setId(Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? "image-splash-logo" : "image-splash-testnet-logo");
logo.setId(Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? "image-logo-splash" : "image-logo-splash-testnet");
logo.setFitWidth(400);
logo.setPreserveRatio(true);
logo.setSmooth(true);
// createBitcoinInfoBox
xmrSplashInfo = new AutoTooltipLabel();
@ -552,7 +586,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
// create P2PNetworkBox
splashP2PNetworkLabel = new AutoTooltipLabel();
splashP2PNetworkLabel.setWrapText(true);
splashP2PNetworkLabel.setMaxWidth(500);
splashP2PNetworkLabel.setMaxWidth(700);
splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER);
splashP2PNetworkLabel.getStyleClass().add("sub-info");
splashP2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
@ -587,9 +621,11 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
ImageView splashP2PNetworkIcon = new ImageView();
splashP2PNetworkIcon.setId("image-connection-tor");
splashP2PNetworkIcon.setFitWidth(networkIconSize);
splashP2PNetworkIcon.setFitHeight(networkIconSize);
splashP2PNetworkIcon.setVisible(false);
splashP2PNetworkIcon.setManaged(false);
HBox.setMargin(splashP2PNetworkIcon, new Insets(0, 0, 5, 0));
HBox.setMargin(splashP2PNetworkIcon, new Insets(0, 0, 0, 0));
splashP2PNetworkIcon.setOnMouseClicked(e -> {
torNetworkSettingsWindow.show();
});
@ -603,6 +639,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
splashP2PNetworkIcon.setId(newValue);
splashP2PNetworkIcon.setVisible(true);
splashP2PNetworkIcon.setManaged(true);
splashP2PNetworkIcon.setFitWidth(networkIconSize);
splashP2PNetworkIcon.setFitHeight(networkIconSize);
// if we can connect in 10 sec. we know that tor is working
showTorNetworkSettingsTimer.stop();
@ -725,15 +763,39 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
setRightAnchor(versionBox, 10d);
setBottomAnchor(versionBox, 7d);
// Dark mode toggle
ImageView useDarkModeIcon = new ImageView();
useDarkModeIcon.setId(preferences.getCssTheme() == 1 ? "image-dark-mode-toggle" : "image-light-mode-toggle");
useDarkModeIcon.setFitHeight(networkIconSize);
useDarkModeIcon.setPreserveRatio(true);
useDarkModeIcon.setPickOnBounds(true);
useDarkModeIcon.setCursor(Cursor.HAND);
setRightAnchor(useDarkModeIcon, 8d);
setBottomAnchor(useDarkModeIcon, 6d);
Tooltip modeToolTip = new Tooltip();
Tooltip.install(useDarkModeIcon, modeToolTip);
useDarkModeIcon.setOnMouseEntered(e -> modeToolTip.setText(Res.get(preferences.getCssTheme() == 1 ? "setting.preferences.useLightMode" : "setting.preferences.useDarkMode")));
useDarkModeIcon.setOnMouseClicked(e -> {
preferences.setCssTheme(preferences.getCssTheme() != 1);
});
preferences.getCssThemeProperty().addListener((observable, oldValue, newValue) -> {
useDarkModeIcon.setId(preferences.getCssTheme() == 1 ? "image-dark-mode-toggle" : "image-light-mode-toggle");
});
// P2P Network
Label p2PNetworkLabel = new AutoTooltipLabel();
p2PNetworkLabel.setId("footer-pane");
p2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
double networkIconRightAnchor = 54d;
ImageView p2PNetworkIcon = new ImageView();
setRightAnchor(p2PNetworkIcon, 10d);
setBottomAnchor(p2PNetworkIcon, 5d);
setRightAnchor(p2PNetworkIcon, networkIconRightAnchor);
setBottomAnchor(p2PNetworkIcon, 6d);
p2PNetworkIcon.setPickOnBounds(true);
p2PNetworkIcon.setCursor(Cursor.HAND);
p2PNetworkIcon.setOpacity(0.4);
p2PNetworkIcon.setFitWidth(networkIconSize);
p2PNetworkIcon.setFitHeight(networkIconSize);
p2PNetworkIcon.idProperty().bind(model.getP2PNetworkIconId());
p2PNetworkLabel.idProperty().bind(model.getP2pNetworkLabelId());
model.getP2pNetworkWarnMsg().addListener((ov, oldValue, newValue) -> {
@ -749,8 +811,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
});
ImageView p2PNetworkStatusIcon = new ImageView();
setRightAnchor(p2PNetworkStatusIcon, 30d);
setBottomAnchor(p2PNetworkStatusIcon, 7d);
p2PNetworkStatusIcon.setPickOnBounds(true);
p2PNetworkStatusIcon.setCursor(Cursor.HAND);
p2PNetworkStatusIcon.setFitWidth(networkIconSize);
p2PNetworkStatusIcon.setFitHeight(networkIconSize);
setRightAnchor(p2PNetworkStatusIcon, networkIconRightAnchor + 22);
setBottomAnchor(p2PNetworkStatusIcon, 6d);
Tooltip p2pNetworkStatusToolTip = new Tooltip();
Tooltip.install(p2PNetworkStatusIcon, p2pNetworkStatusToolTip);
p2PNetworkStatusIcon.setOnMouseEntered(e -> p2pNetworkStatusToolTip.setText(model.getP2pConnectionSummary()));
@ -791,10 +857,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER_RIGHT);
vBox.getChildren().addAll(p2PNetworkLabel, p2pNetworkProgressBar);
setRightAnchor(vBox, 53d);
setRightAnchor(vBox, networkIconRightAnchor + 45);
setBottomAnchor(vBox, 5d);
return new AnchorPane(separator, xmrInfoLabel, versionBox, vBox, p2PNetworkStatusIcon, p2PNetworkIcon) {{
return new AnchorPane(separator, xmrInfoLabel, versionBox, vBox, p2PNetworkStatusIcon, p2PNetworkIcon, useDarkModeIcon) {{
setId("footer-pane");
setMinHeight(30);
setMaxHeight(30);
@ -825,6 +891,9 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
this.setToggleGroup(navButtons);
this.getStyleClass().add("nav-button");
this.setMinWidth(Region.USE_PREF_SIZE); // prevent squashing content
this.setPrefWidth(Region.USE_COMPUTED_SIZE);
// Japanese fonts are dense, increase top nav button text size
if (model.getPreferences() != null && "ja".equals(model.getPreferences().getUserLanguage())) {
this.getStyleClass().add("nav-button-japanese");
@ -836,4 +905,29 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}
}
private class SecondaryNavButton extends NavButton {
SecondaryNavButton(Class<? extends View> viewClass, String title, String iconId) {
super(viewClass, title);
this.getStyleClass().setAll("nav-secondary-button");
// Japanese fonts are dense, increase top nav button text size
if (model.getPreferences() != null && "ja".equals(model.getPreferences().getUserLanguage())) {
this.getStyleClass().setAll("nav-secondary-button-japanese");
}
// add icon
ImageView imageView = new ImageView();
imageView.setId(iconId);
imageView.setFitWidth(15);
imageView.setPreserveRatio(true);
setGraphicTextGap(10);
setGraphic(imageView);
// show cursor hand on any hover
this.setPickOnBounds(true);
}
}
}

View file

@ -86,12 +86,12 @@ public class AccountView extends ActivatableView<TabPane, Void> {
root.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
traditionalAccountsTab.setText(Res.get("account.menu.paymentAccount").toUpperCase());
cryptoAccountsTab.setText(Res.get("account.menu.altCoinsAccountView").toUpperCase());
passwordTab.setText(Res.get("account.menu.password").toUpperCase());
seedWordsTab.setText(Res.get("account.menu.seedWords").toUpperCase());
//walletInfoTab.setText(Res.get("account.menu.walletInfo").toUpperCase());
backupTab.setText(Res.get("account.menu.backup").toUpperCase());
traditionalAccountsTab.setText(Res.get("account.menu.paymentAccount"));
cryptoAccountsTab.setText(Res.get("account.menu.altCoinsAccountView"));
passwordTab.setText(Res.get("account.menu.password"));
seedWordsTab.setText(Res.get("account.menu.seedWords"));
//walletInfoTab.setText(Res.get("account.menu.walletInfo"));
backupTab.setText(Res.get("account.menu.backup"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(AccountView.class) == 1) {

View file

@ -216,7 +216,7 @@ public class CryptoAccountsView extends PaymentAccountsView<GridPane, CryptoAcco
}
removeAccountRows();
addAccountButton.setDisable(false);
accountTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, Res.get("shared.selectedAccount"), Layout.GROUP_DISTANCE);
accountTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, "", Layout.GROUP_DISTANCE);
paymentMethodForm = getPaymentMethodForm(current);
paymentMethodForm.addFormForEditAccount();
gridRow = paymentMethodForm.getGridRow();

View file

@ -26,6 +26,7 @@ import haveno.desktop.components.AutoTooltipButton;
import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.components.AutoTooltipTableColumn;
import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.ImageUtil;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
@ -73,6 +74,7 @@ public class ManageMarketAlertsWindow extends Overlay<ManageMarketAlertsWindow>
private void addContent() {
TableView<MarketAlertFilter> tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
GridPane.setRowIndex(tableView, ++rowIndex);
GridPane.setColumnSpan(tableView, 2);
GridPane.setMargin(tableView, new Insets(10, 0, 0, 0));

View file

@ -535,7 +535,7 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi
}
removeAccountRows();
addAccountButton.setDisable(false);
accountTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, Res.get("shared.selectedAccount"), Layout.GROUP_DISTANCE);
accountTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, "", Layout.GROUP_DISTANCE);
paymentMethodForm = getPaymentMethodForm(current);
if (paymentMethodForm != null) {
paymentMethodForm.addFormForEditAccount();

View file

@ -55,9 +55,9 @@ public class FundsView extends ActivatableView<TabPane, Void> {
@Override
public void initialize() {
depositTab.setText(Res.get("funds.tab.deposit").toUpperCase());
withdrawalTab.setText(Res.get("funds.tab.withdrawal").toUpperCase());
transactionsTab.setText(Res.get("funds.tab.transactions").toUpperCase());
depositTab.setText(Res.get("funds.tab.deposit"));
withdrawalTab.setText(Res.get("funds.tab.withdrawal"));
transactionsTab.setText(Res.get("funds.tab.transactions"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(FundsView.class) == 1)

View file

@ -40,6 +40,7 @@ import com.google.inject.name.Named;
import haveno.common.ThreadUtils;
import haveno.common.UserThread;
import haveno.common.app.DevEnv;
import haveno.common.util.Tuple2;
import haveno.common.util.Tuple3;
import haveno.core.locale.Res;
import haveno.core.trade.HavenoUtils;
@ -89,10 +90,9 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import monero.common.MoneroUtils;
import monero.wallet.model.MoneroTxConfig;
import monero.wallet.model.MoneroWalletListener;
import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;
@ -111,6 +111,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
@FXML
TableColumn<DepositListItem, DepositListItem> addressColumn, balanceColumn, confirmationsColumn, usageColumn;
private ImageView qrCodeImageView;
private StackPane qrCodePane;
private AddressTextField addressTextField;
private Button generateNewAddressButton;
private TitledGroupBg titledGroupBg;
@ -144,6 +145,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
paymentLabelString = Res.get("funds.deposit.fundHavenoWallet");
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
@ -154,6 +156,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
// set loading placeholder
Label placeholderLabel = new Label("Loading...");
tableView.setPlaceholder(placeholderLabel);
tableView.getStyleClass().add("non-interactive-table");
ThreadUtils.execute(() -> {
@ -190,19 +193,19 @@ public class DepositView extends ActivatableView<VBox, Void> {
titledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, Res.get("funds.deposit.fundWallet"));
titledGroupBg.getStyleClass().add("last");
qrCodeImageView = new ImageView();
qrCodeImageView.setFitHeight(150);
qrCodeImageView.setFitWidth(150);
qrCodeImageView.getStyleClass().add("qr-code");
Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodeImageView.setOnMouseClicked(e -> UserThread.runAfter(
Tuple2<StackPane, ImageView> qrCodeTuple = GUIUtil.getSmallXmrQrCodePane();
qrCodePane = qrCodeTuple.first;
qrCodeImageView = qrCodeTuple.second;
Tooltip.install(qrCodePane, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodePane.setOnMouseClicked(e -> UserThread.runAfter(
() -> new QRCodeWindow(getPaymentUri()).show(),
200, TimeUnit.MILLISECONDS));
GridPane.setRowIndex(qrCodeImageView, gridRow);
GridPane.setRowSpan(qrCodeImageView, 4);
GridPane.setColumnIndex(qrCodeImageView, 1);
GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 10));
gridPane.getChildren().add(qrCodeImageView);
GridPane.setRowIndex(qrCodePane, gridRow);
GridPane.setRowSpan(qrCodePane, 4);
GridPane.setColumnIndex(qrCodePane, 1);
GridPane.setMargin(qrCodePane, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 10));
gridPane.getChildren().add(qrCodePane);
addressTextField = addAddressTextField(gridPane, ++gridRow, Res.get("shared.address"), Layout.FIRST_ROW_DISTANCE);
addressTextField.setPaymentLabel(paymentLabelString);
@ -213,8 +216,8 @@ public class DepositView extends ActivatableView<VBox, Void> {
titledGroupBg.setVisible(false);
titledGroupBg.setManaged(false);
qrCodeImageView.setVisible(false);
qrCodeImageView.setManaged(false);
qrCodePane.setVisible(false);
qrCodePane.setManaged(false);
addressTextField.setVisible(false);
addressTextField.setManaged(false);
amountTextField.setManaged(false);
@ -310,8 +313,8 @@ public class DepositView extends ActivatableView<VBox, Void> {
private void fillForm(String address) {
titledGroupBg.setVisible(true);
titledGroupBg.setManaged(true);
qrCodeImageView.setVisible(true);
qrCodeImageView.setManaged(true);
qrCodePane.setVisible(true);
qrCodePane.setManaged(true);
addressTextField.setVisible(true);
addressTextField.setManaged(true);
amountTextField.setManaged(true);
@ -366,10 +369,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
@NotNull
private String getPaymentUri() {
return MoneroUtils.getPaymentUri(new MoneroTxConfig()
.setAddress(addressTextField.getAddress())
.setAmount(HavenoUtils.coinToAtomicUnits(getAmount()))
.setNote(paymentLabelString));
return GUIUtil.getMoneroURI(addressTextField.getAddress(), HavenoUtils.coinToAtomicUnits(getAmount()), paymentLabelString);
}
///////////////////////////////////////////////////////////////////////////////////////////
@ -377,7 +377,6 @@ public class DepositView extends ActivatableView<VBox, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
private void setUsageColumnCellFactory() {
usageColumn.getStyleClass().add("last-column");
usageColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
usageColumn.setCellFactory(new Callback<>() {
@ -390,7 +389,9 @@ public class DepositView extends ActivatableView<VBox, Void> {
public void updateItem(final DepositListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setGraphic(new AutoTooltipLabel(item.getUsage()));
Label usageLabel = new AutoTooltipLabel(item.getUsage());
usageLabel.getStyleClass().add("highlight-text");
setGraphic(usageLabel);
} else {
setGraphic(null);
}
@ -401,7 +402,6 @@ public class DepositView extends ActivatableView<VBox, Void> {
}
private void setAddressColumnCellFactory() {
addressColumn.getStyleClass().add("first-column");
addressColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
addressColumn.setCellFactory(
@ -434,6 +434,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
private void setBalanceColumnCellFactory() {
balanceColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
balanceColumn.getStyleClass().add("highlight-text");
balanceColumn.setCellFactory(new Callback<>() {
@Override

View file

@ -122,6 +122,7 @@ public class LockedView extends ActivatableView<VBox, Void> {
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
balanceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.balanceWithCur", Res.getBaseCurrencyCode())));
GUIUtil.applyTableStyle(tableView);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.locked.noFunds")));
@ -250,7 +251,6 @@ public class LockedView extends ActivatableView<VBox, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
private void setDateColumnCellFactory() {
dateColumn.getStyleClass().add("first-column");
dateColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
dateColumn.setCellFactory(new Callback<>() {
@ -342,7 +342,6 @@ public class LockedView extends ActivatableView<VBox, Void> {
}
private void setBalanceColumnCellFactory() {
balanceColumn.getStyleClass().add("last-column");
balanceColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
balanceColumn.setCellFactory(
new Callback<>() {

View file

@ -122,6 +122,7 @@ public class ReservedView extends ActivatableView<VBox, Void> {
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
balanceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.balanceWithCur", Res.getBaseCurrencyCode())));
GUIUtil.applyTableStyle(tableView);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.reserved.noFunds")));
@ -249,7 +250,6 @@ public class ReservedView extends ActivatableView<VBox, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
private void setDateColumnCellFactory() {
dateColumn.getStyleClass().add("first-column");
dateColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
dateColumn.setCellFactory(new Callback<>() {
@ -313,7 +313,6 @@ public class ReservedView extends ActivatableView<VBox, Void> {
}
private void setAddressColumnCellFactory() {
addressColumn.getStyleClass().add("last-column");
addressColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
addressColumn.setCellFactory(
@ -341,7 +340,6 @@ public class ReservedView extends ActivatableView<VBox, Void> {
}
private void setBalanceColumnCellFactory() {
balanceColumn.getStyleClass().add("last-column");
balanceColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
balanceColumn.setCellFactory(
new Callback<>() {

View file

@ -32,14 +32,14 @@
</padding>
<TableView fx:id="tableView" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="dateColumn" minWidth="180" maxWidth="180"/>
<TableColumn fx:id="detailsColumn" minWidth="220" maxWidth="220"/>
<TableColumn fx:id="addressColumn" minWidth="260"/>
<TableColumn fx:id="dateColumn" minWidth="100" maxWidth="180"/>
<TableColumn fx:id="detailsColumn" minWidth="180" maxWidth="220"/>
<TableColumn fx:id="addressColumn" minWidth="250"/>
<TableColumn fx:id="transactionColumn" minWidth="180"/>
<TableColumn fx:id="amountColumn" minWidth="110" maxWidth="110"/>
<TableColumn fx:id="txFeeColumn" minWidth="110" maxWidth="110"/>
<TableColumn fx:id="confidenceColumn" minWidth="60" maxWidth="130"/>
<TableColumn fx:id="memoColumn" minWidth="40"/>
<TableColumn fx:id="confidenceColumn" minWidth="70" maxWidth="130"/>
<TableColumn fx:id="memoColumn" minWidth="40" maxWidth="250"/>
<TableColumn fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110" visible="false"/>
</columns>
</TableView>

View file

@ -127,6 +127,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
dateColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.dateTime")));
detailsColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.details")));
addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
@ -139,6 +141,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.tx.noTxAvailable")));
tableView.getStyleClass().add("non-interactive-table");
setDateColumnCellFactory();
setDetailsColumnCellFactory();
@ -169,11 +172,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
keyEventEventHandler = event -> {
// Not intended to be public to users as the feature is not well tested
if (Utilities.isAltOrCtrlPressed(KeyCode.R, event)) {
if (revertTxColumn.isVisible()) {
confidenceColumn.getStyleClass().remove("last-column");
} else {
confidenceColumn.getStyleClass().add("last-column");
}
revertTxColumn.setVisible(!revertTxColumn.isVisible());
}
};
@ -265,7 +263,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
///////////////////////////////////////////////////////////////////////////////////////////
private void setDateColumnCellFactory() {
dateColumn.getStyleClass().add("first-column");
dateColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
dateColumn.setMaxWidth(200);
@ -400,6 +397,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void setAmountColumnCellFactory() {
amountColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
amountColumn.getStyleClass().add("highlight-text");
amountColumn.setCellFactory(
new Callback<>() {
@ -427,6 +425,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void setTxFeeColumnCellFactory() {
txFeeColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
txFeeColumn.getStyleClass().add("highlight-text");
txFeeColumn.setCellFactory(
new Callback<>() {
@ -453,6 +452,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
private void setMemoColumnCellFactory() {
memoColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
memoColumn.getStyleClass().add("highlight-text");
memoColumn.setCellFactory(
new Callback<>() {
@ -477,7 +477,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
}
private void setConfidenceColumnCellFactory() {
confidenceColumn.getStyleClass().add("last-column");
confidenceColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
confidenceColumn.setCellFactory(
@ -504,7 +503,6 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
}
private void setRevertTxColumnCellFactory() {
revertTxColumn.getStyleClass().add("last-column");
revertTxColumn.setCellValueFactory((addressListItem) ->
new ReadOnlyObjectWrapper<>(addressListItem.getValue()));
revertTxColumn.setCellFactory(

View file

@ -144,7 +144,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
amountLabel = feeTuple3.first;
amountTextField = feeTuple3.second;
amountTextField.setMinWidth(180);
amountTextField.setMinWidth(200);
HyperlinkWithIcon sendMaxLink = feeTuple3.third;
withdrawMemoTextField = addTopLabelInputTextField(gridPane, ++rowIndex,

View file

@ -88,10 +88,10 @@ public class MarketView extends ActivatableView<TabPane, Void> {
@Override
public void initialize() {
offerBookTab.setText(Res.get("market.tabs.offerBook").toUpperCase());
spreadTab.setText(Res.get("market.tabs.spreadCurrency").toUpperCase());
spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment").toUpperCase());
tradesTab.setText(Res.get("market.tabs.trades").toUpperCase());
offerBookTab.setText(Res.get("market.tabs.offerBook"));
spreadTab.setText(Res.get("market.tabs.spreadCurrency"));
spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment"));
tradesTab.setText(Res.get("market.tabs.trades"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(MarketView.class) == 1)

View file

@ -26,6 +26,7 @@ import haveno.common.util.Tuple3;
import haveno.common.util.Tuple4;
import haveno.core.locale.CurrencyUtil;
import haveno.core.locale.Res;
import haveno.core.monetary.Volume;
import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection;
import haveno.core.util.FormattingUtils;
@ -65,13 +66,13 @@ import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.control.Tab;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
@ -95,7 +96,10 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private AnchorPane chartPane;
private AutocompleteComboBox<CurrencyListItem> currencyComboBox;
private Subscription tradeCurrencySubscriber;
private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private final StringProperty volumeSellColumnLabel = new SimpleStringProperty();
private final StringProperty volumeBuyColumnLabel = new SimpleStringProperty();
private final StringProperty amountSellColumnLabel = new SimpleStringProperty();
private final StringProperty amountBuyColumnLabel = new SimpleStringProperty();
private final StringProperty priceColumnLabel = new SimpleStringProperty();
private AutoTooltipButton sellButton;
private AutoTooltipButton buyButton;
@ -106,10 +110,11 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private ListChangeListener<OfferBookListItem> changeListener;
private ListChangeListener<CurrencyListItem> currencyListItemsListener;
private final double dataLimitFactor = 3;
private final double initialOfferTableViewHeight = 121;
private final double initialOfferTableViewHeight = 78; // decrease as MainView's content-pane's top anchor increases
private final double offerTableExtraMarginBottom = 0;
private final Function<Double, Double> offerTableViewHeight = (screenSize) -> {
// initial visible row count=5, header height=30
double pixelsPerOfferTableRow = (initialOfferTableViewHeight - 30) / 5.0;
double pixelsPerOfferTableRow = (initialOfferTableViewHeight - offerTableExtraMarginBottom) / 5.0;
int extraRows = screenSize <= INITIAL_WINDOW_HEIGHT ? 0 : (int) ((screenSize - INITIAL_WINDOW_HEIGHT) / pixelsPerOfferTableRow);
return extraRows == 0 ? initialOfferTableViewHeight : Math.ceil(initialOfferTableViewHeight + ((extraRows + 1) * pixelsPerOfferTableRow));
};
@ -136,6 +141,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
this.currencyComboBox = currencyComboBoxTuple.third;
this.currencyComboBox.setCellFactory(GUIUtil.getCurrencyListItemCellFactory(Res.get("shared.oneOffer"),
Res.get("shared.multipleOffers"), model.preferences));
this.currencyComboBox.getStyleClass().add("input-with-border");
createChart();
@ -200,7 +206,6 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty,
tradeCurrency -> {
String code = tradeCurrency.getCode();
volumeColumnLabel.set(Res.get("offerbook.volume", code));
xAxis.setTickLabelFormatter(new StringConverter<>() {
final int cryptoPrecision = 3;
final DecimalFormat df = new DecimalFormat(",###");
@ -231,14 +236,20 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
String viewBaseCurrencyCode = CurrencyUtil.isCryptoCurrency(code) ? code : Res.getBaseCurrencyCode();
String viewPriceCurrencyCode = CurrencyUtil.isCryptoCurrency(code) ? Res.getBaseCurrencyCode() : code;
String viewBaseCurrencyCode = model.isCrypto() ? code : Res.getBaseCurrencyCode();
String viewPriceCurrencyCode = model.isCrypto() ? Res.getBaseCurrencyCode() : code;
sellHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", viewBaseCurrencyCode));
sellButton.updateText(Res.get("shared.sellCurrency", viewBaseCurrencyCode, viewPriceCurrencyCode));
sellButton.updateText(Res.get("shared.sellCurrency", viewBaseCurrencyCode));
sellButton.setGraphic(GUIUtil.getCurrencyIconWithBorder(viewBaseCurrencyCode));
sellButton.setOnAction(e -> model.goToOfferView(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY));
sellButton.setId("sell-button-big");
buyHeaderLabel.setText(Res.get("market.offerBook.buyOffersHeaderLabel", viewBaseCurrencyCode));
buyButton.updateText(Res.get("shared.buyCurrency", viewBaseCurrencyCode, viewPriceCurrencyCode));
buyButton.updateText(Res.get( "shared.buyCurrency", viewBaseCurrencyCode));
buyButton.setGraphic(GUIUtil.getCurrencyIconWithBorder(viewBaseCurrencyCode));
buyButton.setOnAction(e -> model.goToOfferView(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL));
buyButton.setId("buy-button-big");
priceColumnLabel.set(Res.get("shared.priceWithCur", viewPriceCurrencyCode));
@ -288,8 +299,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
currencyComboBox.getSelectionModel().select(model.getSelectedCurrencyListItem().get());
};
buyTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.BUY);
sellTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.SELL);
buyTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.BUY);
havenoWindowVerticalSizeListener = (observable, oldValue, newValue) -> layout();
}
@ -345,12 +356,27 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
private synchronized void updateChartData() {
seriesBuy.getData().clear();
// update volume headers
Volume volumeSell = model.getTotalVolume(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL);
Volume volumeBuy = model.getTotalVolume(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY);
String formattedVolumeSell = volumeSell == null ? null : VolumeUtil.formatVolume(volumeSell);
String formattedVolumeBuy = volumeBuy == null ? null : VolumeUtil.formatVolume(volumeBuy);
if (model.getSellData().isEmpty()) formattedVolumeSell = "0.0";
if (model.getBuyData().isEmpty()) formattedVolumeBuy = "0.0";
volumeSellColumnLabel.set(Res.get("offerbook.volumeTotal", model.getCurrencyCode(), formattedVolumeSell == null ? "" : "(" + formattedVolumeSell + ")"));
volumeBuyColumnLabel.set(Res.get("offerbook.volumeTotal", model.getCurrencyCode(), formattedVolumeBuy == null ? "" : "(" + formattedVolumeBuy + ")"));
// update amount headers
amountSellColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(model.isCrypto() ? OfferDirection.BUY : OfferDirection.SELL)));
amountBuyColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(model.isCrypto() ? OfferDirection.SELL : OfferDirection.BUY)));
seriesSell.getData().clear();
seriesBuy.getData().clear();
areaChart.getData().clear();
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData()));
seriesSell.getData().addAll(filterOutliersSell(model.getSellData()));
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData()));
areaChart.getData().addAll(List.of(seriesBuy, seriesSell));
}
@ -426,10 +452,11 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private Tuple4<TableView<OfferListItem>, VBox, Button, Label> getOfferTable(OfferDirection direction) {
TableView<OfferListItem> tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView, false);
tableView.setMinHeight(initialOfferTableViewHeight);
tableView.setPrefHeight(initialOfferTableViewHeight);
tableView.setMinWidth(480);
tableView.getStyleClass().add("offer-table");
tableView.getStyleClass().addAll("offer-table", "non-interactive-table");
// price
TableColumn<OfferListItem, OfferListItem> priceColumn = new TableColumn<>();
@ -484,12 +511,14 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
boolean isSellTable = model.isSellOffer(direction);
// volume
TableColumn<OfferListItem, OfferListItem> volumeColumn = new TableColumn<>();
volumeColumn.setMinWidth(115);
volumeColumn.setSortable(false);
volumeColumn.textProperty().bind(volumeColumnLabel);
volumeColumn.getStyleClass().addAll("number-column", "first-column");
volumeColumn.textProperty().bind(isSellTable ? volumeSellColumnLabel : volumeBuyColumnLabel);
volumeColumn.getStyleClass().addAll("number-column");
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory(
new Callback<>() {
@ -546,7 +575,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
});
// amount
TableColumn<OfferListItem, OfferListItem> amountColumn = new AutoTooltipTableColumn<>(Res.get("shared.XMRMinMax"));
TableColumn<OfferListItem, OfferListItem> amountColumn = new TableColumn<>();
amountColumn.textProperty().bind(isSellTable ? amountSellColumnLabel : amountBuyColumnLabel);
amountColumn.setMinWidth(115);
amountColumn.setSortable(false);
amountColumn.getStyleClass().add("number-column");
@ -570,10 +600,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
boolean isSellOffer = model.isSellOffer(direction);
// trader avatar
TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellOffer ?
TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellTable ?
Res.get("shared.sellerUpperCase") : Res.get("shared.buyerUpperCase")) {
{
setMinWidth(80);
@ -582,7 +610,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
};
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
avatarColumn.getStyleClass().addAll("avatar-column");
avatarColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
avatarColumn.setCellFactory(
new Callback<>() {
@ -629,20 +657,16 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
tableView.setPlaceholder(placeholder);
HBox titleButtonBox = new HBox();
titleButtonBox.getStyleClass().add("offer-table-top");
titleButtonBox.setAlignment(Pos.CENTER);
Label titleLabel = new AutoTooltipLabel();
titleLabel.getStyleClass().add("table-title");
AutoTooltipButton button = new AutoTooltipButton();
ImageView iconView = new ImageView();
iconView.setId(isSellOffer ? "image-buy-white" : "image-sell-white");
button.setGraphic(iconView);
button.setContentDisplay(ContentDisplay.RIGHT);
button.setGraphicTextGap(10);
button.updateText(isSellOffer ? Res.get("market.offerBook.buy") : Res.get("market.offerBook.sell"));
button.setMinHeight(32);
button.setId(isSellOffer ? "buy-button-big" : "sell-button-big");
button.setOnAction(e -> model.goToOfferView(direction));
Region spacer = new Region();
@ -653,9 +677,9 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
VBox vBox = new VBox();
VBox.setVgrow(tableView, Priority.ALWAYS);
vBox.setPadding(new Insets(0, 0, 0, 0));
vBox.setSpacing(10);
vBox.setSpacing(0);
vBox.setFillWidth(true);
vBox.setMinHeight(190);
//vBox.setMinHeight(190);
vBox.getChildren().addAll(titleButtonBox, tableView);
return new Tuple4<>(tableView, vBox, button, titleLabel);

View file

@ -26,6 +26,7 @@ import haveno.core.locale.CurrencyUtil;
import haveno.core.locale.GlobalSettings;
import haveno.core.locale.TradeCurrency;
import haveno.core.monetary.Price;
import haveno.core.monetary.Volume;
import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection;
import haveno.core.offer.OpenOfferManager;
@ -58,6 +59,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@ -212,10 +214,42 @@ class OfferBookChartViewModel extends ActivatableViewModel {
}
public boolean isSellOffer(OfferDirection direction) {
// for cryptocurrency, buy direction is to buy XMR, so we need sell offers
// for traditional currency, buy direction is to sell XMR, so we need buy offers
boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(getCurrencyCode());
return isCryptoCurrency ? direction == OfferDirection.BUY : direction == OfferDirection.SELL;
return direction == OfferDirection.SELL;
}
public double getTotalAmount(OfferDirection direction) {
synchronized (offerBookListItems) {
List<Offer> offerList = offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(direction))
.collect(Collectors.toList());
BigInteger sum = BigInteger.ZERO;
for (Offer offer : offerList) sum = sum.add(offer.getAmount());
return HavenoUtils.atomicUnitsToXmr(sum);
}
}
public Volume getTotalVolume(OfferDirection direction) {
synchronized (offerBookListItems) {
List<Volume> volumes = offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(direction))
.map(Offer::getVolume)
.collect(Collectors.toList());
try {
return VolumeUtil.sum(volumes);
} catch (Exception e) {
// log.error("Cannot compute total volume because prices are unavailable, currency={}, direction={}",
// selectedTradeCurrencyProperty.get().getCode(), direction);
return null; // expected before prices are available
}
}
}
public boolean isCrypto() {
return CurrencyUtil.isCryptoCurrency(getCurrencyCode());
}
public boolean isMyOffer(Offer offer) {

View file

@ -65,6 +65,8 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
@Override
public void initialize() {
tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
tableView.getStyleClass().add("non-interactive-table");
int gridRow = 0;
GridPane.setRowIndex(tableView, gridRow);
@ -144,7 +146,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
setMinWidth(160);
}
};
column.getStyleClass().addAll("number-column", "first-column");
column.getStyleClass().addAll("number-column");
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@ -259,7 +261,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
setMinWidth(140);
}
};
column.getStyleClass().add("number-column");
column.getStyleClass().addAll("number-column", "highlight-text");
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@ -289,7 +291,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode
setMinWidth(110);
}
};
column.getStyleClass().addAll("number-column", "last-column");
column.getStyleClass().addAll("number-column", "highlight-text");
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {

View file

@ -686,6 +686,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
currencyComboBox = currencyComboBoxTuple.third;
currencyComboBox.setCellFactory(GUIUtil.getCurrencyListItemCellFactory(Res.get("shared.trade"),
Res.get("shared.trades"), model.preferences));
currencyComboBox.getStyleClass().add("input-with-border");
Pane spacer = new Pane();
HBox.setHgrow(spacer, Priority.ALWAYS);
@ -730,7 +731,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
private void createTable() {
tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
VBox.setVgrow(tableView, Priority.ALWAYS);
tableView.getStyleClass().add("non-interactive-table");
// date
TableColumn<TradeStatistics3ListItem, TradeStatistics3ListItem> dateColumn = new AutoTooltipTableColumn<>(Res.get("shared.dateTime")) {
@ -739,7 +742,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
setMaxWidth(240);
}
};
dateColumn.getStyleClass().addAll("number-column", "first-column");
dateColumn.getStyleClass().addAll("number-column");
dateColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
dateColumn.setCellFactory(
new Callback<>() {
@ -865,7 +868,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
// paymentMethod
TableColumn<TradeStatistics3ListItem, TradeStatistics3ListItem> paymentMethodColumn = new AutoTooltipTableColumn<>(Res.get("shared.paymentMethod"));
paymentMethodColumn.getStyleClass().add("number-column");
paymentMethodColumn.getStyleClass().addAll("number-column");
paymentMethodColumn.setCellValueFactory((tradeStatistics) -> new ReadOnlyObjectWrapper<>(tradeStatistics.getValue()));
paymentMethodColumn.setCellFactory(
new Callback<>() {

View file

@ -85,6 +85,7 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.util.StringConverter;
@ -149,7 +150,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private ComboBox<PaymentAccount> paymentAccountsComboBox;
private ComboBox<TradeCurrency> currencyComboBox;
private ImageView qrCodeImageView;
private VBox currencySelection, fixedPriceBox, percentagePriceBox, currencyTextFieldBox, triggerPriceVBox;
private StackPane qrCodePane;
private VBox paymentAccountsSelection, currencySelection, fixedPriceBox, percentagePriceBox, currencyTextFieldBox, triggerPriceVBox;
private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox,
priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox,
minAmountValueCurrencyBox, securityDepositAndFeeBox, triggerPriceHBox;
@ -308,7 +310,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
if (!result) {
new Popup().headLine(Res.get("popup.warning.noTradingAccountSetup.headline"))
.instruction(Res.get("popup.warning.noTradingAccountSetup.msg"))
.actionButtonTextWithGoTo("navigation.account")
.actionButtonTextWithGoTo("mainView.menu.account")
.onAction(() -> {
navigation.setReturnPath(navigation.getCurrentPath());
navigation.navigateTo(MainView.class, AccountView.class, TraditionalAccountsView.class);
@ -425,7 +427,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
totalToPayTextField.setContentForInfoPopOver(createInfoPopover());
});
paymentAccountsComboBox.setDisable(true);
paymentAccountsSelection.setDisable(true);
currencySelection.setDisable(true);
editOfferElements.forEach(node -> {
node.setMouseTransparent(true);
@ -449,8 +452,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private void updateOfferElementsStyle() {
GridPane.setColumnSpan(firstRowHBox, 2);
String activeInputStyle = "input-with-border";
String readOnlyInputStyle = "input-with-border-readonly";
String activeInputStyle = "offer-input";
String readOnlyInputStyle = "offer-input-readonly";
amountValueCurrencyBox.getStyleClass().remove(activeInputStyle);
amountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle);
priceAsPercentageValueCurrencyBox.getStyleClass().remove(activeInputStyle);
@ -709,7 +712,11 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
};
extraInfoFocusedListener = (observable, oldValue, newValue) -> {
model.onFocusOutExtraInfoTextArea(oldValue, newValue);
// avoid setting text area to empty text because blinking caret does not appear
if (model.extraInfo.get() != null && !model.extraInfo.get().isEmpty()) {
extraInfoTextArea.setText(model.extraInfo.get());
}
};
errorMessageListener = (o, oldValue, newValue) -> {
@ -749,7 +756,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
UserThread.runAfter(() -> new Popup().headLine(Res.get("createOffer.success.headline"))
.feedback(Res.get("createOffer.success.info"))
.dontShowAgainId(key)
.actionButtonTextWithGoTo("navigation.portfolio.myOpenOffers")
.actionButtonTextWithGoTo("portfolio.tab.openOffers")
.onAction(this::closeAndGoToOpenOffers)
.onClose(this::closeAndGoToOpenOffers)
.show(),
@ -973,7 +980,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private void addGridPane() {
gridPane = new GridPane();
gridPane.getStyleClass().add("content-pane");
gridPane.setPadding(new Insets(25, 25, -1, 25));
gridPane.setPadding(new Insets(25, 25, 25, 25));
gridPane.setHgap(5);
gridPane.setVgap(5);
GUIUtil.setDefaultTwoColumnConstraintsForGridPane(gridPane);
@ -995,8 +1002,9 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
final Tuple3<VBox, Label, ComboBox<TradeCurrency>> currencyBoxTuple = addTopLabelComboBox(
Res.get("shared.currency"), Res.get("list.currency.select"));
paymentAccountsSelection = tradingAccountBoxTuple.first;
currencySelection = currencyBoxTuple.first;
paymentGroupBox.getChildren().addAll(tradingAccountBoxTuple.first, currencySelection);
paymentGroupBox.getChildren().addAll(paymentAccountsSelection, currencySelection);
GridPane.setRowIndex(paymentGroupBox, gridRow);
GridPane.setColumnSpan(paymentGroupBox, 2);
@ -1007,11 +1015,13 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
paymentAccountsComboBox = tradingAccountBoxTuple.third;
paymentAccountsComboBox.setMinWidth(tradingAccountBoxTuple.first.getMinWidth());
paymentAccountsComboBox.setPrefWidth(tradingAccountBoxTuple.first.getMinWidth());
editOfferElements.add(tradingAccountBoxTuple.first);
paymentAccountsComboBox.getStyleClass().add("input-with-border");
editOfferElements.add(paymentAccountsSelection);
// we display either currencyComboBox (multi currency account) or currencyTextField (single)
currencyComboBox = currencyBoxTuple.third;
currencyComboBox.setMaxWidth(tradingAccountBoxTuple.first.getMinWidth() / 2);
currencyComboBox.getStyleClass().add("input-with-border");
editOfferElements.add(currencySelection);
currencyComboBox.setConverter(new StringConverter<>() {
@Override
@ -1094,6 +1104,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
GridPane.setColumnSpan(extraInfoTitledGroupBg, 3);
extraInfoTextArea = new InputTextArea();
extraInfoTextArea.setText("");
extraInfoTextArea.setPromptText(Res.get("payment.shared.extraInfo.prompt.offer"));
extraInfoTextArea.getStyleClass().add("text-area");
extraInfoTextArea.setWrapText(true);
@ -1179,8 +1190,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
totalToPayTextField.setManaged(false);
addressTextField.setVisible(false);
addressTextField.setManaged(false);
qrCodeImageView.setVisible(false);
qrCodeImageView.setManaged(false);
qrCodePane.setVisible(false);
qrCodePane.setManaged(false);
balanceTextField.setVisible(false);
balanceTextField.setManaged(false);
cancelButton2.setVisible(false);
@ -1196,8 +1207,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
totalToPayTextField.setManaged(true);
addressTextField.setVisible(true);
addressTextField.setManaged(true);
qrCodeImageView.setVisible(true);
qrCodeImageView.setManaged(true);
qrCodePane.setVisible(true);
qrCodePane.setManaged(true);
balanceTextField.setVisible(true);
balanceTextField.setManaged(true);
cancelButton2.setVisible(true);
@ -1239,21 +1250,23 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
totalToPayTextField.setVisible(false);
GridPane.setMargin(totalToPayTextField, new Insets(60 + heightAdjustment, 10, 0, 0));
qrCodeImageView = new ImageView();
qrCodeImageView.setVisible(false);
qrCodeImageView.setFitHeight(150);
qrCodeImageView.setFitWidth(150);
qrCodeImageView.getStyleClass().add("qr-code");
Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodeImageView.setOnMouseClicked(e -> UserThread.runAfter(
Tuple2<StackPane, ImageView> qrCodeTuple = GUIUtil.getSmallXmrQrCodePane();
qrCodePane = qrCodeTuple.first;
qrCodeImageView = qrCodeTuple.second;
Tooltip.install(qrCodePane, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodePane.setOnMouseClicked(e -> UserThread.runAfter(
() -> new QRCodeWindow(getMoneroURI()).show(),
200, TimeUnit.MILLISECONDS));
GridPane.setRowIndex(qrCodeImageView, gridRow);
GridPane.setColumnIndex(qrCodeImageView, 1);
GridPane.setRowSpan(qrCodeImageView, 3);
GridPane.setValignment(qrCodeImageView, VPos.BOTTOM);
GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 10));
gridPane.getChildren().add(qrCodeImageView);
GridPane.setRowIndex(qrCodePane, gridRow);
GridPane.setColumnIndex(qrCodePane, 1);
GridPane.setRowSpan(qrCodePane, 3);
GridPane.setValignment(qrCodePane, VPos.BOTTOM);
GridPane.setMargin(qrCodePane, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 10));
gridPane.getChildren().add(qrCodePane);
qrCodePane.setVisible(false);
qrCodePane.setManaged(false);
addressTextField = addAddressTextField(gridPane, ++gridRow,
Res.get("shared.tradeWalletAddress"));

View file

@ -504,7 +504,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
extraInfoStringListener = (ov, oldValue, newValue) -> {
if (newValue != null) {
extraInfo.set(newValue);
extraInfo.set(newValue.trim());
UserThread.execute(() -> onExtraInfoTextAreaChanged());
}
};
@ -727,7 +727,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
new Popup().warning(Res.get("shared.notEnoughFunds",
HavenoUtils.formatXmr(dataModel.totalToPayAsProperty().get(), true),
HavenoUtils.formatXmr(dataModel.getTotalBalance(), true)))
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
.actionButtonTextWithGoTo("funds.tab.deposit")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show();
}
@ -1056,7 +1056,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
FormattingUtils.formatToPercentWithSymbol(preferences.getMaxPriceDistanceInPercent())))
.actionButtonText(Res.get("createOffer.changePrice"))
.onAction(popup::hide)
.closeButtonTextWithGoTo("navigation.settings.preferences")
.closeButtonTextWithGoTo("settings.tab.preferences")
.onClose(() -> navigation.navigateTo(MainView.class, SettingsView.class, PreferencesView.class))
.show();
}

View file

@ -220,14 +220,14 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
labelTab.setClosable(false);
Label offerLabel = new Label(getOfferLabel()); // use overlay for label for custom formatting
offerLabel.getStyleClass().add("titled-group-bg-label");
offerLabel.setStyle("-fx-font-size: 1.4em;");
offerLabel.setStyle("-fx-font-size: 1.3em;");
labelTab.setGraphic(offerLabel);
fiatOfferBookTab = new Tab(Res.get("shared.fiat").toUpperCase());
fiatOfferBookTab = new Tab(Res.get("shared.fiat"));
fiatOfferBookTab.setClosable(false);
cryptoOfferBookTab = new Tab(Res.get("shared.crypto").toUpperCase());
cryptoOfferBookTab = new Tab(Res.get("shared.crypto"));
cryptoOfferBookTab.setClosable(false);
otherOfferBookTab = new Tab(Res.get("shared.other").toUpperCase());
otherOfferBookTab = new Tab(Res.get("shared.other"));
otherOfferBookTab.setClosable(false);
tabPane.getTabs().addAll(labelTab, fiatOfferBookTab, cryptoOfferBookTab, otherOfferBookTab);
}

View file

@ -91,7 +91,6 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;
@ -179,29 +178,29 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
currencyComboBoxContainer = currencyBoxTuple.first;
currencyComboBox = currencyBoxTuple.third;
currencyComboBox.setPrefWidth(250);
currencyComboBox.getStyleClass().add("input-with-border");
Tuple3<VBox, Label, AutocompleteComboBox<PaymentMethod>> paymentBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox(
Res.get("offerbook.filterByPaymentMethod"));
paymentMethodComboBox = paymentBoxTuple.third;
paymentMethodComboBox.setCellFactory(GUIUtil.getPaymentMethodCellFactory());
paymentMethodComboBox.setPrefWidth(250);
matchingOffersToggleButton = AwesomeDude.createIconToggleButton(AwesomeIcon.USER, null, "1.5em", null);
matchingOffersToggleButton.getStyleClass().add("toggle-button-no-slider");
matchingOffersToggleButton.setPrefHeight(27);
Tooltip matchingOffersTooltip = new Tooltip(Res.get("offerbook.matchingOffers"));
Tooltip.install(matchingOffersToggleButton, matchingOffersTooltip);
paymentMethodComboBox.getStyleClass().add("input-with-border");
noDepositOffersToggleButton = new ToggleButton(Res.get("offerbook.filterNoDeposit"));
noDepositOffersToggleButton.getStyleClass().add("toggle-button-no-slider");
noDepositOffersToggleButton.setPrefHeight(27);
Tooltip noDepositOffersTooltip = new Tooltip(Res.get("offerbook.noDepositOffers"));
Tooltip.install(noDepositOffersToggleButton, noDepositOffersTooltip);
matchingOffersToggleButton = AwesomeDude.createIconToggleButton(AwesomeIcon.USER, null, "1.5em", null);
matchingOffersToggleButton.getStyleClass().add("toggle-button-no-slider");
Tooltip matchingOffersTooltip = new Tooltip(Res.get("offerbook.matchingOffers"));
Tooltip.install(matchingOffersToggleButton, matchingOffersTooltip);
createOfferButton = new AutoTooltipButton("");
createOfferButton.setMinHeight(40);
createOfferButton.setGraphicTextGap(10);
createOfferButton.setStyle("-fx-padding: 0 15 0 15;");
createOfferButton.setStyle("-fx-padding: 7 25 7 25;");
disabledCreateOfferButtonTooltip = new Label("");
disabledCreateOfferButtonTooltip.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
disabledCreateOfferButtonTooltip.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
@ -211,15 +210,17 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
disabledCreateOfferButtonTooltip.setManaged(false);
disabledCreateOfferButtonTooltip.setVisible(false);
var createOfferButtonStack = new StackPane(createOfferButton, disabledCreateOfferButtonTooltip);
var createOfferVBox = new VBox(createOfferButton, disabledCreateOfferButtonTooltip);
createOfferVBox.setAlignment(Pos.BOTTOM_RIGHT);
Tuple3<VBox, Label, AutoTooltipTextField> autoToolTipTextField = addTopLabelAutoToolTipTextField("");
VBox filterBox = autoToolTipTextField.first;
filterInputField = autoToolTipTextField.third;
filterInputField.setPromptText(Res.get("market.offerBook.filterPrompt"));
filterInputField.setPromptText(Res.get("shared.filter"));
filterInputField.getStyleClass().add("input-with-border");
offerToolsBox.getChildren().addAll(currencyBoxTuple.first, paymentBoxTuple.first,
filterBox, matchingOffersToggleButton, noDepositOffersToggleButton, getSpacer(), createOfferButtonStack);
filterBox, noDepositOffersToggleButton, matchingOffersToggleButton, getSpacer(), createOfferVBox);
GridPane.setHgrow(offerToolsBox, Priority.ALWAYS);
GridPane.setRowIndex(offerToolsBox, gridRow);
@ -228,6 +229,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
root.getChildren().add(offerToolsBox);
tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
GridPane.setRowIndex(tableView, ++gridRow);
GridPane.setColumnIndex(tableView, 0);
@ -405,14 +407,12 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
if (showAll) {
volumeColumn.setTitleWithHelpText(Res.get("shared.amountMinMax"), Res.get("shared.amountHelp"));
priceColumn.setTitle(Res.get("shared.price"));
priceColumn.getStyleClass().remove("first-column");
if (!tableView.getColumns().contains(marketColumn))
tableView.getColumns().add(0, marketColumn);
} else {
volumeColumn.setTitleWithHelpText(Res.get("offerbook.volume", code), Res.get("shared.amountHelp"));
priceColumn.setTitle(CurrencyUtil.getPriceWithCurrencyCode(code));
priceColumn.getStyleClass().add("first-column");
tableView.getColumns().remove(marketColumn);
}
@ -585,9 +585,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
public void setDirection(OfferDirection direction) {
model.initWithDirection(direction);
ImageView iconView = new ImageView();
createOfferButton.setGraphic(iconView);
iconView.setId(direction == OfferDirection.SELL ? "image-sell-white" : "image-buy-white");
createOfferButton.setGraphic(GUIUtil.getCurrencyIconWithBorder(Res.getBaseCurrencyCode()));
createOfferButton.setContentDisplay(ContentDisplay.RIGHT);
createOfferButton.setId(direction == OfferDirection.SELL ? "sell-button-big" : "buy-button-big");
avatarColumn.setTitle(direction == OfferDirection.SELL ? Res.get("shared.buyerUpperCase") : Res.get("shared.sellerUpperCase"));
if (direction == OfferDirection.SELL) {
@ -750,8 +749,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
() -> {
log.debug(Res.get("offerbook.removeOffer.success"));
if (DontShowAgainLookup.showAgain(key))
new Popup().instruction(Res.get("offerbook.withdrawFundsHint", Res.get("navigation.funds.availableForWithdrawal")))
.actionButtonTextWithGoTo("navigation.funds.availableForWithdrawal")
new Popup().instruction(Res.get("offerbook.withdrawFundsHint", Res.get("funds.tab.withdrawal")))
.actionButtonTextWithGoTo("funds.tab.withdrawal")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class))
.dontShowAgainId(key)
.show();
@ -769,7 +768,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
new Popup().headLine(headline)
.instruction(Res.get("offerbook.warning.noMatchingAccount.msg"))
.actionButtonTextWithGoTo("navigation.account")
.actionButtonTextWithGoTo("mainView.menu.account")
.onAction(() -> {
navigation.setReturnPath(navigation.getCurrentPath());
navigation.navigateTo(MainView.class, AccountView.class, accountViewClass);
@ -812,7 +811,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
setMinWidth(40);
}
};
column.getStyleClass().addAll("number-column", "first-column");
column.getStyleClass().addAll("number-column");
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
column.setCellFactory(
new Callback<>() {
@ -1065,7 +1064,6 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
setSortable(false);
}
};
column.getStyleClass().addAll("last-column", "avatar-column");
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
column.setCellFactory(
new Callback<>() {
@ -1116,7 +1114,12 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
// https://github.com/bisq-network/bisq/issues/4986
if (tableRow != null) {
canTakeOfferResult = model.offerFilterService.canTakeOffer(offer, false);
tableRow.setOpacity(canTakeOfferResult.isValid() || myOffer ? 1 : 0.4);
if (canTakeOfferResult.isValid() || myOffer) {
tableRow.getStyleClass().remove("row-faded");
} else {
if (!tableRow.getStyleClass().contains("row-faded")) tableRow.getStyleClass().add("row-faded");
hbox.getStyleClass().add("cell-faded");
}
if (myOffer) {
button.setDefaultButton(false);
@ -1149,12 +1152,16 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
} else {
boolean isSellOffer = OfferViewUtil.isShownAsSellOffer(offer);
boolean isPrivateOffer = offer.isPrivateOffer();
iconView.setId(isPrivateOffer ? "image-lock2x" : isSellOffer ? "image-buy-white" : "image-sell-white");
if (isPrivateOffer) {
button.setGraphic(GUIUtil.getLockLabel());
} else {
iconView.setId(isSellOffer ? "image-buy-white" : "image-sell-white");
iconView.setFitHeight(16);
iconView.setFitWidth(16);
}
button.setId(isSellOffer ? "buy-button" : "sell-button");
button.setStyle("-fx-text-fill: white");
title = Res.get("offerbook.takeOffer");
title = Res.get(isSellOffer ? "mainView.menu.buyXmr" : "mainView.menu.sellXmr");
button.setTooltip(new Tooltip(Res.get("offerbook.takeOfferButton.tooltip", model.getDirectionLabelTooltip(offer))));
button.setOnAction(e -> onTakeOffer(offer));
button2.setManaged(false);
@ -1179,8 +1186,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
button.setOnAction(null);
button2.setOnAction(null);
if (tableRow != null) {
tableRow.setOpacity(1);
tableRow.setOnMousePressed(null);
tableRow.getStyleClass().remove("row-faded");
}
}
}
@ -1236,7 +1243,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
setSortable(true);
}
};
column.getStyleClass().addAll("last-column", "avatar-column");
column.getStyleClass().addAll("avatar-column");
column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
column.setCellFactory(
new Callback<>() {
@ -1280,8 +1287,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM
private void updateCreateOfferButton() {
createOfferButton.setText(Res.get("offerbook.createNewOffer",
model.getDirection() == OfferDirection.BUY ? Res.get("shared.buy") : Res.get("shared.sell"),
getTradeCurrencyCode()).toUpperCase());
model.getDirection() == OfferDirection.BUY ? Res.get("shared.buy").toUpperCase() : Res.get("shared.sell").toUpperCase(),
getTradeCurrencyCode()));
}
abstract String getTradeCurrencyCode();

View file

@ -40,7 +40,6 @@ import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
@ -98,10 +97,6 @@ public class SignedOfferView extends ActivatableViewAndModel<VBox, SignedOffersV
@Override
public void initialize() {
Label label = new AutoTooltipLabel(Res.get("support.filter"));
HBox.setMargin(label, new Insets(5, 0, 0, 0));
HBox.setHgrow(label, Priority.NEVER);
filterTextField = new InputTextField();
Tooltip tooltip = new Tooltip();
tooltip.setShowDelay(Duration.millis(100));
@ -120,6 +115,7 @@ public class SignedOfferView extends ActivatableViewAndModel<VBox, SignedOffersV
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList);
filterBox.initialize(filteredList, tableView);
filterBox.setPromptText(Res.get("shared.filter"));
filterBox.activate();
contextMenu = new ContextMenu();

View file

@ -108,6 +108,7 @@ import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import net.glxn.qrgen.QRCode;
@ -127,13 +128,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private GridPane gridPane;
private TitledGroupBg noFundingRequiredTitledGroupBg;
private Label noFundingRequiredLabel;
private int lastGridRowNoFundingRequired;
private int gridRowNoFundingRequired;
private TitledGroupBg payFundsTitledGroupBg;
private TitledGroupBg advancedOptionsGroup;
private VBox priceAsPercentageInputBox, amountRangeBox;
private HBox fundingHBox, amountValueCurrencyBox, priceValueCurrencyBox, volumeValueCurrencyBox,
priceAsPercentageValueCurrencyBox, minAmountValueCurrencyBox, advancedOptionsBox,
takeOfferBox, buttonBox, firstRowHBox;
takeOfferBox, nextButtonBox, firstRowHBox;
private ComboBox<PaymentAccount> paymentAccountsComboBox;
private TextArea extraInfoTextArea;
private Label amountDescriptionLabel,
@ -142,7 +143,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
volumeCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel,
waitingForFundsLabel, offerAvailabilityLabel, priceAsPercentageDescription,
tradeFeeDescriptionLabel, resultLabel, tradeFeeInXmrLabel, xLabel,
fakeXLabel;
fakeXLabel, extraInfoLabel;
private InputTextField amountTextField;
private TextField paymentMethodTextField, currencyTextField, priceTextField, priceAsPercentageTextField,
volumeTextField, amountRangeTextField;
@ -153,6 +154,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private Button nextButton, cancelButton1, cancelButton2;
private AutoTooltipButton takeOfferButton, fundFromSavingsWalletButton;
private ImageView qrCodeImageView;
private StackPane qrCodePane;
private BusyAnimation waitingForFundsBusyAnimation, offerAvailabilityBusyAnimation;
private Notification walletFundedNotification;
private OfferView.CloseHandler closeHandler;
@ -200,7 +202,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
createListeners();
addButtons();
addNextButtons();
addOfferAvailabilityLabel();
addFundingGroup();
@ -339,8 +341,10 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (model.isRange()) {
amountRangeTextField.setText(model.getAmountRange());
amountRangeBox.setVisible(true);
amountRangeBox.setManaged(true);
} else {
amountTextField.setDisable(true);
amountTextField.setManaged(true);
}
priceTextField.setText(model.getPrice());
@ -361,20 +365,26 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (offer.hasBuyerAsTakerWithoutDeposit() && offer.getCombinedExtraInfo() != null && !offer.getCombinedExtraInfo().isEmpty()) {
// attach extra info text area
extraInfoTextArea = addCompactTopLabelTextArea(gridPane, ++lastGridRowNoFundingRequired, Res.get("payment.shared.extraInfo.noDeposit"), "").second;
extraInfoTextArea.setText(offer.getCombinedExtraInfo());
extraInfoTextArea.getStyleClass().add("text-area");
//updateOfferElementsStyle();
Tuple2<Label, TextArea> extraInfoTuple = addCompactTopLabelTextArea(gridPane, ++gridRowNoFundingRequired, Res.get("payment.shared.extraInfo.noDeposit"), "");
extraInfoLabel = extraInfoTuple.first;
extraInfoLabel.setVisible(false);
extraInfoLabel.setManaged(false);
extraInfoTextArea = extraInfoTuple.second;
extraInfoTextArea.setVisible(false);
extraInfoTextArea.setManaged(false);
extraInfoTextArea.setText(offer.getCombinedExtraInfo().trim());
extraInfoTextArea.getStyleClass().addAll("text-area", "flat-text-area-with-border");
extraInfoTextArea.setWrapText(true);
extraInfoTextArea.setPrefHeight(75);
extraInfoTextArea.setMinHeight(75);
extraInfoTextArea.setMaxHeight(150);
extraInfoTextArea.setMaxHeight(300);
extraInfoTextArea.setEditable(false);
GridPane.setRowIndex(extraInfoTextArea, lastGridRowNoFundingRequired);
GUIUtil.adjustHeightAutomatically(extraInfoTextArea);
GridPane.setRowIndex(extraInfoTextArea, gridRowNoFundingRequired);
GridPane.setColumnSpan(extraInfoTextArea, GridPane.REMAINING);
GridPane.setColumnIndex(extraInfoTextArea, 0);
// move up take offer buttons
GridPane.setRowIndex(takeOfferBox, lastGridRowNoFundingRequired + 1);
GridPane.setRowIndex(takeOfferBox, gridRowNoFundingRequired + 1);
GridPane.setMargin(takeOfferBox, new Insets(15, 0, 0, 0));
}
}
@ -490,19 +500,33 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
}
cancelButton2.setVisible(true);
cancelButton2.setManaged(true);
// temporarily disabled due to high CPU usage (per issue #4649)
//waitingForFundsBusyAnimation.play();
if (model.getOffer().hasBuyerAsTakerWithoutDeposit()) {
noFundingRequiredTitledGroupBg.setVisible(true);
noFundingRequiredTitledGroupBg.setManaged(true);
noFundingRequiredLabel.setVisible(true);
noFundingRequiredLabel.setManaged(true);
if (model.getOffer().getCombinedExtraInfo() != null && !model.getOffer().getCombinedExtraInfo().isEmpty()) {
extraInfoLabel.setVisible(true);
extraInfoLabel.setManaged(true);
extraInfoTextArea.setVisible(true);
extraInfoTextArea.setManaged(true);
}
} else {
payFundsTitledGroupBg.setVisible(true);
payFundsTitledGroupBg.setManaged(true);
totalToPayTextField.setVisible(true);
totalToPayTextField.setManaged(true);
addressTextField.setVisible(true);
qrCodeImageView.setVisible(true);
addressTextField.setManaged(true);
qrCodePane.setVisible(true);
qrCodePane.setManaged(true);
balanceTextField.setVisible(true);
balanceTextField.setManaged(true);
}
totalToPayTextField.setFundsStructure(Res.get("takeOffer.fundsBox.fundsStructure",
@ -536,8 +560,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private void updateOfferElementsStyle() {
GridPane.setColumnSpan(firstRowHBox, 1);
final String activeInputStyle = "input-with-border";
final String readOnlyInputStyle = "input-with-border-readonly";
final String activeInputStyle = "offer-input";
final String readOnlyInputStyle = "offer-input-readonly";
amountValueCurrencyBox.getStyleClass().remove(activeInputStyle);
amountValueCurrencyBox.getStyleClass().add(readOnlyInputStyle);
priceAsPercentageValueCurrencyBox.getStyleClass().remove(activeInputStyle);
@ -631,7 +655,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
UserThread.runAfter(() -> new Popup().warning(newValue + "\n\n" +
Res.get("takeOffer.alreadyPaidInFunds"))
.actionButtonTextWithGoTo("navigation.funds.availableForWithdrawal")
.actionButtonTextWithGoTo("funds.tab.withdrawal")
.onAction(() -> {
errorPopupDisplayed.set(true);
model.resetOfferWarning();
@ -663,6 +687,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (isOfferAvailable) {
offerAvailabilityBusyAnimation.stop();
offerAvailabilityBusyAnimation.setVisible(false);
offerAvailabilityBusyAnimation.setManaged(false);
if (!model.isRange() && !model.showPayFundsScreenDisplayed.get())
showNextStepAfterAmountIsSet();
}
@ -693,7 +718,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
if (DontShowAgainLookup.showAgain(key)) {
UserThread.runAfter(() -> new Popup().headLine(Res.get("takeOffer.success.headline"))
.feedback(Res.get("takeOffer.success.info"))
.actionButtonTextWithGoTo("navigation.portfolio.pending")
.actionButtonTextWithGoTo("portfolio.tab.pendingTrades")
.dontShowAgainId(key)
.onAction(() -> {
UserThread.runAfter(
@ -755,7 +780,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
private void addGridPane() {
gridPane = new GridPane();
gridPane.getStyleClass().add("content-pane");
gridPane.setPadding(new Insets(15, 15, -1, 15));
gridPane.setPadding(new Insets(25, 25, 25, 25));
gridPane.setHgap(5);
gridPane.setVgap(5);
GUIUtil.setDefaultTwoColumnConstraintsForGridPane(gridPane);
@ -837,11 +862,11 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
advancedOptionsBox.getChildren().addAll(tradeFeeFieldsBox);
}
private void addButtons() {
private void addNextButtons() {
Tuple3<Button, Button, HBox> tuple = add2ButtonsWithBox(gridPane, ++gridRow,
Res.get("shared.nextStep"), Res.get("shared.cancel"), 15, true);
buttonBox = tuple.third;
nextButtonBox = tuple.third;
nextButton = tuple.first;
nextButton.setMaxWidth(200);
@ -870,7 +895,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
offerAvailabilityBusyAnimation = new BusyAnimation(false);
offerAvailabilityLabel = new AutoTooltipLabel(Res.get("takeOffer.fundsBox.isOfferAvailable"));
HBox.setMargin(offerAvailabilityLabel, new Insets(6, 0, 0, 0));
buttonBox.getChildren().addAll(offerAvailabilityBusyAnimation, offerAvailabilityLabel);
nextButtonBox.getChildren().addAll(offerAvailabilityBusyAnimation, offerAvailabilityLabel);
}
private void addFundingGroup() {
@ -881,16 +906,18 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
noFundingRequiredTitledGroupBg.getStyleClass().add("last");
GridPane.setColumnSpan(noFundingRequiredTitledGroupBg, 2);
noFundingRequiredTitledGroupBg.setVisible(false);
noFundingRequiredTitledGroupBg.setManaged(false);
// no funding required description
noFundingRequiredLabel = new AutoTooltipLabel(Res.get("takeOffer.fundsBox.noFundingRequiredDescription"));
noFundingRequiredLabel.setVisible(false);
noFundingRequiredLabel.setManaged(false);
//GridPane.setRowSpan(noFundingRequiredLabel, 1);
GridPane.setRowIndex(noFundingRequiredLabel, gridRow);
noFundingRequiredLabel.setPadding(new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
GridPane.setHalignment(noFundingRequiredLabel, HPos.LEFT);
gridPane.getChildren().add(noFundingRequiredLabel);
lastGridRowNoFundingRequired = gridRow;
gridRowNoFundingRequired = gridRow;
// funding title
payFundsTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 3,
@ -898,32 +925,38 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
payFundsTitledGroupBg.getStyleClass().add("last");
GridPane.setColumnSpan(payFundsTitledGroupBg, 2);
payFundsTitledGroupBg.setVisible(false);
payFundsTitledGroupBg.setManaged(false);
totalToPayTextField = addFundsTextfield(gridPane, gridRow,
Res.get("shared.totalsNeeded"), Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE);
totalToPayTextField.setVisible(false);
totalToPayTextField.setManaged(false);
qrCodeImageView = new ImageView();
qrCodeImageView.setVisible(false);
qrCodeImageView.setFitHeight(150);
qrCodeImageView.setFitWidth(150);
qrCodeImageView.getStyleClass().add("qr-code");
Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodeImageView.setOnMouseClicked(e -> UserThread.runAfter(
Tuple2<StackPane, ImageView> qrCodeTuple = GUIUtil.getSmallXmrQrCodePane();
qrCodePane = qrCodeTuple.first;
qrCodeImageView = qrCodeTuple.second;
Tooltip.install(qrCodePane, new Tooltip(Res.get("shared.openLargeQRWindow")));
qrCodePane.setOnMouseClicked(e -> UserThread.runAfter(
() -> new QRCodeWindow(getMoneroURI()).show(),
200, TimeUnit.MILLISECONDS));
GridPane.setRowIndex(qrCodeImageView, gridRow);
GridPane.setColumnIndex(qrCodeImageView, 1);
GridPane.setRowSpan(qrCodeImageView, 3);
GridPane.setValignment(qrCodeImageView, VPos.BOTTOM);
GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 10));
gridPane.getChildren().add(qrCodeImageView);
GridPane.setRowIndex(qrCodePane, gridRow);
GridPane.setColumnIndex(qrCodePane, 1);
GridPane.setRowSpan(qrCodePane, 3);
GridPane.setValignment(qrCodePane, VPos.BOTTOM);
GridPane.setMargin(qrCodePane, new Insets(Layout.FIRST_ROW_DISTANCE - 9, 0, 0, 10));
gridPane.getChildren().add(qrCodePane);
qrCodePane.setVisible(false);
qrCodePane.setManaged(false);
addressTextField = addAddressTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletAddress"));
addressTextField.setVisible(false);
addressTextField.setManaged(false);
balanceTextField = addBalanceTextField(gridPane, ++gridRow, Res.get("shared.tradeWalletBalance"));
balanceTextField.setVisible(false);
balanceTextField.setManaged(false);
fundingHBox = new HBox();
fundingHBox.setVisible(false);
@ -1000,6 +1033,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
});
cancelButton2.setDefaultButton(false);
cancelButton2.setVisible(false);
cancelButton2.setManaged(false);
}
private void openWallet() {
@ -1100,6 +1134,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
fakeXLabel = new Label();
fakeXIcon = getIconForLabel(MaterialDesignIcon.CLOSE, "2em", fakeXLabel);
fakeXLabel.setVisible(false); // we just use it to get the same layout as the upper row
fakeXIcon.setManaged(false);
fakeXLabel.getStyleClass().add("opaque-icon-character");
HBox hBox = new HBox();
@ -1147,7 +1182,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
UserThread.runAfter(() -> {
new GenericMessageWindow()
.preamble(Res.get("payment.tradingRestrictions"))
.instruction(offer.getCombinedExtraInfo())
.instruction(offer.getCombinedExtraInfo().trim())
.actionButtonText(Res.get("shared.iConfirm"))
.closeButtonText(Res.get("shared.close"))
.width(Layout.INITIAL_WINDOW_WIDTH)

View file

@ -256,7 +256,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
new Popup().warning(Res.get("shared.notEnoughFunds",
HavenoUtils.formatXmr(dataModel.getTotalToPay().get(), true),
HavenoUtils.formatXmr(dataModel.getTotalAvailableBalance(), true)))
.actionButtonTextWithGoTo("navigation.funds.depositFunds")
.actionButtonTextWithGoTo("funds.tab.deposit")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, DepositView.class))
.show();
return false;

View file

@ -19,6 +19,8 @@ package haveno.desktop.main.overlays;
import com.google.common.reflect.TypeToken;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView;
import haveno.common.Timer;
import haveno.common.UserThread;
import haveno.common.config.Config;
@ -42,8 +44,6 @@ import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
@ -52,6 +52,7 @@ import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.NodeOrientation;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
@ -122,7 +123,7 @@ public abstract class Overlay<T extends Overlay<T>> {
Notification(AnimationType.SlideFromRightTop, ChangeBackgroundType.BlurLight),
BackgroundInfo(AnimationType.SlideDownFromCenterTop, ChangeBackgroundType.BlurUltraLight),
Feedback(AnimationType.SlideDownFromCenterTop, ChangeBackgroundType.Darken),
Feedback(AnimationType.SlideDownFromCenterTop, ChangeBackgroundType.BlurLight),
Information(AnimationType.FadeInAtCenter, ChangeBackgroundType.BlurLight),
Instruction(AnimationType.ScaleFromCenter, ChangeBackgroundType.BlurLight),
@ -141,6 +142,9 @@ public abstract class Overlay<T extends Overlay<T>> {
}
}
private static int numCenterOverlays = 0;
private static int numBlurEffects = 0;
protected final static double DEFAULT_WIDTH = 668;
protected Stage stage;
protected GridPane gridPane;
@ -168,7 +172,7 @@ public abstract class Overlay<T extends Overlay<T>> {
protected boolean showScrollPane = false;
protected TextArea messageTextArea;
protected Label headlineIcon, copyIcon, headLineLabel;
protected Label headlineIcon, copyLabel, headLineLabel;
protected String headLine, message, closeButtonText, actionButtonText,
secondaryActionButtonText, dontShowAgainId, dontShowAgainText,
truncatedMessage;
@ -249,6 +253,7 @@ public abstract class Overlay<T extends Overlay<T>> {
protected void animateHide() {
animateHide(() -> {
if (isCentered()) numCenterOverlays--;
removeEffectFromBackground();
if (stage != null)
@ -541,6 +546,14 @@ public abstract class Overlay<T extends Overlay<T>> {
layout();
// add dropshadow if light mode or multiple centered overlays
if (isCentered()) {
numCenterOverlays++;
}
if (!CssTheme.isDarkTheme() || numCenterOverlays > 1) {
getRootContainer().getStyleClass().add("popup-dropshadow");
}
addEffectToBackground();
// On Linux the owner stage does not move the child stage as it does on Mac
@ -739,6 +752,8 @@ public abstract class Overlay<T extends Overlay<T>> {
}
protected void addEffectToBackground() {
numBlurEffects++;
if (numBlurEffects > 1) return;
if (type.changeBackgroundType == ChangeBackgroundType.BlurUltraLight)
MainView.blurUltraLight();
else if (type.changeBackgroundType == ChangeBackgroundType.BlurLight)
@ -758,12 +773,14 @@ public abstract class Overlay<T extends Overlay<T>> {
if (headLineLabel != null) {
if (copyIcon != null) {
copyIcon.getStyleClass().add("popup-icon-information");
copyIcon.setManaged(true);
copyIcon.setVisible(true);
FormBuilder.getIconForLabel(AwesomeIcon.COPY, copyIcon, "1.1em");
copyIcon.addEventHandler(MOUSE_CLICKED, mouseEvent -> {
if (copyLabel != null) {
copyLabel.getStyleClass().add("popup-icon-information");
copyLabel.setManaged(true);
copyLabel.setVisible(true);
MaterialDesignIconView copyIcon = new MaterialDesignIconView(MaterialDesignIcon.CONTENT_COPY, "1.2em");
copyLabel.setGraphic(copyIcon);
copyLabel.setCursor(Cursor.HAND);
copyLabel.addEventHandler(MOUSE_CLICKED, mouseEvent -> {
if (message != null) {
Utilities.copyToClipboard(getClipboardText());
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
@ -808,6 +825,8 @@ public abstract class Overlay<T extends Overlay<T>> {
}
protected void removeEffectFromBackground() {
numBlurEffects--;
if (numBlurEffects > 0) return;
MainView.removeEffect();
}
@ -828,15 +847,15 @@ public abstract class Overlay<T extends Overlay<T>> {
headLineLabel.setStyle(headlineStyle);
if (message != null) {
copyIcon = new Label();
copyIcon.setManaged(false);
copyIcon.setVisible(false);
copyIcon.setPadding(new Insets(3));
copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
copyLabel = new Label();
copyLabel.setManaged(false);
copyLabel.setVisible(false);
copyLabel.setPadding(new Insets(3));
copyLabel.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
final Pane spacer = new Pane();
HBox.setHgrow(spacer, Priority.ALWAYS);
spacer.setMinSize(Layout.PADDING, 1);
hBox.getChildren().addAll(headlineIcon, headLineLabel, spacer, copyIcon);
hBox.getChildren().addAll(headlineIcon, headLineLabel, spacer, copyLabel);
} else {
hBox.getChildren().addAll(headlineIcon, headLineLabel);
}
@ -852,23 +871,8 @@ public abstract class Overlay<T extends Overlay<T>> {
if (message != null) {
messageTextArea = new TextArea(truncatedMessage);
messageTextArea.setEditable(false);
messageTextArea.getStyleClass().add("text-area-no-border");
messageTextArea.sceneProperty().addListener((o, oldScene, newScene) -> {
if (newScene != null) {
// avoid javafx css warning
CssTheme.loadSceneStyles(newScene, CssTheme.CSS_THEME_LIGHT, false);
messageTextArea.applyCss();
var text = messageTextArea.lookup(".text");
messageTextArea.prefHeightProperty().bind(Bindings.createDoubleBinding(() -> {
return messageTextArea.getFont().getSize() + text.getBoundsInLocal().getHeight();
}, text.boundsInLocalProperty()));
text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> {
Platform.runLater(() -> messageTextArea.requestLayout());
});
}
});
messageTextArea.getStyleClass().add("text-area-popup");
GUIUtil.adjustHeightAutomatically(messageTextArea);
messageTextArea.setWrapText(true);
Region messageRegion;
@ -1093,4 +1097,10 @@ public abstract class Overlay<T extends Overlay<T>> {
", message='" + message + '\'' +
'}';
}
private boolean isCentered() {
if (type.animationType == AnimationType.SlideDownFromCenterTop) return false;
if (type.animationType == AnimationType.SlideFromRightTop) return false;
return true;
}
}

View file

@ -71,7 +71,7 @@ public class PasswordPopup extends Overlay<PasswordPopup> {
@Override
public void show() {
actionButtonText("CONFIRM");
actionButtonText("Confirm");
createGridPane();
addHeadLine();
addContent();

View file

@ -42,6 +42,7 @@ public class Notification extends Overlay<Notification> {
private boolean hasBeenDisplayed;
private boolean autoClose;
private Timer autoCloseTimer;
private static final int BORDER_PADDING = 10;
public Notification() {
width = 413; // 320 visible bg because of insets
@ -205,8 +206,8 @@ public class Notification extends Overlay<Notification> {
Window window = owner.getScene().getWindow();
double titleBarHeight = window.getHeight() - owner.getScene().getHeight();
double shadowInset = 44;
stage.setX(Math.round(window.getX() + window.getWidth() + shadowInset - stage.getWidth()));
stage.setY(Math.round(window.getY() + titleBarHeight - shadowInset));
stage.setX(Math.round(window.getX() + window.getWidth() + shadowInset - stage.getWidth() - BORDER_PADDING));
stage.setY(Math.round(window.getY() + titleBarHeight - shadowInset + BORDER_PADDING));
}
@Override

View file

@ -216,7 +216,7 @@ public class NotificationCenter {
if (DontShowAgainLookup.showAgain(key)) {
Notification notification = new Notification().tradeHeadLine(trade.getShortId()).message(message);
if (navigation.getCurrentPath() != null && !navigation.getCurrentPath().contains(PendingTradesView.class)) {
notification.actionButtonTextWithGoTo("navigation.portfolio.pending")
notification.actionButtonTextWithGoTo("portfolio.tab.pendingTrades")
.onAction(() -> {
DontShowAgainLookup.dontShowAgain(key, true);
navigation.navigateTo(MainView.class, PortfolioView.class, PendingTradesView.class);
@ -318,7 +318,7 @@ public class NotificationCenter {
private void goToSupport(Trade trade, String message, Class<? extends DisputeView> viewClass) {
Notification notification = new Notification().disputeHeadLine(trade.getShortId()).message(message);
if (navigation.getCurrentPath() != null && !navigation.getCurrentPath().contains(viewClass)) {
notification.actionButtonTextWithGoTo("navigation.support")
notification.actionButtonTextWithGoTo("mainView.menu.support")
.onAction(() -> navigation.navigateTo(MainView.class, SupportView.class, viewClass))
.show();
} else {

View file

@ -46,6 +46,7 @@ import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon;
import static haveno.desktop.util.FormBuilder.addLabelExplorerAddressTextField;
import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField;
import static haveno.desktop.util.FormBuilder.addSeparator;
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import haveno.desktop.util.Layout;
import haveno.network.p2p.NodeAddress;
@ -137,15 +138,20 @@ public class ContractWindow extends Overlay<ContractWindow> {
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("contractWindow.title"));
addConfirmationLabelTextField(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
Layout.TWICE_FIRST_ROW_DISTANCE);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("contractWindow.dates"),
DisplayUtils.formatDateTime(offer.getDate()) + " / " + DisplayUtils.formatDateTime(dispute.getTradeDate()));
String currencyCode = offer.getCurrencyCode();
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.offerType"),
DisplayUtils.getDirectionBothSides(offer.getDirection(), offer.isPrivateOffer()));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
FormattingUtils.formatPrice(contract.getPrice()));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradeAmount"),
HavenoUtils.formatXmr(contract.getTradeAmount(), true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
VolumeUtil.formatVolumeLabel(currencyCode, ":"),
@ -157,16 +163,20 @@ public class ContractWindow extends Overlay<ContractWindow> {
Res.getWithColAndCap("shared.seller") +
" " +
HavenoUtils.formatXmr(offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(contract.getTradeAmount()), true);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("contractWindow.xmrAddresses"),
contract.getBuyerPayoutAddressString() + " / " + contract.getSellerPayoutAddressString());
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("contractWindow.onions"),
contract.getBuyerNodeAddress().getFullAddress() + " / " + contract.getSellerNodeAddress().getFullAddress());
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("contractWindow.accountAge"),
@ -176,16 +186,19 @@ public class ContractWindow extends Overlay<ContractWindow> {
DisputeManager<? extends DisputeList<Dispute>> disputeManager = getDisputeManager(dispute);
String nrOfDisputesAsBuyer = disputeManager != null ? disputeManager.getNrOfDisputes(true, contract) : "";
String nrOfDisputesAsSeller = disputeManager != null ? disputeManager.getNrOfDisputes(false, contract) : "";
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("contractWindow.numDisputes"),
nrOfDisputesAsBuyer + " / " + nrOfDisputesAsSeller);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("shared.paymentDetails", Res.get("shared.buyer")),
dispute.getBuyerPaymentAccountPayload() != null
? dispute.getBuyerPaymentAccountPayload().getPaymentDetails()
: "NA");
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane,
++rowIndex,
Res.get("shared.paymentDetails", Res.get("shared.seller")),
@ -219,6 +232,7 @@ public class ContractWindow extends Overlay<ContractWindow> {
NodeAddress agentNodeAddress = disputeManager.getAgentNodeAddress(dispute);
if (agentNodeAddress != null) {
String value = agentMatrixUserName + " (" + agentNodeAddress.getFullAddress() + ")";
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, title, value);
}
}
@ -232,40 +246,53 @@ public class ContractWindow extends Overlay<ContractWindow> {
countries = CountryUtil.getCodesString(acceptedCountryCodes);
tooltip = new Tooltip(CountryUtil.getNamesByCodesString(acceptedCountryCodes));
}
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.acceptedTakerCountries"), countries)
.second.setTooltip(tooltip);
}
if (showAcceptedBanks) {
if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK)) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.bankName"), acceptedBanks.get(0));
} else if (offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) {
String value = Joiner.on(", ").join(acceptedBanks);
Tooltip tooltip = new Tooltip(Res.get("shared.acceptedBanks") + value);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.acceptedBanks"), value)
.second.setTooltip(tooltip);
}
}
addSeparator(gridPane, ++rowIndex);
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerDepositTransactionId"), contract.getMakerDepositTxHash());
if (contract.getTakerDepositTxHash() != null)
if (contract.getTakerDepositTxHash() != null) {
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerDepositTransactionId"), contract.getTakerDepositTxHash());
}
if (dispute.getDelayedPayoutTxId() != null)
if (dispute.getDelayedPayoutTxId() != null) {
addSeparator(gridPane, ++rowIndex);
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.delayedPayoutTxId"), dispute.getDelayedPayoutTxId());
}
if (dispute.getDonationAddressOfDelayedPayoutTx() != null) {
addSeparator(gridPane, ++rowIndex);
addLabelExplorerAddressTextField(gridPane, ++rowIndex, Res.get("shared.delayedPayoutTxReceiverAddress"),
dispute.getDonationAddressOfDelayedPayoutTx());
}
if (dispute.getPayoutTxSerialized() != null)
if (dispute.getPayoutTxSerialized() != null) {
addSeparator(gridPane, ++rowIndex);
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.payoutTxId"), dispute.getPayoutTxId());
}
if (dispute.getContractHash() != null)
if (dispute.getContractHash() != null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("contractWindow.contractHash"),
Utils.HEX.encode(dispute.getContractHash())).second.setMouseTransparent(false);
}
addSeparator(gridPane, ++rowIndex);
Button viewContractButton = addConfirmationLabelButton(gridPane, ++rowIndex, Res.get("shared.contractAsJson"),
Res.get("shared.viewContractAsJson"), 0).second;
viewContractButton.setDefaultButton(false);

View file

@ -188,7 +188,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
protected void createGridPane() {
super.createGridPane();
gridPane.setPadding(new Insets(35, 40, 30, 40));
gridPane.getStyleClass().add("grid-pane");
gridPane.getStyleClass().addAll("grid-pane", "popup-with-input");
gridPane.getColumnConstraints().get(0).setHalignment(HPos.LEFT);
gridPane.setPrefWidth(width);
}
@ -413,11 +413,13 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
private void addPayoutAmountTextFields() {
buyerPayoutAmountInputTextField = new InputTextField();
buyerPayoutAmountInputTextField.setLabelFloat(true);
buyerPayoutAmountInputTextField.getStyleClass().add("label-float");
buyerPayoutAmountInputTextField.setEditable(false);
buyerPayoutAmountInputTextField.setPromptText(Res.get("disputeSummaryWindow.payoutAmount.buyer"));
sellerPayoutAmountInputTextField = new InputTextField();
sellerPayoutAmountInputTextField.setLabelFloat(true);
sellerPayoutAmountInputTextField.getStyleClass().add("label-float");
sellerPayoutAmountInputTextField.setPromptText(Res.get("disputeSummaryWindow.payoutAmount.seller"));
sellerPayoutAmountInputTextField.setEditable(false);

View file

@ -18,6 +18,7 @@
package haveno.desktop.main.overlays.windows;
import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
@ -28,6 +29,7 @@ import static haveno.desktop.util.FormBuilder.addTextArea;
public class GenericMessageWindow extends Overlay<GenericMessageWindow> {
private String preamble;
private static final double MAX_TEXT_AREA_HEIGHT = 250;
public GenericMessageWindow() {
super();
@ -54,20 +56,11 @@ public class GenericMessageWindow extends Overlay<GenericMessageWindow> {
}
checkNotNull(message, "message must not be null");
TextArea textArea = addTextArea(gridPane, ++rowIndex, "", 10);
textArea.getStyleClass().add("flat-text-area-with-border");
textArea.setText(message);
textArea.setEditable(false);
textArea.setWrapText(true);
// sizes the textArea to fit within its parent container
double verticalSizePercentage = ensureRange(countLines(message) / 20.0, 0.2, 0.7);
textArea.setPrefSize(Layout.INITIAL_WINDOW_WIDTH, Layout.INITIAL_WINDOW_HEIGHT * verticalSizePercentage);
}
private static int countLines(String str) {
String[] lines = str.split("\r\n|\r|\n");
return lines.length;
}
private static double ensureRange(double value, double min, double max) {
return Math.min(Math.max(value, min), max);
textArea.setPrefWidth(Layout.INITIAL_WINDOW_WIDTH);
GUIUtil.adjustHeightAutomatically(textArea, MAX_TEXT_AREA_HEIGHT);
}
}

View file

@ -20,10 +20,16 @@ package haveno.desktop.main.overlays.windows;
import com.google.common.base.Joiner;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView;
import haveno.common.UserThread;
import haveno.common.crypto.KeyRing;
import haveno.common.util.Tuple2;
import haveno.common.util.Tuple4;
import haveno.common.util.Utilities;
import haveno.core.locale.CountryUtil;
import haveno.core.locale.Res;
import haveno.core.monetary.Price;
@ -45,30 +51,37 @@ import haveno.desktop.components.BusyAnimation;
import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.main.overlays.editor.PasswordPopup;
import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.CssTheme;
import haveno.desktop.util.DisplayUtils;
import static haveno.desktop.util.FormBuilder.addButtonAfterGroup;
import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon;
import static haveno.desktop.util.FormBuilder.addLabel;
import static haveno.desktop.util.FormBuilder.addSeparator;
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.Tooltip;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
import org.slf4j.Logger;
@ -115,7 +128,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
this.tradePrice = tradePrice;
rowIndex = -1;
width = 1118;
width = Layout.DETAILS_WINDOW_WIDTH;
createGridPane();
addContent();
display();
@ -124,7 +137,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
public void show(Offer offer) {
this.offer = offer;
rowIndex = -1;
width = 1118;
width = Layout.DETAILS_WINDOW_WIDTH;
createGridPane();
addContent();
display();
@ -194,7 +207,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
rows++;
}
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get(offer.isPrivateOffer() ? "shared.Offer" : "shared.Offer"));
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.Offer"));
String counterCurrencyDirectionInfo = "";
String xmrDirectionInfo = "";
@ -218,17 +231,22 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
DisplayUtils.getDirectionBothSides(direction, offer.isPrivateOffer()), firstRowDistance);
}
String amount = Res.get("shared.xmrAmount");
addSeparator(gridPane, ++rowIndex);
if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
HavenoUtils.formatXmr(tradeAmount, true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
} else {
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
HavenoUtils.formatXmr(offer.getAmount(), true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"),
HavenoUtils.formatXmr(offer.getMinAmount(), true));
addSeparator(gridPane, ++rowIndex);
String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume());
String minVolume = "";
if (offer.getVolume() != null && offer.getMinVolume() != null &&
@ -239,6 +257,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
}
String priceLabel = Res.get("shared.price");
addSeparator(gridPane, ++rowIndex);
if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, FormattingUtils.formatPrice(tradePrice));
} else {
@ -264,6 +283,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId);
String countryCode = offer.getCountryCode();
boolean isMyOffer = offer.isMyOffer(keyRing);
addSeparator(gridPane, ++rowIndex);
if (isMyOffer && makerPaymentAccountId != null && myPaymentAccount != null) {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName());
} else {
@ -272,6 +292,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
}
if (showXmrAutoConf) {
addSeparator(gridPane, ++rowIndex);
String isAutoConf = offer.isXmrAutoConf() ?
Res.get("shared.yes") :
Res.get("shared.no");
@ -280,8 +301,10 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
if (showAcceptedBanks) {
if (paymentMethod.equals(PaymentMethod.SAME_BANK)) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.bankId"), acceptedBanks.get(0));
} else if (isSpecificBanks) {
addSeparator(gridPane, ++rowIndex);
String value = Joiner.on(", ").join(acceptedBanks);
String acceptedBanksLabel = Res.get("shared.acceptedBanks");
Tooltip tooltip = new Tooltip(acceptedBanksLabel + " " + value);
@ -291,6 +314,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
}
}
if (showAcceptedCountryCodes) {
addSeparator(gridPane, ++rowIndex);
String countries;
Tooltip tooltip = null;
if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes)) {
@ -313,29 +337,16 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
}
if (isF2F) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("payment.f2f.city"), offer.getF2FCity());
}
if (showOfferExtraInfo) {
addSeparator(gridPane, ++rowIndex);
TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo"), "", 0).second;
textArea.setText(offer.getCombinedExtraInfo());
textArea.setMaxHeight(200);
textArea.sceneProperty().addListener((o, oldScene, newScene) -> {
if (newScene != null) {
// avoid javafx css warning
CssTheme.loadSceneStyles(newScene, CssTheme.CSS_THEME_LIGHT, false);
textArea.applyCss();
var text = textArea.lookup(".text");
textArea.prefHeightProperty().bind(Bindings.createDoubleBinding(() -> {
return textArea.getFont().getSize() + text.getBoundsInLocal().getHeight();
}, text.boundsInLocalProperty()));
text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> {
Platform.runLater(() -> textArea.requestLayout());
});
}
});
textArea.setText(offer.getCombinedExtraInfo().trim());
textArea.setMaxHeight(Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
textArea.setEditable(false);
GUIUtil.adjustHeightAutomatically(textArea, Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
}
// get amount reserved for the offer
@ -355,13 +366,16 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
if (offerChallenge != null)
rows++;
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.COMPACT_GROUP_DISTANCE);
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
Layout.TWICE_FIRST_ROW_AND_COMPACT_GROUP_DISTANCE);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.makersOnion"),
offer.getMakerNodeAddress().getFullAddress());
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.creationDate"),
DisplayUtils.formatDateTime(offer.getDate()));
addSeparator(gridPane, ++rowIndex);
String value = Res.getWithColAndCap("shared.buyer") +
" " +
HavenoUtils.formatXmr(takeOfferHandlerOptional.isPresent() ? offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(tradeAmount) : offer.getOfferPayload().getMaxBuyerSecurityDeposit(), true) +
@ -372,27 +386,75 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
if (reservedAmount != null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.reservedAmount"), HavenoUtils.formatXmr(reservedAmount, true));
}
if (countryCode != null && !isF2F)
if (countryCode != null && !isF2F) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
CountryUtil.getNameAndCode(countryCode));
}
if (offerChallenge != null)
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.challenge"), offerChallenge);
if (offerChallenge != null) {
addSeparator(gridPane, ++rowIndex);
// add label
Label label = addLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.challenge"), 0);
label.getStyleClass().addAll("confirmation-label", "regular-text-color");
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setValignment(label, VPos.TOP);
// add vbox with passphrase and copy button
VBox vbox = new VBox(13);
vbox.setAlignment(Pos.TOP_CENTER);
VBox.setVgrow(vbox, Priority.ALWAYS);
vbox.getStyleClass().addAll("passphrase-copy-box");
// add passphrase
JFXTextField centerLabel = new JFXTextField(offerChallenge);
centerLabel.getStyleClass().add("confirmation-value");
centerLabel.setAlignment(Pos.CENTER);
centerLabel.setFocusTraversable(false);
// add copy button
Label copyLabel = new Label();
copyLabel.getStyleClass().addAll("icon");
copyLabel.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
MaterialDesignIconView copyIcon = new MaterialDesignIconView(MaterialDesignIcon.CONTENT_COPY, "1.2em");
copyIcon.setFill(Color.WHITE);
copyLabel.setGraphic(copyIcon);
JFXButton copyButton = new JFXButton(Res.get("offerDetailsWindow.challenge.copy"), copyLabel);
copyButton.setContentDisplay(ContentDisplay.LEFT);
copyButton.setGraphicTextGap(8);
copyButton.setOnMouseClicked(e -> {
Utilities.copyToClipboard(offerChallenge);
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
Node node = (Node) e.getSource();
UserThread.runAfter(() -> tp.hide(), 1);
tp.show(node, e.getScreenX() + Layout.PADDING, e.getScreenY() + Layout.PADDING);
});
copyButton.setId("buy-button");
copyButton.setFocusTraversable(false);
vbox.getChildren().addAll(centerLabel, copyButton);
// add vbox to grid pane in next column
GridPane.setRowIndex(vbox, rowIndex);
GridPane.setColumnIndex(vbox, 1);
gridPane.getChildren().add(vbox);
}
if (placeOfferHandlerOptional.isPresent()) {
addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("offerDetailsWindow.commitment"), Layout.GROUP_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("offerDetailsWindow.commitment"), Layout.COMPACT_GROUP_DISTANCE);
final Tuple2<Label, Label> labelLabelTuple2 = addConfirmationLabelLabel(gridPane, rowIndex, Res.get("offerDetailsWindow.agree"), Res.get("createOffer.tac"),
Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
Layout.TWICE_FIRST_ROW_AND_COMPACT_GROUP_DISTANCE);
labelLabelTuple2.second.setWrapText(true);
addConfirmAndCancelButtons(true);
} else if (takeOfferHandlerOptional.isPresent()) {
addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("shared.contract"), Layout.GROUP_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("shared.contract"), Layout.COMPACT_GROUP_DISTANCE);
final Tuple2<Label, Label> labelLabelTuple2 = addConfirmationLabelLabel(gridPane, rowIndex, Res.get("offerDetailsWindow.tac"), Res.get("takeOffer.tac"),
Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
Layout.TWICE_FIRST_ROW_AND_COMPACT_GROUP_DISTANCE);
labelLabelTuple2.second.setWrapText(true);
addConfirmAndCancelButtons(false);
@ -418,9 +480,6 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
Res.get("offerDetailsWindow.confirm.taker", Res.get("shared.buy")) :
Res.get("offerDetailsWindow.confirm.taker", Res.get("shared.sell"));
ImageView iconView = new ImageView();
iconView.setId(isBuyerRole ? "image-buy-white" : "image-sell-white");
Tuple4<Button, BusyAnimation, Label, HBox> placeOfferTuple = addButtonBusyAnimationLabelAfterGroup(gridPane,
++rowIndex, 1,
isPlaceOffer ? placeOfferButtonText : takeOfferButtonText);
@ -428,11 +487,18 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
AutoTooltipButton confirmButton = (AutoTooltipButton) placeOfferTuple.first;
confirmButton.setMinHeight(40);
confirmButton.setPadding(new Insets(0, 20, 0, 20));
confirmButton.setGraphic(iconView);
confirmButton.setGraphicTextGap(10);
confirmButton.setId(isBuyerRole ? "buy-button-big" : "sell-button-big");
confirmButton.updateText(isPlaceOffer ? placeOfferButtonText : takeOfferButtonText);
if (offer.hasBuyerAsTakerWithoutDeposit()) {
confirmButton.setGraphic(GUIUtil.getLockLabel());
} else {
ImageView iconView = new ImageView();
iconView.setId(isBuyerRole ? "image-buy-white" : "image-sell-white");
confirmButton.setGraphic(iconView);
}
busyAnimation = placeOfferTuple.second;
Label spinnerInfoLabel = placeOfferTuple.third;

View file

@ -17,9 +17,12 @@
package haveno.desktop.main.overlays.windows;
import haveno.common.util.Tuple2;
import haveno.common.util.Utilities;
import haveno.core.locale.Res;
import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.util.GUIUtil;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@ -27,31 +30,35 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.net.URI;
public class QRCodeWindow extends Overlay<QRCodeWindow> {
private static final Logger log = LoggerFactory.getLogger(QRCodeWindow.class);
private final ImageView qrCodeImageView;
private final StackPane qrCodePane;
private final String moneroUri;
public QRCodeWindow(String bitcoinURI) {
this.moneroUri = bitcoinURI;
public QRCodeWindow(String moneroUri) {
this.moneroUri = moneroUri;
Tuple2<StackPane, ImageView> qrCodeTuple = GUIUtil.getBigXmrQrCodePane();
qrCodePane = qrCodeTuple.first;
ImageView qrCodeImageView = qrCodeTuple.second;
final byte[] imageBytes = QRCode
.from(bitcoinURI)
.from(moneroUri)
.withSize(300, 300)
.to(ImageType.PNG)
.stream()
.toByteArray();
Image qrImage = new Image(new ByteArrayInputStream(imageBytes));
qrCodeImageView = new ImageView(qrImage);
qrCodeImageView.setFitHeight(250);
qrCodeImageView.setFitWidth(250);
qrCodeImageView.getStyleClass().add("qr-code");
qrCodeImageView.setImage(qrImage);
type = Type.Information;
width = 468;
@ -65,10 +72,11 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> {
addHeadLine();
addMessage();
GridPane.setRowIndex(qrCodeImageView, ++rowIndex);
GridPane.setColumnSpan(qrCodeImageView, 2);
GridPane.setHalignment(qrCodeImageView, HPos.CENTER);
gridPane.getChildren().add(qrCodeImageView);
qrCodePane.setOnMouseClicked(event -> openWallet());
GridPane.setRowIndex(qrCodePane, ++rowIndex);
GridPane.setColumnSpan(qrCodePane, 2);
GridPane.setHalignment(qrCodePane, HPos.CENTER);
gridPane.getChildren().add(qrCodePane);
String request = moneroUri.replace("%20", " ").replace("?", "\n?").replace("&", "\n&");
Label infoLabel = new AutoTooltipLabel(Res.get("qRCodeWindow.request", request));
@ -91,4 +99,12 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> {
public String getClipboardText() {
return moneroUri;
}
private void openWallet() {
try {
Utilities.openURI(URI.create(moneroUri));
} catch (Exception e) {
log.warn(e.getMessage());
}
}
}

View file

@ -113,7 +113,7 @@ public class SignPaymentAccountsWindow extends Overlay<SignPaymentAccountsWindow
// We want to have more space to read list entries... initial screen does not look so nice now, but
// dynamically updating height of window is a bit tricky.... @christoph feel free to improve if you like...
gridPane.setPrefHeight(600);
gridPane.getStyleClass().add("popup-with-input");
gridPane.getColumnConstraints().get(1).setHgrow(Priority.NEVER);
headLine(Res.get("popup.accountSigning.selectAccounts.headline"));

View file

@ -67,6 +67,7 @@ public class SignSpecificWitnessWindow extends Overlay<SignSpecificWitnessWindow
gridPane.setPrefHeight(600);
gridPane.getColumnConstraints().get(1).setHgrow(Priority.NEVER);
gridPane.getStyleClass().add("popup-with-input");
headLine(Res.get("popup.accountSigning.singleAccountSelect.headline"));
type = Type.Attention;

View file

@ -92,6 +92,7 @@ public class SignUnsignedPubKeysWindow extends Overlay<SignUnsignedPubKeysWindow
gridPane.setPrefHeight(600);
gridPane.getColumnConstraints().get(1).setHgrow(Priority.NEVER);
gridPane.getStyleClass().add("popup-with-input");
headLine(Res.get("popup.accountSigning.singleAccountSelect.headline"));
type = Type.Attention;

View file

@ -38,22 +38,21 @@ import haveno.core.xmr.wallet.BtcWalletService;
import haveno.desktop.components.HavenoTextArea;
import haveno.desktop.main.MainView;
import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.util.CssTheme;
import haveno.desktop.util.DisplayUtils;
import haveno.desktop.util.GUIUtil;
import static haveno.desktop.util.DisplayUtils.getAccountWitnessDescription;
import static haveno.desktop.util.FormBuilder.add2ButtonsWithBox;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField;
import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField;
import static haveno.desktop.util.FormBuilder.addSeparator;
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import haveno.desktop.util.Layout;
import haveno.network.p2p.NodeAddress;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
@ -107,7 +106,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
this.trade = trade;
rowIndex = -1;
width = 918;
width = Layout.DETAILS_WINDOW_WIDTH;
createGridPane();
addContent();
display();
@ -127,7 +126,6 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
@Override
protected void createGridPane() {
super.createGridPane();
gridPane.setPadding(new Insets(35, 40, 30, 40));
gridPane.getStyleClass().add("grid-pane");
}
@ -135,7 +133,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
Offer offer = trade.getOffer();
Contract contract = trade.getContract();
int rows = 5;
int rows = 9;
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("tradeDetailsWindow.headline"));
boolean myOffer = tradeManager.isMyOffer(offer);
@ -156,18 +154,22 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
xmrDirectionInfo = toSpend;
}
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.xmrAmount") + xmrDirectionInfo,
HavenoUtils.formatXmr(trade.getAmount(), true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex,
VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + counterCurrencyDirectionInfo,
VolumeUtil.formatVolumeWithCode(trade.getVolume()));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
FormattingUtils.formatPrice(trade.getPrice()));
String paymentMethodText = Res.get(offer.getPaymentMethod().getId());
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), paymentMethodText);
// second group
rows = 7;
rows = 5;
if (offer.getCombinedExtraInfo() != null && !offer.getCombinedExtraInfo().isEmpty())
rows++;
@ -200,9 +202,10 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
if (trade.getTradePeerNodeAddress() != null)
rows++;
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.COMPACT_GROUP_DISTANCE);
addConfirmationLabelTextField(gridPane, rowIndex, Res.get("shared.tradeId"),
trade.getId(), Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
trade.getId(), Layout.TWICE_FIRST_ROW_AND_COMPACT_GROUP_DISTANCE);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.tradeDate"),
DisplayUtils.formatDateTime(trade.getDate()));
String securityDeposit = Res.getWithColAndCap("shared.buyer") +
@ -212,40 +215,30 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
Res.getWithColAndCap("shared.seller") +
" " +
HavenoUtils.formatXmr(trade.getSellerSecurityDepositBeforeMiningFee(), true);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit);
NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress();
if (arbitratorNodeAddress != null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex,
Res.get("tradeDetailsWindow.agentAddresses"),
arbitratorNodeAddress.getFullAddress());
}
if (trade.getTradePeerNodeAddress() != null)
if (trade.getTradePeerNodeAddress() != null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.tradePeersOnion"),
trade.getTradePeerNodeAddress().getFullAddress());
}
if (offer.getCombinedExtraInfo() != null && !offer.getCombinedExtraInfo().isEmpty()) {
addSeparator(gridPane, ++rowIndex);
TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo.offer"), "", 0).second;
textArea.setText(offer.getCombinedExtraInfo());
textArea.setMaxHeight(200);
textArea.sceneProperty().addListener((o, oldScene, newScene) -> {
if (newScene != null) {
// avoid javafx css warning
CssTheme.loadSceneStyles(newScene, CssTheme.CSS_THEME_LIGHT, false);
textArea.applyCss();
var text = textArea.lookup(".text");
textArea.prefHeightProperty().bind(Bindings.createDoubleBinding(() -> {
return textArea.getFont().getSize() + text.getBoundsInLocal().getHeight();
}, text.boundsInLocalProperty()));
text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> {
Platform.runLater(() -> textArea.requestLayout());
});
}
});
textArea.setText(offer.getCombinedExtraInfo().trim());
textArea.setMaxHeight(Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
textArea.setEditable(false);
GUIUtil.adjustHeightAutomatically(textArea, Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
}
if (contract != null) {
@ -254,6 +247,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
if (buyerPaymentAccountPayload != null) {
String paymentDetails = buyerPaymentAccountPayload.getPaymentDetails();
String postFix = " / " + buyersAccountAge;
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex,
Res.get("shared.paymentDetails", Res.get("shared.buyer")),
paymentDetails + postFix).second.setTooltip(new Tooltip(paymentDetails + postFix));
@ -261,21 +255,27 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
if (sellerPaymentAccountPayload != null) {
String paymentDetails = sellerPaymentAccountPayload.getPaymentDetails();
String postFix = " / " + sellersAccountAge;
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex,
Res.get("shared.paymentDetails", Res.get("shared.seller")),
paymentDetails + postFix).second.setTooltip(new Tooltip(paymentDetails + postFix));
}
if (buyerPaymentAccountPayload == null && sellerPaymentAccountPayload == null)
if (buyerPaymentAccountPayload == null && sellerPaymentAccountPayload == null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.paymentMethod"),
Res.get(contract.getPaymentMethodId()));
}
}
if (trade.getMaker().getDepositTxHash() != null)
if (trade.getMaker().getDepositTxHash() != null) {
addSeparator(gridPane, ++rowIndex);
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerDepositTransactionId"),
trade.getMaker().getDepositTxHash());
if (trade.getTaker().getDepositTxHash() != null)
}
if (trade.getTaker().getDepositTxHash() != null) {
addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerDepositTransactionId"),
trade.getTaker().getDepositTxHash());
}
if (showDisputedTx) {
@ -287,6 +287,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
}
if (trade.hasFailed()) {
addSeparator(gridPane, ++rowIndex);
textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("shared.errorMessage"), "", 0).second;
textArea.setText(trade.getErrorMessage());
textArea.setEditable(false);
@ -302,6 +303,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
textArea.scrollTopProperty().addListener(changeListener);
textArea.setScrollTop(30);
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.tradePhase"), trade.getPhase().name());
}

View file

@ -40,7 +40,7 @@ public class TradeFeedbackWindow extends Overlay<TradeFeedbackWindow> {
@Override
public void show() {
headLine(Res.get("tradeFeedbackWindow.title"));
message(Res.get("tradeFeedbackWindow.msg.part1"));
//message(Res.get("tradeFeedbackWindow.msg.part1")); // TODO: this message part has padding which remaining message does not have
hideCloseButton();
actionButtonText(Res.get("shared.close"));
@ -51,6 +51,17 @@ public class TradeFeedbackWindow extends Overlay<TradeFeedbackWindow> {
protected void addMessage() {
super.addMessage();
AutoTooltipLabel messageLabel1 = new AutoTooltipLabel(Res.get("tradeFeedbackWindow.msg.part1"));
messageLabel1.setMouseTransparent(true);
messageLabel1.setWrapText(true);
GridPane.setHalignment(messageLabel1, HPos.LEFT);
GridPane.setHgrow(messageLabel1, Priority.ALWAYS);
GridPane.setRowIndex(messageLabel1, ++rowIndex);
GridPane.setColumnIndex(messageLabel1, 0);
GridPane.setColumnSpan(messageLabel1, 2);
gridPane.getChildren().add(messageLabel1);
GridPane.setMargin(messageLabel1, new Insets(10, 0, 10, 0));
AutoTooltipLabel messageLabel2 = new AutoTooltipLabel(Res.get("tradeFeedbackWindow.msg.part2"));
messageLabel2.setMouseTransparent(true);
messageLabel2.setWrapText(true);

View file

@ -30,7 +30,6 @@ import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon;
import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField;
import static haveno.desktop.util.FormBuilder.addMultilineLabel;
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import java.math.BigInteger;
@ -50,21 +49,20 @@ public class TxDetailsWindow extends Overlay<TxDetailsWindow> {
this.item = item;
rowIndex = -1;
width = 918;
if (headLine == null)
headLine = Res.get("txDetailsWindow.headline");
createGridPane();
gridPane.setHgap(15);
addHeadLine();
addContent();
addButtons();
addDontShowAgainCheckBox();
applyStyles();
display();
}
protected void addContent() {
int rows = 10;
MoneroTxWallet tx = item.getTx();
String memo = tx.getNote();
if (memo != null && !"".equals(memo)) rows++;
String txKey = null;
boolean isOutgoing = tx.getOutgoingTransfer() != null;
if (isOutgoing) {
@ -74,18 +72,11 @@ public class TxDetailsWindow extends Overlay<TxDetailsWindow> {
// TODO (monero-java): wallet.getTxKey() should return null if key does not exist instead of throwing exception
}
}
if (txKey != null && !"".equals(txKey)) rows++;
// add title
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("txDetailsWindow.headline"));
Region spacer = new Region();
spacer.setMinHeight(15);
gridPane.add(spacer, 0, ++rowIndex);
// add sent or received note
String resKey = isOutgoing ? "txDetailsWindow.xmr.noteSent" : "txDetailsWindow.xmr.noteReceived";
GridPane.setColumnSpan(addMultilineLabel(gridPane, ++rowIndex, Res.get(resKey), 0), 2);
spacer = new Region();
Region spacer = new Region();
spacer.setMinHeight(15);
gridPane.add(spacer, 0, ++rowIndex);

View file

@ -77,6 +77,7 @@ public class VerifyDisputeResultSignatureWindow extends Overlay<VerifyDisputeRes
gridPane.setVgap(5);
gridPane.setPadding(new Insets(64, 64, 64, 64));
gridPane.setPrefWidth(width);
gridPane.getStyleClass().add("popup-with-input");
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHalignment(HPos.RIGHT);

View file

@ -80,9 +80,9 @@ public class PortfolioView extends ActivatableView<TabPane, Void> {
root.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
failedTradesTab.setClosable(false);
openOffersTab.setText(Res.get("portfolio.tab.openOffers").toUpperCase());
pendingTradesTab.setText(Res.get("portfolio.tab.pendingTrades").toUpperCase());
closedTradesTab.setText(Res.get("portfolio.tab.history").toUpperCase());
openOffersTab.setText(Res.get("portfolio.tab.openOffers"));
pendingTradesTab.setText(Res.get("portfolio.tab.pendingTrades"));
closedTradesTab.setText(Res.get("portfolio.tab.history"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(PortfolioView.class) == 1)

View file

@ -156,6 +156,8 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
widthListener = (observable, oldValue, newValue) -> onWidthChange((double) newValue);
tradeFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_FEE.toString().replace(" BTC", "")));
buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.BUYER_SEC.toString()));
@ -252,6 +254,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
tableView.setItems(sortedList);
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
filterBox.setPromptText(Res.get("shared.filter"));
filterBox.activate();
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
@ -326,7 +329,6 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
}
private void setTradeIdColumnCellFactory() {
tradeIdColumn.getStyleClass().add("first-column");
tradeIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
tradeIdColumn.setCellFactory(
new Callback<>() {
@ -463,7 +465,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
@SuppressWarnings("UnusedReturnValue")
private TableColumn<ClosedTradesListItem, ClosedTradesListItem> setAvatarColumnCellFactory() {
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
avatarColumn.getStyleClass().add("avatar-column");
avatarColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
avatarColumn.setCellFactory(
new Callback<>() {
@ -696,7 +698,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades
if (!empty && newItem != null && !trade.isPayoutConfirmed()) {
Label icon = FormBuilder.getIcon(AwesomeIcon.UNDO);
JFXButton iconButton = new JFXButton("", icon);
iconButton.setStyle("-fx-cursor: hand;");
iconButton.setStyle("-fx-cursor: hand; -fx-padding: 0 10 0 10;");
iconButton.getStyleClass().add("hidden-icon-button");
iconButton.setTooltip(new Tooltip(Res.get("portfolio.failed.revertToPending")));
iconButton.setOnAction(e -> onRevertTrade(trade));

View file

@ -115,6 +115,8 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amount")));
@ -385,7 +387,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
}
private void setTradeIdColumnCellFactory() {
tradeIdColumn.getStyleClass().add("first-column");
tradeIdColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
tradeIdColumn.setCellFactory(
new Callback<>() {
@ -455,7 +456,6 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades
}
private void setStateColumnCellFactory() {
stateColumn.getStyleClass().add("last-column");
stateColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
stateColumn.setCellFactory(
new Callback<>() {

View file

@ -35,7 +35,6 @@
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
</padding>
<HBox fx:id="searchBox">
<AutoTooltipLabel fx:id="filterLabel"/>
<InputTextField fx:id="filterTextField" minWidth="500"/>
<Pane fx:id="searchBoxSpacer"/>
<AutoTooltipSlideToggleButton fx:id="selectToggleButton"/>

View file

@ -116,8 +116,6 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
@FXML
HBox searchBox;
@FXML
AutoTooltipLabel filterLabel;
@FXML
InputTextField filterTextField;
@FXML
Pane searchBoxSpacer;
@ -156,6 +154,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
widthListener = (observable, oldValue, newValue) -> onWidthChange((double) newValue);
groupIdColumn.setGraphic(new AutoTooltipLabel(ColumnNames.GROUP_ID.toString()));
paymentMethodColumn.setGraphic(new AutoTooltipLabel(ColumnNames.PAYMENT_METHOD.toString()));
@ -231,8 +231,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
return row;
});
filterLabel.setText(Res.get("shared.filter"));
HBox.setMargin(filterLabel, new Insets(5, 0, 0, 10));
filterTextField.setPromptText(Res.get("shared.filter"));
filterTextFieldListener = (observable, oldValue, newValue) -> applyFilteredListPredicate(filterTextField.getText());
searchBox.setSpacing(5);
HBox.setHgrow(searchBoxSpacer, Priority.ALWAYS);
@ -470,8 +469,8 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
String key = "WithdrawFundsAfterRemoveOfferInfo";
if (DontShowAgainLookup.showAgain(key)) {
new Popup().instruction(Res.get("offerbook.withdrawFundsHint", Res.get("navigation.funds.availableForWithdrawal")))
.actionButtonTextWithGoTo("navigation.funds.availableForWithdrawal")
new Popup().instruction(Res.get("offerbook.withdrawFundsHint", Res.get("funds.tab.withdrawal")))
.actionButtonTextWithGoTo("funds.tab.withdrawal")
.onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class))
.dontShowAgainId(key)
.show();
@ -527,7 +526,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
private void setOfferIdColumnCellFactory() {
offerIdColumn.setCellValueFactory((openOfferListItem) -> new ReadOnlyObjectWrapper<>(openOfferListItem.getValue()));
offerIdColumn.getStyleClass().addAll("number-column", "first-column");
offerIdColumn.getStyleClass().addAll("number-column");
offerIdColumn.setCellFactory(
new Callback<>() {
@ -903,7 +902,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
}
private void setRemoveColumnCellFactory() {
removeItemColumn.getStyleClass().addAll("last-column", "avatar-column");
removeItemColumn.getStyleClass().addAll("avatar-column");
removeItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue()));
removeItemColumn.setCellFactory(
new Callback<>() {

View file

@ -55,6 +55,7 @@ import haveno.desktop.main.shared.ChatView;
import haveno.desktop.util.CssTheme;
import haveno.desktop.util.DisplayUtils;
import haveno.desktop.util.FormBuilder;
import haveno.desktop.util.GUIUtil;
import haveno.network.p2p.NodeAddress;
import java.util.Comparator;
import java.util.HashMap;
@ -171,6 +172,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
@Override
public void initialize() {
GUIUtil.applyTableStyle(tableView);
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode())));
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amount")));
@ -281,6 +284,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
tableView.setMaxHeight(200);
filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here
filterBox.setPromptText(Res.get("shared.filter"));
filterBox.activate();
updateMoveTradeToFailedColumnState();
@ -607,7 +611,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
///////////////////////////////////////////////////////////////////////////////////////////
private void setTradeIdColumnCellFactory() {
tradeIdColumn.getStyleClass().add("first-column");
tradeIdColumn.setCellValueFactory((pendingTradesListItem) -> new ReadOnlyObjectWrapper<>(pendingTradesListItem.getValue()));
tradeIdColumn.setCellFactory(
new Callback<>() {
@ -821,7 +824,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
@SuppressWarnings("UnusedReturnValue")
private TableColumn<PendingTradesListItem, PendingTradesListItem> setAvatarColumnCellFactory() {
avatarColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
avatarColumn.getStyleClass().addAll("last-column", "avatar-column");
avatarColumn.getStyleClass().add("avatar-column");
avatarColumn.setCellFactory(
new Callback<>() {
@ -860,7 +863,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
@SuppressWarnings("UnusedReturnValue")
private TableColumn<PendingTradesListItem, PendingTradesListItem> setChatColumnCellFactory() {
chatColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue()));
chatColumn.getStyleClass().addAll("last-column", "avatar-column");
chatColumn.getStyleClass().addAll("avatar-column");
chatColumn.setSortable(false);
chatColumn.setCellFactory(
new Callback<>() {

View file

@ -125,6 +125,7 @@ public abstract class TradeStepView extends AnchorPane {
gridPane.setHgap(Layout.GRID_GAP);
gridPane.setVgap(Layout.GRID_GAP);
gridPane.setPadding(new Insets(0, 0, 25, 0));
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHgrow(Priority.ALWAYS);

View file

@ -142,7 +142,7 @@ public class BuyerStep4View extends TradeStepView {
if (!DevEnv.isDevMode()) {
UserThread.runAfter(() -> new Popup().headLine(Res.get("portfolio.pending.step5_buyer.tradeCompleted.headline"))
.feedback(Res.get("portfolio.pending.step5_buyer.tradeCompleted.msg"))
.actionButtonTextWithGoTo("navigation.portfolio.closedTrades")
.actionButtonTextWithGoTo("portfolio.tab.history")
.onAction(() -> model.dataModel.navigation.navigateTo(MainView.class, PortfolioView.class, ClosedTradesView.class))
.dontShowAgainId("tradeCompleteWithdrawCompletedInfo")
.show(), 500, TimeUnit.MILLISECONDS);

View file

@ -56,9 +56,9 @@ public class SettingsView extends ActivatableView<TabPane, Void> {
@Override
public void initialize() {
preferencesTab.setText(Res.get("settings.tab.preferences").toUpperCase());
networkTab.setText(Res.get("settings.tab.network").toUpperCase());
aboutTab.setText(Res.get("settings.tab.about").toUpperCase());
preferencesTab.setText(Res.get("settings.tab.preferences"));
networkTab.setText(Res.get("settings.tab.network"));
aboutTab.setText(Res.get("settings.tab.about"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(SettingsView.class) == 1)

View file

@ -19,6 +19,7 @@ package haveno.desktop.main.settings.about;
import com.google.inject.Inject;
import haveno.common.app.Version;
import haveno.core.filter.FilterManager;
import haveno.core.locale.Res;
import haveno.desktop.common.view.ActivatableView;
import haveno.desktop.common.view.FxmlView;
@ -35,16 +36,18 @@ import javafx.scene.layout.GridPane;
@FxmlView
public class AboutView extends ActivatableView<GridPane, Void> {
private final FilterManager filterManager;
private int gridRow = 0;
@Inject
public AboutView() {
public AboutView(FilterManager filterManager) {
super();
this.filterManager = filterManager;
}
@Override
public void initialize() {
addTitledGroupBg(root, gridRow, 4, Res.get("setting.about.aboutHaveno"));
addTitledGroupBg(root, gridRow, 5, Res.get("setting.about.aboutHaveno"));
Label label = addLabel(root, gridRow, Res.get("setting.about.about"), Layout.TWICE_FIRST_ROW_DISTANCE);
label.setWrapText(true);
@ -77,8 +80,11 @@ public class AboutView extends ActivatableView<GridPane, Void> {
if (isXmr)
addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.feeEstimation.label"), "Monero node");
addTitledGroupBg(root, ++gridRow, 2, Res.get("setting.about.versionDetails"), Layout.GROUP_DISTANCE);
String minVersion = filterManager.getDisableTradeBelowVersion() == null ? Res.get("shared.none") : filterManager.getDisableTradeBelowVersion();
addTitledGroupBg(root, ++gridRow, 3, Res.get("setting.about.versionDetails"), Layout.GROUP_DISTANCE);
addCompactTopLabelTextField(root, gridRow, Res.get("setting.about.version"), Version.VERSION, Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
addCompactTopLabelTextField(root, ++gridRow, Res.get("filterWindow.disableTradeBelowVersion"), minVersion);
addCompactTopLabelTextField(root, ++gridRow,
Res.get("setting.about.subsystems.label"),
Res.get("setting.about.subsystems.val",

View file

@ -53,7 +53,7 @@
<PropertyValueFactory property="address"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="moneroConnectionConnectedColumn" minWidth="80" maxWidth="90">
<TableColumn fx:id="moneroConnectionConnectedColumn" minWidth="80" maxWidth="110">
<cellValueFactory>
<PropertyValueFactory property="connected"/>
</cellValueFactory>
@ -108,6 +108,9 @@
</HavenoTextField>
<VBox GridPane.rowIndex="6" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES">
<GridPane.margin>
<Insets top="0" right="0" bottom="10" left="0"/>
</GridPane.margin>
<AutoTooltipLabel fx:id="p2PPeersLabel" styleClass="small-text"/>
<TableView fx:id="p2pPeersTableView">
<columns>
@ -159,10 +162,7 @@
<HavenoTextField fx:id="chainHeightTextField" GridPane.rowIndex="9" editable="false"
focusTraversable="false" labelFloat="true"/>
<HavenoTextField fx:id="minVersionForTrading" GridPane.rowIndex="10" editable="false"
focusTraversable="false" labelFloat="true"/>
<AutoTooltipButton fx:id="openTorSettingsButton" GridPane.rowIndex="11" GridPane.columnIndex="0"/>
<AutoTooltipButton fx:id="openTorSettingsButton" GridPane.rowIndex="10" GridPane.columnIndex="0"/>
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" minWidth="500"/>

View file

@ -75,7 +75,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
@FXML
InputTextField xmrNodesInputTextField;
@FXML
TextField onionAddress, sentDataTextField, receivedDataTextField, chainHeightTextField, minVersionForTrading;
TextField onionAddress, sentDataTextField, receivedDataTextField, chainHeightTextField;
@FXML
Label p2PPeersLabel, moneroConnectionsLabel;
@FXML
@ -149,6 +149,14 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
@Override
public void initialize() {
GUIUtil.applyTableStyle(p2pPeersTableView);
GUIUtil.applyTableStyle(moneroConnectionsTableView);
onionAddress.getStyleClass().add("label-float");
sentDataTextField.getStyleClass().add("label-float");
receivedDataTextField.getStyleClass().add("label-float");
chainHeightTextField.getStyleClass().add("label-float");
btcHeader.setText(Res.get("settings.net.xmrHeader"));
p2pHeader.setText(Res.get("settings.net.p2pHeader"));
onionAddress.setPromptText(Res.get("settings.net.onionAddressLabel"));
@ -160,7 +168,6 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
useTorForXmrOnRadio.setText(Res.get("settings.net.useTorForXmrOnRadio"));
moneroNodesLabel.setText(Res.get("settings.net.moneroNodesLabel"));
moneroConnectionAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address")));
moneroConnectionAddressColumn.getStyleClass().add("first-column");
moneroConnectionConnectedColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.connection")));
localhostXmrNodeInfoLabel.setText(Res.get("settings.net.localhostXmrNodeInfo"));
useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio"));
@ -170,18 +177,15 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
rescanOutputsButton.updateText(Res.get("settings.net.rescanOutputsButton"));
p2PPeersLabel.setText(Res.get("settings.net.p2PPeersLabel"));
onionAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn")));
onionAddressColumn.getStyleClass().add("first-column");
creationDateColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.creationDateColumn")));
connectionTypeColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.connectionTypeColumn")));
sentDataTextField.setPromptText(Res.get("settings.net.sentDataLabel"));
receivedDataTextField.setPromptText(Res.get("settings.net.receivedDataLabel"));
chainHeightTextField.setPromptText(Res.get("settings.net.chainHeightLabel"));
minVersionForTrading.setPromptText(Res.get("filterWindow.disableTradeBelowVersion"));
roundTripTimeColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.roundTripTimeColumn")));
sentBytesColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.sentBytesColumn")));
receivedBytesColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.receivedBytesColumn")));
peerTypeColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.peerTypeColumn")));
peerTypeColumn.getStyleClass().add("last-column");
openTorSettingsButton.updateText(Res.get("settings.net.openTorSettingsButton"));
// TODO: hiding button to rescan outputs until supported
@ -504,10 +508,6 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
selectMoneroPeersToggle();
onMoneroPeersToggleSelected(false);
}
// set min version for trading
String minVersion = filterManager.getDisableTradeBelowVersion();
minVersionForTrading.textProperty().setValue(minVersion == null ? Res.get("shared.none") : minVersion);
}
private boolean isPublicNodesDisabled() {

View file

@ -102,7 +102,7 @@ import org.apache.commons.lang3.StringUtils;
@FxmlView
public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> {
private final User user;
private TextField btcExplorerTextField;
private TextField xmrExplorerTextField;
private ComboBox<String> userLanguageComboBox;
private ComboBox<Country> userCountryComboBox;
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
@ -220,9 +220,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
userCountryComboBox.setButtonCell(GUIUtil.getComboBoxButtonCell(Res.get("shared.country"), userCountryComboBox,
false));
Tuple2<TextField, Button> btcExp = addTextFieldWithEditButton(root, ++gridRow, Res.get("setting.preferences.explorer"));
btcExplorerTextField = btcExp.first;
editCustomBtcExplorer = btcExp.second;
Tuple2<TextField, Button> xmrExp = addTextFieldWithEditButton(root, ++gridRow, Res.get("setting.preferences.explorer"));
xmrExplorerTextField = xmrExp.first;
editCustomBtcExplorer = xmrExp.second;
// deviation
deviationInputTextField = addInputTextField(root, ++gridRow,
@ -688,7 +688,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
}
});
btcExplorerTextField.setText(preferences.getBlockChainExplorer().name);
xmrExplorerTextField.setText(preferences.getBlockChainExplorer().name);
deviationInputTextField.setText(FormattingUtils.formatToPercentWithSymbol(preferences.getMaxPriceDistanceInPercent()));
deviationInputTextField.textProperty().addListener(deviationListener);
@ -779,7 +779,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
.actionButtonText(Res.get("shared.save"))
.onAction(() -> {
preferences.setBlockChainExplorer(urlWindow.getEditedBlockChainExplorer());
btcExplorerTextField.setText(preferences.getBlockChainExplorer().name);
xmrExplorerTextField.setText(preferences.getBlockChainExplorer().name);
})
.closeButtonText(Res.get("shared.cancel"))
.onClose(urlWindow::hide)

View file

@ -26,7 +26,7 @@ import haveno.desktop.main.overlays.notifications.Notification;
import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.DisplayUtils;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import haveno.core.locale.Res;
import haveno.core.support.SupportManager;
import haveno.core.support.SupportSession;
@ -43,7 +43,8 @@ import com.google.common.io.ByteStreams;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView;
import javafx.stage.FileChooser;
import javafx.scene.Node;
@ -204,6 +205,7 @@ public class ChatView extends AnchorPane {
inputTextArea = new HavenoTextArea();
inputTextArea.setPrefHeight(70);
inputTextArea.setWrapText(true);
inputTextArea.getStyleClass().add("input-with-border");
if (!supportSession.isDisputeAgent()) {
inputTextArea.setPromptText(Res.get("support.input.prompt"));
@ -271,7 +273,7 @@ public class ChatView extends AnchorPane {
ImageView arrow = new ImageView();
Label headerLabel = new AutoTooltipLabel();
Label messageLabel = new AutoTooltipLabel();
Label copyIcon = new Label();
Label copyLabel = new Label();
HBox attachmentsBox = new HBox();
AnchorPane messageAnchorPane = new AnchorPane();
Label statusIcon = new Label();
@ -292,10 +294,10 @@ public class ChatView extends AnchorPane {
statusIcon.getStyleClass().add("small-text");
statusInfoLabel.getStyleClass().add("small-text");
statusInfoLabel.setPadding(new Insets(3, 0, 0, 0));
copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
copyLabel.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
statusHBox.setSpacing(5);
statusHBox.getChildren().addAll(statusIcon, statusInfoLabel);
messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyIcon, attachmentsBox, statusHBox);
messageAnchorPane.getChildren().addAll(bg, arrow, headerLabel, messageLabel, copyLabel, attachmentsBox, statusHBox);
}
@Override
@ -303,7 +305,13 @@ public class ChatView extends AnchorPane {
UserThread.execute(() -> {
super.updateItem(message, empty);
if (message != null && !empty) {
copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(messageLabel.getText()));
copyLabel.setOnMouseClicked(e -> {
Utilities.copyToClipboard(messageLabel.getText());
Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard"));
Node node = (Node) e.getSource();
UserThread.runAfter(() -> tp.hide(), 1);
tp.show(node, e.getScreenX() + Layout.PADDING, e.getScreenY() + Layout.PADDING);
});
messageLabel.setOnMouseClicked(event -> {
if (2 > event.getClickCount()) {
return;
@ -319,7 +327,7 @@ public class ChatView extends AnchorPane {
AnchorPane.clearConstraints(headerLabel);
AnchorPane.clearConstraints(arrow);
AnchorPane.clearConstraints(messageLabel);
AnchorPane.clearConstraints(copyIcon);
AnchorPane.clearConstraints(copyLabel);
AnchorPane.clearConstraints(statusHBox);
AnchorPane.clearConstraints(attachmentsBox);
@ -328,7 +336,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setTopAnchor(headerLabel, 0d);
AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d);
AnchorPane.setTopAnchor(messageLabel, 25d);
AnchorPane.setTopAnchor(copyIcon, 25d);
AnchorPane.setTopAnchor(copyLabel, 25d);
AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10);
boolean senderIsTrader = message.isSenderIsTrader();
@ -341,20 +349,20 @@ public class ChatView extends AnchorPane {
headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text",
"highlight-static");
messageLabel.getStyleClass().removeAll("my-message", "message");
copyIcon.getStyleClass().removeAll("my-message", "message");
copyLabel.getStyleClass().removeAll("my-message", "message");
if (message.isSystemMessage()) {
headerLabel.getStyleClass().addAll("message-header", "success-text");
bg.setId("message-bubble-green");
messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message");
copyLabel.getStyleClass().add("my-message");
message.addWeakMessageStateListener(() -> UserThread.execute(() -> updateMsgState(message)));
updateMsgState(message);
} else if (isMyMsg) {
headerLabel.getStyleClass().add("my-message-header");
bg.setId("message-bubble-blue");
messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message");
copyLabel.getStyleClass().add("my-message");
if (supportSession.isClient())
arrow.setId("bubble_arrow_blue_left");
else
@ -375,7 +383,7 @@ public class ChatView extends AnchorPane {
headerLabel.getStyleClass().add("message-header");
bg.setId("message-bubble-grey");
messageLabel.getStyleClass().add("message");
copyIcon.getStyleClass().add("message");
copyLabel.getStyleClass().add("message");
if (supportSession.isClient())
arrow.setId("bubble_arrow_grey_right");
else
@ -389,7 +397,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setRightAnchor(bg, border);
AnchorPane.setLeftAnchor(messageLabel, padding);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight);
AnchorPane.setRightAnchor(copyIcon, padding);
AnchorPane.setRightAnchor(copyLabel, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.setLeftAnchor(statusHBox, padding);
@ -400,7 +408,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setLeftAnchor(arrow, border);
AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight);
AnchorPane.setRightAnchor(copyIcon, padding);
AnchorPane.setRightAnchor(copyLabel, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(statusHBox, padding);
@ -411,7 +419,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setRightAnchor(arrow, border);
AnchorPane.setLeftAnchor(messageLabel, padding);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight + arrowWidth);
AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth);
AnchorPane.setRightAnchor(copyLabel, padding + arrowWidth);
AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setLeftAnchor(statusHBox, padding);
@ -454,8 +462,9 @@ public class ChatView extends AnchorPane {
}
// Need to set it here otherwise style is not correct
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY, "16.0");
copyIcon.getStyleClass().addAll("icon", "copy-icon-disputes");
copyLabel.getStyleClass().addAll("icon", "copy-icon-disputes");
MaterialDesignIconView copyIcon = new MaterialDesignIconView(MaterialDesignIcon.CONTENT_COPY, "16.0");
copyLabel.setGraphic(copyIcon);
// TODO There are still some cell rendering issues on updates
setGraphic(messageAnchorPane);
@ -465,7 +474,7 @@ public class ChatView extends AnchorPane {
messageAnchorPane.prefWidthProperty().unbind();
copyIcon.setOnMouseClicked(null);
copyLabel.setOnMouseClicked(null);
messageLabel.setOnMouseClicked(null);
setGraphic(null);
}

View file

@ -139,9 +139,9 @@ public class SupportView extends ActivatableView<TabPane, Void> {
// Has to be called before loadView
updateAgentTabs();
tradersMediationDisputesTab.setText(Res.get("support.tab.mediation.support").toUpperCase());
tradersRefundDisputesTab.setText(Res.get("support.tab.refund.support").toUpperCase());
tradersArbitrationDisputesTab.setText(Res.get("support.tab.arbitration.support").toUpperCase());
tradersMediationDisputesTab.setText(Res.get("support.tab.mediation.support"));
tradersRefundDisputesTab.setText(Res.get("support.tab.refund.support"));
tradersArbitrationDisputesTab.setText(Res.get("support.tab.arbitration.support"));
navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(SupportView.class) == 1)
@ -221,16 +221,16 @@ public class SupportView extends ActivatableView<TabPane, Void> {
// We might get that method called before we have the map is filled in the arbitratorManager
if (arbitratorTab != null) {
arbitratorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.arbitrator")).toUpperCase());
arbitratorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.arbitrator")));
}
if (signedOfferTab != null) {
signedOfferTab.setText(Res.get("support.tab.SignedOffers").toUpperCase());
signedOfferTab.setText(Res.get("support.tab.SignedOffers"));
}
if (mediatorTab != null) {
mediatorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.mediator")).toUpperCase());
mediatorTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.mediator")));
}
if (refundAgentTab != null) {
refundAgentTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.refundAgentForSupportStaff")).toUpperCase());
refundAgentTab.setText(Res.get("support.tab.ArbitratorsSupportTickets", Res.get("shared.refundAgentForSupportStaff")));
}
}

View file

@ -223,12 +223,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
@Override
public void initialize() {
Label label = new AutoTooltipLabel(Res.get("support.filter"));
HBox.setMargin(label, new Insets(5, 0, 0, 0));
HBox.setHgrow(label, Priority.NEVER);
filterTextField = new InputTextField();
filterTextField.setPromptText(Res.get("support.filter.prompt"));
filterTextField.setPromptText(Res.get("shared.filter"));
Tooltip tooltip = new Tooltip();
tooltip.setShowDelay(Duration.millis(100));
tooltip.setShowDuration(Duration.seconds(10));
@ -298,8 +294,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
HBox filterBox = new HBox();
filterBox.setSpacing(5);
filterBox.getChildren().addAll(label,
filterTextField,
filterBox.getChildren().addAll(filterTextField,
alertIconLabel,
spacer,
reOpenButton,
@ -311,6 +306,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
VBox.setVgrow(filterBox, Priority.NEVER);
tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
VBox.setVgrow(tableView, Priority.SOMETIMES);
tableView.setMinHeight(150);
@ -957,7 +953,6 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
{
setMaxWidth(80);
setMinWidth(65);
getStyleClass().addAll("first-column", "avatar-column");
setSortable(false);
}
};
@ -1354,7 +1349,6 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
setMinWidth(50);
}
};
column.getStyleClass().add("last-column");
column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue()));
column.setCellFactory(
new Callback<>() {

View file

@ -208,7 +208,6 @@ public abstract class DisputeAgentView extends DisputeView implements MultipleHo
protected void setupTable() {
super.setupTable();
stateColumn.getStyleClass().remove("last-column");
tableView.getColumns().add(getAlertColumn());
}
@ -243,7 +242,6 @@ public abstract class DisputeAgentView extends DisputeView implements MultipleHo
setMinWidth(50);
}
};
column.getStyleClass().add("last-column");
column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue()));
column.setCellFactory(
c -> new TableCell<>() {

View file

@ -20,10 +20,10 @@
/* haveno main colors */
-bs-color-primary: #0b65da;
-bs-color-primary-dark: #0c59bd;
-bs-text-color: #dadada;
-bs-background-color: #29292a;
-bs-background-gray: #2B2B2B;
-bs-content-background-gray: #1F1F1F;
-bs-text-color: white;
-bs-background-color: black;
-bs-background-gray: transparent;
-bs-content-background-gray: black;
/* fifty shades of gray */
-bs-color-gray-13: #bbb;
@ -43,7 +43,19 @@
-bs-color-gray-bbb: #5a5a5a;
-bs-color-gray-aaa: #29292a;
-bs-color-gray-fafa: #0a0a0a;
-bs-color-gray-background: #1F1F1F;
-bs-color-gray-background: black;
-bs-color-background-popup: rgb(38, 38, 38);
-bs-color-background-popup-blur: rgb(9, 9, 9);
-bs-color-background-popup-input: rgb(9, 9, 9);
-bs-color-background-form-field: rgb(26, 26, 26);
-bs-color-background-form-field-readonly: rgb(18, 18, 18);
-bs-color-border-form-field: rgb(65, 65, 65);
-bs-color-background-pane: rgb(15, 15, 15);
-bs-color-background-row-even: rgb(19, 19, 19);
-bs-color-background-row-odd: rgb(9, 9, 9);
-bs-color-table-cell-dim: -bs-color-gray-ccc;
-bs-text-color-dim1: rgb(87, 87, 87);
-bs-text-color-dim2: rgb(130, 130, 130);
/* lesser used colors */
-bs-color-blue-5: #0a4576;
@ -70,11 +82,15 @@
-bs-rd-nav-border: #535353;
-bs-rd-nav-primary-border: rgba(0, 0, 0, 0);
-bs-rd-nav-border-color: rgba(255, 255, 255, 0.1);
-bs-rd-nav-background: #141414;
-bs-rd-nav-primary-background: rgba(255, 255, 255, 0.015);
-bs-rd-nav-selected: #fff;
-bs-rd-nav-deselected: rgba(255, 255, 255, 0.45);
-bs-rd-nav-button-hover: rgba(255, 255, 255, 0.03);
-bs-rd-nav-background: rgb(15, 15, 15);
-bs-rd-nav-primary-background: rgb(15, 15, 15);
-bs-rd-nav-selected: black;
-bs-rd-nav-deselected: rgba(255, 255, 255, 1);
-bs-rd-nav-secondary-selected: -fx-accent;
-bs-rd-nav-secondary-deselected: -bs-rd-font-light;
-bs-rd-nav-button-hover: derive(-bs-rd-nav-background, 10%);
-bs-rd-nav-primary-button-hover: derive(-bs-rd-nav-primary-background, 10%);
-bs-rd-nav-hover-text: black;
-bs-content-pane-bg-top: #212121;
-bs-rd-tab-border: rgba(255, 255, 255, 0.00);
@ -90,7 +106,7 @@
-bs-footer-pane-text: #cfcecf;
-bs-footer-pane-line: #29292a;
-bs-rd-font-balance: #bbbbbb;
-bs-rd-font-balance: white;
-bs-rd-font-dark-gray: #d4d4d4;
-bs-rd-font-dark: #cccccc;
-bs-rd-font-light: #b4b4b4;
@ -99,28 +115,28 @@
-bs-rd-font-confirmation-label: #504f52;
-bs-rd-font-balance-label: #999999;
-bs-text-color-transparent-dark: rgba(29, 29, 33, 0.54);
-bs-text-color-dropshadow: rgba(45, 45, 49, .75);
-bs-text-color-dropshadow-light-mode: transparent;
-bs-text-color-transparent: rgba(29, 29, 33, 0.2);
-bs-color-gray-line: #504f52;
-bs-rd-separator: #1F1F1F;
-bs-rd-separator-dark: #1F1F1F;
-bs-rd-separator-dark: rgb(255, 255, 255, 0.1);
-bs-rd-error-red: #d83431;
-bs-rd-error-field: #521C1C;
-bs-rd-message-bubble: #0086c6;
-bs-rd-tooltip-truncated: #afaeb0;
-bs-toggle-selected: #25b135;
/*-bs-toggle-selected: rgb(12, 89, 189);*/
-bs-toggle-selected: rgb(12, 89, 190);
-bs-warning: #db6300;
-bs-buy: #006600;
-bs-buy-focus: black;
-bs-buy-hover: #237b2d;
-bs-buy-transparent: rgba(46, 163, 60, 0.3);
-bs-sell: #660000;
-bs-sell-focus: #090202;
-bs-sell-hover: #b42522;
-bs-sell-transparent: rgba(216, 52, 49, 0.3);
-bs-volume-transparent: rgba(37, 177, 54, 0.5);
-bs-buy: rgb(80, 180, 90);
-bs-buy-focus: derive(-bs-buy, -50%);
-bs-buy-hover: derive(-bs-buy, -10%);
-bs-sell: rgb(213, 63, 46);
-bs-sell-focus: derive(-bs-sell, -50%);
-bs-sell-hover: derive(-bs-sell, -10%);
-bs-volume-transparent: -bs-buy;
-bs-candle-stick-average-line: rgba(21, 188, 29, 0.8);
-bs-candle-stick-loss: #ee6563;
-bs-candle-stick-won: #15bc1d;
@ -154,7 +170,7 @@
/* Monero orange color code */
-xmr-orange: #f26822;
-bs-support-chat-background: #cccccc;
-bs-support-chat-background: rgb(125, 125, 125);
}
/* table view */
@ -164,7 +180,7 @@
}
.table-view .column-header {
-fx-background-color: derive(-bs-background-color,-50%);
-fx-background-color: -bs-color-background-pane;
-fx-border-width: 0;
}
@ -173,21 +189,31 @@
-fx-border-width: 0;
}
/** These must be set to override default styles */
.table-view .table-row-cell:even .table-cell {
-fx-background-color: derive(-bs-background-color, -5%);
-fx-border-color: derive(-bs-background-color, -5%);
-fx-background-color: -bs-color-background-row-even;
-fx-border-color: -bs-color-background-row-even;
}
.table-view .table-row-cell:odd .table-cell {
-fx-background-color: derive(-bs-background-color,-30%);
-fx-border-color: derive(-bs-background-color,-30%);
-fx-background-color: -bs-color-background-row-odd;
-fx-border-color: -bs-color-background-row-odd;
}
.table-view .table-row-cell:selected .table-cell {
-fx-background: -fx-accent;
-fx-background-color: -fx-selection-bar;
-fx-border-color: -fx-selection-bar;
}
.table-view .table-row-cell:selected .table-cell,
.table-view .table-row-cell:selected .table-cell .label,
.table-view .table-row-cell:selected .table-cell .text {
-fx-text-fill: -fx-dark-text-color;
}
.table-view .table-row-cell:selected .table-cell .hyperlink,
.table-view .table-row-cell:selected .table-cell .hyperlink .text,
.table-view .table-row-cell:selected .table-cell .hyperlink-with-icon,
.table-view .table-row-cell:selected .table-cell .hyperlink-with-icon .text {
-fx-fill: -fx-dark-text-color;
}
.table-row-cell {
-fx-border-color: -bs-background-color;
@ -208,35 +234,49 @@
-fx-background-color: -bs-tab-content-area;
}
.jfx-tab-pane .viewport {
-fx-background-color: -bs-viewport-background;
.jfx-tab-pane .headers-region .tab:selected .tab-container .tab-label {
-fx-text-fill: white;
}
.jfx-tab-pane .tab-header-background {
-fx-background-color: derive(-bs-color-gray-background, -20%);
.nav-secondary-button:selected .text {
-fx-fill: white;
}
.jfx-tab-pane .headers-region > .tab > .jfx-rippler {
-jfx-rippler-fill: none;
}
.jfx-tab-pane .viewport {
-fx-background-color: -bs-viewport-background;
}
/* text field */
.jfx-text-field, .jfx-text-area,
.jfx-combo-box, .jfx-combo-box > .list-cell {
-fx-background-color: derive(-bs-background-color, 15%);
-fx-prompt-text-fill: -bs-color-gray-6;
-fx-text-fill: -bs-color-gray-12;
}
.jfx-text-area:readonly, .jfx-text-field:readonly,
.jfx-text-area:readonly,
.jfx-text-field:readonly,
.hyperlink-with-icon {
-fx-background: -bs-background-color;
-fx-background-color: -bs-background-color;
-fx-background-color: -bs-color-background-form-field-readonly;
-fx-prompt-text-fill: -bs-color-gray-2;
-fx-text-fill: -bs-color-gray-3;
}
.popover > .content .text-field {
-fx-background-color: -bs-color-background-form-field !important;
}
.jfx-combo-box > .text,
.jfx-text-field-top-label, .jfx-text-area-top-label {
-fx-text-fill: -bs-color-gray-11;
}
.input-with-border {
.offer-input {
-fx-border-color: -bs-color-gray-2;
-fx-border-width: 0 0 10 0;
}
@ -254,11 +294,6 @@
-fx-text-fill: -fx-dark-text-color;
}
.chart-pane, .chart-plot-background,
#charts .chart-plot-background,
#charts-dao .chart-plot-background {
-fx-background-color: transparent;
}
.axis:top, .axis:right, .axis:bottom, .axis:left {
-fx-border-color: transparent transparent transparent transparent;
}
@ -332,7 +367,7 @@
}
.combo-box-popup > .list-view{
-fx-background-color: -bs-background-color;
-fx-background-color: -bs-color-background-pane;
}
.jfx-combo-box > .arrow-button > .arrow {
@ -352,7 +387,6 @@
}
.list-view .list-cell:odd, .list-view .list-cell:even {
-fx-background-color: -bs-background-color;
-fx-border-width: 0;
}
@ -371,18 +405,6 @@
-fx-border-width: 0;
}
.jfx-text-field {
-fx-background-radius: 4;
}
.jfx-text-field > .input-line {
-fx-translate-x: 0;
}
.jfx-text-field > .input-focused-line {
-fx-translate-x: 0;
}
.jfx-text-field-top-label {
-fx-text-fill: -bs-color-gray-dim;
}
@ -401,7 +423,6 @@
.jfx-combo-box:error:focused,
.jfx-text-field:error:focused{
-fx-text-fill: -bs-rd-error-red;
-fx-background-color: derive(-bs-rd-error-field, -5%);
}
@ -417,11 +438,7 @@
-jfx-disable-animation: true;
}
.jfx-password-field {
-fx-background-color: derive(-bs-background-color, -15%);
}
.input-with-border {
.offer-input {
-fx-border-width: 0;
-fx-border-color: -bs-background-color;
}
@ -448,11 +465,6 @@
-jfx-disable-animation: true;
}
.top-navigation {
-fx-border-width: 0 0 0 0;
-fx-padding: 0 7 0 0;
}
.nav-price-balance {
-fx-effect: null;
}
@ -462,37 +474,17 @@
}
.nav-button:selected {
-fx-background-color: derive(-bs-color-primary-dark, -10%);
-fx-background-color: white;
-fx-effect: null;
}
.nav-button:hover {
-fx-background-color: -bs-rd-nav-button-hover;
}
.nav-primary .nav-button:selected {
-fx-background-color: derive(-bs-color-primary-dark, -5%);
-fx-background-color: derive(white, -5%);
}
.table-view {
-fx-border-color: transparent;
}
.table-view .table-cell {
-fx-padding: 6 0 4 0;
-fx-text-fill: -bs-text-color;
}
.table-view .table-cell.last-column {
-fx-padding: 6 10 4 0;
}
.table-view .table-cell.last-column.avatar-column {
-fx-padding: 6 0 4 0;
}
.table-view .table-cell.first-column {
-fx-padding: 6 0 4 10;
}
.jfx-tab-pane .headers-region .tab .tab-container .tab-label {
-fx-cursor: hand;
-jfx-disable-animation: true;
@ -559,12 +551,95 @@
}
.toggle-button-no-slider {
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 3;
-fx-background-insets: 0, 1;
-fx-background-color: -bs-color-background-form-field;
}
.toggle-button-no-slider:selected {
-fx-text-fill: white;
-fx-background-color: -bs-color-gray-ccc;
-fx-border-color: -bs-color-gray-ccc;
-fx-border-width: 1px;
}
.toggle-button-no-slider:hover {
-fx-cursor: hand;
-fx-background-color: -bs-color-gray-ddd;
-fx-border-color: -bs-color-gray-ddd;
}
.toggle-button-no-slider:selected:hover {
-fx-cursor: hand;
-fx-background-color: -bs-color-gray-3;
-fx-border-color: -bs-color-gray-3;
}
.toggle-button-no-slider:pressed, .toggle-button-no-slider:selected:hover:pressed {
-fx-background-color: -bs-color-gray-bbb;
}
#image-logo-splash {
-fx-image: url("../../images/logo_splash_dark.png");
}
#image-logo-splash-testnet {
-fx-image: url("../../images/logo_splash_testnet_dark.png");
}
#image-logo-landscape {
-fx-image: url("../../images/logo_landscape_dark.png");
}
.table-view .placeholder {
-fx-background-color: -bs-color-background-pane;
}
#charts .default-color0.chart-series-area-fill {
-fx-fill: linear-gradient(to bottom,
rgba(80, 181, 90, 0.45) 0%,
rgba(80, 181, 90, 0.0) 100%
);
}
#charts .default-color1.chart-series-area-fill {
-fx-fill: linear-gradient(to bottom,
rgba(213, 63, 46, 0.45) 0%,
rgba(213, 63, 46, 0.0) 100%
);
}
.table-view .table-row-cell .label {
-fx-text-fill: -bs-text-color;
}
.table-view.non-interactive-table .table-cell,
.table-view.non-interactive-table .table-cell .label,
.table-view.non-interactive-table .label,
.table-view.non-interactive-table .text,
.table-view.non-interactive-table .hyperlink,
.table-view.non-interactive-table .hyperlink-with-icon,
.table-view.non-interactive-table .table-row-cell .hyperlink .text {
-fx-text-fill: -bs-color-gray-dim;
}
.table-view.non-interactive-table .hyperlink,
.table-view.non-interactive-table .hyperlink-with-icon,
.table-view.non-interactive-table .table-row-cell .hyperlink .text {
-fx-fill: -bs-color-gray-dim;
}
.table-view.non-interactive-table .table-cell.highlight-text,
.table-view.non-interactive-table .table-cell.highlight-text .label,
.table-view.non-interactive-table .table-cell.highlight-text .text,
.table-view.non-interactive-table .table-cell.highlight-text .hyperlink,
.table-view.non-interactive-table .table-cell.highlight-text .hyperlink .text {
-fx-text-fill: -fx-dark-text-color;
}
/* Match specificity to override. */
.table-view.non-interactive-table .table-cell.highlight-text .zero-decimals {
-fx-text-fill: -bs-color-gray-3;
}
.regular-text-color {
-fx-text-fill: -bs-text-color;
}

View file

@ -41,12 +41,17 @@
-bs-rd-green: #0b65da;
-bs-rd-green-dark: #3EA34A;
-bs-rd-nav-selected: #0b65da;
-bs-rd-nav-deselected: rgba(255, 255, 255, 0.75);
-bs-rd-nav-background: #0c59bd;
-bs-rd-nav-deselected: rgba(255, 255, 255, 1);
-bs-rd-nav-secondary-selected: -fx-accent;
-bs-rd-nav-secondary-deselected: -bs-rd-font-light;
-bs-rd-nav-background: #0b65da;
-bs-rd-nav-primary-background: #0b65da;
-bs-rd-nav-button-hover: derive(-bs-rd-nav-background, 10%);
-bs-rd-nav-primary-button-hover: derive(-bs-rd-nav-primary-background, 10%);
-bs-rd-nav-primary-border: #0B65DA;
-bs-rd-nav-border: #535353;
-bs-rd-nav-border-color: rgba(255, 255, 255, 0.31);
-bs-rd-nav-hover-text: white;
-bs-rd-tab-border: #e2e0e0;
-bs-tab-content-area: #ffffff;
-bs-color-gray-background: #f2f2f2;
@ -58,32 +63,31 @@
-bs-footer-pane-background: #dddddd;
-bs-footer-pane-text: #4b4b4b;
-bs-footer-pane-line: #bbb;
-bs-rd-font-balance: #4f4f4f;
-bs-rd-font-balance: white;
-bs-rd-font-dark-gray: #3c3c3c;
-bs-rd-font-dark: #4b4b4b;
-bs-rd-font-light: #8d8d8d;
-bs-rd-font-lighter: #a7a7a7;
-bs-rd-font-confirmation-label: #504f52;
-bs-rd-font-balance-label: #8e8e8e;
-bs-text-color-transparent-dark: rgba(0, 0, 0, 0.54);
-bs-rd-font-balance-label: #bbbbbb;
-bs-text-color-dropshadow: rgba(0, 0, 0, 0.54);
-bs-text-color-dropshadow-light-mode: rgba(0, 0, 0, 0.54);
-bs-text-color-transparent: rgba(0, 0, 0, 0.2);
-bs-color-gray-line: #979797;
-bs-rd-separator: #dbdbdb;
-bs-rd-separator-dark: #d5e0d6;
-bs-rd-separator-dark: rgb(255, 255, 255, 0.1);
-bs-rd-error-red: #dd0000;
-bs-rd-message-bubble: #0086c6;
-bs-toggle-selected: #7b7b7b;
-bs-rd-tooltip-truncated: #0a0a0a;
-bs-warning: #ff8a2b;
-bs-buy: #3ea34a;
-bs-buy: rgb(80, 180, 90);
-bs-buy-focus: derive(-bs-buy, -50%);
-bs-buy-hover: derive(-bs-buy, -10%);
-bs-buy-transparent: rgba(62, 163, 74, 0.3);
-bs-sell: #d73030;
-bs-sell: rgb(213, 63, 46);
-bs-sell-focus: derive(-bs-sell, -50%);
-bs-sell-hover: derive(-bs-sell, -10%);
-bs-sell-transparent: rgba(215, 48, 48, 0.3);
-bs-volume-transparent: rgba(37, 177, 53, 0.3);
-bs-volume-transparent: -bs-buy;
-bs-candle-stick-average-line: -bs-rd-green;
-bs-candle-stick-loss: #fe3001;
-bs-candle-stick-won: #20b221;
@ -104,6 +108,19 @@
-bs-prompt-text: -fx-control-inner-background;
-bs-soft-red: #aa4c3b;
-bs-turquoise-light: #11eeee;
-bs-color-border-form-field: -bs-background-gray;
-bs-color-background-form-field-readonly: -bs-color-gray-1;
-bs-color-background-pane: -bs-background-color;
-bs-color-background-row-even: -bs-color-background-pane;
-bs-color-background-row-odd: derive(-bs-color-background-pane, -6%);
-bs-color-table-cell-dim: -bs-color-gray-ccc;
-bs-color-background-popup: white;
-bs-color-background-popup-blur: white;
-bs-color-background-popup-input: -bs-color-gray-background;
-bs-color-background-form-field: white;
-bs-text-color-dim1: black;
-bs-text-color-dim2: black;
/* Monero orange color code */
-xmr-orange: #f26822;
@ -126,7 +143,33 @@
-fx-background-color: -bs-color-gray-3;
}
.toggle-button-no-slider {
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
#image-logo-splash {
-fx-image: url("../../images/logo_splash_light.png");
}
#image-logo-splash-testnet {
-fx-image: url("../../images/logo_splash_testnet_light.png");
}
#image-logo-landscape {
-fx-image: url("../../images/logo_landscape_light.png");
}
#charts .default-color0.chart-series-area-fill {
-fx-fill: linear-gradient(to bottom,
rgba(62, 163, 74, 0.45) 0%,
rgba(62, 163, 74, 0.0) 100%
);
}
#charts .default-color1.chart-series-area-fill {
-fx-fill: linear-gradient(to bottom,
rgba(215, 48, 48, 0.45) 0%,
rgba(215, 48, 48, 0.0) 100%
);
}
/* All inputs have border in light mode. */
.jfx-combo-box, .jfx-text-field, .jfx-text-area, .jfx-password-field {
-fx-border-color: -bs-color-border-form-field;
}

View file

@ -58,6 +58,10 @@ public class CssTheme {
scene.getStylesheets().add(cssThemeFolder + "theme-dev.css");
}
public static int getCurrentTheme() {
return currentCSSTheme;
}
public static boolean isDarkTheme() {
return currentCSSTheme == CSS_THEME_DARK;
}

View file

@ -18,6 +18,8 @@
package haveno.desktop.util;
import com.google.common.collect.Lists;
import haveno.core.locale.CurrencyUtil;
import haveno.core.locale.TradeCurrency;
import haveno.core.user.Preferences;
import javafx.collections.FXCollections;
@ -92,14 +94,13 @@ public class CurrencyList {
}
private Comparator<CurrencyListItem> getComparator() {
Comparator<CurrencyListItem> result;
if (preferences.isSortMarketCurrenciesNumerically()) {
Comparator<CurrencyListItem> byCount = Comparator.comparingInt(left -> left.numTrades);
result = byCount.reversed();
return Comparator
.comparingInt((CurrencyListItem item) -> item.numTrades).reversed()
.thenComparing(item -> CurrencyUtil.isCryptoCurrency(item.tradeCurrency.getCode()) ? item.tradeCurrency.getName() : item.tradeCurrency.getCode());
} else {
result = Comparator.comparing(item -> item.tradeCurrency);
return Comparator.comparing(item -> CurrencyUtil.isCryptoCurrency(item.tradeCurrency.getCode()) ? item.tradeCurrency.getName() : item.tradeCurrency.getCode());
}
return result;
}
private Map<TradeCurrency, Integer> countTrades(List<TradeCurrency> currencies) {

View file

@ -135,6 +135,24 @@ public class FormBuilder {
return titledGroupBg;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Divider
///////////////////////////////////////////////////////////////////////////////////////////
public static Region addSeparator(GridPane gridPane, int rowIndex) {
Region separator = new Region();
separator.getStyleClass().add("grid-pane-separator");
separator.setPrefHeight(1);
separator.setMinHeight(1);
separator.setMaxHeight(1);
GridPane.setRowIndex(separator, rowIndex);
GridPane.setColumnIndex(separator, 0);
GridPane.setColumnSpan(separator, 2);
gridPane.getChildren().add(separator);
separator.setPrefHeight(1);
GridPane.setMargin(separator, new Insets(0, 0, 3, 0));
return separator;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Label
@ -361,7 +379,7 @@ public class FormBuilder {
textField.setPrefWidth(Layout.INITIAL_WINDOW_WIDTH);
Button button = new AutoTooltipButton("...");
button.setStyle("-fx-min-width: 26; -fx-pref-height: 26; -fx-padding: 0 0 10 0; -fx-background-color: -fx-background;");
button.setStyle("-fx-min-width: 32; -fx-padding: 0 0 10 0; -fx-background-color: -fx-background;");
button.managedProperty().bind(button.visibleProperty());
HBox hbox = new HBox(textField, button);
@ -369,6 +387,7 @@ public class FormBuilder {
hbox.setSpacing(8);
VBox vbox = getTopLabelVBox(0);
vbox.setSpacing(2);
vbox.getChildren().addAll(getTopLabel(title), hbox);
gridPane.getChildren().add(vbox);
@ -490,6 +509,7 @@ public class FormBuilder {
GridPane.setColumnIndex(textArea, 1);
GridPane.setMargin(label, new Insets(top, 0, 0, 0));
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setValignment(label, VPos.TOP);
GridPane.setMargin(textArea, new Insets(top, 0, 0, 0));
return new Tuple2<>(label, textArea);
@ -617,6 +637,7 @@ public class FormBuilder {
JFXTextArea textArea = new HavenoTextArea();
textArea.setPromptText(prompt);
textArea.setLabelFloat(true);
textArea.getStyleClass().add("label-float");
textArea.setWrapText(true);
GridPane.setRowIndex(textArea, rowIndex);
@ -805,9 +826,9 @@ public class FormBuilder {
}
public static InputTextField addInputTextField(GridPane gridPane, int rowIndex, String title, double top) {
InputTextField inputTextField = new InputTextField();
inputTextField.setLabelFloat(true);
inputTextField.getStyleClass().add("label-float");
inputTextField.setPromptText(title);
GridPane.setRowIndex(inputTextField, rowIndex);
GridPane.setColumnIndex(inputTextField, 0);
@ -884,6 +905,8 @@ public class FormBuilder {
public static PasswordTextField addPasswordTextField(GridPane gridPane, int rowIndex, String title, double top) {
PasswordTextField passwordField = new PasswordTextField();
passwordField.getStyleClass().addAll("label-float");
GUIUtil.applyFilledStyle(passwordField);
passwordField.setPromptText(title);
GridPane.setRowIndex(passwordField, rowIndex);
GridPane.setColumnIndex(passwordField, 0);
@ -1006,8 +1029,10 @@ public class FormBuilder {
InputTextField inputTextField1 = new InputTextField();
inputTextField1.setPromptText(title1);
inputTextField1.setLabelFloat(true);
inputTextField1.getStyleClass().add("label-float");
InputTextField inputTextField2 = new InputTextField();
inputTextField2.setLabelFloat(true);
inputTextField2.getStyleClass().add("label-float");
inputTextField2.setPromptText(title2);
HBox hBox = new HBox();
@ -1228,6 +1253,7 @@ public class FormBuilder {
public static <T> ComboBox<T> addComboBox(GridPane gridPane, int rowIndex, int top) {
final JFXComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
GridPane.setRowIndex(comboBox, rowIndex);
GridPane.setMargin(comboBox, new Insets(top, 0, 0, 0));
@ -1264,7 +1290,9 @@ public class FormBuilder {
VBox vBox = getTopLabelVBox(top);
final JFXComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
comboBox.setPromptText(prompt);
comboBox.setPadding(new Insets(top, 0, 0, 12));
vBox.getChildren().addAll(label, comboBox);
@ -1389,7 +1417,9 @@ public class FormBuilder {
public static <T> ComboBox<T> addComboBox(GridPane gridPane, int rowIndex, String title, double top) {
JFXComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
comboBox.setLabelFloat(true);
comboBox.getStyleClass().add("label-float");
comboBox.setPromptText(title);
comboBox.setMaxWidth(Double.MAX_VALUE);
@ -1399,6 +1429,7 @@ public class FormBuilder {
GridPane.setRowIndex(comboBox, rowIndex);
GridPane.setColumnIndex(comboBox, 0);
comboBox.setPadding(new Insets(0, 0, 0, 12));
GridPane.setMargin(comboBox, new Insets(top + Layout.FLOATING_LABEL_DISTANCE, 0, 0, 0));
gridPane.getChildren().add(comboBox);
@ -1407,7 +1438,9 @@ public class FormBuilder {
public static <T> AutocompleteComboBox<T> addAutocompleteComboBox(GridPane gridPane, int rowIndex, String title, double top) {
var comboBox = new AutocompleteComboBox<T>();
GUIUtil.applyFilledStyle(comboBox);
comboBox.setLabelFloat(true);
comboBox.getStyleClass().add("label-float");
comboBox.setPromptText(title);
comboBox.setMaxWidth(Double.MAX_VALUE);
@ -1469,6 +1502,7 @@ public class FormBuilder {
AutocompleteComboBox<T> comboBox = new AutocompleteComboBox<>();
comboBox.setPromptText(titleCombobox);
comboBox.setLabelFloat(true);
comboBox.getStyleClass().add("label-float");
topLabelVBox2.getChildren().addAll(topLabel2, comboBox);
hBox.getChildren().addAll(topLabelVBox1, topLabelVBox2);
@ -1498,7 +1532,9 @@ public class FormBuilder {
hBox.setSpacing(10);
ComboBox<T> comboBox1 = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox1);
ComboBox<R> comboBox2 = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox2);
hBox.getChildren().addAll(comboBox1, comboBox2);
final Tuple2<Label, VBox> topLabelWithVBox = addTopLabelWithVBox(gridPane, rowIndex, title, hBox, top);
@ -1526,8 +1562,10 @@ public class FormBuilder {
hBox.setSpacing(10);
JFXComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
comboBox.setPromptText(titleCombobox);
comboBox.setLabelFloat(true);
comboBox.getStyleClass().add("label-float");
TextField textField = new HavenoTextField();
@ -1570,6 +1608,7 @@ public class FormBuilder {
button.setDefaultButton(true);
ComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
hBox.getChildren().addAll(comboBox, button);
@ -1604,6 +1643,7 @@ public class FormBuilder {
hBox.setSpacing(10);
ComboBox<T> comboBox = new JFXComboBox<>();
GUIUtil.applyFilledStyle(comboBox);
TextField textField = new TextField(textFieldText);
textField.setEditable(false);
textField.setMouseTransparent(true);
@ -1797,6 +1837,7 @@ public class FormBuilder {
return new Tuple2<>(label, textFieldWithCopyIcon);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Label + AddressTextField
///////////////////////////////////////////////////////////////////////////////////////////
@ -2181,11 +2222,13 @@ public class FormBuilder {
Label label = new AutoTooltipLabel(Res.getBaseCurrencyCode());
label.getStyleClass().add("input-label");
HBox.setMargin(label, new Insets(0, 8, 0, 0));
HBox box = new HBox();
HBox.setHgrow(input, Priority.ALWAYS);
input.setMaxWidth(Double.MAX_VALUE);
box.getStyleClass().add("input-with-border");
box.setAlignment(Pos.CENTER_LEFT);
box.getStyleClass().add("offer-input");
box.getChildren().addAll(input, label);
return new Tuple3<>(box, input, label);
}
@ -2197,11 +2240,13 @@ public class FormBuilder {
Label label = new AutoTooltipLabel(Res.getBaseCurrencyCode());
label.getStyleClass().add("input-label");
HBox.setMargin(label, new Insets(0, 8, 0, 0));
HBox box = new HBox();
HBox.setHgrow(infoInputTextField, Priority.ALWAYS);
infoInputTextField.setMaxWidth(Double.MAX_VALUE);
box.getStyleClass().add("input-with-border");
box.setAlignment(Pos.CENTER_LEFT);
box.getStyleClass().add("offer-input");
box.getChildren().addAll(infoInputTextField, label);
return new Tuple3<>(box, infoInputTextField, label);
}
@ -2444,6 +2489,7 @@ public class FormBuilder {
if (groupStyle != null) titledGroupBg.getStyleClass().add(groupStyle);
TableView<T> tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
GridPane.setRowIndex(tableView, rowIndex);
GridPane.setMargin(tableView, new Insets(top + 30, -10, 5, -10));
gridPane.getChildren().add(tableView);

Some files were not shown because too many files have changed in this diff Show more