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.math.BigInteger;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale; import java.util.Locale;
public class VolumeUtil { public class VolumeUtil {
@ -187,4 +188,35 @@ public class VolumeUtil {
private static MonetaryFormat getMonetaryFormat(String currencyCode) { private static MonetaryFormat getMonetaryFormat(String currencyCode) {
return CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode) ? VOLUME_FORMAT_UNIT : VOLUME_FORMAT_PRECISE; 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.spreadPayment=Offers by Payment Method
market.tabs.trades=Trades market.tabs.trades=Trades
# OfferBookView
market.offerBook.filterPrompt=Filter
# OfferBookChartView # OfferBookChartView
market.offerBook.sellOffersHeaderLabel=Sell {0} to market.offerBook.sellOffersHeaderLabel=Sell {0} to
market.offerBook.buyOffersHeaderLabel=Buy {0} from 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.nrOffers=No. of offers: {0}
offerbook.volume={0} (min - max) offerbook.volume={0} (min - max)
offerbook.volumeTotal={0} {1}
offerbook.deposit=Deposit XMR (%) 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.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.createNewOffer=Create offer to {0} {1}
offerbook.createOfferDisabled.tooltip=You can only create one offer at a time 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.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets 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.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\ 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\ 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.showOwnOffers=Show my own offers in offer book
setting.preferences.useAnimations=Use animations setting.preferences.useAnimations=Use animations
setting.preferences.useDarkMode=Use dark mode 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.sortWithNumOffers=Sort market lists with no. of offers/trades
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API 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.creationDate=Creation date
offerDetailsWindow.makersOnion=Maker's onion address offerDetailsWindow.makersOnion=Maker's onion address
offerDetailsWindow.challenge=Offer passphrase offerDetailsWindow.challenge=Offer passphrase
offerDetailsWindow.challenge.copy=Copy passphrase to share with your peer
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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 market.tabs.trades=Obchody
# OfferBookView # OfferBookView
market.offerBook.filterPrompt=Filtr
# OfferBookChartView # OfferBookChartView
market.offerBook.sellOffersHeaderLabel=Prodat {0} kupujícímu 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.arbitration.support=Arbitráž
support.tab.legacyArbitration.support=Starší arbitráž support.tab.legacyArbitration.support=Starší arbitráž
support.tab.ArbitratorsSupportTickets=Úkoly pro {0} 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.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\ 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\ 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.showOwnOffers=Zobrazit mé vlastní nabídky v seznamu nabídek
setting.preferences.useAnimations=Použít animace setting.preferences.useAnimations=Použít animace
setting.preferences.useDarkMode=Použít tmavý režim 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.sortWithNumOffers=Seřadit seznamy trhů s počtem nabídek/obchodů
setting.preferences.onlyShowPaymentMethodsFromAccount=Skrýt nepodporované způsoby platby setting.preferences.onlyShowPaymentMethodsFromAccount=Skrýt nepodporované způsoby platby
setting.preferences.denyApiTaker=Odmítat příjemce, kteří používají API 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.creationDate=Datum vzniku
offerDetailsWindow.makersOnion=Onion adresa tvůrce offerDetailsWindow.makersOnion=Onion adresa tvůrce
offerDetailsWindow.challenge=Passphrase nabídky 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.headline=QR Kód
qRCodeWindow.msg=Použijte tento QR kód k financování vaší peněženky Haveno z vaší externí peněženky. 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.arbitration.support=Vermittlung
support.tab.legacyArbitration.support=Legacy-Vermittlung support.tab.legacyArbitration.support=Legacy-Vermittlung
support.tab.ArbitratorsSupportTickets={0} Tickets 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.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. 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.showOwnOffers=Eigenen Angebote im Angebotsbuch zeigen
setting.preferences.useAnimations=Animationen abspielen setting.preferences.useAnimations=Animationen abspielen
setting.preferences.useDarkMode=Nacht-Modus benutzen setting.preferences.useDarkMode=Nacht-Modus benutzen
setting.preferences.useLightMode=Leichtmodus verwenden
setting.preferences.sortWithNumOffers=Marktlisten nach Anzahl der Angebote/Trades sortieren setting.preferences.sortWithNumOffers=Marktlisten nach Anzahl der Angebote/Trades sortieren
setting.preferences.onlyShowPaymentMethodsFromAccount=Nicht unterstützte Zahlungsmethoden ausblenden setting.preferences.onlyShowPaymentMethodsFromAccount=Nicht unterstützte Zahlungsmethoden ausblenden
setting.preferences.denyApiTaker=Taker die das API nutzen vermeiden 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.creationDate=Erstellungsdatum
offerDetailsWindow.makersOnion=Onion-Adresse des Erstellers offerDetailsWindow.makersOnion=Onion-Adresse des Erstellers
offerDetailsWindow.challenge=Angebots-Passphrase offerDetailsWindow.challenge=Angebots-Passphrase
offerDetailsWindow.challenge.copy=Passphrase kopieren, um sie mit Ihrem Handelspartner zu teilen
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Bitte nutzen Sie diesen QR Code um Ihr Haveno Wallet von Ihrem externen Wallet aufzuladen. 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.arbitration.support=Arbitraje
support.tab.legacyArbitration.support=Legado de arbitraje support.tab.legacyArbitration.support=Legado de arbitraje
support.tab.ArbitratorsSupportTickets=Tickets de {0} 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.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. 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.showOwnOffers=Mostrar mis propias ofertas en el libro de ofertas
setting.preferences.useAnimations=Usar animaciones setting.preferences.useAnimations=Usar animaciones
setting.preferences.useDarkMode=Usar modo oscuro 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.sortWithNumOffers=Ordenar listas de mercado por número de ofertas/intercambios
setting.preferences.onlyShowPaymentMethodsFromAccount=Ocultar métodos de pago no soportados setting.preferences.onlyShowPaymentMethodsFromAccount=Ocultar métodos de pago no soportados
setting.preferences.denyApiTaker=Denegar tomadores usando la misma API 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.creationDate=Fecha de creación
offerDetailsWindow.makersOnion=Dirección onion del creador offerDetailsWindow.makersOnion=Dirección onion del creador
offerDetailsWindow.challenge=Frase de contraseña de la oferta 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.headline=Código QR
qRCodeWindow.msg=Por favor, utilice este código QR para fondear su billetera Haveno desde su billetera externa. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=فیلتر
shared.enabled=Enabled shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=افزودن آلتکوین
setting.preferences.displayOptions=نمایش گزینه‌ها setting.preferences.displayOptions=نمایش گزینه‌ها
setting.preferences.showOwnOffers=نمایش پیشنهادهای من در دفتر پیشنهاد setting.preferences.showOwnOffers=نمایش پیشنهادهای من در دفتر پیشنهاد
setting.preferences.useAnimations=استفاده از انیمیشن‌ها setting.preferences.useAnimations=استفاده از انیمیشن‌ها
setting.preferences.useDarkMode=Use dark mode setting.preferences.useDarkMode=حالت تاریک را استفاده کنید
setting.preferences.useLightMode=حالت روشن را استفاده کنید
setting.preferences.sortWithNumOffers=مرتب سازی لیست‌ها با تعداد معاملات/پیشنهادها setting.preferences.sortWithNumOffers=مرتب سازی لیست‌ها با تعداد معاملات/پیشنهادها
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API setting.preferences.denyApiTaker=Deny takers using the API
@ -1473,6 +1472,7 @@ offerDetailsWindow.confirm.taker=تأیید: پیشنهاد را به {0} بپذ
offerDetailsWindow.creationDate=تاریخ ایجاد offerDetailsWindow.creationDate=تاریخ ایجاد
offerDetailsWindow.makersOnion=آدرس Onion سفارش گذار offerDetailsWindow.makersOnion=آدرس Onion سفارش گذار
offerDetailsWindow.challenge=Passphrase de l'offre offerDetailsWindow.challenge=Passphrase de l'offre
offerDetailsWindow.challenge.copy=عبارت عبور را برای به اشتراک‌گذاری با همتا کپی کنید
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.arbitration.support=Arbitrage
support.tab.legacyArbitration.support=Conclusion d'arbitrage support.tab.legacyArbitration.support=Conclusion d'arbitrage
support.tab.ArbitratorsSupportTickets=Tickets de {0} 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.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. 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.showOwnOffers=Montrer mes ordres dans le livre des ordres
setting.preferences.useAnimations=Utiliser des animations setting.preferences.useAnimations=Utiliser des animations
setting.preferences.useDarkMode=Utiliser le mode sombre 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.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.onlyShowPaymentMethodsFromAccount=Masquer les méthodes de paiement non supportées
setting.preferences.denyApiTaker=Refuser les preneurs utilisant l'API 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.creationDate=Date de création
offerDetailsWindow.makersOnion=Adresse onion du maker offerDetailsWindow.makersOnion=Adresse onion du maker
offerDetailsWindow.challenge=Phrase secrète de l'offre 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.headline=QR Code
qRCodeWindow.msg=Veuillez utiliser le code QR pour recharger du portefeuille externe au portefeuille Haveno. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=Al momento, hai troppe transazioni non confermate. Per favore riprova più tardi. shared.unconfirmedTransactionsLimitReached=Al momento, hai troppe transazioni non confermate. Per favore riprova più tardi.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=Filtro
shared.enabled=Enabled shared.enabled=Enabled
@ -927,8 +927,6 @@ support.tab.mediation.support=Mediazione
support.tab.arbitration.support=Arbitrato support.tab.arbitration.support=Arbitrato
support.tab.legacyArbitration.support=Arbitrato Legacy support.tab.legacyArbitration.support=Arbitrato Legacy
support.tab.ArbitratorsSupportTickets=I ticket di {0} 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result 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.showOwnOffers=Mostra le mie offerte nel libro delle offerte
setting.preferences.useAnimations=Usa animazioni setting.preferences.useAnimations=Usa animazioni
setting.preferences.useDarkMode=Usa modalità notte 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.sortWithNumOffers=Ordina le liste di mercato con n. di offerte/scambi
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API 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.creationDate=Data di creazione
offerDetailsWindow.makersOnion=Indirizzo .onion del maker offerDetailsWindow.makersOnion=Indirizzo .onion del maker
offerDetailsWindow.challenge=Passphrase dell'offerta offerDetailsWindow.challenge=Passphrase dell'offerta
offerDetailsWindow.challenge.copy=Copia la frase segreta da condividere con il tuo interlocutore
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.arbitration.support=仲裁
support.tab.legacyArbitration.support=レガシー仲裁 support.tab.legacyArbitration.support=レガシー仲裁
support.tab.ArbitratorsSupportTickets={0} のチケット support.tab.ArbitratorsSupportTickets={0} のチケット
support.filter=係争を検索
support.filter.prompt=トレードID、日付、onionアドレスまたはアカウントデータを入力してください
support.sigCheck.button=Check signature support.sigCheck.button=Check signature
support.sigCheck.popup.info=仲裁プロセスの要約メッセージを貼り付けてください。このツールを使用すると、どんなユーザーでも仲裁者の署名が要約メッセージと一致するかどうかを確認できます。 support.sigCheck.popup.info=仲裁プロセスの要約メッセージを貼り付けてください。このツールを使用すると、どんなユーザーでも仲裁者の署名が要約メッセージと一致するかどうかを確認できます。
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=表示設定
setting.preferences.showOwnOffers=オファーブックに自分のオファーを表示 setting.preferences.showOwnOffers=オファーブックに自分のオファーを表示
setting.preferences.useAnimations=アニメーションを使用 setting.preferences.useAnimations=アニメーションを使用
setting.preferences.useDarkMode=ダークモードを利用 setting.preferences.useDarkMode=ダークモードを利用
setting.preferences.useLightMode=ライトモードを使用する
setting.preferences.sortWithNumOffers=市場リストをオファー/トレードの数で並び替える setting.preferences.sortWithNumOffers=市場リストをオファー/トレードの数で並び替える
setting.preferences.onlyShowPaymentMethodsFromAccount=サポートされていない支払い方法を非表示にする setting.preferences.onlyShowPaymentMethodsFromAccount=サポートされていない支払い方法を非表示にする
setting.preferences.denyApiTaker=APIを使用するテイカーを拒否する setting.preferences.denyApiTaker=APIを使用するテイカーを拒否する
@ -1477,6 +1476,7 @@ offerDetailsWindow.confirm.taker=承認: ビットコインを{0}オファーを
offerDetailsWindow.creationDate=作成日 offerDetailsWindow.creationDate=作成日
offerDetailsWindow.makersOnion=メイカーのonionアドレス offerDetailsWindow.makersOnion=メイカーのonionアドレス
offerDetailsWindow.challenge=オファーパスフレーズ offerDetailsWindow.challenge=オファーパスフレーズ
offerDetailsWindow.challenge.copy=ピアと共有するためにパスフレーズをコピーする
qRCodeWindow.headline=QRコード qRCodeWindow.headline=QRコード
qRCodeWindow.msg=外部ウォレットからHavenoウォレットへ送金するのに、この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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=No momento, você possui muitas transações não-confirmadas. Tente novamente mais tarde. shared.unconfirmedTransactionsLimitReached=No momento, você possui muitas transações não-confirmadas. Tente novamente mais tarde.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=Filtro
shared.enabled=Enabled shared.enabled=Enabled
@ -929,8 +929,6 @@ support.tab.mediation.support=Mediação
support.tab.arbitration.support=Arbitragem support.tab.arbitration.support=Arbitragem
support.tab.legacyArbitration.support=Arbitração antiga support.tab.legacyArbitration.support=Arbitração antiga
support.tab.ArbitratorsSupportTickets=Tickets de {0} 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result 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.showOwnOffers=Exibir minhas ofertas no livro de ofertas
setting.preferences.useAnimations=Usar animações setting.preferences.useAnimations=Usar animações
setting.preferences.useDarkMode=Usar modo escuro setting.preferences.useDarkMode=Usar modo escuro
setting.preferences.useLightMode=Usar modo claro
setting.preferences.sortWithNumOffers=Ordenar pelo nº de ofertas/negociações setting.preferences.sortWithNumOffers=Ordenar pelo nº de ofertas/negociações
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API 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.creationDate=Criada em
offerDetailsWindow.makersOnion=Endereço onion do ofertante offerDetailsWindow.makersOnion=Endereço onion do ofertante
offerDetailsWindow.challenge=Passphrase da oferta offerDetailsWindow.challenge=Passphrase da oferta
offerDetailsWindow.challenge.copy=Copiar frase secreta para compartilhar com seu par
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=Filtro
shared.enabled=Enabled shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediação
support.tab.arbitration.support=Arbitragem support.tab.arbitration.support=Arbitragem
support.tab.legacyArbitration.support=Arbitragem Antiga support.tab.legacyArbitration.support=Arbitragem Antiga
support.tab.ArbitratorsSupportTickets=Bilhetes de {0} 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result 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.showOwnOffers=Mostrar as minhas próprias ofertas no livro de ofertas
setting.preferences.useAnimations=Usar animações setting.preferences.useAnimations=Usar animações
setting.preferences.useDarkMode=Usar o modo escuro 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.sortWithNumOffers=Ordenar listas de mercado por nº de ofertas/negociações:
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API 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.creationDate=Data de criação
offerDetailsWindow.makersOnion=Endereço onion do ofertante offerDetailsWindow.makersOnion=Endereço onion do ofertante
offerDetailsWindow.challenge=Passphrase da oferta offerDetailsWindow.challenge=Passphrase da oferta
offerDetailsWindow.challenge.copy=Copiar frase secreta para compartilhar com seu parceiro
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=Фильтр
shared.enabled=Enabled shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets support.tab.ArbitratorsSupportTickets={0}'s tickets
support.filter=Search disputes
support.filter.prompt=Введите идентификатор сделки, дату, onion-адрес или данные учётной записи
support.sigCheck.button=Check signature support.sigCheck.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=Добавить альткойн
setting.preferences.displayOptions=Параметры отображения setting.preferences.displayOptions=Параметры отображения
setting.preferences.showOwnOffers=Показать мои предложения в списке предложений setting.preferences.showOwnOffers=Показать мои предложения в списке предложений
setting.preferences.useAnimations=Использовать анимацию setting.preferences.useAnimations=Использовать анимацию
setting.preferences.useDarkMode=Use dark mode setting.preferences.useDarkMode=Использовать тёмный режим
setting.preferences.useLightMode=Использовать светлый режим
setting.preferences.sortWithNumOffers=Сортировать списки по кол-ву предложений/сделок setting.preferences.sortWithNumOffers=Сортировать списки по кол-ву предложений/сделок
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API setting.preferences.denyApiTaker=Deny takers using the API
@ -1474,6 +1473,7 @@ offerDetailsWindow.confirm.taker=Подтвердите: принять пред
offerDetailsWindow.creationDate=Дата создания offerDetailsWindow.creationDate=Дата создания
offerDetailsWindow.makersOnion=Onion-адрес мейкера offerDetailsWindow.makersOnion=Onion-адрес мейкера
offerDetailsWindow.challenge=Пароль предложения offerDetailsWindow.challenge=Пароль предложения
offerDetailsWindow.challenge.copy=Скопируйте кодовую фразу, чтобы поделиться с партнёром
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=ตัวกรอง
shared.enabled=Enabled shared.enabled=Enabled
@ -926,8 +926,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.header=Verify dispute result signature
@ -1031,7 +1029,8 @@ setting.preferences.addCrypto=เพิ่ม crypto
setting.preferences.displayOptions=แสดงตัวเลือกเพิ่มเติม setting.preferences.displayOptions=แสดงตัวเลือกเพิ่มเติม
setting.preferences.showOwnOffers=แสดงข้อเสนอของฉันเองในสมุดข้อเสนอ setting.preferences.showOwnOffers=แสดงข้อเสนอของฉันเองในสมุดข้อเสนอ
setting.preferences.useAnimations=ใช้ภาพเคลื่อนไหว setting.preferences.useAnimations=ใช้ภาพเคลื่อนไหว
setting.preferences.useDarkMode=Use dark mode setting.preferences.useDarkMode=ใช้โหมดมืด
setting.preferences.useLightMode=ใช้โหมดสว่าง
setting.preferences.sortWithNumOffers=จัดเรียงรายการโดยเลขของข้อเสนอ / การซื้อขาย setting.preferences.sortWithNumOffers=จัดเรียงรายการโดยเลขของข้อเสนอ / การซื้อขาย
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API setting.preferences.denyApiTaker=Deny takers using the API
@ -1474,6 +1473,7 @@ offerDetailsWindow.confirm.taker=ยืนยัน: รับข้อเสน
offerDetailsWindow.creationDate=วันที่สร้าง offerDetailsWindow.creationDate=วันที่สร้าง
offerDetailsWindow.makersOnion=ที่อยู่ onion ของผู้สร้าง offerDetailsWindow.makersOnion=ที่อยู่ onion ของผู้สร้าง
offerDetailsWindow.challenge=รหัสผ่านสำหรับข้อเสนอ offerDetailsWindow.challenge=รหัสผ่านสำหรับข้อเสนอ
offerDetailsWindow.challenge.copy=คัดลอกวลีรหัสเพื่อแชร์กับเพื่อนของคุณ
qRCodeWindow.headline=QR Code qRCodeWindow.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.delayedPayoutTxReceiverAddress=Gecikmiş ödeme işlemi gönderildi
shared.unconfirmedTransactionsLimitReached=Şu anda çok fazla onaylanmamış işleminiz var. Lütfen daha sonra tekrar deneyin. shared.unconfirmedTransactionsLimitReached=Şu anda çok fazla onaylanmamış işleminiz var. Lütfen daha sonra tekrar deneyin.
shared.numItemsLabel=Girdi sayısı: {0} shared.numItemsLabel=Girdi sayısı: {0}
shared.filter=Filtrele shared.filter=Filtre
shared.enabled=Etkin shared.enabled=Etkin
shared.pending=Beklemede shared.pending=Beklemede
shared.me=Ben shared.me=Ben
@ -1120,8 +1120,6 @@ support.tab.refund.support=Geri Ödeme
support.tab.arbitration.support=Arbitraj support.tab.arbitration.support=Arbitraj
support.tab.legacyArbitration.support=Eski Arbitraj support.tab.legacyArbitration.support=Eski Arbitraj
support.tab.ArbitratorsSupportTickets={0}'nin biletleri 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.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\ 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\ 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.showOwnOffers=Teklif defterinde kendi tekliflerini göster
setting.preferences.useAnimations=Animasyonları kullan setting.preferences.useAnimations=Animasyonları kullan
setting.preferences.useDarkMode=Karanlık modu 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.sortWithNumOffers=Piyasaları teklif sayısına göre sırala
setting.preferences.onlyShowPaymentMethodsFromAccount=Olmayan ödeme yöntemlerini gizle setting.preferences.onlyShowPaymentMethodsFromAccount=Olmayan ödeme yöntemlerini gizle
setting.preferences.denyApiTaker=API kullanan alıcıları reddet 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.creationDate=Oluşturma tarihi
offerDetailsWindow.makersOnion=Yapıcı'nın onion adresi offerDetailsWindow.makersOnion=Yapıcı'nın onion adresi
offerDetailsWindow.challenge=Teklif şifresi offerDetailsWindow.challenge=Teklif şifresi
offerDetailsWindow.challenge.copy=Parolanızı eşinizle paylaşmak için kopyalayın
qRCodeWindow.headline=QR Kodu 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. 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.delayedPayoutTxReceiverAddress=Delayed payout transaction sent to
shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later. shared.unconfirmedTransactionsLimitReached=You have too many unconfirmed transactions at the moment. Please try again later.
shared.numItemsLabel=Number of entries: {0} shared.numItemsLabel=Number of entries: {0}
shared.filter=Filter shared.filter=Bộ lọc
shared.enabled=Enabled shared.enabled=Enabled
@ -928,8 +928,6 @@ support.tab.mediation.support=Mediation
support.tab.arbitration.support=Arbitration support.tab.arbitration.support=Arbitration
support.tab.legacyArbitration.support=Legacy Arbitration support.tab.legacyArbitration.support=Legacy Arbitration
support.tab.ArbitratorsSupportTickets={0}'s tickets 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.button=Check signature
support.sigCheck.popup.header=Verify dispute result 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.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.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.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.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.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API 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.creationDate=Ngày tạo
offerDetailsWindow.makersOnion=Địa chỉ onion của người tạo offerDetailsWindow.makersOnion=Địa chỉ onion của người tạo
offerDetailsWindow.challenge=Mã bảo vệ giao dịch 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.headline=QR Code
qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. 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.arbitration.support=仲裁
support.tab.legacyArbitration.support=历史仲裁 support.tab.legacyArbitration.support=历史仲裁
support.tab.ArbitratorsSupportTickets={0} 的工单 support.tab.ArbitratorsSupportTickets={0} 的工单
support.filter=查找纠纷
support.filter.prompt=输入 交易 ID、日期、洋葱地址或账户信息
support.sigCheck.button=Check signature support.sigCheck.button=Check signature
support.sigCheck.popup.info=请粘贴仲裁过程的摘要信息。使用这个工具,任何用户都可以检查仲裁者的签名是否与摘要信息相符。 support.sigCheck.popup.info=请粘贴仲裁过程的摘要信息。使用这个工具,任何用户都可以检查仲裁者的签名是否与摘要信息相符。
@ -1035,6 +1033,7 @@ setting.preferences.displayOptions=显示选项
setting.preferences.showOwnOffers=在报价列表中显示我的报价 setting.preferences.showOwnOffers=在报价列表中显示我的报价
setting.preferences.useAnimations=使用动画 setting.preferences.useAnimations=使用动画
setting.preferences.useDarkMode=使用夜间模式 setting.preferences.useDarkMode=使用夜间模式
setting.preferences.useLightMode=使用浅色模式
setting.preferences.sortWithNumOffers=使用“报价ID/交易ID”筛选列表 setting.preferences.sortWithNumOffers=使用“报价ID/交易ID”筛选列表
setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods setting.preferences.onlyShowPaymentMethodsFromAccount=Hide non-supported payment methods
setting.preferences.denyApiTaker=Deny takers using the API setting.preferences.denyApiTaker=Deny takers using the API
@ -1478,6 +1477,7 @@ offerDetailsWindow.confirm.taker=确定:下单买入 {0} 比特币
offerDetailsWindow.creationDate=创建时间 offerDetailsWindow.creationDate=创建时间
offerDetailsWindow.makersOnion=卖家的匿名地址 offerDetailsWindow.makersOnion=卖家的匿名地址
offerDetailsWindow.challenge=提供密码 offerDetailsWindow.challenge=提供密码
offerDetailsWindow.challenge.copy=复制助记词以与您的交易对手共享
qRCodeWindow.headline=二维码 qRCodeWindow.headline=二维码
qRCodeWindow.msg=请使用二维码从外部钱包充值至 Haveno 钱包 qRCodeWindow.msg=请使用二维码从外部钱包充值至 Haveno 钱包

View file

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

View file

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

View file

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

View file

@ -216,7 +216,10 @@ public class HavenoAppMain extends HavenoExecutable {
// Set the dialog content // Set the dialog content
VBox vbox = new VBox(10); 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); vbox.setAlignment(Pos.TOP_CENTER);
getDialogPane().setContent(vbox); getDialogPane().setContent(vbox);

View file

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

View file

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

View file

@ -24,6 +24,7 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.event.Event; import javafx.event.Event;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.scene.control.ListView;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -44,6 +45,7 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
private List<? extends T> extendedList; private List<? extends T> extendedList;
private List<T> matchingList; private List<T> matchingList;
private JFXComboBoxListViewSkin<T> comboBoxListViewSkin; private JFXComboBoxListViewSkin<T> comboBoxListViewSkin;
private boolean selectAllShortcut = false;
public AutocompleteComboBox() { public AutocompleteComboBox() {
this(FXCollections.observableArrayList()); this(FXCollections.observableArrayList());
@ -153,6 +155,27 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
private void reactToQueryChanges() { private void reactToQueryChanges() {
getEditor().addEventHandler(KeyEvent.KEY_RELEASED, (KeyEvent event) -> { 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(() -> { UserThread.execute(() -> {
String query = getEditor().getText(); String query = getEditor().getText();
var exactMatch = list.stream().anyMatch(item -> asString(item).equalsIgnoreCase(query)); var exactMatch = list.stream().anyMatch(item -> asString(item).equalsIgnoreCase(query));
@ -180,6 +203,10 @@ public class AutocompleteComboBox<T> extends JFXComboBox<T> {
if (matchingListSize() > 0) { if (matchingListSize() > 0) {
comboBoxListViewSkin.getPopupContent().autosize(); comboBoxListViewSkin.getPopupContent().autosize();
show(); show();
if (comboBoxListViewSkin.getPopupContent() instanceof ListView<?> listView) {
listView.applyCss();
listView.layout();
}
} else { } else {
hide(); hide();
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,12 +18,15 @@
package haveno.desktop.components; package haveno.desktop.components;
import com.jfoenix.controls.JFXTextField; 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.common.util.Utilities;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
@ -45,12 +48,13 @@ public class TextFieldWithCopyIcon extends AnchorPane {
} }
public TextFieldWithCopyIcon(String customStyleClass) { public TextFieldWithCopyIcon(String customStyleClass) {
Label copyIcon = new Label(); Label copyLabel = new Label();
copyIcon.setLayoutY(3); copyLabel.setLayoutY(Layout.FLOATING_ICON_Y);
copyIcon.getStyleClass().addAll("icon", "highlight"); copyLabel.getStyleClass().addAll("icon", "highlight");
copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard"))); if (customStyleClass != null) copyLabel.getStyleClass().add(customStyleClass + "-icon");
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); copyLabel.setTooltip(new Tooltip(Res.get("shared.copyToClipboard")));
copyIcon.setOnMouseClicked(e -> { copyLabel.setGraphic(GUIUtil.getCopyIcon());
copyLabel.setOnMouseClicked(e -> {
String text = getText(); String text = getText();
if (text != null && text.length() > 0) { if (text != null && text.length() > 0) {
String copyText; String copyText;
@ -70,17 +74,25 @@ public class TextFieldWithCopyIcon extends AnchorPane {
copyText = text; copyText = text;
} }
Utilities.copyToClipboard(copyText); 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 = new JFXTextField();
textField.setEditable(false); textField.setEditable(false);
if (customStyleClass != null) textField.getStyleClass().add(customStyleClass); if (customStyleClass != null) textField.getStyleClass().add(customStyleClass);
textField.textProperty().bindBidirectional(text); textField.textProperty().bindBidirectional(text);
AnchorPane.setRightAnchor(copyIcon, 5.0); AnchorPane.setRightAnchor(copyLabel, 5.0);
AnchorPane.setRightAnchor(textField, 30.0); AnchorPane.setRightAnchor(textField, 30.0);
AnchorPane.setLeftAnchor(textField, 0.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()); textField.focusTraversableProperty().set(focusTraversableProperty().get());
getChildren().addAll(textField, copyIcon); getChildren().addAll(textField, copyLabel);
} }
public void setPromptText(String value) { 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.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.fontawesome.AwesomeIcon;
import haveno.common.UserThread; import haveno.common.UserThread;
import haveno.desktop.util.Layout;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
@ -53,10 +54,10 @@ public class TextFieldWithIcon extends AnchorPane {
iconLabel = new Label(); iconLabel = new Label();
iconLabel.setLayoutX(0); iconLabel.setLayoutX(0);
iconLabel.setLayoutY(3); iconLabel.setLayoutY(Layout.FLOATING_ICON_Y);
dummyTextField.widthProperty().addListener((observable, oldValue, newValue) -> { 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); getChildren().addAll(textField, dummyTextField, iconLabel);

View file

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

View file

@ -494,7 +494,7 @@ public class PopOver extends PopupControl {
* @since 1.0 * @since 1.0
*/ */
public final void hide(Duration fadeOutDuration) { 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. //We must remove EventFilter in order to prevent memory leak.
if (ownerWindow != null) { if (ownerWindow != null) {
ownerWindow.removeEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, ownerWindow.removeEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST,

View file

@ -17,13 +17,10 @@
package haveno.desktop.components.list; package haveno.desktop.components.list;
import haveno.core.locale.Res;
import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.components.InputTextField; import haveno.desktop.components.InputTextField;
import haveno.desktop.util.filtering.FilterableListItem; import haveno.desktop.util.filtering.FilterableListItem;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.FilteredList;
import javafx.geometry.Insets;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
@ -37,13 +34,10 @@ public class FilterBox extends HBox {
super(); super();
setSpacing(5.0); 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 = new InputTextField();
textField.setMinWidth(500); textField.setMinWidth(500);
getChildren().addAll(label, textField); getChildren().addAll(textField);
} }
public void initialize(FilteredList<? extends FilterableListItem> filteredList, public void initialize(FilteredList<? extends FilterableListItem> filteredList,
@ -67,4 +61,8 @@ public class FilterBox extends HBox {
private void applyFilteredListPredicate(String filterString) { private void applyFilteredListPredicate(String filterString) {
filteredList.setPredicate(item -> item.match(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.components.InputTextField;
import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.FormBuilder; import haveno.desktop.util.FormBuilder;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout; import haveno.desktop.util.Layout;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
@ -202,6 +203,8 @@ public class AssetsForm extends PaymentMethodForm {
CurrencyUtil.getActiveSortedCryptoCurrencies(filterManager)); CurrencyUtil.getActiveSortedCryptoCurrencies(filterManager));
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 10)); currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 10));
currencyComboBox.setCellFactory(GUIUtil.getTradeCurrencyCellFactoryNameAndCode());
currencyComboBox.setConverter(new StringConverter<>() { currencyComboBox.setConverter(new StringConverter<>() {
@Override @Override
public String toString(TradeCurrency tradeCurrency) { 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 { #image-info {
-fx-image: url("../../images/info.png"); -fx-image: url("../../images/info.png");
} }
@ -23,16 +10,29 @@
-fx-image: url("../../images/alert_round.png"); -fx-image: url("../../images/alert_round.png");
} }
#image-red_circle_solid {
-fx-image: url("../../images/red_circle_solid.png");
}
#image-green_circle { #image-green_circle {
-fx-image: url("../../images/green_circle.png"); -fx-image: url("../../images/green_circle.png");
} }
#image-green_circle_solid {
-fx-image: url("../../images/green_circle_solid.png");
}
#image-yellow_circle { #image-yellow_circle {
-fx-image: url("../../images/yellow_circle.png"); -fx-image: url("../../images/yellow_circle.png");
} }
#image-blue_circle { #image-yellow_circle_solid {
-fx-image: url("../../images/blue_circle.png"); -fx-image: url("../../images/yellow_circle_solid.png");
}
#image-blue_circle_solid {
-fx-image: url("../../images/blue_circle_solid.png");
} }
#image-remove { #image-remove {
@ -300,3 +300,59 @@
#image-new-trade-protocol-screenshot { #image-new-trade-protocol-screenshot {
-fx-image: url("../../images/new_trade_protocol_screenshot.png"); -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.LanguageUtil;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.MarketPrice;
import haveno.core.user.Preferences;
import haveno.desktop.Navigation; import haveno.desktop.Navigation;
import haveno.desktop.common.view.CachingViewLoader; import haveno.desktop.common.view.CachingViewLoader;
import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.FxmlView;
@ -73,6 +74,7 @@ import javafx.geometry.Insets;
import javafx.geometry.NodeOrientation; import javafx.geometry.NodeOrientation;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@ -92,6 +94,7 @@ import static javafx.scene.layout.AnchorPane.setRightAnchor;
import static javafx.scene.layout.AnchorPane.setTopAnchor; import static javafx.scene.layout.AnchorPane.setTopAnchor;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
@ -125,17 +128,19 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Label xmrSplashInfo; private Label xmrSplashInfo;
private Popup p2PNetworkWarnMsgPopup, xmrNetworkWarnMsgPopup; private Popup p2PNetworkWarnMsgPopup, xmrNetworkWarnMsgPopup;
private final TorNetworkSettingsWindow torNetworkSettingsWindow; private final TorNetworkSettingsWindow torNetworkSettingsWindow;
private final Preferences preferences;
private static final int networkIconSize = 20;
public static StackPane getRootContainer() { public static StackPane getRootContainer() {
return MainView.rootContainer; return MainView.rootContainer;
} }
public static void blurLight() { 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() { 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() { public static void darken() {
@ -151,12 +156,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
CachingViewLoader viewLoader, CachingViewLoader viewLoader,
Navigation navigation, Navigation navigation,
Transitions transitions, Transitions transitions,
TorNetworkSettingsWindow torNetworkSettingsWindow) { TorNetworkSettingsWindow torNetworkSettingsWindow,
Preferences preferences) {
super(model); super(model);
this.viewLoader = viewLoader; this.viewLoader = viewLoader;
this.navigation = navigation; this.navigation = navigation;
MainView.transitions = transitions; MainView.transitions = transitions;
this.torNetworkSettingsWindow = torNetworkSettingsWindow; this.torNetworkSettingsWindow = torNetworkSettingsWindow;
this.preferences = preferences;
} }
@Override @Override
@ -165,15 +172,15 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
if (LanguageUtil.isDefaultLanguageRTL()) if (LanguageUtil.isDefaultLanguageRTL())
MainView.rootContainer.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); MainView.rootContainer.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
ToggleButton marketButton = new NavButton(MarketView.class, Res.get("mainView.menu.market").toUpperCase()); ToggleButton marketButton = new NavButton(MarketView.class, Res.get("mainView.menu.market"));
ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buyXmr").toUpperCase()); ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buyXmr"));
ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sellXmr").toUpperCase()); ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sellXmr"));
ToggleButton portfolioButton = new NavButton(PortfolioView.class, Res.get("mainView.menu.portfolio").toUpperCase()); ToggleButton portfolioButton = new NavButton(PortfolioView.class, Res.get("mainView.menu.portfolio"));
ToggleButton fundsButton = new NavButton(FundsView.class, Res.get("mainView.menu.funds").toUpperCase()); ToggleButton fundsButton = new NavButton(FundsView.class, Res.get("mainView.menu.funds"));
ToggleButton supportButton = new NavButton(SupportView.class, Res.get("mainView.menu.support")); ToggleButton supportButton = new SecondaryNavButton(SupportView.class, Res.get("mainView.menu.support"), "image-support");
ToggleButton accountButton = new NavButton(AccountView.class, Res.get("mainView.menu.account")); ToggleButton accountButton = new SecondaryNavButton(AccountView.class, Res.get("mainView.menu.account"), "image-account");
ToggleButton settingsButton = new NavButton(SettingsView.class, Res.get("mainView.menu.settings")); ToggleButton settingsButton = new SecondaryNavButton(SettingsView.class, Res.get("mainView.menu.settings"), "image-settings");
JFXBadge portfolioButtonWithBadge = new JFXBadge(portfolioButton); JFXBadge portfolioButtonWithBadge = new JFXBadge(portfolioButton);
JFXBadge supportButtonWithBadge = new JFXBadge(supportButton); JFXBadge supportButtonWithBadge = new JFXBadge(supportButton);
@ -298,47 +305,56 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
} }
}); });
HBox primaryNav = new HBox(marketButton, getNavigationSeparator(), buyButton, getNavigationSeparator(), HBox primaryNav = new HBox(getLogoPane(), marketButton, getNavigationSpacer(), buyButton, getNavigationSpacer(),
sellButton, getNavigationSeparator(), portfolioButtonWithBadge, getNavigationSeparator(), fundsButton); sellButton, getNavigationSpacer(), portfolioButtonWithBadge, getNavigationSpacer(), fundsButton);
primaryNav.setAlignment(Pos.CENTER_LEFT); primaryNav.setAlignment(Pos.CENTER_LEFT);
primaryNav.getStyleClass().add("nav-primary"); primaryNav.getStyleClass().add("nav-primary");
HBox.setHgrow(primaryNav, Priority.SOMETIMES); 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, HBox priceAndBalance = new HBox(marketPriceBox.second, getNavigationSeparator(), availableBalanceBox.second,
getNavigationSeparator(), pendingBalanceBox.second, getNavigationSeparator(), reservedBalanceBox.second); getNavigationSeparator(), pendingBalanceBox.second, getNavigationSeparator(), reservedBalanceBox.second);
priceAndBalance.setMaxHeight(41);
priceAndBalance.setAlignment(Pos.CENTER); priceAndBalance.setAlignment(Pos.CENTER);
priceAndBalance.setSpacing(9); priceAndBalance.setSpacing(12);
priceAndBalance.getStyleClass().add("nav-price-balance"); priceAndBalance.getStyleClass().add("nav-price-balance");
HBox navPane = new HBox(primaryNav, secondaryNav, getNavigationSpacer(), HBox navPane = new HBox(primaryNav, priceAndBalance) {{
priceAndBalance) {{ setLeftAnchor(this, 25d);
setLeftAnchor(this, 0d); setRightAnchor(this, 25d);
setRightAnchor(this, 0d); setTopAnchor(this, 20d);
setTopAnchor(this, 0d);
setPadding(new Insets(0, 0, 0, 0)); setPadding(new Insets(0, 0, 0, 0));
getStyleClass().add("top-navigation"); getStyleClass().add("top-navigation");
}}; }};
navPane.setAlignment(Pos.CENTER); 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() {{ AnchorPane contentContainer = new AnchorPane() {{
getStyleClass().add("content-pane"); getStyleClass().add("content-pane");
setLeftAnchor(this, 0d); setLeftAnchor(this, 0d);
setRightAnchor(this, 0d); setRightAnchor(this, 0d);
setTopAnchor(this, 57d); setTopAnchor(this, 95d);
setBottomAnchor(this, 0d); setBottomAnchor(this, 0d);
}}; }};
AnchorPane applicationContainer = new AnchorPane(navPane, contentContainer) {{ AnchorPane applicationContainer = new AnchorPane(navPane, contentContainer, secondaryNavContainer) {{
setId("application-container"); setId("application-container");
}}; }};
@ -398,15 +414,32 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
private Separator getNavigationSeparator() { private Separator getNavigationSeparator() {
final Separator separator = new Separator(Orientation.VERTICAL); final Separator separator = new Separator(Orientation.VERTICAL);
HBox.setHgrow(separator, Priority.ALWAYS); HBox.setHgrow(separator, Priority.ALWAYS);
separator.setMaxHeight(22);
separator.setMaxWidth(Double.MAX_VALUE); separator.setMaxWidth(Double.MAX_VALUE);
separator.getStyleClass().add("nav-separator");
return 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 @NotNull
private Region getNavigationSpacer() { private Region getNavigationSpacer() {
final Region spacer = new Region(); final Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS); HBox.setHgrow(spacer, Priority.ALWAYS);
spacer.getStyleClass().add("nav-spacer");
return spacer; return spacer;
} }
@ -447,7 +480,6 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
priceComboBox.setVisibleRowCount(12); priceComboBox.setVisibleRowCount(12);
priceComboBox.setFocusTraversable(false); priceComboBox.setFocusTraversable(false);
priceComboBox.setId("price-feed-combo"); priceComboBox.setId("price-feed-combo");
priceComboBox.setPadding(new Insets(0, -4, -4, 0));
priceComboBox.setCellFactory(p -> getPriceFeedComboBoxListCell()); priceComboBox.setCellFactory(p -> getPriceFeedComboBoxListCell());
ListCell<PriceFeedComboBoxItem> buttonCell = getPriceFeedComboBoxListCell(); ListCell<PriceFeedComboBoxItem> buttonCell = getPriceFeedComboBoxListCell();
buttonCell.setId("price-feed-combo"); buttonCell.setId("price-feed-combo");
@ -458,7 +490,6 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
updateMarketPriceLabel(marketPriceLabel); updateMarketPriceLabel(marketPriceLabel);
marketPriceLabel.getStyleClass().add("nav-balance-label"); marketPriceLabel.getStyleClass().add("nav-balance-label");
marketPriceLabel.setPadding(new Insets(-2, 0, 4, 9));
marketPriceBox.getChildren().addAll(priceComboBox, marketPriceLabel); marketPriceBox.getChildren().addAll(priceComboBox, marketPriceLabel);
@ -509,7 +540,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
vBox.setId("splash"); vBox.setId("splash");
ImageView logo = new ImageView(); 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 // createBitcoinInfoBox
xmrSplashInfo = new AutoTooltipLabel(); xmrSplashInfo = new AutoTooltipLabel();
@ -552,7 +586,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
// create P2PNetworkBox // create P2PNetworkBox
splashP2PNetworkLabel = new AutoTooltipLabel(); splashP2PNetworkLabel = new AutoTooltipLabel();
splashP2PNetworkLabel.setWrapText(true); splashP2PNetworkLabel.setWrapText(true);
splashP2PNetworkLabel.setMaxWidth(500); splashP2PNetworkLabel.setMaxWidth(700);
splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER); splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER);
splashP2PNetworkLabel.getStyleClass().add("sub-info"); splashP2PNetworkLabel.getStyleClass().add("sub-info");
splashP2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo()); splashP2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
@ -587,9 +621,11 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
ImageView splashP2PNetworkIcon = new ImageView(); ImageView splashP2PNetworkIcon = new ImageView();
splashP2PNetworkIcon.setId("image-connection-tor"); splashP2PNetworkIcon.setId("image-connection-tor");
splashP2PNetworkIcon.setFitWidth(networkIconSize);
splashP2PNetworkIcon.setFitHeight(networkIconSize);
splashP2PNetworkIcon.setVisible(false); splashP2PNetworkIcon.setVisible(false);
splashP2PNetworkIcon.setManaged(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 -> { splashP2PNetworkIcon.setOnMouseClicked(e -> {
torNetworkSettingsWindow.show(); torNetworkSettingsWindow.show();
}); });
@ -603,6 +639,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
splashP2PNetworkIcon.setId(newValue); splashP2PNetworkIcon.setId(newValue);
splashP2PNetworkIcon.setVisible(true); splashP2PNetworkIcon.setVisible(true);
splashP2PNetworkIcon.setManaged(true); splashP2PNetworkIcon.setManaged(true);
splashP2PNetworkIcon.setFitWidth(networkIconSize);
splashP2PNetworkIcon.setFitHeight(networkIconSize);
// if we can connect in 10 sec. we know that tor is working // if we can connect in 10 sec. we know that tor is working
showTorNetworkSettingsTimer.stop(); showTorNetworkSettingsTimer.stop();
@ -725,15 +763,39 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
setRightAnchor(versionBox, 10d); setRightAnchor(versionBox, 10d);
setBottomAnchor(versionBox, 7d); 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 // P2P Network
Label p2PNetworkLabel = new AutoTooltipLabel(); Label p2PNetworkLabel = new AutoTooltipLabel();
p2PNetworkLabel.setId("footer-pane"); p2PNetworkLabel.setId("footer-pane");
p2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo()); p2PNetworkLabel.textProperty().bind(model.getP2PNetworkInfo());
double networkIconRightAnchor = 54d;
ImageView p2PNetworkIcon = new ImageView(); ImageView p2PNetworkIcon = new ImageView();
setRightAnchor(p2PNetworkIcon, 10d); setRightAnchor(p2PNetworkIcon, networkIconRightAnchor);
setBottomAnchor(p2PNetworkIcon, 5d); setBottomAnchor(p2PNetworkIcon, 6d);
p2PNetworkIcon.setPickOnBounds(true);
p2PNetworkIcon.setCursor(Cursor.HAND);
p2PNetworkIcon.setOpacity(0.4); p2PNetworkIcon.setOpacity(0.4);
p2PNetworkIcon.setFitWidth(networkIconSize);
p2PNetworkIcon.setFitHeight(networkIconSize);
p2PNetworkIcon.idProperty().bind(model.getP2PNetworkIconId()); p2PNetworkIcon.idProperty().bind(model.getP2PNetworkIconId());
p2PNetworkLabel.idProperty().bind(model.getP2pNetworkLabelId()); p2PNetworkLabel.idProperty().bind(model.getP2pNetworkLabelId());
model.getP2pNetworkWarnMsg().addListener((ov, oldValue, newValue) -> { model.getP2pNetworkWarnMsg().addListener((ov, oldValue, newValue) -> {
@ -749,8 +811,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
}); });
ImageView p2PNetworkStatusIcon = new ImageView(); ImageView p2PNetworkStatusIcon = new ImageView();
setRightAnchor(p2PNetworkStatusIcon, 30d); p2PNetworkStatusIcon.setPickOnBounds(true);
setBottomAnchor(p2PNetworkStatusIcon, 7d); p2PNetworkStatusIcon.setCursor(Cursor.HAND);
p2PNetworkStatusIcon.setFitWidth(networkIconSize);
p2PNetworkStatusIcon.setFitHeight(networkIconSize);
setRightAnchor(p2PNetworkStatusIcon, networkIconRightAnchor + 22);
setBottomAnchor(p2PNetworkStatusIcon, 6d);
Tooltip p2pNetworkStatusToolTip = new Tooltip(); Tooltip p2pNetworkStatusToolTip = new Tooltip();
Tooltip.install(p2PNetworkStatusIcon, p2pNetworkStatusToolTip); Tooltip.install(p2PNetworkStatusIcon, p2pNetworkStatusToolTip);
p2PNetworkStatusIcon.setOnMouseEntered(e -> p2pNetworkStatusToolTip.setText(model.getP2pConnectionSummary())); p2PNetworkStatusIcon.setOnMouseEntered(e -> p2pNetworkStatusToolTip.setText(model.getP2pConnectionSummary()));
@ -791,10 +857,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
VBox vBox = new VBox(); VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER_RIGHT); vBox.setAlignment(Pos.CENTER_RIGHT);
vBox.getChildren().addAll(p2PNetworkLabel, p2pNetworkProgressBar); vBox.getChildren().addAll(p2PNetworkLabel, p2pNetworkProgressBar);
setRightAnchor(vBox, 53d); setRightAnchor(vBox, networkIconRightAnchor + 45);
setBottomAnchor(vBox, 5d); 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"); setId("footer-pane");
setMinHeight(30); setMinHeight(30);
setMaxHeight(30); setMaxHeight(30);
@ -825,6 +891,9 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
this.setToggleGroup(navButtons); this.setToggleGroup(navButtons);
this.getStyleClass().add("nav-button"); 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 // Japanese fonts are dense, increase top nav button text size
if (model.getPreferences() != null && "ja".equals(model.getPreferences().getUserLanguage())) { if (model.getPreferences() != null && "ja".equals(model.getPreferences().getUserLanguage())) {
this.getStyleClass().add("nav-button-japanese"); 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); root.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
traditionalAccountsTab.setText(Res.get("account.menu.paymentAccount").toUpperCase()); traditionalAccountsTab.setText(Res.get("account.menu.paymentAccount"));
cryptoAccountsTab.setText(Res.get("account.menu.altCoinsAccountView").toUpperCase()); cryptoAccountsTab.setText(Res.get("account.menu.altCoinsAccountView"));
passwordTab.setText(Res.get("account.menu.password").toUpperCase()); passwordTab.setText(Res.get("account.menu.password"));
seedWordsTab.setText(Res.get("account.menu.seedWords").toUpperCase()); seedWordsTab.setText(Res.get("account.menu.seedWords"));
//walletInfoTab.setText(Res.get("account.menu.walletInfo").toUpperCase()); //walletInfoTab.setText(Res.get("account.menu.walletInfo"));
backupTab.setText(Res.get("account.menu.backup").toUpperCase()); backupTab.setText(Res.get("account.menu.backup"));
navigationListener = (viewPath, data) -> { navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(AccountView.class) == 1) { if (viewPath.size() == 3 && viewPath.indexOf(AccountView.class) == 1) {

View file

@ -216,7 +216,7 @@ public class CryptoAccountsView extends PaymentAccountsView<GridPane, CryptoAcco
} }
removeAccountRows(); removeAccountRows();
addAccountButton.setDisable(false); 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 = getPaymentMethodForm(current);
paymentMethodForm.addFormForEditAccount(); paymentMethodForm.addFormForEditAccount();
gridRow = paymentMethodForm.getGridRow(); gridRow = paymentMethodForm.getGridRow();

View file

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

View file

@ -535,7 +535,7 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi
} }
removeAccountRows(); removeAccountRows();
addAccountButton.setDisable(false); 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 = getPaymentMethodForm(current);
if (paymentMethodForm != null) { if (paymentMethodForm != null) {
paymentMethodForm.addFormForEditAccount(); paymentMethodForm.addFormForEditAccount();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -88,10 +88,10 @@ public class MarketView extends ActivatableView<TabPane, Void> {
@Override @Override
public void initialize() { public void initialize() {
offerBookTab.setText(Res.get("market.tabs.offerBook").toUpperCase()); offerBookTab.setText(Res.get("market.tabs.offerBook"));
spreadTab.setText(Res.get("market.tabs.spreadCurrency").toUpperCase()); spreadTab.setText(Res.get("market.tabs.spreadCurrency"));
spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment").toUpperCase()); spreadTabPaymentMethod.setText(Res.get("market.tabs.spreadPayment"));
tradesTab.setText(Res.get("market.tabs.trades").toUpperCase()); tradesTab.setText(Res.get("market.tabs.trades"));
navigationListener = (viewPath, data) -> { navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(MarketView.class) == 1) 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.common.util.Tuple4;
import haveno.core.locale.CurrencyUtil; import haveno.core.locale.CurrencyUtil;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.core.monetary.Volume;
import haveno.core.offer.Offer; import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection; import haveno.core.offer.OfferDirection;
import haveno.core.util.FormattingUtils; import haveno.core.util.FormattingUtils;
@ -65,13 +66,13 @@ import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart; import javafx.scene.chart.XYChart;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.SingleSelectionModel; import javafx.scene.control.SingleSelectionModel;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.control.TableCell; import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
@ -95,7 +96,10 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private AnchorPane chartPane; private AnchorPane chartPane;
private AutocompleteComboBox<CurrencyListItem> currencyComboBox; private AutocompleteComboBox<CurrencyListItem> currencyComboBox;
private Subscription tradeCurrencySubscriber; 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 final StringProperty priceColumnLabel = new SimpleStringProperty();
private AutoTooltipButton sellButton; private AutoTooltipButton sellButton;
private AutoTooltipButton buyButton; private AutoTooltipButton buyButton;
@ -106,10 +110,11 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private ListChangeListener<OfferBookListItem> changeListener; private ListChangeListener<OfferBookListItem> changeListener;
private ListChangeListener<CurrencyListItem> currencyListItemsListener; private ListChangeListener<CurrencyListItem> currencyListItemsListener;
private final double dataLimitFactor = 3; 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) -> { private final Function<Double, Double> offerTableViewHeight = (screenSize) -> {
// initial visible row count=5, header height=30 // 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); int extraRows = screenSize <= INITIAL_WINDOW_HEIGHT ? 0 : (int) ((screenSize - INITIAL_WINDOW_HEIGHT) / pixelsPerOfferTableRow);
return extraRows == 0 ? initialOfferTableViewHeight : Math.ceil(initialOfferTableViewHeight + ((extraRows + 1) * 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 = currencyComboBoxTuple.third;
this.currencyComboBox.setCellFactory(GUIUtil.getCurrencyListItemCellFactory(Res.get("shared.oneOffer"), this.currencyComboBox.setCellFactory(GUIUtil.getCurrencyListItemCellFactory(Res.get("shared.oneOffer"),
Res.get("shared.multipleOffers"), model.preferences)); Res.get("shared.multipleOffers"), model.preferences));
this.currencyComboBox.getStyleClass().add("input-with-border");
createChart(); createChart();
@ -200,7 +206,6 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty, tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty,
tradeCurrency -> { tradeCurrency -> {
String code = tradeCurrency.getCode(); String code = tradeCurrency.getCode();
volumeColumnLabel.set(Res.get("offerbook.volume", code));
xAxis.setTickLabelFormatter(new StringConverter<>() { xAxis.setTickLabelFormatter(new StringConverter<>() {
final int cryptoPrecision = 3; final int cryptoPrecision = 3;
final DecimalFormat df = new DecimalFormat(",###"); 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 viewBaseCurrencyCode = model.isCrypto() ? code : Res.getBaseCurrencyCode();
String viewPriceCurrencyCode = CurrencyUtil.isCryptoCurrency(code) ? Res.getBaseCurrencyCode() : code; String viewPriceCurrencyCode = model.isCrypto() ? Res.getBaseCurrencyCode() : code;
sellHeaderLabel.setText(Res.get("market.offerBook.sellOffersHeaderLabel", viewBaseCurrencyCode)); 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)); 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)); priceColumnLabel.set(Res.get("shared.priceWithCur", viewPriceCurrencyCode));
@ -288,8 +299,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
currencyComboBox.getSelectionModel().select(model.getSelectedCurrencyListItem().get()); currencyComboBox.getSelectionModel().select(model.getSelectedCurrencyListItem().get());
}; };
buyTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.BUY);
sellTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.SELL); sellTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.SELL);
buyTableRowSelectionListener = (observable, oldValue, newValue) -> model.goToOfferView(OfferDirection.BUY);
havenoWindowVerticalSizeListener = (observable, oldValue, newValue) -> layout(); havenoWindowVerticalSizeListener = (observable, oldValue, newValue) -> layout();
} }
@ -345,12 +356,27 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
} }
private synchronized void updateChartData() { 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(); seriesSell.getData().clear();
seriesBuy.getData().clear();
areaChart.getData().clear(); areaChart.getData().clear();
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData()));
seriesSell.getData().addAll(filterOutliersSell(model.getSellData())); seriesSell.getData().addAll(filterOutliersSell(model.getSellData()));
seriesBuy.getData().addAll(filterOutliersBuy(model.getBuyData()));
areaChart.getData().addAll(List.of(seriesBuy, seriesSell)); 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) { private Tuple4<TableView<OfferListItem>, VBox, Button, Label> getOfferTable(OfferDirection direction) {
TableView<OfferListItem> tableView = new TableView<>(); TableView<OfferListItem> tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView, false);
tableView.setMinHeight(initialOfferTableViewHeight); tableView.setMinHeight(initialOfferTableViewHeight);
tableView.setPrefHeight(initialOfferTableViewHeight); tableView.setPrefHeight(initialOfferTableViewHeight);
tableView.setMinWidth(480); tableView.setMinWidth(480);
tableView.getStyleClass().add("offer-table"); tableView.getStyleClass().addAll("offer-table", "non-interactive-table");
// price // price
TableColumn<OfferListItem, OfferListItem> priceColumn = new TableColumn<>(); TableColumn<OfferListItem, OfferListItem> priceColumn = new TableColumn<>();
@ -484,12 +511,14 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
} }
}); });
boolean isSellTable = model.isSellOffer(direction);
// volume // volume
TableColumn<OfferListItem, OfferListItem> volumeColumn = new TableColumn<>(); TableColumn<OfferListItem, OfferListItem> volumeColumn = new TableColumn<>();
volumeColumn.setMinWidth(115); volumeColumn.setMinWidth(115);
volumeColumn.setSortable(false); volumeColumn.setSortable(false);
volumeColumn.textProperty().bind(volumeColumnLabel); volumeColumn.textProperty().bind(isSellTable ? volumeSellColumnLabel : volumeBuyColumnLabel);
volumeColumn.getStyleClass().addAll("number-column", "first-column"); volumeColumn.getStyleClass().addAll("number-column");
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory( volumeColumn.setCellFactory(
new Callback<>() { new Callback<>() {
@ -546,7 +575,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}); });
// amount // 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.setMinWidth(115);
amountColumn.setSortable(false); amountColumn.setSortable(false);
amountColumn.getStyleClass().add("number-column"); amountColumn.getStyleClass().add("number-column");
@ -570,10 +600,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
} }
}); });
boolean isSellOffer = model.isSellOffer(direction);
// trader avatar // trader avatar
TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellOffer ? TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellTable ?
Res.get("shared.sellerUpperCase") : Res.get("shared.buyerUpperCase")) { Res.get("shared.sellerUpperCase") : Res.get("shared.buyerUpperCase")) {
{ {
setMinWidth(80); 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.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
avatarColumn.setCellFactory( avatarColumn.setCellFactory(
new Callback<>() { new Callback<>() {
@ -629,20 +657,16 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
tableView.setPlaceholder(placeholder); tableView.setPlaceholder(placeholder);
HBox titleButtonBox = new HBox(); HBox titleButtonBox = new HBox();
titleButtonBox.getStyleClass().add("offer-table-top");
titleButtonBox.setAlignment(Pos.CENTER); titleButtonBox.setAlignment(Pos.CENTER);
Label titleLabel = new AutoTooltipLabel(); Label titleLabel = new AutoTooltipLabel();
titleLabel.getStyleClass().add("table-title"); titleLabel.getStyleClass().add("table-title");
AutoTooltipButton button = new AutoTooltipButton(); AutoTooltipButton button = new AutoTooltipButton();
ImageView iconView = new ImageView(); button.setContentDisplay(ContentDisplay.RIGHT);
iconView.setId(isSellOffer ? "image-buy-white" : "image-sell-white");
button.setGraphic(iconView);
button.setGraphicTextGap(10); button.setGraphicTextGap(10);
button.updateText(isSellOffer ? Res.get("market.offerBook.buy") : Res.get("market.offerBook.sell"));
button.setMinHeight(32); button.setMinHeight(32);
button.setId(isSellOffer ? "buy-button-big" : "sell-button-big");
button.setOnAction(e -> model.goToOfferView(direction));
Region spacer = new Region(); Region spacer = new Region();
@ -653,9 +677,9 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
VBox vBox = new VBox(); VBox vBox = new VBox();
VBox.setVgrow(tableView, Priority.ALWAYS); VBox.setVgrow(tableView, Priority.ALWAYS);
vBox.setPadding(new Insets(0, 0, 0, 0)); vBox.setPadding(new Insets(0, 0, 0, 0));
vBox.setSpacing(10); vBox.setSpacing(0);
vBox.setFillWidth(true); vBox.setFillWidth(true);
vBox.setMinHeight(190); //vBox.setMinHeight(190);
vBox.getChildren().addAll(titleButtonBox, tableView); vBox.getChildren().addAll(titleButtonBox, tableView);
return new Tuple4<>(tableView, vBox, button, titleLabel); 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.GlobalSettings;
import haveno.core.locale.TradeCurrency; import haveno.core.locale.TradeCurrency;
import haveno.core.monetary.Price; import haveno.core.monetary.Price;
import haveno.core.monetary.Volume;
import haveno.core.offer.Offer; import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection; import haveno.core.offer.OfferDirection;
import haveno.core.offer.OpenOfferManager; import haveno.core.offer.OpenOfferManager;
@ -58,6 +59,7 @@ import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart; import javafx.scene.chart.XYChart;
import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -212,10 +214,42 @@ class OfferBookChartViewModel extends ActivatableViewModel {
} }
public boolean isSellOffer(OfferDirection direction) { public boolean isSellOffer(OfferDirection direction) {
// for cryptocurrency, buy direction is to buy XMR, so we need sell offers return direction == OfferDirection.SELL;
// 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; 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) { public boolean isMyOffer(Offer offer) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,10 +20,16 @@ package haveno.desktop.main.overlays.windows;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.name.Named; 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.UserThread;
import haveno.common.crypto.KeyRing; import haveno.common.crypto.KeyRing;
import haveno.common.util.Tuple2; import haveno.common.util.Tuple2;
import haveno.common.util.Tuple4; import haveno.common.util.Tuple4;
import haveno.common.util.Utilities;
import haveno.core.locale.CountryUtil; import haveno.core.locale.CountryUtil;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.core.monetary.Price; 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.Overlay;
import haveno.desktop.main.overlays.editor.PasswordPopup; import haveno.desktop.main.overlays.editor.PasswordPopup;
import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.popups.Popup;
import haveno.desktop.util.CssTheme;
import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.DisplayUtils;
import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; import static haveno.desktop.util.FormBuilder.addButtonAfterGroup;
import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel; import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea; import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea;
import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; 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 static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import haveno.desktop.util.GUIUtil; import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout; import haveno.desktop.util.Layout;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; 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.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextArea; import javafx.scene.control.TextArea;
import javafx.scene.control.Tooltip; import javafx.scene.control.Tooltip;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox; 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.EasyBind;
import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.Subscription;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -115,7 +128,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
this.tradePrice = tradePrice; this.tradePrice = tradePrice;
rowIndex = -1; rowIndex = -1;
width = 1118; width = Layout.DETAILS_WINDOW_WIDTH;
createGridPane(); createGridPane();
addContent(); addContent();
display(); display();
@ -124,7 +137,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
public void show(Offer offer) { public void show(Offer offer) {
this.offer = offer; this.offer = offer;
rowIndex = -1; rowIndex = -1;
width = 1118; width = Layout.DETAILS_WINDOW_WIDTH;
createGridPane(); createGridPane();
addContent(); addContent();
display(); display();
@ -194,7 +207,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
rows++; rows++;
} }
addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get(offer.isPrivateOffer() ? "shared.Offer" : "shared.Offer")); addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.Offer"));
String counterCurrencyDirectionInfo = ""; String counterCurrencyDirectionInfo = "";
String xmrDirectionInfo = ""; String xmrDirectionInfo = "";
@ -218,17 +231,22 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel, addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel,
DisplayUtils.getDirectionBothSides(direction, offer.isPrivateOffer()), firstRowDistance); DisplayUtils.getDirectionBothSides(direction, offer.isPrivateOffer()), firstRowDistance);
} }
String amount = Res.get("shared.xmrAmount"); String amount = Res.get("shared.xmrAmount");
addSeparator(gridPane, ++rowIndex);
if (takeOfferHandlerOptional.isPresent()) { if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
HavenoUtils.formatXmr(tradeAmount, true)); HavenoUtils.formatXmr(tradeAmount, true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo,
VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount))); VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount)));
} else { } else {
addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo, addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo,
HavenoUtils.formatXmr(offer.getAmount(), true)); HavenoUtils.formatXmr(offer.getAmount(), true));
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"),
HavenoUtils.formatXmr(offer.getMinAmount(), true)); HavenoUtils.formatXmr(offer.getMinAmount(), true));
addSeparator(gridPane, ++rowIndex);
String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume()); String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume());
String minVolume = ""; String minVolume = "";
if (offer.getVolume() != null && offer.getMinVolume() != null && if (offer.getVolume() != null && offer.getMinVolume() != null &&
@ -239,6 +257,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
} }
String priceLabel = Res.get("shared.price"); String priceLabel = Res.get("shared.price");
addSeparator(gridPane, ++rowIndex);
if (takeOfferHandlerOptional.isPresent()) { if (takeOfferHandlerOptional.isPresent()) {
addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, FormattingUtils.formatPrice(tradePrice)); addConfirmationLabelLabel(gridPane, ++rowIndex, priceLabel, FormattingUtils.formatPrice(tradePrice));
} else { } else {
@ -264,6 +283,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId); final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId);
String countryCode = offer.getCountryCode(); String countryCode = offer.getCountryCode();
boolean isMyOffer = offer.isMyOffer(keyRing); boolean isMyOffer = offer.isMyOffer(keyRing);
addSeparator(gridPane, ++rowIndex);
if (isMyOffer && makerPaymentAccountId != null && myPaymentAccount != null) { if (isMyOffer && makerPaymentAccountId != null && myPaymentAccount != null) {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName()); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName());
} else { } else {
@ -272,6 +292,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
} }
if (showXmrAutoConf) { if (showXmrAutoConf) {
addSeparator(gridPane, ++rowIndex);
String isAutoConf = offer.isXmrAutoConf() ? String isAutoConf = offer.isXmrAutoConf() ?
Res.get("shared.yes") : Res.get("shared.yes") :
Res.get("shared.no"); Res.get("shared.no");
@ -280,8 +301,10 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
if (showAcceptedBanks) { if (showAcceptedBanks) {
if (paymentMethod.equals(PaymentMethod.SAME_BANK)) { if (paymentMethod.equals(PaymentMethod.SAME_BANK)) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.bankId"), acceptedBanks.get(0)); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.bankId"), acceptedBanks.get(0));
} else if (isSpecificBanks) { } else if (isSpecificBanks) {
addSeparator(gridPane, ++rowIndex);
String value = Joiner.on(", ").join(acceptedBanks); String value = Joiner.on(", ").join(acceptedBanks);
String acceptedBanksLabel = Res.get("shared.acceptedBanks"); String acceptedBanksLabel = Res.get("shared.acceptedBanks");
Tooltip tooltip = new Tooltip(acceptedBanksLabel + " " + value); Tooltip tooltip = new Tooltip(acceptedBanksLabel + " " + value);
@ -291,6 +314,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
} }
} }
if (showAcceptedCountryCodes) { if (showAcceptedCountryCodes) {
addSeparator(gridPane, ++rowIndex);
String countries; String countries;
Tooltip tooltip = null; Tooltip tooltip = null;
if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes)) { if (CountryUtil.containsAllSepaEuroCountries(acceptedCountryCodes)) {
@ -313,29 +337,16 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
} }
if (isF2F) { if (isF2F) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("payment.f2f.city"), offer.getF2FCity()); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("payment.f2f.city"), offer.getF2FCity());
} }
if (showOfferExtraInfo) { if (showOfferExtraInfo) {
addSeparator(gridPane, ++rowIndex);
TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo"), "", 0).second; TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo"), "", 0).second;
textArea.setText(offer.getCombinedExtraInfo()); textArea.setText(offer.getCombinedExtraInfo().trim());
textArea.setMaxHeight(200); textArea.setMaxHeight(Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
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.setEditable(false); textArea.setEditable(false);
GUIUtil.adjustHeightAutomatically(textArea, Layout.DETAILS_WINDOW_EXTRA_INFO_MAX_HEIGHT);
} }
// get amount reserved for the offer // get amount reserved for the offer
@ -355,13 +366,16 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
if (offerChallenge != null) if (offerChallenge != null)
rows++; 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(), 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"), addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.makersOnion"),
offer.getMakerNodeAddress().getFullAddress()); offer.getMakerNodeAddress().getFullAddress());
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.creationDate"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.creationDate"),
DisplayUtils.formatDateTime(offer.getDate())); DisplayUtils.formatDateTime(offer.getDate()));
addSeparator(gridPane, ++rowIndex);
String value = Res.getWithColAndCap("shared.buyer") + String value = Res.getWithColAndCap("shared.buyer") +
" " + " " +
HavenoUtils.formatXmr(takeOfferHandlerOptional.isPresent() ? offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(tradeAmount) : offer.getOfferPayload().getMaxBuyerSecurityDeposit(), true) + 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); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
if (reservedAmount != null) { if (reservedAmount != null) {
addSeparator(gridPane, ++rowIndex);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.reservedAmount"), HavenoUtils.formatXmr(reservedAmount, true)); 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"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
CountryUtil.getNameAndCode(countryCode)); CountryUtil.getNameAndCode(countryCode));
}
if (offerChallenge != null) if (offerChallenge != null) {
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.challenge"), offerChallenge); 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()) { 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"), 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); labelLabelTuple2.second.setWrapText(true);
addConfirmAndCancelButtons(true); addConfirmAndCancelButtons(true);
} else if (takeOfferHandlerOptional.isPresent()) { } 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"), 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); labelLabelTuple2.second.setWrapText(true);
addConfirmAndCancelButtons(false); 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.buy")) :
Res.get("offerDetailsWindow.confirm.taker", Res.get("shared.sell")); 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, Tuple4<Button, BusyAnimation, Label, HBox> placeOfferTuple = addButtonBusyAnimationLabelAfterGroup(gridPane,
++rowIndex, 1, ++rowIndex, 1,
isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); isPlaceOffer ? placeOfferButtonText : takeOfferButtonText);
@ -428,11 +487,18 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
AutoTooltipButton confirmButton = (AutoTooltipButton) placeOfferTuple.first; AutoTooltipButton confirmButton = (AutoTooltipButton) placeOfferTuple.first;
confirmButton.setMinHeight(40); confirmButton.setMinHeight(40);
confirmButton.setPadding(new Insets(0, 20, 0, 20)); confirmButton.setPadding(new Insets(0, 20, 0, 20));
confirmButton.setGraphic(iconView);
confirmButton.setGraphicTextGap(10); confirmButton.setGraphicTextGap(10);
confirmButton.setId(isBuyerRole ? "buy-button-big" : "sell-button-big"); confirmButton.setId(isBuyerRole ? "buy-button-big" : "sell-button-big");
confirmButton.updateText(isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); 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; busyAnimation = placeOfferTuple.second;
Label spinnerInfoLabel = placeOfferTuple.third; Label spinnerInfoLabel = placeOfferTuple.third;

View file

@ -17,9 +17,12 @@
package haveno.desktop.main.overlays.windows; package haveno.desktop.main.overlays.windows;
import haveno.common.util.Tuple2;
import haveno.common.util.Utilities;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.AutoTooltipLabel;
import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.Overlay;
import haveno.desktop.util.GUIUtil;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@ -27,31 +30,35 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import net.glxn.qrgen.QRCode; import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType; import net.glxn.qrgen.image.ImageType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.net.URI;
public class QRCodeWindow extends Overlay<QRCodeWindow> { public class QRCodeWindow extends Overlay<QRCodeWindow> {
private static final Logger log = LoggerFactory.getLogger(QRCodeWindow.class); private static final Logger log = LoggerFactory.getLogger(QRCodeWindow.class);
private final ImageView qrCodeImageView; private final StackPane qrCodePane;
private final String moneroUri; private final String moneroUri;
public QRCodeWindow(String bitcoinURI) { public QRCodeWindow(String moneroUri) {
this.moneroUri = bitcoinURI; this.moneroUri = moneroUri;
Tuple2<StackPane, ImageView> qrCodeTuple = GUIUtil.getBigXmrQrCodePane();
qrCodePane = qrCodeTuple.first;
ImageView qrCodeImageView = qrCodeTuple.second;
final byte[] imageBytes = QRCode final byte[] imageBytes = QRCode
.from(bitcoinURI) .from(moneroUri)
.withSize(300, 300) .withSize(300, 300)
.to(ImageType.PNG) .to(ImageType.PNG)
.stream() .stream()
.toByteArray(); .toByteArray();
Image qrImage = new Image(new ByteArrayInputStream(imageBytes)); Image qrImage = new Image(new ByteArrayInputStream(imageBytes));
qrCodeImageView = new ImageView(qrImage); qrCodeImageView.setImage(qrImage);
qrCodeImageView.setFitHeight(250);
qrCodeImageView.setFitWidth(250);
qrCodeImageView.getStyleClass().add("qr-code");
type = Type.Information; type = Type.Information;
width = 468; width = 468;
@ -65,10 +72,11 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> {
addHeadLine(); addHeadLine();
addMessage(); addMessage();
GridPane.setRowIndex(qrCodeImageView, ++rowIndex); qrCodePane.setOnMouseClicked(event -> openWallet());
GridPane.setColumnSpan(qrCodeImageView, 2); GridPane.setRowIndex(qrCodePane, ++rowIndex);
GridPane.setHalignment(qrCodeImageView, HPos.CENTER); GridPane.setColumnSpan(qrCodePane, 2);
gridPane.getChildren().add(qrCodeImageView); GridPane.setHalignment(qrCodePane, HPos.CENTER);
gridPane.getChildren().add(qrCodePane);
String request = moneroUri.replace("%20", " ").replace("?", "\n?").replace("&", "\n&"); String request = moneroUri.replace("%20", " ").replace("?", "\n?").replace("&", "\n&");
Label infoLabel = new AutoTooltipLabel(Res.get("qRCodeWindow.request", request)); Label infoLabel = new AutoTooltipLabel(Res.get("qRCodeWindow.request", request));
@ -91,4 +99,12 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> {
public String getClipboardText() { public String getClipboardText() {
return moneroUri; 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 // 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... // dynamically updating height of window is a bit tricky.... @christoph feel free to improve if you like...
gridPane.setPrefHeight(600); gridPane.setPrefHeight(600);
gridPane.getStyleClass().add("popup-with-input");
gridPane.getColumnConstraints().get(1).setHgrow(Priority.NEVER); gridPane.getColumnConstraints().get(1).setHgrow(Priority.NEVER);
headLine(Res.get("popup.accountSigning.selectAccounts.headline")); headLine(Res.get("popup.accountSigning.selectAccounts.headline"));

View file

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

View file

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

View file

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

View file

@ -40,7 +40,7 @@ public class TradeFeedbackWindow extends Overlay<TradeFeedbackWindow> {
@Override @Override
public void show() { public void show() {
headLine(Res.get("tradeFeedbackWindow.title")); 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(); hideCloseButton();
actionButtonText(Res.get("shared.close")); actionButtonText(Res.get("shared.close"));
@ -51,6 +51,17 @@ public class TradeFeedbackWindow extends Overlay<TradeFeedbackWindow> {
protected void addMessage() { protected void addMessage() {
super.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")); AutoTooltipLabel messageLabel2 = new AutoTooltipLabel(Res.get("tradeFeedbackWindow.msg.part2"));
messageLabel2.setMouseTransparent(true); messageLabel2.setMouseTransparent(true);
messageLabel2.setWrapText(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.addConfirmationLabelTextFieldWithCopyIcon;
import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField;
import static haveno.desktop.util.FormBuilder.addMultilineLabel; import static haveno.desktop.util.FormBuilder.addMultilineLabel;
import static haveno.desktop.util.FormBuilder.addTitledGroupBg;
import java.math.BigInteger; import java.math.BigInteger;
@ -50,21 +49,20 @@ public class TxDetailsWindow extends Overlay<TxDetailsWindow> {
this.item = item; this.item = item;
rowIndex = -1; rowIndex = -1;
width = 918; width = 918;
if (headLine == null)
headLine = Res.get("txDetailsWindow.headline");
createGridPane(); createGridPane();
gridPane.setHgap(15); gridPane.setHgap(15);
addHeadLine(); addHeadLine();
addContent(); addContent();
addButtons(); addButtons();
addDontShowAgainCheckBox();
applyStyles(); applyStyles();
display(); display();
} }
protected void addContent() { protected void addContent() {
int rows = 10;
MoneroTxWallet tx = item.getTx(); MoneroTxWallet tx = item.getTx();
String memo = tx.getNote(); String memo = tx.getNote();
if (memo != null && !"".equals(memo)) rows++;
String txKey = null; String txKey = null;
boolean isOutgoing = tx.getOutgoingTransfer() != null; boolean isOutgoing = tx.getOutgoingTransfer() != null;
if (isOutgoing) { 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 // 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 // add sent or received note
String resKey = isOutgoing ? "txDetailsWindow.xmr.noteSent" : "txDetailsWindow.xmr.noteReceived"; String resKey = isOutgoing ? "txDetailsWindow.xmr.noteSent" : "txDetailsWindow.xmr.noteReceived";
GridPane.setColumnSpan(addMultilineLabel(gridPane, ++rowIndex, Res.get(resKey), 0), 2); GridPane.setColumnSpan(addMultilineLabel(gridPane, ++rowIndex, Res.get(resKey), 0), 2);
spacer = new Region(); Region spacer = new Region();
spacer.setMinHeight(15); spacer.setMinHeight(15);
gridPane.add(spacer, 0, ++rowIndex); gridPane.add(spacer, 0, ++rowIndex);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -56,9 +56,9 @@ public class SettingsView extends ActivatableView<TabPane, Void> {
@Override @Override
public void initialize() { public void initialize() {
preferencesTab.setText(Res.get("settings.tab.preferences").toUpperCase()); preferencesTab.setText(Res.get("settings.tab.preferences"));
networkTab.setText(Res.get("settings.tab.network").toUpperCase()); networkTab.setText(Res.get("settings.tab.network"));
aboutTab.setText(Res.get("settings.tab.about").toUpperCase()); aboutTab.setText(Res.get("settings.tab.about"));
navigationListener = (viewPath, data) -> { navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(SettingsView.class) == 1) 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 com.google.inject.Inject;
import haveno.common.app.Version; import haveno.common.app.Version;
import haveno.core.filter.FilterManager;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.ActivatableView;
import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.FxmlView;
@ -35,16 +36,18 @@ import javafx.scene.layout.GridPane;
@FxmlView @FxmlView
public class AboutView extends ActivatableView<GridPane, Void> { public class AboutView extends ActivatableView<GridPane, Void> {
private final FilterManager filterManager;
private int gridRow = 0; private int gridRow = 0;
@Inject @Inject
public AboutView() { public AboutView(FilterManager filterManager) {
super(); super();
this.filterManager = filterManager;
} }
@Override @Override
public void initialize() { 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 label = addLabel(root, gridRow, Res.get("setting.about.about"), Layout.TWICE_FIRST_ROW_DISTANCE);
label.setWrapText(true); label.setWrapText(true);
@ -77,8 +80,11 @@ public class AboutView extends ActivatableView<GridPane, Void> {
if (isXmr) if (isXmr)
addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.feeEstimation.label"), "Monero node"); 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("setting.about.version"), Version.VERSION, Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
addCompactTopLabelTextField(root, ++gridRow, Res.get("filterWindow.disableTradeBelowVersion"), minVersion);
addCompactTopLabelTextField(root, ++gridRow, addCompactTopLabelTextField(root, ++gridRow,
Res.get("setting.about.subsystems.label"), Res.get("setting.about.subsystems.label"),
Res.get("setting.about.subsystems.val", Res.get("setting.about.subsystems.val",

View file

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

View file

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

View file

@ -102,7 +102,7 @@ import org.apache.commons.lang3.StringUtils;
@FxmlView @FxmlView
public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> { public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> {
private final User user; private final User user;
private TextField btcExplorerTextField; private TextField xmrExplorerTextField;
private ComboBox<String> userLanguageComboBox; private ComboBox<String> userLanguageComboBox;
private ComboBox<Country> userCountryComboBox; private ComboBox<Country> userCountryComboBox;
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox; private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
@ -220,9 +220,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
userCountryComboBox.setButtonCell(GUIUtil.getComboBoxButtonCell(Res.get("shared.country"), userCountryComboBox, userCountryComboBox.setButtonCell(GUIUtil.getComboBoxButtonCell(Res.get("shared.country"), userCountryComboBox,
false)); false));
Tuple2<TextField, Button> btcExp = addTextFieldWithEditButton(root, ++gridRow, Res.get("setting.preferences.explorer")); Tuple2<TextField, Button> xmrExp = addTextFieldWithEditButton(root, ++gridRow, Res.get("setting.preferences.explorer"));
btcExplorerTextField = btcExp.first; xmrExplorerTextField = xmrExp.first;
editCustomBtcExplorer = btcExp.second; editCustomBtcExplorer = xmrExp.second;
// deviation // deviation
deviationInputTextField = addInputTextField(root, ++gridRow, 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.setText(FormattingUtils.formatToPercentWithSymbol(preferences.getMaxPriceDistanceInPercent()));
deviationInputTextField.textProperty().addListener(deviationListener); deviationInputTextField.textProperty().addListener(deviationListener);
@ -779,7 +779,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
.actionButtonText(Res.get("shared.save")) .actionButtonText(Res.get("shared.save"))
.onAction(() -> { .onAction(() -> {
preferences.setBlockChainExplorer(urlWindow.getEditedBlockChainExplorer()); preferences.setBlockChainExplorer(urlWindow.getEditedBlockChainExplorer());
btcExplorerTextField.setText(preferences.getBlockChainExplorer().name); xmrExplorerTextField.setText(preferences.getBlockChainExplorer().name);
}) })
.closeButtonText(Res.get("shared.cancel")) .closeButtonText(Res.get("shared.cancel"))
.onClose(urlWindow::hide) .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.main.overlays.popups.Popup;
import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.DisplayUtils;
import haveno.desktop.util.GUIUtil; import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.core.support.SupportManager; import haveno.core.support.SupportManager;
import haveno.core.support.SupportSession; 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.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon; 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.stage.FileChooser;
import javafx.scene.Node; import javafx.scene.Node;
@ -204,6 +205,7 @@ public class ChatView extends AnchorPane {
inputTextArea = new HavenoTextArea(); inputTextArea = new HavenoTextArea();
inputTextArea.setPrefHeight(70); inputTextArea.setPrefHeight(70);
inputTextArea.setWrapText(true); inputTextArea.setWrapText(true);
inputTextArea.getStyleClass().add("input-with-border");
if (!supportSession.isDisputeAgent()) { if (!supportSession.isDisputeAgent()) {
inputTextArea.setPromptText(Res.get("support.input.prompt")); inputTextArea.setPromptText(Res.get("support.input.prompt"));
@ -271,7 +273,7 @@ public class ChatView extends AnchorPane {
ImageView arrow = new ImageView(); ImageView arrow = new ImageView();
Label headerLabel = new AutoTooltipLabel(); Label headerLabel = new AutoTooltipLabel();
Label messageLabel = new AutoTooltipLabel(); Label messageLabel = new AutoTooltipLabel();
Label copyIcon = new Label(); Label copyLabel = new Label();
HBox attachmentsBox = new HBox(); HBox attachmentsBox = new HBox();
AnchorPane messageAnchorPane = new AnchorPane(); AnchorPane messageAnchorPane = new AnchorPane();
Label statusIcon = new Label(); Label statusIcon = new Label();
@ -292,10 +294,10 @@ public class ChatView extends AnchorPane {
statusIcon.getStyleClass().add("small-text"); statusIcon.getStyleClass().add("small-text");
statusInfoLabel.getStyleClass().add("small-text"); statusInfoLabel.getStyleClass().add("small-text");
statusInfoLabel.setPadding(new Insets(3, 0, 0, 0)); 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.setSpacing(5);
statusHBox.getChildren().addAll(statusIcon, statusInfoLabel); 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 @Override
@ -303,7 +305,13 @@ public class ChatView extends AnchorPane {
UserThread.execute(() -> { UserThread.execute(() -> {
super.updateItem(message, empty); super.updateItem(message, empty);
if (message != null && !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 -> { messageLabel.setOnMouseClicked(event -> {
if (2 > event.getClickCount()) { if (2 > event.getClickCount()) {
return; return;
@ -319,7 +327,7 @@ public class ChatView extends AnchorPane {
AnchorPane.clearConstraints(headerLabel); AnchorPane.clearConstraints(headerLabel);
AnchorPane.clearConstraints(arrow); AnchorPane.clearConstraints(arrow);
AnchorPane.clearConstraints(messageLabel); AnchorPane.clearConstraints(messageLabel);
AnchorPane.clearConstraints(copyIcon); AnchorPane.clearConstraints(copyLabel);
AnchorPane.clearConstraints(statusHBox); AnchorPane.clearConstraints(statusHBox);
AnchorPane.clearConstraints(attachmentsBox); AnchorPane.clearConstraints(attachmentsBox);
@ -328,7 +336,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setTopAnchor(headerLabel, 0d); AnchorPane.setTopAnchor(headerLabel, 0d);
AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d); AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d);
AnchorPane.setTopAnchor(messageLabel, 25d); AnchorPane.setTopAnchor(messageLabel, 25d);
AnchorPane.setTopAnchor(copyIcon, 25d); AnchorPane.setTopAnchor(copyLabel, 25d);
AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10); AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10);
boolean senderIsTrader = message.isSenderIsTrader(); boolean senderIsTrader = message.isSenderIsTrader();
@ -341,20 +349,20 @@ public class ChatView extends AnchorPane {
headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text", headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text",
"highlight-static"); "highlight-static");
messageLabel.getStyleClass().removeAll("my-message", "message"); messageLabel.getStyleClass().removeAll("my-message", "message");
copyIcon.getStyleClass().removeAll("my-message", "message"); copyLabel.getStyleClass().removeAll("my-message", "message");
if (message.isSystemMessage()) { if (message.isSystemMessage()) {
headerLabel.getStyleClass().addAll("message-header", "success-text"); headerLabel.getStyleClass().addAll("message-header", "success-text");
bg.setId("message-bubble-green"); bg.setId("message-bubble-green");
messageLabel.getStyleClass().add("my-message"); messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message"); copyLabel.getStyleClass().add("my-message");
message.addWeakMessageStateListener(() -> UserThread.execute(() -> updateMsgState(message))); message.addWeakMessageStateListener(() -> UserThread.execute(() -> updateMsgState(message)));
updateMsgState(message); updateMsgState(message);
} else if (isMyMsg) { } else if (isMyMsg) {
headerLabel.getStyleClass().add("my-message-header"); headerLabel.getStyleClass().add("my-message-header");
bg.setId("message-bubble-blue"); bg.setId("message-bubble-blue");
messageLabel.getStyleClass().add("my-message"); messageLabel.getStyleClass().add("my-message");
copyIcon.getStyleClass().add("my-message"); copyLabel.getStyleClass().add("my-message");
if (supportSession.isClient()) if (supportSession.isClient())
arrow.setId("bubble_arrow_blue_left"); arrow.setId("bubble_arrow_blue_left");
else else
@ -375,7 +383,7 @@ public class ChatView extends AnchorPane {
headerLabel.getStyleClass().add("message-header"); headerLabel.getStyleClass().add("message-header");
bg.setId("message-bubble-grey"); bg.setId("message-bubble-grey");
messageLabel.getStyleClass().add("message"); messageLabel.getStyleClass().add("message");
copyIcon.getStyleClass().add("message"); copyLabel.getStyleClass().add("message");
if (supportSession.isClient()) if (supportSession.isClient())
arrow.setId("bubble_arrow_grey_right"); arrow.setId("bubble_arrow_grey_right");
else else
@ -389,7 +397,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setRightAnchor(bg, border); AnchorPane.setRightAnchor(bg, border);
AnchorPane.setLeftAnchor(messageLabel, padding); AnchorPane.setLeftAnchor(messageLabel, padding);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight);
AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setRightAnchor(copyLabel, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.setLeftAnchor(statusHBox, padding); AnchorPane.setLeftAnchor(statusHBox, padding);
@ -400,7 +408,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setLeftAnchor(arrow, border); AnchorPane.setLeftAnchor(arrow, border);
AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth); AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight);
AnchorPane.setRightAnchor(copyIcon, padding); AnchorPane.setRightAnchor(copyLabel, padding);
AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth); AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setRightAnchor(attachmentsBox, padding); AnchorPane.setRightAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(statusHBox, padding); AnchorPane.setRightAnchor(statusHBox, padding);
@ -411,7 +419,7 @@ public class ChatView extends AnchorPane {
AnchorPane.setRightAnchor(arrow, border); AnchorPane.setRightAnchor(arrow, border);
AnchorPane.setLeftAnchor(messageLabel, padding); AnchorPane.setLeftAnchor(messageLabel, padding);
AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight + arrowWidth); AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight + arrowWidth);
AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth); AnchorPane.setRightAnchor(copyLabel, padding + arrowWidth);
AnchorPane.setLeftAnchor(attachmentsBox, padding); AnchorPane.setLeftAnchor(attachmentsBox, padding);
AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth); AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth);
AnchorPane.setLeftAnchor(statusHBox, padding); AnchorPane.setLeftAnchor(statusHBox, padding);
@ -454,8 +462,9 @@ public class ChatView extends AnchorPane {
} }
// Need to set it here otherwise style is not correct // Need to set it here otherwise style is not correct
AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY, "16.0"); copyLabel.getStyleClass().addAll("icon", "copy-icon-disputes");
copyIcon.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 // TODO There are still some cell rendering issues on updates
setGraphic(messageAnchorPane); setGraphic(messageAnchorPane);
@ -465,7 +474,7 @@ public class ChatView extends AnchorPane {
messageAnchorPane.prefWidthProperty().unbind(); messageAnchorPane.prefWidthProperty().unbind();
copyIcon.setOnMouseClicked(null); copyLabel.setOnMouseClicked(null);
messageLabel.setOnMouseClicked(null); messageLabel.setOnMouseClicked(null);
setGraphic(null); setGraphic(null);
} }

View file

@ -139,9 +139,9 @@ public class SupportView extends ActivatableView<TabPane, Void> {
// Has to be called before loadView // Has to be called before loadView
updateAgentTabs(); updateAgentTabs();
tradersMediationDisputesTab.setText(Res.get("support.tab.mediation.support").toUpperCase()); tradersMediationDisputesTab.setText(Res.get("support.tab.mediation.support"));
tradersRefundDisputesTab.setText(Res.get("support.tab.refund.support").toUpperCase()); tradersRefundDisputesTab.setText(Res.get("support.tab.refund.support"));
tradersArbitrationDisputesTab.setText(Res.get("support.tab.arbitration.support").toUpperCase()); tradersArbitrationDisputesTab.setText(Res.get("support.tab.arbitration.support"));
navigationListener = (viewPath, data) -> { navigationListener = (viewPath, data) -> {
if (viewPath.size() == 3 && viewPath.indexOf(SupportView.class) == 1) 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 // We might get that method called before we have the map is filled in the arbitratorManager
if (arbitratorTab != null) { 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) { if (signedOfferTab != null) {
signedOfferTab.setText(Res.get("support.tab.SignedOffers").toUpperCase()); signedOfferTab.setText(Res.get("support.tab.SignedOffers"));
} }
if (mediatorTab != null) { 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) { 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 @Override
public void initialize() { 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 = new InputTextField();
filterTextField.setPromptText(Res.get("support.filter.prompt")); filterTextField.setPromptText(Res.get("shared.filter"));
Tooltip tooltip = new Tooltip(); Tooltip tooltip = new Tooltip();
tooltip.setShowDelay(Duration.millis(100)); tooltip.setShowDelay(Duration.millis(100));
tooltip.setShowDuration(Duration.seconds(10)); tooltip.setShowDuration(Duration.seconds(10));
@ -298,8 +294,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
HBox filterBox = new HBox(); HBox filterBox = new HBox();
filterBox.setSpacing(5); filterBox.setSpacing(5);
filterBox.getChildren().addAll(label, filterBox.getChildren().addAll(filterTextField,
filterTextField,
alertIconLabel, alertIconLabel,
spacer, spacer,
reOpenButton, reOpenButton,
@ -311,6 +306,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
VBox.setVgrow(filterBox, Priority.NEVER); VBox.setVgrow(filterBox, Priority.NEVER);
tableView = new TableView<>(); tableView = new TableView<>();
GUIUtil.applyTableStyle(tableView);
VBox.setVgrow(tableView, Priority.SOMETIMES); VBox.setVgrow(tableView, Priority.SOMETIMES);
tableView.setMinHeight(150); tableView.setMinHeight(150);
@ -957,7 +953,6 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
{ {
setMaxWidth(80); setMaxWidth(80);
setMinWidth(65); setMinWidth(65);
getStyleClass().addAll("first-column", "avatar-column");
setSortable(false); setSortable(false);
} }
}; };
@ -1354,7 +1349,6 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> implements
setMinWidth(50); setMinWidth(50);
} }
}; };
column.getStyleClass().add("last-column");
column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue()));
column.setCellFactory( column.setCellFactory(
new Callback<>() { new Callback<>() {

View file

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

View file

@ -20,10 +20,10 @@
/* haveno main colors */ /* haveno main colors */
-bs-color-primary: #0b65da; -bs-color-primary: #0b65da;
-bs-color-primary-dark: #0c59bd; -bs-color-primary-dark: #0c59bd;
-bs-text-color: #dadada; -bs-text-color: white;
-bs-background-color: #29292a; -bs-background-color: black;
-bs-background-gray: #2B2B2B; -bs-background-gray: transparent;
-bs-content-background-gray: #1F1F1F; -bs-content-background-gray: black;
/* fifty shades of gray */ /* fifty shades of gray */
-bs-color-gray-13: #bbb; -bs-color-gray-13: #bbb;
@ -43,7 +43,19 @@
-bs-color-gray-bbb: #5a5a5a; -bs-color-gray-bbb: #5a5a5a;
-bs-color-gray-aaa: #29292a; -bs-color-gray-aaa: #29292a;
-bs-color-gray-fafa: #0a0a0a; -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 */ /* lesser used colors */
-bs-color-blue-5: #0a4576; -bs-color-blue-5: #0a4576;
@ -70,11 +82,15 @@
-bs-rd-nav-border: #535353; -bs-rd-nav-border: #535353;
-bs-rd-nav-primary-border: rgba(0, 0, 0, 0); -bs-rd-nav-primary-border: rgba(0, 0, 0, 0);
-bs-rd-nav-border-color: rgba(255, 255, 255, 0.1); -bs-rd-nav-border-color: rgba(255, 255, 255, 0.1);
-bs-rd-nav-background: #141414; -bs-rd-nav-background: rgb(15, 15, 15);
-bs-rd-nav-primary-background: rgba(255, 255, 255, 0.015); -bs-rd-nav-primary-background: rgb(15, 15, 15);
-bs-rd-nav-selected: #fff; -bs-rd-nav-selected: black;
-bs-rd-nav-deselected: rgba(255, 255, 255, 0.45); -bs-rd-nav-deselected: rgba(255, 255, 255, 1);
-bs-rd-nav-button-hover: rgba(255, 255, 255, 0.03); -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-content-pane-bg-top: #212121;
-bs-rd-tab-border: rgba(255, 255, 255, 0.00); -bs-rd-tab-border: rgba(255, 255, 255, 0.00);
@ -90,7 +106,7 @@
-bs-footer-pane-text: #cfcecf; -bs-footer-pane-text: #cfcecf;
-bs-footer-pane-line: #29292a; -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-gray: #d4d4d4;
-bs-rd-font-dark: #cccccc; -bs-rd-font-dark: #cccccc;
-bs-rd-font-light: #b4b4b4; -bs-rd-font-light: #b4b4b4;
@ -99,28 +115,28 @@
-bs-rd-font-confirmation-label: #504f52; -bs-rd-font-confirmation-label: #504f52;
-bs-rd-font-balance-label: #999999; -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-text-color-transparent: rgba(29, 29, 33, 0.2);
-bs-color-gray-line: #504f52; -bs-color-gray-line: #504f52;
-bs-rd-separator: #1F1F1F; -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-red: #d83431;
-bs-rd-error-field: #521C1C; -bs-rd-error-field: #521C1C;
-bs-rd-message-bubble: #0086c6; -bs-rd-message-bubble: #0086c6;
-bs-rd-tooltip-truncated: #afaeb0; -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-warning: #db6300;
-bs-buy: #006600; -bs-buy: rgb(80, 180, 90);
-bs-buy-focus: black; -bs-buy-focus: derive(-bs-buy, -50%);
-bs-buy-hover: #237b2d; -bs-buy-hover: derive(-bs-buy, -10%);
-bs-buy-transparent: rgba(46, 163, 60, 0.3); -bs-sell: rgb(213, 63, 46);
-bs-sell: #660000; -bs-sell-focus: derive(-bs-sell, -50%);
-bs-sell-focus: #090202; -bs-sell-hover: derive(-bs-sell, -10%);
-bs-sell-hover: #b42522; -bs-volume-transparent: -bs-buy;
-bs-sell-transparent: rgba(216, 52, 49, 0.3);
-bs-volume-transparent: rgba(37, 177, 54, 0.5);
-bs-candle-stick-average-line: rgba(21, 188, 29, 0.8); -bs-candle-stick-average-line: rgba(21, 188, 29, 0.8);
-bs-candle-stick-loss: #ee6563; -bs-candle-stick-loss: #ee6563;
-bs-candle-stick-won: #15bc1d; -bs-candle-stick-won: #15bc1d;
@ -154,7 +170,7 @@
/* Monero orange color code */ /* Monero orange color code */
-xmr-orange: #f26822; -xmr-orange: #f26822;
-bs-support-chat-background: #cccccc; -bs-support-chat-background: rgb(125, 125, 125);
} }
/* table view */ /* table view */
@ -164,7 +180,7 @@
} }
.table-view .column-header { .table-view .column-header {
-fx-background-color: derive(-bs-background-color,-50%); -fx-background-color: -bs-color-background-pane;
-fx-border-width: 0; -fx-border-width: 0;
} }
@ -173,21 +189,31 @@
-fx-border-width: 0; -fx-border-width: 0;
} }
/** These must be set to override default styles */
.table-view .table-row-cell:even .table-cell { .table-view .table-row-cell:even .table-cell {
-fx-background-color: derive(-bs-background-color, -5%); -fx-background-color: -bs-color-background-row-even;
-fx-border-color: derive(-bs-background-color, -5%); -fx-border-color: -bs-color-background-row-even;
} }
.table-view .table-row-cell:odd .table-cell { .table-view .table-row-cell:odd .table-cell {
-fx-background-color: derive(-bs-background-color,-30%); -fx-background-color: -bs-color-background-row-odd;
-fx-border-color: derive(-bs-background-color,-30%); -fx-border-color: -bs-color-background-row-odd;
} }
.table-view .table-row-cell:selected .table-cell { .table-view .table-row-cell:selected .table-cell {
-fx-background: -fx-accent; -fx-background: -fx-accent;
-fx-background-color: -fx-selection-bar; -fx-background-color: -fx-selection-bar;
-fx-border-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 { .table-row-cell {
-fx-border-color: -bs-background-color; -fx-border-color: -bs-background-color;
@ -208,35 +234,49 @@
-fx-background-color: -bs-tab-content-area; -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 { .nav-secondary-button:selected .text {
-fx-background-color: derive(-bs-color-gray-background, -20%); -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 */ /* text field */
.jfx-text-field, .jfx-text-area, .jfx-text-field, .jfx-text-area,
.jfx-combo-box, .jfx-combo-box > .list-cell { .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-prompt-text-fill: -bs-color-gray-6;
-fx-text-fill: -bs-color-gray-12; -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 { .hyperlink-with-icon {
-fx-background: -bs-background-color; -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-prompt-text-fill: -bs-color-gray-2;
-fx-text-fill: -bs-color-gray-3; -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-combo-box > .text,
.jfx-text-field-top-label, .jfx-text-area-top-label { .jfx-text-field-top-label, .jfx-text-area-top-label {
-fx-text-fill: -bs-color-gray-11; -fx-text-fill: -bs-color-gray-11;
} }
.input-with-border { .offer-input {
-fx-border-color: -bs-color-gray-2; -fx-border-color: -bs-color-gray-2;
-fx-border-width: 0 0 10 0; -fx-border-width: 0 0 10 0;
} }
@ -254,11 +294,6 @@
-fx-text-fill: -fx-dark-text-color; -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 { .axis:top, .axis:right, .axis:bottom, .axis:left {
-fx-border-color: transparent transparent transparent transparent; -fx-border-color: transparent transparent transparent transparent;
} }
@ -332,7 +367,7 @@
} }
.combo-box-popup > .list-view{ .combo-box-popup > .list-view{
-fx-background-color: -bs-background-color; -fx-background-color: -bs-color-background-pane;
} }
.jfx-combo-box > .arrow-button > .arrow { .jfx-combo-box > .arrow-button > .arrow {
@ -352,7 +387,6 @@
} }
.list-view .list-cell:odd, .list-view .list-cell:even { .list-view .list-cell:odd, .list-view .list-cell:even {
-fx-background-color: -bs-background-color;
-fx-border-width: 0; -fx-border-width: 0;
} }
@ -371,18 +405,6 @@
-fx-border-width: 0; -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 { .jfx-text-field-top-label {
-fx-text-fill: -bs-color-gray-dim; -fx-text-fill: -bs-color-gray-dim;
} }
@ -401,7 +423,6 @@
.jfx-combo-box:error:focused, .jfx-combo-box:error:focused,
.jfx-text-field:error:focused{ .jfx-text-field:error:focused{
-fx-text-fill: -bs-rd-error-red;
-fx-background-color: derive(-bs-rd-error-field, -5%); -fx-background-color: derive(-bs-rd-error-field, -5%);
} }
@ -417,11 +438,7 @@
-jfx-disable-animation: true; -jfx-disable-animation: true;
} }
.jfx-password-field { .offer-input {
-fx-background-color: derive(-bs-background-color, -15%);
}
.input-with-border {
-fx-border-width: 0; -fx-border-width: 0;
-fx-border-color: -bs-background-color; -fx-border-color: -bs-background-color;
} }
@ -448,11 +465,6 @@
-jfx-disable-animation: true; -jfx-disable-animation: true;
} }
.top-navigation {
-fx-border-width: 0 0 0 0;
-fx-padding: 0 7 0 0;
}
.nav-price-balance { .nav-price-balance {
-fx-effect: null; -fx-effect: null;
} }
@ -462,37 +474,17 @@
} }
.nav-button:selected { .nav-button:selected {
-fx-background-color: derive(-bs-color-primary-dark, -10%); -fx-background-color: white;
-fx-effect: null; -fx-effect: null;
} }
.nav-button:hover {
-fx-background-color: -bs-rd-nav-button-hover;
}
.nav-primary .nav-button:selected { .nav-primary .nav-button:selected {
-fx-background-color: derive(-bs-color-primary-dark, -5%); -fx-background-color: derive(white, -5%);
} }
.table-view { .table-view {
-fx-border-color: transparent; -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 { .jfx-tab-pane .headers-region .tab .tab-container .tab-label {
-fx-cursor: hand; -fx-cursor: hand;
-jfx-disable-animation: true; -jfx-disable-animation: true;
@ -559,12 +551,95 @@
} }
.toggle-button-no-slider { .toggle-button-no-slider {
-fx-focus-color: transparent; -fx-background-color: -bs-color-background-form-field;
-fx-faint-focus-color: transparent;
-fx-background-radius: 3;
-fx-background-insets: 0, 1;
} }
.toggle-button-no-slider:selected { .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; -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: #0b65da;
-bs-rd-green-dark: #3EA34A; -bs-rd-green-dark: #3EA34A;
-bs-rd-nav-selected: #0b65da; -bs-rd-nav-selected: #0b65da;
-bs-rd-nav-deselected: rgba(255, 255, 255, 0.75); -bs-rd-nav-deselected: rgba(255, 255, 255, 1);
-bs-rd-nav-background: #0c59bd; -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-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-primary-border: #0B65DA;
-bs-rd-nav-border: #535353; -bs-rd-nav-border: #535353;
-bs-rd-nav-border-color: rgba(255, 255, 255, 0.31); -bs-rd-nav-border-color: rgba(255, 255, 255, 0.31);
-bs-rd-nav-hover-text: white;
-bs-rd-tab-border: #e2e0e0; -bs-rd-tab-border: #e2e0e0;
-bs-tab-content-area: #ffffff; -bs-tab-content-area: #ffffff;
-bs-color-gray-background: #f2f2f2; -bs-color-gray-background: #f2f2f2;
@ -58,32 +63,31 @@
-bs-footer-pane-background: #dddddd; -bs-footer-pane-background: #dddddd;
-bs-footer-pane-text: #4b4b4b; -bs-footer-pane-text: #4b4b4b;
-bs-footer-pane-line: #bbb; -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-gray: #3c3c3c;
-bs-rd-font-dark: #4b4b4b; -bs-rd-font-dark: #4b4b4b;
-bs-rd-font-light: #8d8d8d; -bs-rd-font-light: #8d8d8d;
-bs-rd-font-lighter: #a7a7a7; -bs-rd-font-lighter: #a7a7a7;
-bs-rd-font-confirmation-label: #504f52; -bs-rd-font-confirmation-label: #504f52;
-bs-rd-font-balance-label: #8e8e8e; -bs-rd-font-balance-label: #bbbbbb;
-bs-text-color-transparent-dark: rgba(0, 0, 0, 0.54); -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-text-color-transparent: rgba(0, 0, 0, 0.2);
-bs-color-gray-line: #979797; -bs-color-gray-line: #979797;
-bs-rd-separator: #dbdbdb; -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-error-red: #dd0000;
-bs-rd-message-bubble: #0086c6; -bs-rd-message-bubble: #0086c6;
-bs-toggle-selected: #7b7b7b; -bs-toggle-selected: #7b7b7b;
-bs-rd-tooltip-truncated: #0a0a0a; -bs-rd-tooltip-truncated: #0a0a0a;
-bs-warning: #ff8a2b; -bs-warning: #ff8a2b;
-bs-buy: #3ea34a; -bs-buy: rgb(80, 180, 90);
-bs-buy-focus: derive(-bs-buy, -50%); -bs-buy-focus: derive(-bs-buy, -50%);
-bs-buy-hover: derive(-bs-buy, -10%); -bs-buy-hover: derive(-bs-buy, -10%);
-bs-buy-transparent: rgba(62, 163, 74, 0.3); -bs-sell: rgb(213, 63, 46);
-bs-sell: #d73030;
-bs-sell-focus: derive(-bs-sell, -50%); -bs-sell-focus: derive(-bs-sell, -50%);
-bs-sell-hover: derive(-bs-sell, -10%); -bs-sell-hover: derive(-bs-sell, -10%);
-bs-sell-transparent: rgba(215, 48, 48, 0.3); -bs-volume-transparent: -bs-buy;
-bs-volume-transparent: rgba(37, 177, 53, 0.3);
-bs-candle-stick-average-line: -bs-rd-green; -bs-candle-stick-average-line: -bs-rd-green;
-bs-candle-stick-loss: #fe3001; -bs-candle-stick-loss: #fe3001;
-bs-candle-stick-won: #20b221; -bs-candle-stick-won: #20b221;
@ -104,6 +108,19 @@
-bs-prompt-text: -fx-control-inner-background; -bs-prompt-text: -fx-control-inner-background;
-bs-soft-red: #aa4c3b; -bs-soft-red: #aa4c3b;
-bs-turquoise-light: #11eeee; -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 */ /* Monero orange color code */
-xmr-orange: #f26822; -xmr-orange: #f26822;
@ -126,7 +143,33 @@
-fx-background-color: -bs-color-gray-3; -fx-background-color: -bs-color-gray-3;
} }
.toggle-button-no-slider { #image-logo-splash {
-fx-focus-color: transparent; -fx-image: url("../../images/logo_splash_light.png");
-fx-faint-focus-color: transparent; }
#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"); scene.getStylesheets().add(cssThemeFolder + "theme-dev.css");
} }
public static int getCurrentTheme() {
return currentCSSTheme;
}
public static boolean isDarkTheme() { public static boolean isDarkTheme() {
return currentCSSTheme == CSS_THEME_DARK; return currentCSSTheme == CSS_THEME_DARK;
} }

View file

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

View file

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

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