Browse Source

Merge branch 'master' into pirate-chain

# Conflicts:
#	qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js
#	qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js
pirate-chain
CalDescent 2 years ago
parent
commit
f4563157b2
  1. 1
      .gitignore
  2. BIN
      img/ru-flag-round-icon-32.png
  3. 10
      package.json
  4. 16
      qortal-ui-core/language/de.json
  5. 16
      qortal-ui-core/language/es.json
  6. 18
      qortal-ui-core/language/fr.json
  7. 16
      qortal-ui-core/language/hindi.json
  8. 16
      qortal-ui-core/language/hr.json
  9. 1132
      qortal-ui-core/language/hu.json
  10. 16
      qortal-ui-core/language/it.json
  11. 20
      qortal-ui-core/language/pl.json
  12. 16
      qortal-ui-core/language/pt.json
  13. 16
      qortal-ui-core/language/rs.json
  14. 589
      qortal-ui-core/language/ru.json
  15. 16
      qortal-ui-core/language/us.json
  16. 18
      qortal-ui-core/language/zhc.json
  17. 16
      qortal-ui-core/language/zht.json
  18. 26
      qortal-ui-core/package.json
  19. 3
      qortal-ui-core/src/components/app-view.js
  20. 4
      qortal-ui-core/src/components/language-selector.js
  21. 37
      qortal-ui-core/src/components/login-view/create-account-section.js
  22. 186
      qortal-ui-core/src/components/login-view/loading-ripple_old.js
  23. 3
      qortal-ui-core/src/components/sidenav-menu.js
  24. 10
      qortal-ui-core/src/functional-components/loading-ripple.js
  25. 1
      qortal-ui-core/src/redux/app/version.js
  26. 21
      qortal-ui-plugins/package.json
  27. 164
      qortal-ui-plugins/plugins/core/components/BlockAddress.js
  28. 87
      qortal-ui-plugins/plugins/core/components/ChatPage.js
  29. 34
      qortal-ui-plugins/plugins/core/components/ChatScroller.js
  30. 2
      qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js
  31. 622
      qortal-ui-plugins/plugins/core/components/NameMenu.js
  32. 1
      qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js
  33. 24
      qortal-ui-plugins/plugins/core/minting/minting-info.src.js
  34. 180
      qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js

1
.gitignore vendored

@ -4,6 +4,7 @@ yarn.lock
# Derived js files
qortal-ui-plugins/plugins/core/**/*.js
!*.src.js
qortal-ui-core/src/redux/app/version.js
# Node modules
node_modules/

BIN
img/ru-flag-round-icon-32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

10
package.json

@ -1,6 +1,6 @@
{
"name": "qortal-ui",
"version": "1.9.1",
"version": "1.9.2",
"description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet",
"keywords": [
"QORT",
@ -31,14 +31,14 @@
"publish": "electron-builder -p always"
},
"dependencies": {
"electron-updater": "5.0.1",
"electron-updater": "4.6.5",
"electron-log": "4.4.6"
},
"devDependencies": {
"electron": "17.4.1",
"electron-builder": "23.0.3",
"electron": "17.1.2",
"electron-builder": "22.14.13",
"electron-notarize": "1.2.1",
"electron-packager": "15.5.1",
"electron-packager": "15.4.0",
"shelljs": "0.8.5"
},
"engines": {

16
qortal-ui-core/language/de.json

@ -14,7 +14,8 @@
"portuguese": "Portugiesisch",
"hungarian": "Ungarisch",
"serbian": "Serbisch",
"italian": "Italienisch"
"italian": "Italienisch",
"russian": "Russisch"
},
"sidemenu": {
"mintingdetails": "PRÄGUNGSDETAILS",
@ -211,7 +212,9 @@
"wchange39": "Adresse kann nicht kopiert werden.",
"wchange40": "ZAHLUNG",
"wchange41": "Status",
"wchange42": "Bestätigungen"
"wchange42": "Bestätigungen",
"wchange43": "Ihre Transaktion wird erst angezeigt, wenn sie bestätigt wurde. Seien Sie geduldig...",
"wchange44": "Bitte versuche es erneut..."
},
"tradepage": {
"tchange1": "Handelsportal",
@ -434,10 +437,15 @@
"wcchange9": "Senden fehlgeschlagen, bitte erneut versuchen..."
},
"blockpage": {
"bcchange1": "blockieren",
"bcchange1": "Benutzer Blockieren",
"bcchange2": "Dieser Benutzer wurde erfolgreich blockiert!",
"bcchange3": "Beim Blockieren dieses Benutzers ist ein Fehler aufgetreten. Bitte versuche es erneut!",
"bcchange4": "Kein Name registriert"
"bcchange4": "Kein Name registriert",
"bcchange5": "Diesen Benutzer Blockieren",
"bcchange6": "Möchten Sie diesen Benutzer wirklich blockieren?",
"bcchange7": "MENÜ",
"bcchange8": "Adresse Kopieren",
"bcchange9": "Private Nachricht"
},
"grouppage": {
"gchange1": "Qortal-Gruppen",

16
qortal-ui-core/language/es.json

@ -14,7 +14,8 @@
"portuguese": "Portugués",
"hungarian": "Húngaro",
"serbian": "Serbio",
"italian": "Italiano"
"italian": "Italiano",
"russian": "Ruso"
},
"sidemenu": {
"mintingdetails": "DETALLES DE ACUÑACIÓN",
@ -211,7 +212,9 @@
"wchange39": "No se puede copiar la dirección.",
"wchange40": "PAGO",
"wchange41": "Estado",
"wchange42": "Confirmaciones"
"wchange42": "Confirmaciones",
"wchange43": "Su transacción no se mostrará hasta que se confirme, sea paciente...",
"wchange44": "Inténtalo de nuevo..."
},
"tradepage": {
"tchange1": "Portal de Comercio",
@ -434,10 +437,15 @@
"wcchange9": "El envío ha fallado, por favor intente de nuevo..."
},
"blockpage": {
"bcchange1": "bloquear",
"bcchange1": "Bloquear Usuario",
"bcchange2": "Se ha bloqueado con éxito a este usuario!",
"bcchange3": "Ha ocurrido un error al intentar bloquear este usuario. Por favor, inténtelo de nuevo!",
"bcchange4": "Nombre no registrado"
"bcchange4": "Nombre no registrado",
"bcchange5": "Bloquear solicitud de usuario",
"bcchange6": "Estás seguro de bloquear a este usuario?",
"bcchange7": "MENÚ",
"bcchange8": "Copiar Dirección",
"bcchange9": "Mensaje Privado"
},
"grouppage": {
"gchange1": "Grupos Qortal",

18
qortal-ui-core/language/fr.json

@ -14,7 +14,8 @@
"portuguese": "Portugais",
"hungarian": "Hongrois",
"serbian": "Serbe",
"italian": "Italien"
"italian": "Italien",
"russian": "Russe"
},
"sidemenu": {
"mintingdetails": "DETAILS DE FRAPPE",
@ -186,7 +187,7 @@
"wchange14": "Date",
"wchange15": "Signature de la transaction",
"wchange16": "Hachage de la transaction",
"wchange17": "Envoyé",
"wchange17": "Envoyer",
"wchange18": "Depuis l'adresse",
"wchange19": "Solde disponible",
"wchange20": "A (adresse ou nom)",
@ -211,7 +212,9 @@
"wchange39": "Impossible de copier l’adresse.",
"wchange40": "PAIEMENT",
"wchange41": "Status",
"wchange42": "Confirmations"
"wchange42": "Confirmations",
"wchange43": "Votre transaction ne s'affichera pas tant qu'elle n'aura pas été confirmée, soyez patient...",
"wchange44": "Veuillez réessayer..."
},
"tradepage": {
"tchange1": "Portail de commerce",
@ -434,10 +437,15 @@
"wcchange9": "Échec de l’envoi, veuillez réessayer..."
},
"blockpage": {
"bcchange1": "bloquer",
"bcchange1": "Bloquer un Utilisateur",
"bcchange2": "Blocage réussi de cet utilisateur!",
"bcchange3": "Une erreur s’est produite lors de la tentative de blocage de cet utilisateur. Veuillez réessayer!",
"bcchange4": "Pas de nom enregistré"
"bcchange4": "Pas de nom enregistré",
"bcchange5": "Bloquer la demande de l'utilisateur",
"bcchange6": "Êtes-vous sûr de bloquer cet utilisateur ?",
"bcchange7": "MENU",
"bcchange8": "Copier l'Adresse",
"bcchange9": "Message Privé"
},
"grouppage": {
"gchange1": "Groupes Qortal",

16
qortal-ui-core/language/hindi.json

@ -15,7 +15,8 @@
"portuguese": "पतग",
"hungarian": "ह",
"serbian": "सरिई",
"italian": "इतलव"
"italian": "इतलव",
"russian": "र"
},
"sidemenu": {
@ -218,7 +219,9 @@
"wchange39": "पत करन असमरथ",
"wchange40": "भगतन",
"wchange41": "सिि",
"wchange42": "पि"
"wchange42": "पि",
"wchange43": "कनफरम ह तक आपकशन नहि, धय रख...",
"wchange44": "कपयन: परयस कर..."
},
"tradepage": {
"tchange1": "वर पटल",
@ -441,10 +444,15 @@
"wcchange9": "भजनिफल, कपयन: परयस कर..."
},
"blockpage": {
"bcchange1": "",
"bcchange1": "ड उपयगकर",
"bcchange2": "इस उपयगकर सफलतवक अवरध!",
"bcchange3": "इस उपयगकरक करनिश करत समय तिई कपयिर सरयस कर!",
"bcchange4": "कई पत नम नह"
"bcchange4": "कई पत नम नह",
"bcchange5": "उपयगकर अनध कक कर",
"bcchange6": "क आप वकई इस उपयगकरक करनहत?",
"bcchange7": "म",
"bcchange8": "क पत",
"bcchange9": "निश"
},
"grouppage": {
"gchange1": "कटल समह",

16
qortal-ui-core/language/hr.json

@ -14,7 +14,8 @@
"portuguese": "Portugalski",
"hungarian": "Mađarski",
"serbian": "Srpski",
"italian": "Talijanski"
"italian": "Talijanski",
"russian": "Ruski"
},
"sidemenu": {
"mintingdetails": "DETALJI O MINTANJU",
@ -211,7 +212,9 @@
"wchange39": "Nije moguće kopirati adresu.",
"wchange40": "PLAĆANJE",
"wchange41": "Status",
"wchange42": "Potvrde"
"wchange42": "Potvrde",
"wchange43": "Vaša transakcija se neće prikazati dok se ne potvrdi, budite strpljivi...",
"wchange44": "Molim te pokušaj ponovno..."
},
"tradepage": {
"tchange1": "Portal razmjene",
@ -434,10 +437,15 @@
"wcchange9": "Slanje neuspješno, molimo ponovite..."
},
"blockpage": {
"bcchange1": "blokiraj",
"bcchange1": "Blokirati Korisnika",
"bcchange2": "Uspješno blokiran ovaj korisnik",
"bcchange3": "Došlo je do pogreške prilikom pokušaja blokiranja ovog korisnika. Molimo pokušajte ponovno!",
"bcchange4": "Nema registrirano ime"
"bcchange4": "Nema registrirano ime",
"bcchange5": "Blokiraj korisnički zahtjev",
"bcchange6": "Jeste li sigurni da ćete blokirati ovog korisnika?",
"bcchange7": "MENI",
"bcchange8": "Kopiraj Adresu",
"bcchange9": "Privatna Poruka"
},
"grouppage": {
"gchange1": "Qortal Grupe",

1132
qortal-ui-core/language/hu.json

File diff suppressed because it is too large Load Diff

16
qortal-ui-core/language/it.json

@ -14,7 +14,8 @@
"portuguese": "Portoghese",
"hungarian": "Ungherese",
"serbian": "Serbo",
"italian": "Italiano"
"italian": "Italiano",
"russian": "Russo"
},
"sidemenu": {
"mintingdetails": "DETTAGLI DI MINTING",
@ -211,7 +212,9 @@
"wchange39": "Impossibile copiare l'indirizzo.",
"wchange40": "PAGAMENTO",
"wchange41": "Stato",
"wchange42": "Conferme"
"wchange42": "Conferme",
"wchange43": "La tua transazione non verrà mostrata fino a quando non sarà confermata, sii paziente...",
"wchange44": "Per favore riprova..."
},
"tradepage": {
"tchange1": "Portale commerciale",
@ -434,10 +437,15 @@
"wcchange9": "Invio fallito, riprovare..."
},
"blockpage": {
"bcchange1": "blocco",
"bcchange1": "Blocca Utente",
"bcchange2": "Bloccato con successo questo utente!",
"bcchange3": "Si è verificato un errore durante il tentativo di bloccare questo utente. Per favore, riprova!",
"bcchange4": "Nessun nome registrato"
"bcchange4": "Nessun nome registrato",
"bcchange5": "Blocca richiesta utente",
"bcchange6": "Sei sicuro di bloccare questo utente?",
"bcchange7": "MENÙ",
"bcchange8": "Copia Indirizzo",
"bcchange9": "Messaggio Privato"
},
"grouppage": {
"gchange1": "Gruppi Qortal",

20
qortal-ui-core/language/pl.json

@ -14,7 +14,8 @@
"portuguese": "Portugalski",
"hungarian": "Węgierski",
"serbian": "Serbski",
"italian": "Włoski"
"italian": "Włoski",
"russian": "Rosyjski"
},
"sidemenu": {
"mintingdetails": "SZCZEGÓŁY MINTOWANIA",
@ -211,7 +212,9 @@
"wchange39": "Nie można skopiować adresu.",
"wchange40": "PŁATNOŚĆ",
"wchange41": "Status",
"wchange42": "Potwierdzenia"
"wchange42": "Potwierdzenia",
"wchange43": "Twoja transakcja nie pojawi się, dopóki nie zostanie potwierdzona, bądź cierpliwy...",
"wchange44": "Proszę spróbuj ponownie..."
},
"tradepage": {
"tchange1": "Portal Handlowy",
@ -434,10 +437,15 @@
"wcchange9": "Wysyłanie nie powiodło się, spróbuj ponownie..."
},
"blockpage": {
"bcchange1": "zablokuj",
"bcchange2": "Pomyślnie zablokowano tego użytkownika!",
"bcchange3": "Wystąpił błąd podczas próby zablokowania tego użytkownika. Spróbuj ponownie!",
"bcchange4": "Brak zarejestrowanej nazwy"
"bcchange1": "Zablokuj Użytkownika",
"bcchange2": "Pomyślnie zablokowano tego użytkownika!",
"bcchange3": "Wystąpił błąd podczas próby zablokowania tego użytkownika. Spróbuj ponownie!",
"bcchange4": "Brak zarejestrowanej nazwy",
"bcchange5": "Zablokuj żądanie użytkownika",
"bcchange6": "Czy na pewno chcesz zablokować tego użytkownika?",
"bcchange7": "MENU",
"bcchange8": "Kopiuj Adres",
"bcchange9": "Prywatna Wiadomość"
},
"grouppage": {
"gchange1": "Grupy Qortal",

16
qortal-ui-core/language/pt.json

@ -14,7 +14,8 @@
"portuguese": "Português",
"hungarian": "Húngaro",
"serbian": "Sérvio",
"italian": "Italiano"
"italian": "Italiano",
"russian": "Russo"
},
"sidemenu": {
"mintingdetails": "DETALHES DA MINERAÇÃO",
@ -211,7 +212,9 @@
"wchange39": "Não é possível copiar o endereço.",
"wchange40": "PAGAMENTO",
"wchange41": "Status",
"wchange42": "Confirmações"
"wchange42": "Confirmações",
"wchange43": "Sua transação não será exibida até ser confirmada, seja paciente...",
"wchange44": "Por favor, tente novamente..."
},
"tradepage": {
"tchange1": "Portal do Comércio",
@ -434,10 +437,15 @@
"wcchange9": "Envio falhou, por favor tente novamente..."
},
"blockpage": {
"bcchange1": "Bloquear",
"bcchange1": "Bloquear Usuário",
"bcchange2": "Bloqueou com sucesso este usuário!",
"bcchange3": "Ocorreu um erro ao tentar bloquear esse usuário. Por favor, tente de novo!",
"bcchange4": "Nenhum nome registrado"
"bcchange4": "Nenhum nome registrado",
"bcchange5": "Bloquear solicitação de usuário",
"bcchange6": "Tem certeza de bloquear este usuário?",
"bcchange7": "MENU",
"bcchange8": "Copiar Endereço",
"bcchange9": "Mensagem Privada"
},
"grouppage": {
"gchange1": "Grupos Qortal",

16
qortal-ui-core/language/rs.json

@ -14,7 +14,8 @@
"portuguese": "Portugalski",
"hungarian": "Mađarski",
"serbian": "Srpski",
"italian": "Italijan"
"italian": "Italijan",
"russian": "Ruski"
},
"sidemenu": {
"mintingdetails": "DETALJI MINTOVANJA",
@ -211,7 +212,9 @@
"wchange39": "Nemogućnost kopiranja adrese.",
"wchange40": "UPLATA",
"wchange41": "Status",
"wchange42": "Potvrde"
"wchange42": "Potvrde",
"wchange43": "Vaša transakcija se neće prikazati dok se ne potvrdi, budite strpljivi...",
"wchange44": "Molim vas, pokušajte ponovo..."
},
"tradepage": {
"tchange1": "Trgovinski prozor",
@ -434,10 +437,15 @@
"wcchange9": "Slanje neuspešno, Molim pokušajte ponov..."
},
"blockpage": {
"bcchange1": "blokirajte",
"bcchange1": "Blokirajte Korisnika",
"bcchange2": "Korisnik uspešno blokiran!",
"bcchange3": "Desila se greška pri pokušaju blokiranja ovog korisnika. Molim pokušajte ponovo!",
"bcchange4": "Bez registrovanih imena"
"bcchange4": "Bez registrovanih imena",
"bcchange5": "Blokiraj korisnički zahtev",
"bcchange6": "Da li ste sigurni da blokirate ovog korisnika?",
"bcchange7": "MENI",
"bcchange8": "Kopiraj Adresu",
"bcchange9": "Privatna Poruka"
},
"grouppage": {
"gchange1": "Qortal Grupe",

589
qortal-ui-core/language/ru.json

@ -0,0 +1,589 @@
{
"selectmenu": {
"selectlanguage": "Выберите язык",
"languageflag": "ru",
"english": "Английский",
"chinese1": "Китайский (упрощенный)",
"chinese2": "Китайский (традиционный)",
"german": "Немецкий",
"french": "Французкий",
"polish": "Польский",
"spanish": "Испанский",
"hindi": "Хинди",
"croatian": "Хорватский",
"portuguese": "Португальский",
"hungarian": "Венгерский",
"serbian": "Сербский",
"italian": "Итальянский",
"russian": "Русский"
},
"sidemenu": {
"mintingdetails": "ДЕТАЛИ ЧЕКАНКИ",
"wallets": "КОШЕЛЬКИ",
"tradeportal": "ТОРГОВЫЙ ПОРТАЛ",
"rewardshare": "ДОЛЯ ВОЗНАГРАЖДЕНИЯ",
"nameregistration": "РЕГИСТРАЦИЯ ИМЕНИ",
"websites": "ВЕБ-САЙТЫ",
"datamanagement": "УПРАВЛЕНИЕ ДАННЫМИ",
"qchat": "Q-ЧАТ",
"groupmanagement": "УПРАВЛЕНИЕ ГРУППАМИ",
"puzzles": "ЗАГАДКИ",
"nodemanagement": "УПРАВЛЕНИЕ УЗЛАМИ"
},
"login": {
"login": "Войти",
"createaccount": "Создать аккаунт",
"name": "Имя",
"address": "Адрес",
"password": "Пароль",
"youraccounts": "Ваши аккаунты",
"clickto": "Нажмите на свою учетную запись, чтобы войти с ее помощью",
"needcreate": "Вам необходимо создать или сохранить учетную запись, прежде чем вы сможете войти в нее!",
"upload": "Загрузить резервную копию вашего qortal",
"howlogin": "Как бы вы хотели войти?",
"seed": "Seed-фраза",
"seedphrase": "seed-фраза",
"saved": "Сохраненный аккаунт",
"qora": "Seed адреса Qora",
"backup": "Резервная копия кошелька Qortal",
"decrypt": "Расшифровать резервную копию",
"save": "Сохранить в этом браузере",
"prepare": "Подготовка вашей учетной записи",
"areyousure": "Вы уверены, что хотите удалить этот кошелек из сохраненных кошельков?",
"error1": "Резервная копия должна быть в формате JSON",
"error2": "Вариант входа не выбран",
"createwelcome": "Добро пожаловать в Qortal, вы обнаружите, что это похоже на ролевую игру, вы, как минтер в сети Qortal (если вы решите им стать), будете иметь возможность повысить уровень своей учетной записи, что даст вам большее вознаграждения за блок QORT, а также большее влияние на сеть с точки зрения голосования по решениям для платформы.",
"createa": "A",
"click": "Нажмите, чтобы просмотреть исходную фразу",
"confirmpass": "Подтвердить пароль",
"willbe": "Будет генерироваться случайным образом в фоновом режиме. Он используется в качестве генератора приватного ключа для вашей учетной записи блокчейна в Qortal.",
"clicknext": "Создайте учетную запись Qortal, нажав кнопку ДАЛЕЕ ниже.",
"ready": "Теперь ваша учетная запись готова к созданию. Она будет сохранена в этом браузере. Если вы не хотите, чтобы ваша новая учетная запись сохранялась в вашем браузере, вы можете снять флажок ниже. Вы по-прежнему сможете войдите в свою новую учетную запись (после выхода), используя файл резервной копии вашего кошелька, который вы ДОЛЖНЫ загрузить после создания учетной записи.",
"welmessage": "Добро пожаловать в Qortal",
"pleaseenter": "Пожалуйста, введите пароль!",
"notmatch": "Пароли не совпадают!",
"lessthen8": "Ваш пароль содержит менее 8 символов! Это не рекомендуется. Вы можете продолжить, игнорировав это предупреждение.",
"entername": "Пожалуйста, введите Имя!",
"downloaded": "Файл резервной копии кошелька будет загружен!",
"loading": "Идет загрузка, пожалуйста, подождите...",
"createdseed": "Ваша созданная Seed-фраза",
"saveseed": "Сохранить Seed-фразу",
"savein": "Сохранить в браузере",
"backup2": "Этот файл является ЕДИНСТВЕННЫМ способом доступа к вашей учетной записи в системе, в которой он не сохранен в приложении/браузере. ОБЯЗАТЕЛЬНО СДЕЛАЙТЕ РЕЗЕРВНУЮ КОПИЮ ЭТОГО ФАЙЛА В НЕСКОЛЬКИХ МЕСТАХ. Файл очень надежно зашифрован и расшифровывается с помощью вашего локального пароля, который вы создали на предыдущем шаге. Вы можете безопасно сохранить его в любом месте, но не забудьте сделать это в нескольких местах.",
"savewallet": "Сохранить файл резервной копии кошелька",
"created1": "Ваша учетная запись создана",
"created2": "и будет сохранено в этом браузере.",
"downloadbackup": "Скачать файл резервной копии кошелька"
},
"logout": {
"logout": "ВЫХОД",
"confirmlogout": "Вы уверены, что хотите выйти из системы?"
},
"fragfile": {
"selectfile": "Выбрать файл",
"dragfile": "Перетащите резервную копию сюда"
},
"settings": {
"generalinfo": "Общая информация об учетной записи",
"address": "Адрес",
"publickey": "Открытый ключ",
"settings": "Настройки",
"account": "Учетная запись",
"security": "Безопасность",
"notifications": "Уведомления",
"accountsecurity": "Безопасность учетной записи",
"password": "Пароль",
"download": "Загрузить файл резервной копии",
"choose": "Пожалуйста, выберите пароль для шифрования вашей резервной копии. (Это может быть тот же пароль, с которым вы вошли в систему, или другой)",
"block": "Блокировать уведомления (скоро…)",
"playsound": "Воспроизвести звук",
"shownotifications": "Показать уведомления",
"nodeurl": "URL-адрес узла",
"nodehint": "Выберите узел из списка узлов по умолчанию выше или добавьте пользовательский узел в список выше, нажав кнопку ниже",
"addcustomnode": "Добавить пользовательский узел",
"addandsave": "Добавить и Сохранить",
"protocol": "Протокол",
"domain": "Домен",
"port": "Порт"
},
"appinfo": {
"blockheight": "Высота блока",
"uiversion": "UI-версия",
"coreversion": "Версия ядра",
"minting": "(Чеканка)",
"synchronizing": "Синхронизация"
},
"walletprofile": {
"minterlevel": "Уровень Minter",
"blocksminted": "Отчеканеные блоки"
},
"general": {
"yes": "Да",
"no": "Нет",
"confirm": "Подтвердить",
"decline": "Отклонить",
"open": "Открыть",
"close": "Закрыть",
"back": "Назад",
"next": "Следующий",
"create": "Создать",
"continue": "Продолжить",
"save": "Сохранить"
},
"mintingpage": {
"mchange1": "Общие сведения о чеканке",
"mchange2": "Статистика блокчейна",
"mchange3": "Среднее время блока",
"mchange4": "Среднее количество блоков в день",
"mchange5": "Среднее количество созданных QORT в день",
"mchange6": "Детали аккаунта",
"mchange7": "Нет чеканки",
"mchange8": "Чеканка",
"mchange9": "Не чеканит",
"mchange10": "Активировать данные учетной записи",
"mchange11": "Не активировано",
"mchange12": "Активировать свою учетную запись",
"mchange13": "Введение",
"mchange14": "Чтобы активировать вашу учетную запись, необходимо выполнить ИСХОДЯЩУЮ транзакцию. Регистрация имени является наиболее распространенным методом. Вы можете попросить кого-нибудь в Q-Chat отправить вам небольшую сумму QORT, чтобы вы могли активировать свою учетную запись, или купите QORT на Торговом Портале, затем совершите ИСХОДЯЩУЮ транзакцию любого вида, она запишет ваш открытый ключ в блокчейне. Пока вы этого не сделаете, ваш открытый ключ известен только вам в вашем пользовательском интерфейсе, и никто другой не может получить ваш открытый ключ ключ от цепочки.",
"mchange15": "Текущий статус",
"mchange16": "Текущий уровень",
"mchange17": "Блоки до следующего уровеня",
"mchange18": "Если вы продолжите чеканить 24/7, вы достигнете уровня",
"mchange19": "Информация о наградах за чеканку",
"mchange20": "Текущий уровень",
"mchange21": "Всего минтеров на уровне",
"mchange22": "Доля уровней на блок",
"mchange23": "Вознаграждение за блок",
"mchange24": "Вознаграждение в день",
"mchange25": "Секунды",
"mchange26": "Блоки",
"mchange27": "Уровень",
"mchange28": "Уровень",
"mchange29": "дни",
"mchange30": "Минтеры",
"mchange31": "Нажмите для помощи",
"mchange32": "Стань Минтером",
"mchange33": "Введение",
"mchange34": "В Qortal, чтобы стать минтером и начать зарабатывать вознаграждения QORT с повышением уровня Minter, вы должны сначала быть спосированы «спонсором». Спонсором в Qortal является любой другой минтер уровня 5 или выше, или Основатель Qortal. Вы получите спонсорский ключ от спонсора и используете этот ключ, чтобы перейти на уровень 1. Достигнув уровня 1, вы сможете создать свой собственный ключ чеканки и начать зарабатывать вознаграждения за помощь в защите блокчейна Qortal.",
"mchange35": "Спонсорство",
"mchange36": "Ваш спонсор выдаст вам ‘Спонсорский ключ’, который вы будете использовать для добавления в свой узел и начнете чеканку (без вознаграждения до достижения уровня 1). Как только вы достигнете уровня 1, вы создадите/назначите свой собственный ‘Ключ Чеканки’ и начните зарабатывать вознаграждения. У вас осталось XXXX блоков в период вашего спонсорства.",
"mchange37": "Просто обратитесь к минтеру в Кортале, уровень которого достаточно высок, чтобы выдать спонсорский ключ, получите этот ключ, затем вернитесь сюда и введите ключ, чтобы начать свое путешествие по чеканке!",
"mchange38": "в"
},
"walletpage": {
"wchange1": "Получение баланса...",
"wchange2": "Текущий кошелек",
"wchange3": "Скопировать адрес кошелька в буфер обмена",
"wchange4": "Адрес скопирован в буфер обмена",
"wchange5": "Сведения о транзакции",
"wchange6": "Тип транзакции",
"wchange7": "ВЫХОД",
"wchange8": "В",
"wchange9": "Отправитель",
"wchange10": "Получатель",
"wchange11": "Сумма",
"wchange12": "Комиссия за транзакцию",
"wchange13": "Блок",
"wchange14": "Время",
"wchange15": "Подпись транзакции",
"wchange16": "Хэш транзакции",
"wchange17": "Отправитель",
"wchange18": "От адреса",
"wchange19": "Доступные средства",
"wchange20": "Кому (адрес или имя)",
"wchange21": "Текущая статическая плата:",
"wchange22": "Кошельки",
"wchange23": "Кому (адрес)",
"wchange24": "Текущая плата за байт",
"wchange25": "Низкие комиссии могут привести к медленным или неподтвержденным транзакциям.",
"wchange26": "Недостаточно средств!",
"wchange27": "Недопустимая сумма!",
"wchange28": "Получатель не может быть пустым!",
"wchange29": "Неверный получатель!",
"wchange30": "Транзакция прошла успешно!",
"wchange31": "Транзакция не удалась!",
"wchange32": "Не удалось получить баланс QORT. Попробуйте еще раз!",
"wchange33": "Не удалось получить",
"wchange34": "Баланс. Попробуйте еще раз!",
"wchange35": "Тип",
"wchange36": "Платеж",
"wchange37": "Общая сумма",
"wchange38": "В адресе еще нет транзакций.",
"wchange39": "Не удалось скопировать адрес.",
"wchange40": "ОПЛАТА",
"wchange41": "Статус",
"wchange42": "Подтверждено",
"wchange43": "Ваша транзакция не будет отображаться, пока не будет подтверждена, наберитесь терпения...",
"wchange44": "Пожалуйста, попробуйте еще раз..."
},
"tradepage": {
"tchange1": "Торговый портал",
"tchange2": "Выбрать торговую пару",
"tchange3": "ИСТОРИЧЕСКИЕ РЫНОЧНЫЕ СДЕЛКИ",
"tchange4": "МОЯ ТОРГОВАЯ ИСТОРИЯ",
"tchange5": "ОРДЕРА НА ПРОДАЖУ",
"tchange6": "МОИ ЗАКАЗЫ",
"tchange7": "Зависшие предложения",
"tchange8": "Сумма",
"tchange9": "Цена",
"tchange10": "Всего",
"tchange11": "Дата",
"tchange12": "Статус",
"tchange13": "Продавец",
"tchange14": "Цена за штуку",
"tchange15": "Очистить форму",
"tchange16": "У вас есть",
"tchange17": "Действие",
"tchange18": "КУПИТЬ",
"tchange19": "ПРОДАТЬ",
"tchange20": "Не удалось создать сделку. Повторите попытку!",
"tchange21": "Не удалось создать сделку. Код ошибки",
"tchange22": "Недостаточно средств!",
"tchange23": "Запрос на покупку выполнен успешно!",
"tchange24": "Запрос на покупку существует!",
"tchange25": "Не удалось создать сделку. Код ошибки",
"tchange26": "Выполняется отмена сделки!",
"tchange27": "Не удалось отменить сделку. Повторите попытку!",
"tchange28": "Не удалось отменить сделку. Код ошибки",
"tchange29": "ОТМЕНА",
"tchange30": "Не удалось получить баланс. Повторите попытку!",
"tchange31": "ПРОДАНО",
"tchange32": "КУПИЛ"
},
"rewardsharepage": {
"rchange1": "Вознаграждения",
"rchange2": "Создать долю вознаграждения",
"rchange3": "Вознаграждения, связанные с этой учетной записью",
"rchange4": "Учетная запись Minting",
"rchange5": "Доля в процентах",
"rchange6": "Получатель",
"rchange7": "Действие",
"rchange8": "Тип",
"rchange9": "Уровень 1–4 может создать собственную акцию, а уровень 5 или выше может создать акцию вознаграждения!",
"rchange10": "Открытый ключ получателя",
"rchange11": "Процент доли вознаграждения",
"rchange12": "Делаю что-нибудь вкусненькое",
"rchange13": "Добавление минтинг-аккаунта",
"rchange14": "Добавить",
"rchange15": "Учетная запись не участвует ни в каких вознаграждениях",
"rchange16": "Собственная доля вознаграждения",
"rchange17": "Удалить",
"rchange18": "Невозможно создать несколько долей вознаграждения!",
"rchange19": "Невозможно создать несколько личных ресурсов!",
"rchange20": "НЕ МОЖЕТЕ СОЗДАТЬ ДОЛЮ НАГРАДЫ! на уровне",
"rchange21": "Раздача вознаграждения прошла успешно!",
"rchange22": "Доля вознаграждения успешно удалена!"
},
"registernamepage": {
"nchange1": "Регистрация имени",
"nchange2": "Зарегистрировать имя",
"nchange3": "Зарегистрированные имена",
"nchange4": "Аватар",
"nchange5": "Имя",
"nchange6": "Владелец",
"nchange7": "Действие",
"nchange8": "Нет имен, зарегистрированных для этой учетной записи!",
"nchange9": "Зарегистрируйте имя!",
"nchange10": "Описание (необязательно)",
"nchange11": "Делаю что-нибудь вкусненькое",
"nchange12": "Регистрация имени",
"nchange13": "Стоимость регистрации текущего имени составляет",
"nchange14": "Зарегистрироваться",
"nchange15": "Установить аватар",
"nchange16": "Требуется обновление ядра",
"nchange17": "Имя уже существует!",
"nchange18": "Регистрация имени прошло успешно!"
},
"websitespage": {
"schange1": "Просматривать веб-сайты",
"schange2": "Отслеживаемые сайты",
"schange3": "Заблокированные сайты",
"schange4": "Поиск на сайтах",
"schange5": "Аватар",
"schange6": "Подробнее",
"schange7": "Опубликовано",
"schange8": "Действия",
"schange9": "Веб-сайты",
"schange10": "Нет доступных веб-сайтов",
"schange11": "Сайты, на которые вы подписаны",
"schange12": "Отслеживаемые сайты",
"schange13": "Вы не подписаны ни на один сайт",
"schange14": "Ваши заблокированные сайты",
"schange15": "Заблокированные сайты",
"schange16": "Вы не заблокировали ни один сайт",
"schange17": "Имя не найдено!",
"schange18": "Режим ретрансляции включен. Это означает, что ваш узел будет помогать передавать зашифрованные данные по сети, когда их запрашивает одноранговый узел. Вы можете отказаться в настройках",
"schange19": "в",
"schange20": "Режим реле отключен. Вы можете включить его в настройках",
"schange21": "Опубликовать сайт",
"schange22": "Произошла ошибка при попытке подписаться на это зарегистрированное имя. Повторите попытку!",
"schange23": "Произошла ошибка при попытке отписаться от этого зарегистрированного имени. Повторите попытку!",
"schange24": "Произошла ошибка при попытке заблокировать это зарегистрированное имя. Повторите попытку!",
"schange25": "Произошла ошибка при попытке разблокировать это зарегистрированное имя. Пожалуйста, попробуйте еще раз!",
"schange26": "Без категории",
"schange27": "Размер",
"schange28": "Статус",
"schange29": "Подписаться",
"schange30": "Отписаться",
"schange31": "Заблокировать",
"schange32": "Разблокировать",
"schange33": "Имя для поиска",
"schange34": "Имя не может быть пустым!",
"schange35": "Поиск"
},
"publishpage": {
"pchange1": "Опубликовать",
"pchange2": "Обновить",
"pchange3": "Примечание: рекомендуется настроить переадресацию портов перед размещением данных, чтобы к ним был более легкий доступ для одноранговых узлов в сети.",
"pchange4": "Выберите имя",
"pchange5": "Название",
"pchange6": "Описание",
"pchange7": "Выберите категорию",
"pchange8": "Тег",
"pchange9": "Сервис",
"pchange10": "Идентификатор",
"pchange11": "Опубликовать",
"pchange12": "Выберите zip-файл со статическим содержимым",
"pchange13": "Локальный путь к статическим файлам",
"pchange14": "Пожалуйста, выберите зарегистрированное имя для публикации данных",
"pchange15": "Выберите файл для размещения",
"pchange16": "Пожалуйста, выберите zip-файл для размещения",
"pchange17": "Пожалуйста, введите путь к каталогу, содержащему статическое содержимое",
"pchange18": "Пожалуйста, введите имя службы",
"pchange19": "Обработка данных... это может занять некоторое время...",
"pchange20": "Ошибка:",
"pchange21": "Внутренняя ошибка сервера при публикации данных",
"pchange22": "Вычисление доказательства работы... это может занять некоторое время...",
"pchange23": "Транзакция прошла успешно!",
"pchange24": "Невозможно подписать и обработать транзакцию",
"pchange25": "Выбрать файл"
},
"browserpage": {
"bchange1": "Вперед",
"bchange2": "Перезагрузить",
"bchange3": "Вернуться к списку",
"bchange4": "Удалить",
"bchange5": "из узла",
"bchange6": "Ваш браузер не поддерживает iframe",
"bchange7": "Подписаться",
"bchange8": "Отписаться",
"bchange9": "Заблокировать",
"bchange10": "Разблокировать",
"bchange11": "Произошла ошибка при попытке подписаться на это зарегистрированное имя. Повторите попытку!",
"bchange12": "Произошла ошибка при попытке отписаться от этого зарегистрированного имени. Повторите попытку!",
"bchange13": "Произошла ошибка при попытке заблокировать это зарегистрированное имя. Повторите попытку!",
"bchange14": "Произошла ошибка при попытке разблокировать это зарегистрированное имя. Повторите попытку!",
"bchange15": "Невозможно удалить данные из имен, на которые вы подписаны. Сначала отмените подписку.",
"bchange16": "Произошла ошибка при попытке удалить этот ресурс. Повторите попытку!"
},
"datapage": {
"dchange1": "Управление данными",
"dchange2": "Поиск в размещенных данных по этому узлу",
"dchange3": "Данные для поиска",
"dchange4": "Поиск",
"dchange5": "Зарегистрированное имя",
"dchange6": "Сервис",
"dchange7": "Идентификатор",
"dchange8": "Действия",
"dchange9": "Данные, размещенные на этом узле",
"dchange10": "Имя данных не может быть пустым!",
"dchange11": "Данные не найдены!",
"dchange12": "Не удалось получить список размещенных данных с узла",
"dchange13": "На этом узле нет данных",
"dchange14": "Отписаться",
"dchange15": "Удалить",
"dchange16": "Заблокировать",
"dchange17": "Разблокировать",
"dchange18": "Произошла ошибка при попытке заблокировать это зарегистрированное имя. Пожалуйста, попробуйте еще раз!",
"dchange19": "Произошла ошибка при попытке отписаться от этого зарегистрированного имени. Повторите попытку!",
"dchange20": "Произошла ошибка при попытке разблокировать это зарегистрированное имя. Пожалуйста, попробуйте еще раз!",
"dchange21": "Произошла ошибка при попытке удалить этот ресурс. Повторите попытку!"
},
"chatpage": {
"cchange1": "Новое личное сообщение",
"cchange2": "Загружается...",
"cchange3": "Заблокированные пользователи",
"cchange4": "Новое сообщение",
"cchange5": "(Нажмите, чтобы прокрутить вниз)",
"cchange6": "Введите имя или адрес того, с кем вы хотите пообщаться, чтобы отправить личное сообщение!",
"cchange7": "Имя/Адрес",
"cchange8": "Сообщение...",
"cchange9": "Отправить",
"cchange10": "Список заблокированных пользователей",
"cchange11": "Имя",
"cchange12": "Владелец",
"cchange13": "Действие",
"cchange14": "Эта учетная запись не заблокировала ни одного пользователя.",
"cchange15": "Нет зарегистрированного имени",
"cchange16": "Успешно разблокирован этот пользователь.",
"cchange17": "Произошла ошибка при попытке разблокировать этого пользователя. Повторите попытку!",
"cchange18": "разблокировать",
"cchange19": "Неверное имя/адрес. Проверьте имя/адрес и повторите попытку...",
"cchange20": "Сообщение успешно отправлено!",
"cchange21": "Ошибка отправки. Повторите попытку...",
"cchange22": "Загружаются сообщения...",
"cchange23": "Невозможно расшифровать сообщение!",
"cchange24": "Максимальное количество символов в сообщении - 255"
},
"welcomepage": {
"wcchange1": "Добро пожаловать в Q-Chat",
"wcchange2": "Новое личное сообщение",
"wcchange3": "Введите имя или адрес того, с кем вы хотите пообщаться, чтобы отправить личное сообщение!",
"wcchange4": "Имя/адрес",
"wcchange5": "Сообщение...",
"wcchange6": "Отправить",
"wcchange7": "Неверное имя/адрес, проверьте имя/адрес и повторите попытку...",
"wcchange8": "Сообщение успешно отправлено!",
"wcchange9": "Отправка не удалась, повторите попытку..."
},
"blockpage": {
"bcchange1": "заблокировать",
"bcchange2": "Успешно заблокирован этот пользователь!",
"bcchange3": "Произошла ошибка при попытке заблокировать этого пользователя. Повторите попытку!",
"bcchange4": "Нет зарегистрированного имени"
},
"grouppage": {
"gchange1": "Кортальные группы",
"gchange2": "Создать группу",
"gchange3": "Ваши присоединенные группы",
"gchange4": "Имя группы",
"gchange5": "Описание",
"gchange6": "Роль",
"gchange7": "Действие",
"gchange8": "Не состоит ни в одной группе!",
"gchange9": "Общие группы",
"gchange10": "Владелец",
"gchange11": "Открытые публичные группы недоступны!",
"gchange12": "Создать новую группу",
"gchange13": "Тип группы",
"gchange14": "Это поле обязательно для заполнения",
"gchange15": "Выберите вариант",
"gchange16": "Общедоступный",
"gchange17": "Частный",
"gchange18": "Порог одобрения группы (количество / процент администраторов, которые должны одобрить транзакцию):",
"gchange19": "НЕТ",
"gchange20": "ОДИН",
"gchange21": "Минимальная задержка блокировки для утверждения групповых транзакций:",
"gchange22": "минуты",
"gchange23": "час",
"gchange24": "часы",
"gchange25": "день",
"gchange26": "дни",
"gchange27": "Максимальная задержка блокировки для утверждения групповых транзакций:",
"gchange28": "Создание группы",
"gchange29": "Создать группу",
"gchange30": "Запрос на вступление в группу",
"gchange31": "Дата создания",
"gchange32": "Дата обновления",
"gchange33": "Присоединение",
"gchange34": "Вступить в группу",
"gchange35": "Запрос на выход из группы",
"gchange36": "Уход",
"gchange37": "Покинуть группу",
"gchange38": "Управление владельцем группы:",
"gchange39": "Управление администратором группы:",
"gchange40": "Управление группой",
"gchange41": "Группа создана успешно!",
"gchange42": "Недопустимое имя группы",
"gchange43": "Недопустимое описание группы",
"gchange44": "Выберите тип группы",
"gchange45": "Выберите порог одобрения группы",
"gchange46": "Выберите минимальную задержку блокировки для утверждения групповых транзакций",
"gchange47": "Выберите максимальную задержку блокировки для утверждения групповых транзакций",
"gchange48": "Запрос на присоединение к группе успешно отправлен!",
"gchange49": "Запрос на выход из группы успешно отправлен!",
"gchange50": "Выйти",
"gchange51": "Присоединиться",
"gchange52": "Администратор",
"gchange53": "Член",
"gchange54": "Члены"
},
"puzzlepage": {
"pchange1": "Головоломки",
"pchange2": "Награда",
"pchange3": "РЕШЕНО",
"pchange4": "Имя",
"pchange5": "Описание",
"pchange6": "Подсказка/Ответ",
"pchange7": "Действие",
"pchange8": "Угадай",
"pchange9": "Введите свое предположение, чтобы решить эту головоломку и выиграть",
"pchange10": "Ваше предположение должно состоять из 43 или 44 символов и",
"pchange11": "нет",
"pchange12": "включить 0 (ноль), I (верхний i), O (верхний o) или l (нижний L).",
"pchange13": "Ваша догадка",
"pchange14": "Проверяю ваши предположения...",
"pchange15": "Отправить",
"pchange16": "Неверное предположение!",
"pchange17": "Заявка на вознаграждение отправлена — проверьте кошелек на наличие вознаграждения!"
},
"nodepage": {
"nchange1": "Управление узлом для:",
"nchange2": "Узел был в сети в течении:",
"nchange3": "Учетные записи чеканки узла",
"nchange4": "Добавить минтинг-аккаунт",
"nchange5": "Если вы хотите чеканить с помощью своей учетной записи, вам нужно будет создать транзакцию вознаграждения для себя (с процентом вознаграждения, установленным на 0), а затем чеканить с помощью ключа вознаграждения, который он вам дает.",
"nchange6": "Ключ вознаграждения",
"nchange7": "Добавление минтинг-аккаунта",
"nchange8": "Добавить",
"nchange9": "Учетная запись Minting",
"nchange10": "Учетная запись получателя",
"nchange11": "Действие",
"nchange12": "Удалить",
"nchange13": "Для этого узла не найдено ни одного минтинг-аккаунта",
"nchange14": "Пиры, подключенные к этому узлу",
"nchange15": "Добавить одноранговый узел",
"nchange16": "Введите ниже адрес пира, которого вы хотите добавить",
"nchange17": "Адрес узла",
"nchange18": "Адрес",
"nchange19": "Последняя высота",
"nchange20": "Версия сборки",
"nchange21": "Подключено для",
"nchange22": "Действие",
"nchange23": "Принудительная синхронизация",
"nchange24": "У узла нет подключенных пиров",
"nchange25": "Запуск синхронизации с узлом: ",
"nchange26": "Пир успешно удален: ",
"nchange27": "Узел Minting успешно добавлен!",
"nchange28": "Не удалось добавить узел Minting!",
"nchange29": "Учетная запись Minting успешно удалена!",
"nchange30": "Не удалось удалить учетную запись Minting!",
"nchange31": "Остановить узел",
"nchange32": "Запрос на остановку успешно отправлен!"
},
"transpage": {
"tchange1": "Запрос транзакции",
"tchange2": "Отклонить",
"tchange3": "Подтвердить",
"tchange4": "Кому",
"tchange5": "Сумма"
},
"apipage": {
"achange1": "Добавить ключ API",
"achange2": "Ключ API",
"achange3": "Пожалуйста, введите ключ API для этого узла. Его можно найти в файле с именем «apikey.txt» в каталоге, где установлено ядро. Либо нажмите «Отмена», чтобы использовать ядро с ограниченной функциональностью.",
"achange4": "Отмена",
"achange5": "Добавить",
"achange6": "Ключ API успешно добавлен",
"achange7": "Ключ API неверный, ключ API не добавленed"
},
"transactions": {
"amount": "Сумма",
"to": "к",
"declined": "Пользователь отклонил транзакцию!",
"namemedialog1": "Вы регистрируете имя ниже:",
"namemedialog2": "При нажатии подтверждения имя будет зарегистрировано!",
"groupdialog1": "Вы запрашиваете вступление в группу ниже:",
"groupdialog2": "При нажатии подтверждения будет отправлен запрос на вступление в группу!",
"groupdialog3": "Вы запрашиваете выход из группы ниже:",
"groupdialog4": "При нажатии подтверждения будет отправлен запрос на выход из группы!",
"groupdialog5": "Вы запрашиваете создание группы ниже:",
"groupdialog6": "При нажатии подтверждения будет отправлен запрос на создание группы!",
"rewarddialog1": "Хотели бы вы создать транзакцию обмена вознаграждением, обмен",
"rewarddialog2": "из ваших наград за чеканку",
"rewarddialog3": "Если да, вам нужно будет сохранить приведенный ниже ключ, чтобы чеканить. Его можно передать любому узлу, чтобы он мог чеканить от вашего имени.",
"rewarddialog4": "При нажатии кнопки подтверждения будет создана доля вознаграждения, но вам все равно нужно будет предоставить вышеуказанный ключ узлу, чтобы создать учетную запись.",
"rewarddialog5": "Вы удаляете транзакцию распределения вознаграждения, связанную с аккаунтом:",
"rewarddialog6": "При нажатии кнопки подтверждения доля вознаграждения будет удалена, а ключ чеканки станет недействительным."
}
}

16
qortal-ui-core/language/us.json

@ -14,7 +14,8 @@
"portuguese": "Portuguese",
"hungarian": "Hungarian",
"serbian": "Serbian",
"italian": "Italian"
"italian": "Italian",
"russian": "Russian"
},
"sidemenu": {
"mintingdetails": "MINTING DETAILS",
@ -211,7 +212,9 @@
"wchange39": "Unable to copy address.",
"wchange40": "PAYMENT",
"wchange41": "Status",
"wchange42": "Confirmations"
"wchange42": "Confirmations",
"wchange43": "Your transaction will not show until confirmed, be patient...",
"wchange44": "Please try again..."
},
"tradepage": {
"tchange1": "Trade Portal",
@ -434,10 +437,15 @@
"wcchange9": "Sending failed, Please retry..."
},
"blockpage": {
"bcchange1": "block",
"bcchange1": "Block User",
"bcchange2": "Successfully blocked this user!",
"bcchange3": "Error occurred when trying to block this user. Please try again!",
"bcchange4": "No registered name"
"bcchange4": "No registered name",
"bcchange5": "Block User Request",
"bcchange6": "Are you sure to block this user ?",
"bcchange7": "MENU",
"bcchange8": "Copy Address",
"bcchange9": "Private Message"
},
"grouppage": {
"gchange1": "Qortal Groups",

18
qortal-ui-core/language/zhc.json

@ -14,7 +14,8 @@
"portuguese": "葡萄牙文",
"hungarian": "匈牙利文",
"serbian": "塞尔维亚文",
"italian": "意大利文"
"italian": "意大利文",
"russian": "俄语"
},
"sidemenu": {
"mintingdetails": "铸币信息",
@ -211,7 +212,9 @@
"wchange39": "无法复制钱包地址.",
"wchange40": "交易",
"wchange41": "状态",
"wchange42": "确认数"
"wchange42": "确认数",
"wchange43": "您的交易在确认之前不会显示,请耐心等待...",
"wchange44": "请再试一次..."
},
"tradepage": {
"tchange1": "交易门户",
@ -434,10 +437,15 @@
"wcchange9": "发送失败, 请再此尝试..."
},
"blockpage": {
"bcchange1": "封锁",
"bcchange1": "阻止用户",
"bcchange2": "成功封锁此用户!",
"bcchange3": "尝试封锁此用户时出错。 请再试一次!",
"bcchange4": "没有注册名称"
"bcchange4": "没有注册名称",
"bcchange5": "阻止用户请求",
"bcchange6": "你确定要屏蔽这个用户吗?",
"bcchange7": "菜单",
"bcchange8": "复制地址",
"bcchange9": "私人讯息"
},
"grouppage": {
"gchange1": "Qortal 群组",
@ -580,7 +588,7 @@
"rewarddialog2": "给",
"rewarddialog3": "如果是的话,请保存下面的铸币密钥并添加到任何节点上,以允许它代表您铸币.",
"rewarddialog4": "点击确认后,奖励分享密钥将会创建,但你必须将该密钥添加到节点中才能成功铸币并获得相对应的奖励.",
"rewarddialog5": "您正在删除与此账号关联的奖励分享交易:",
"rewarddialog5": "您正在删除与此账号关联的奖励分享交易:",
"rewarddialog6": "点击确认后,奖励分享将被移除,已创建的铸币密钥也随之失效。"
}
}

16
qortal-ui-core/language/zht.json

@ -14,7 +14,8 @@
"portuguese": "葡萄牙文",
"hungarian": "匈牙利文",
"serbian": "塞爾維亞文",
"italian": "意大利文"
"italian": "意大利文",
"russian": "俄語"
},
"sidemenu": {
"mintingdetails": "鑄幣信息",
@ -211,7 +212,9 @@
"wchange39": "無法複製錢包地址.",
"wchange40": "交易",
"wchange41": "狀態",
"wchange42": "確認數"
"wchange42": "確認數",
"wchange43": "您的交易在確認之前不會顯示,請耐心等待...",
"wchange44": "請再試一次..."
},
"tradepage": {
"tchange1": "交易門戶",
@ -434,10 +437,15 @@
"wcchange9": "發送失敗, 請再此嘗試..."
},
"blockpage": {
"bcchange1": "封鎖",
"bcchange1": "阻止用戶",
"bcchange2": "成功封鎖此用戶!",
"bcchange3": "嘗試封鎖此用戶時出錯。 請再試一次!",
"bcchange4": "沒有註冊名稱"
"bcchange4": "沒有註冊名稱",
"bcchange5": "阻止用戶請求",
"bcchange6": "你確定要屏蔽這個用戶嗎?",
"bcchange7": "菜單",
"bcchange8": "複製地址",
"bcchange9": "私人讯息"
},
"grouppage": {
"gchange1": "Qortal 群組",

26
qortal-ui-core/package.json

@ -17,12 +17,12 @@
"author": "QORTAL <[email protected]>",
"license": "GPL-3.0",
"dependencies": {
"@hapi/hapi": "20.2.1",
"@hapi/hapi": "20.2.2",
"@hapi/inert": "6.0.5",
"sass": "1.50.0"
"sass": "1.51.0"
},
"devDependencies": {
"@babel/core": "7.17.9",
"@babel/core": "7.17.10",
"@material/mwc-button": "0.25.3",
"@material/mwc-checkbox": "0.25.3",
"@material/mwc-dialog": "0.25.3",
@ -55,24 +55,24 @@
"@polymer/paper-tooltip": "3.0.1",
"@rollup/plugin-alias": "3.1.9",
"@rollup/plugin-babel": "5.3.1",
"@rollup/plugin-commonjs": "21.1.0",
"@rollup/plugin-node-resolve": "13.2.1",
"@rollup/plugin-commonjs": "22.0.0",
"@rollup/plugin-node-resolve": "13.3.0",
"@rollup/plugin-replace": "4.0.0",
"@vaadin/grid": "23.0.6",
"@vaadin/icons": "23.0.6",
"@vaadin/password-field": "23.0.6",
"@vaadin/grid": "23.0.7",
"@vaadin/icons": "23.0.7",
"@vaadin/password-field": "23.0.7",
"asmcrypto.js": "2.3.2",
"bcryptjs": "2.4.3",
"epml": "0.3.3",
"file-saver": "2.0.5",
"lit": "2.2.2",
"lit-translate": "2.0.0",
"postcss": "8.4.12",
"lit": "2.2.3",
"lit-translate": "2.0.1",
"postcss": "8.4.13",
"pwa-helpers": "0.9.1",
"random-sentence-generator": "0.0.8",
"redux": "4.1.2",
"redux": "4.2.0",
"redux-thunk": "2.4.1",
"rollup": "2.70.2",
"rollup": "2.72.0",
"rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-postcss": "4.0.2",
"rollup-plugin-progress": "1.1.2",

3
qortal-ui-core/src/components/app-view.js

@ -13,9 +13,6 @@ import './show-plugin.js'
import './qort-theme-toggle.js'
import './language-selector.js'
import '@material/mwc-drawer'
import '@material/mwc-icon'
import '@polymer/app-layout/app-layout.js'
import '@polymer/paper-ripple'

4
qortal-ui-core/src/components/language-selector.js

@ -51,13 +51,14 @@ class LanguageSelector extends connect(store)(LitElement) {
constructor() {
super()
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
render() {
return html`
<div style="display: inline;">
<select @change="${this.changeLanguage}">
<option value="us">${translate("selectmenu.selectlanguage")}</option>
<option value="us">${translate("selectmenu.selectlanguage")}</option>
<option value="us">US - ${translate("selectmenu.english")}</option>
<option value="de">DE - ${translate("selectmenu.german")}</option>
<option value="es">ES - ${translate("selectmenu.spanish")}</option>
@ -69,6 +70,7 @@ class LanguageSelector extends connect(store)(LitElement) {
<option value="pl">PL - ${translate("selectmenu.polish")}</option>
<option value="pt">PT - ${translate("selectmenu.portuguese")}</option>
<option value="rs">RS - ${translate("selectmenu.serbian")}</option>
<option value="ru">RU - ${translate("selectmenu.russian")}</option>
<option value="zht">ZHT - ${translate("selectmenu.chinese2")}</option>
<option value="zhc">ZHC - ${translate("selectmenu.chinese1")}</option>
</select>

37
qortal-ui-core/src/components/login-view/create-account-section.js

@ -1,7 +1,7 @@
import { LitElement, html, css } from 'lit'
import { connect } from 'pwa-helpers'
import { store } from '../../store.js'
import { translate, translateUnsafeHTML } from 'lit-translate'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import { createWallet } from '../../../../qortal-ui-crypto/api/createWallet.js'
import FileSaver from 'file-saver'
@ -121,24 +121,27 @@ class CreateAccountSection extends connect(store)(LitElement) {
const rePassword = this.shadowRoot.getElementById('rePassword').value
if (password === '') {
let snackbar1string = get("login.pleaseenter")
snackbar.add({
labelText: this.renderEnterPassText(),
labelText: `${snackbar1string}`,
dismiss: true
})
return
}
if (password != rePassword) {
let snackbar2string = get("login.notmatch")
snackbar.add({
labelText: this.renderNotMatchText(),
labelText: `${snackbar2string}`,
dismiss: true
})
return
}
if (password.length < 8 && lastPassword !== password) {
let snackbar3string = get("login.lessthen8")
snackbar.add({
labelText: this.renderLessText(),
labelText: `${snackbar3string}`,
dismiss: true
})
lastPassword = password
@ -146,8 +149,9 @@ class CreateAccountSection extends connect(store)(LitElement) {
}
if (this.saveAccount === true && nameInput === '') {
let snackbar4string = get("login.entername")
snackbar.add({
labelText: this.renderEnterNameText(),
labelText: `${snackbar4string}`,
dismiss: true
})
return
@ -194,8 +198,9 @@ class CreateAccountSection extends connect(store)(LitElement) {
backup: {
next: e => {
if (!this.isDownloadedBackup) {
let snackbar5string = get("login.downloaded")
snackbar.add({
labelText: this.renderBackupText(),
labelText: `${snackbar5string}`,
dismiss: true
})
} else {
@ -494,30 +499,10 @@ class CreateAccountSection extends connect(store)(LitElement) {
return html`${translate("login.prepare")}`
}
renderBackupText() {
return html`${translate("login.downloaded")}`
}
renderWelcomeText() {
return html`${translate("login.welmessage")}`
}
renderEnterPassText() {
return html`${translate("login.pleaseenter")}`
}
renderNotMatchText() {
return html`${translate("login.notmatch")}`
}
renderLessText() {
return html`${translate("login.lessthen8")}`
}
renderEnterNameText() {
return html`${translate("login.entername")}`
}
renderLoadingText() {
return html`${translate("login.loading")}`
}

186
qortal-ui-core/src/components/login-view/loading-ripple_old.js

@ -1,186 +0,0 @@
import { LitElement, html, css } from 'lit'
import { connect } from 'pwa-helpers'
import { store } from '../../store.js'
const TRANSITION_EVENT_NAMES = ['transitionend', 'webkitTransitionEnd', 'oTransitionEnd', 'MSTransitionEnd']
class LoadingRipple extends connect(store)(LitElement) {
static get properties () {
return {
welcomeMessage: {
type: String,
attribute: 'welcome-message',
reflectToAttribute: true
},
loadingMessage: {
type: String,
attribute: 'loading-message',
reflectToAttribute: true
}
}
}
constructor () {
super()
this.welcomeMessage = ''
this.loadingMessage = ''
}
static get styles () {
return css`
* {
--paper-spinner-color: var(--mdc-theme-secondary);
}
`
}
render () {
return html`
<style>
#rippleWrapper{
position:fixed;
top:0;
left:0;
bottom:0;
right:0;
height:0;
width:0;
z-index:999;
overflow: visible;
--ripple-activating-transition: transform 0.3s cubic-bezier(0.6, 0.0, 1, 1), opacity 0.3s cubic-bezier(0.6, 0.0, 1, 1);
--ripple-disable-transition: opacity 0.5s ease;
}
#ripple{
border-radius:50%;
border-width:0;
margin-left:-100vmax;
margin-top: -100vmax;
height:200vmax;
width:200vmax;
overflow:hidden;
background: var(--mdc-theme-secondary);
transform: scale(0);
overflow:hidden;
}
#ripple.error {
transition: var(--ripple-activating-transition);
background: var(--mdc-theme-error)
}
#rippleShader {
background: var(--mdc-theme-surface);
opacity:0;
height:100%;
width:100%;
}
#ripple.activating{
transition: var(--ripple-activating-transition);
transform: scale(1)
}
.activating #rippleShader {
transition: var(--ripple-activating-transition);
opacity: 1;
}
#ripple.disabling{
transition: var(--ripple-disable-transition);
opacity: 0;
}
#rippleContentWrapper {
position: absolute;
top:100vmax;
left:100vmax;
height:var(--window-height);
width:100vw;
display: flex;
align-items: center;
justify-content: center;
}
#rippleContent {
opacity: 0;
text-align:center;
}
.activating-done #rippleContent {
opacity: 1;
transition: var(--ripple-activating-transition);
}
</style>
<div id="rippleWrapper">
<div id="ripple">
<div id="rippleShader"></div>
<div id="rippleContentWrapper">
<div id="rippleContent">
<h1>${this.welcomeMessage}</h1>
<paper-spinner-lite active></paper-spinner-lite>
<p>${this.loadingMessage}</p>
</div>
</div>
</div>
</div>
`
}
firstUpdated () {
this._rippleWrapper = this.shadowRoot.getElementById('rippleWrapper')
this._ripple = this.shadowRoot.getElementById('ripple')
this._rippleContentWrapper = this.shadowRoot.getElementById('rippleContentWrapper')
}
// duh
open (origin) {
this._rippleWrapper.style.top = origin.y + 'px'
this._rippleWrapper.style.left = origin.x + 'px'
this._rippleContentWrapper.style.marginTop = -origin.y + 'px'
this._rippleContentWrapper.style.marginLeft = -origin.x + 'px'
return new Promise((resolve, reject) => {
this._ripple.classList.add('activating')
let isOpened = false
const doneOpeningEvent = () => {
if (isOpened) return
// Clear events
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, doneOpeningEvent))
this._ripple.classList.add('activating-done')
isOpened = true
resolve()
}
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, doneOpeningEvent))
})
}
// Fades out
fade () {
return new Promise((resolve, reject) => {
// CAN'T FADE OUT CAUSE THE STUPID THING GETS KILLED CAUSE OF STATE.APP.LOGGEEDIN
// let rippleClosed = false
this._ripple.classList.remove('activating')
this._ripple.classList.remove('activating-done')
this._ripple.classList.remove('disabling')
resolve()
})
}
// un-ripples...
close () {
return new Promise((resolve, reject) => {
let rippleClosed = false
this._ripple.classList.add('error')
this._ripple.classList.remove('activating')
this._ripple.classList.remove('activating-done')
const rippleClosedEvent = () => {
if (rippleClosed) return
rippleClosed = true
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, rippleClosedEvent))
// Reset the ripple
this._ripple.classList.remove('error')
this.rippleIsOpen = false
resolve()
}
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, rippleClosedEvent))
})
}
stateChanged (state) {
}
}
window.customElements.define('loading-ripple', LoadingRipple)

3
qortal-ui-core/src/components/sidenav-menu.js

@ -3,7 +3,6 @@ import { connect } from 'pwa-helpers'
import { store } from '../store.js'
import { translate, translateUnsafeHTML } from 'lit-translate'
import '@material/mwc-icon'
import '@polymer/paper-ripple'
import '@vaadin/icon'
import '@vaadin/icons'
@ -18,7 +17,6 @@ class SidenavMenu extends connect(store)(LitElement) {
urls: { type: Object },
theme: { type: String, reflect: true }
}
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
static get styles() {
@ -51,6 +49,7 @@ class SidenavMenu extends connect(store)(LitElement) {
constructor() {
super()
this.urls = []
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
render() {

10
qortal-ui-core/src/functional-components/loading-ripple.js

@ -29,6 +29,8 @@ class LoadingRipple extends LitElement {
static get styles () {
return css`
* {
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
--paper-spinner-color: var(--mdc-theme-secondary);
}
@ -53,7 +55,7 @@ class LoadingRipple extends LitElement {
height:200vmax;
width:200vmax;
overflow:hidden;
background: var(--mdc-theme-primary);
background: var(--black);
transform: scale(0);
overflow:hidden;
}
@ -62,7 +64,7 @@ class LoadingRipple extends LitElement {
background: var(--mdc-theme-error)
}
#rippleShader {
background: var(--mdc-theme-surface);
background: var(--white);
opacity:0;
height:100%;
width:100%;
@ -108,9 +110,9 @@ class LoadingRipple extends LitElement {
<div id="rippleShader"></div>
<div id="rippleContentWrapper">
<div id="rippleContent">
<h1>${this.welcomeMessage}</h1>
<h1 style="color: var(--black);">${this.welcomeMessage}</h1>
<paper-spinner-lite active></paper-spinner-lite>
<p>${this.loadingMessage}</p>
<p style="color: var(--black);">${this.loadingMessage}</p>
</div>
</div>
</div>

1
qortal-ui-core/src/redux/app/version.js

@ -1 +0,0 @@
export const UI_VERSION = "1.8.2";

21
qortal-ui-plugins/package.json

@ -22,7 +22,7 @@
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js"
},
"devDependencies": {
"@babel/core": "7.17.9",
"@babel/core": "7.17.10",
"@github/time-elements": "3.1.2",
"@material/mwc-button": "0.25.3",
"@material/mwc-checkbox": "0.25.3",
@ -35,22 +35,25 @@
"@material/mwc-tab": "0.25.3",
"@material/mwc-tab-bar": "0.25.3",
"@material/mwc-textfield": "0.25.3",
"@polymer/iron-icons": "3.0.1",
"@polymer/paper-icon-button": "3.0.2",
"@polymer/paper-progress": "3.0.1",
"@polymer/paper-slider": "3.0.1",
"@polymer/paper-spinner": "3.0.2",
"@polymer/paper-tooltip": "3.0.1",
"@rollup/plugin-alias": "3.1.9",
"@rollup/plugin-babel": "5.3.1",
"@rollup/plugin-commonjs": "21.1.0",
"@rollup/plugin-node-resolve": "13.2.1",
"@rollup/plugin-commonjs": "22.0.0",
"@rollup/plugin-node-resolve": "13.3.0",
"@rollup/plugin-replace": "4.0.0",
"@vaadin/button": "23.0.6",
"@vaadin/grid": "23.0.6",
"@vaadin/icons": "23.0.6",
"@vaadin/button": "23.0.7",
"@vaadin/grid": "23.0.7",
"@vaadin/icons": "23.0.7",
"epml": "0.3.3",
"html-escaper": "3.0.3",
"lit": "2.2.2",
"lit-translate": "2.0.0",
"rollup": "2.70.2",
"lit": "2.2.3",
"lit-translate": "2.0.1",
"rollup": "2.72.0",
"rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2",
"rollup-plugin-terser": "7.0.2"

164
qortal-ui-plugins/plugins/core/components/BlockAddress.js

@ -1,164 +0,0 @@
import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import snackbar from './snackbar.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@material/mwc-snackbar'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class BlockAddress extends LitElement {
static get properties() {
return {
toblockaddress: { type: String, attribute: true },
chatBlockedAdresses: { type: Array }
}
}
static get styles() {
return css`
* {
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
--mdc-dialog-content-ink-color: var(--black);
--mdc-theme-surface: var(--white);
--mdc-theme-text-primary-on-background: var(--black);
}
`
}
constructor() {
super()
this.chatBlockedAdresses = []
}
render() {
return html`
<mwc-button dense unelevated label="${translate("blockpage.bcchange1")}" icon="voice_over_off" @click="${() => this.chatBlockAddress()}"></mwc-button>
`
}
firstUpdated() {
this.changeLanguage()
this.getChatBlockedAdresses()
setInterval(() => {
this.getChatBlockedAdresses();
}, 60000)
window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage')
use(checkLanguage)
})
}
updated(changedProps) {
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
}
}
async getChatBlockedAdresses() {
const chatBlockedAdresses = await parentEpml.request('apiCall', {
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`
})
this.chatBlockedAdresses = chatBlockedAdresses
}
async chatBlockAddress() {
let address = this.toblockaddress
let items = [
address
]
let addressJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: `${addressJsonString}`
})
if (ret === true) {
this.chatBlockedAdresses = this.chatBlockedAdresses.filter(item => item != address)
this.chatBlockedAdresses.push(address)
this.getChatBlockedList()
let err1string = get("blockpage.bcchange2")
snackbar.add({
labelText: `${err1string}`,
dismiss: true
})
} else {
let err2string = get("blockpage.bcchange2")
snackbar.add({
labelText: `${err2string}`,
dismiss: true
})
}
return ret
}
getChatBlockedList() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const blockedAddressesUrl = `${nodeUrl}/lists/blockedAddresses?apiKey=${this.getApiKey()}`
const err3string = 'No regitered name'
localStorage.removeItem("ChatBlockedAddresses")
var obj = [];
fetch(blockedAddressesUrl).then(response => {
return response.json()
}).then(data => {
return data.map(item => {
const noName = {
name: err3string,
owner: item
}
fetch(`${nodeUrl}/names/address/${item}?limit=0&reverse=true`).then(res => {
return res.json()
}).then(jsonRes => {
if(jsonRes.length) {
jsonRes.map (item => {
obj.push(item)
})
} else {
obj.push(noName)
}
localStorage.setItem("ChatBlockedAddresses", JSON.stringify(obj))
})
})
})
}
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey;
return apiKey;
}
}
window.customElements.define('block-address', BlockAddress)

87
qortal-ui-plugins/plugins/core/components/ChatPage.js

@ -10,7 +10,7 @@ registerTranslateConfig({
import { escape, unescape } from 'html-escaper';
import { inputKeyCodes } from '../../utils/keyCodes.js'
import './ChatScroller.js'
import './BlockAddress.js'
import './NameMenu.js'
import './TimeAgo.js'
import { EmojiPicker } from 'emoji-picker-js';
import '@polymer/paper-spinner/paper-spinner-lite.js'
@ -258,9 +258,6 @@ class ChatPage extends LitElement {
parentEpml.imReady();
}
updated(changedProps) {
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
@ -358,7 +355,7 @@ class ChatPage extends LitElement {
*/
chatMessageTemplate(messageObj) {
let avatarImg = '';
let blockButton = '';
let nameMenu = '';
if (messageObj.senderName) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
@ -366,18 +363,17 @@ class ChatPage extends LitElement {
avatarImg = `<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`;
}
if (messageObj.sender === this.selectedAddress.address) {
blockButton = ``
if (messageObj.sender === this.myAddress) {
nameMenu = `${messageObj.senderName ? messageObj.senderName : messageObj.sender}`
} else {
blockButton = `<block-address toblockaddress="${messageObj.sender}"></block-address>`
nameMenu = `<name-menu toblockaddress="${messageObj.sender}" nametodialog="${messageObj.senderName ? messageObj.senderName : messageObj.sender}"></name-menu>`
}
return `
<li class="clearfix">
<div class="message-data ${messageObj.sender === this.selectedAddress.address ? "align-right" : ""}">
<span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span>
<span class="message-data-name">${nameMenu}</span>
<span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span>
<span class="message-data-block">${blockButton}</span>
</div>
<div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.selectedAddress.address ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div>
<div class="message ${messageObj.sender === this.selectedAddress.address ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(escape(messageObj.decodedMessage))}</div>
@ -662,7 +658,7 @@ class ChatPage extends LitElement {
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const difficulty = this.balance === 0 ? 14 : 8;
const difficulty = this.balance === 0 ? 12 : 8;
const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty);
@ -698,7 +694,6 @@ class ChatPage extends LitElement {
* @param { Boolean } isDown
*/
setIsUserDown(isDown) {
this.isUserDown = isDown;
}
@ -790,40 +785,40 @@ class ChatPage extends LitElement {
editor.styles = document.createElement('style');
editor.styles.setAttribute('type', 'text/css');
editor.styles.innerText = `
html {
cursor: text;
}
body {
font-size: 1rem;
line-height: 1.38rem;
font-weight: 400;
font-family: "Open Sans", helvetica, sans-serif;
padding-right: 3px;
text-align: left;
white-space: break-spaces;
word-break: break-word;
outline: none;
}
body[contentEditable=true]:empty:before {
content: attr(data-placeholder);
display: block;
color: rgb(103, 107, 113);
text-overflow: ellipsis;
overflow: hidden;
user-select: none;
white-space: nowrap;
}
body[contentEditable=false]{
background: rgba(0,0,0,0.1);
}
img.emoji {
width: 1.7em;
height: 1.5em;
margin-bottom: -2px;
vertical-align: bottom;
}
`;
editor.content.head.appendChild(editor.styles);
html {
cursor: text;
}
body {
font-size: 1rem;
line-height: 1.38rem;
font-weight: 400;
font-family: "Open Sans", helvetica, sans-serif;
padding-right: 3px;
text-align: left;
white-space: break-spaces;
word-break: break-word;
outline: none;
}
body[contentEditable=true]:empty:before {
content: attr(data-placeholder);
display: block;
color: rgb(103, 107, 113);
text-overflow: ellipsis;
overflow: hidden;
user-select: none;
white-space: nowrap;
}
body[contentEditable=false]{
background: rgba(0,0,0,0.1);
}
img.emoji {
width: 1.7em;
height: 1.5em;
margin-bottom: -2px;
vertical-align: bottom;
}
`;
editor.content.head.appendChild(editor.styles);
};
ChatEditor.prototype.enable = function () {

34
qortal-ui-plugins/plugins/core/components/ChatScroller.js

@ -2,7 +2,7 @@ import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import './BlockAddress.js'
import './NameMenu.js'
import '@material/mwc-button'
import '@material/mwc-dialog'
@ -36,6 +36,8 @@ class ChatScroller extends LitElement {
* {
scrollbar-width: thin;
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
}
*::-webkit-scrollbar-track {
@ -48,6 +50,11 @@ class ChatScroller extends LitElement {
border: 3px solid var(--scrollbarBG);
}
a {
color: var(--black);
text-decoration: none;
}
ul {
list-style: none;
margin: 0;
@ -56,7 +63,7 @@ class ChatScroller extends LitElement {
.chat-list {
overflow-y: auto;
height: 91vh;
height: 92vh;
box-sizing: border-box;
}
@ -66,23 +73,14 @@ class ChatScroller extends LitElement {
.message-data-name {
color: var(--black);
cursor: pointer;
}
.message-data-time {
color: #a8aab1;
font-size: 13px;
padding-left: 6px;
}
.message-data-block {
color: #03a9f4;
font-size: 16px;
padding-left: 6px;
}
.blockicon {
color: #03a9f4;
--mdc-icon-size: 16px;
padding-bottom: 4px;
}
.message {
@ -204,7 +202,7 @@ class ChatScroller extends LitElement {
chatMessageTemplate(messageObj) {
let avatarImg = '';
let blockButton = '';
let nameMenu = '';
if (messageObj.senderName) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
@ -213,17 +211,17 @@ class ChatScroller extends LitElement {
}
if (messageObj.sender === this.myAddress) {
blockButton = ``
nameMenu = `${messageObj.senderName ? messageObj.senderName : messageObj.sender}`
} else {
blockButton = `<block-address toblockaddress="${messageObj.sender}"></block-address>`
nameMenu = `<name-menu toblockaddress="${messageObj.sender}" nametodialog="${messageObj.senderName ? messageObj.senderName : messageObj.sender}"></name-menu>`
}
return `
<li class="clearfix">
<div class="message-data ${messageObj.sender === this.myAddress ? "align-right" : ""}">
<span class="message-data-name">${messageObj.senderName ? messageObj.senderName : messageObj.sender}</span>
<span class="message-data-name">${nameMenu}</span>
<span class="message-data-time"><message-time timestamp=${messageObj.timestamp}></message-time></span>
<span class="message-data-block">${blockButton}</span>
</div>
</div>
<div class="message-data-avatar" style="width:42px; height:42px; ${messageObj.sender === this.myAddress ? "float:right;" : "float:left;"} margin:3px;">${avatarImg}</div>
<div id="messageContent" class="message ${messageObj.sender === this.myAddress ? "my-message float-right" : "other-message float-left"}">${this.emojiPicker.parse(this.escapeHTML(messageObj.decodedMessage))}</div>

2
qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js

@ -432,7 +432,7 @@ class ChatWelcomePage extends LitElement {
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const difficulty = this.balance === 0 ? 14 : 8;
const difficulty = this.balance === 0 ? 12 : 8;
const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);

622
qortal-ui-plugins/plugins/core/components/NameMenu.js

@ -0,0 +1,622 @@
import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import snackbar from './snackbar.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '@material/mwc-snackbar'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@polymer/paper-tooltip/paper-tooltip.js'
import '@polymer/paper-spinner/paper-spinner-lite.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class NameMenu extends LitElement {
static get properties() {
return {
toblockaddress: { type: String, attribute: true },
nametodialog: { type: String, attribute: true },
chatBlockedAdresses: { type: Array },
selectedAddress: { type: Object },
config: { type: Object },
myAddress: { type: Object, reflect: true },
messages: { type: Array },
btnDisable: { type: Boolean },
isLoading: { type: Boolean },
balance: { type: Number }
}
}
static get styles() {
return css`
* {
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
--mdc-dialog-content-ink-color: var(--black);
--mdc-theme-surface: var(--white);
--mdc-theme-text-primary-on-background: var(--black);
--paper-input-container-focus-color: var(--mdc-theme-primary);
--lumo-primary-text-color: rgb(0, 167, 245);
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
--lumo-primary-color: hsl(199, 100%, 48%);
--lumo-base-color: var(--white);
--lumo-body-text-color: var(--black);
}
a {
background-color: transparent;
color: var(--black);
text-decoration: none;
display: inline;
position: relative;
}
a:hover {
background-color: transparent;
color: var(--black);
text-decoration: none;
display: inline;
position: relative;
}
a:after {
content: '';
position: absolute;
width: 100%;
transform: scaleX(0);
height: 2px;
bottom: 0;
left: 0;
background-color: #03a9f4;
transform-origin: bottom right;
transition: transform 0.25s ease-out;
}
a:hover:after {
transform: scaleX(1);
transform-origin: bottom left;
}
.block {
}
.red {
--mdc-theme-primary: red;
}
h2 {
margin:0;
}
h2, h3, h4, h5 {
color:# var(--black);
font-weight: 400;
}
.custom {
--paper-tooltip-background: #03a9f4;
--paper-tooltip-text-color: #fff;
}
.dropdown {
position: relative;
display: inline;
}
.dropdown a:hover {
background-color: transparent;
}
.dropdown-content {
display: none;
position: absolute;
bottom: 25px;
left: 10px;
background-color: var(--white);
min-width: 200px;
overflow: auto;
border: 1px solid transparent;
border-radius: 10px;
box-shadow: var(--qchatshadow);
z-index: 1;
}
.dropdown-content span {
color: var(--nav-text-color);
text-align: center;
padding-top: 12px;
display: block;
}
.dropdown-content a {
color: var(--nav-text-color);
padding: 12px 12px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {
background-color: var(--nav-color-hover);
}
.showList {
display: block;
}
.input {
width: 90%;
border: none;
display: inline-block;
font-size: 16px;
padding: 10px 20px;
border-radius: 5px;
resize: none;
background: #eee;
}
.textarea {
width: 90%;
border: none;
display: inline-block;
font-size: 16px;
padding: 10px 20px;
border-radius: 5px;
height: 120px;
resize: none;
background: #eee;
}
`
}
constructor() {
super()
this.chatBlockedAdresses = []
this.selectedAddress = window.parent.reduxStore.getState().app.selectedAddress.address
this.myAddress = {}
this.balance = 1
this.messages = []
this.btnDisable = false
this.isLoading = false
}
render() {
return html`
<div class="dropdown">
<a class="block" id="myNameMenu" href="#" @click="${() => this.myMenu()}">${this.nametodialog}</a>
<paper-tooltip class="custom" for="myNameMenu" position="right">${translate("blockpage.bcchange7")}</paper-tooltip>
<div id="myDropdown" class="dropdown-content">
<span>${this.nametodialog}</span>
<hr style="color: var(--nav-text-color); border-radius: 90%;">
<a href="#" @click="${() => this.shadowRoot.querySelector('#blockNameDialog').show()}">${translate("blockpage.bcchange1")}</a>
<a href="#" @click="${() => this.copyToClipboard(this.toblockaddress)}">${translate("blockpage.bcchange8")}</a>
<a href="#" @click="${() => this.shadowRoot.querySelector('#startPmDialog').show()}">${translate("blockpage.bcchange9")}</a>
<a class="block" href="#" @click="${() => this.myMenu()}">${translate("general.close")}</a>
</div>
</div>
<mwc-dialog id="blockNameDialog">
<div style="text-align:center">
<h1>${translate("blockpage.bcchange5")}</h1>
<hr>
<h2>${translate("blockpage.bcchange6")}</h2><br>
<h2>${this.nametodialog}</h2>
</div>
<mwc-button
slot="secondaryAction"
@click="${() => this.chatBlockAddress()}"
class="block"
>
${translate("general.yes")}
</mwc-button>
<mwc-button
slot="primaryAction"
@click="${() => this.myMenu()}"
class="block red"
>
${translate("general.no")}
</mwc-button>
</mwc-dialog>
<mwc-dialog id="startPmDialog" scrimClickAction="${this.isLoading ? '' : 'close'}">
<div style="text-align:center">
<h1>${translate("welcomepage.wcchange2")}</h1>
<hr>
</div>
<p>${translate("welcomepage.wcchange3")}</p>
<textarea class="input" ?disabled=${this.isLoading} id="sendTo" rows="1">${this.nametodialog}</textarea>
<p style="margin-bottom:0;">
<textarea class="textarea" @keydown=${(e) => this._textArea(e)} ?disabled=${this.isLoading} id="messageBox" placeholder="${translate("welcomepage.wcchange5")}" rows="1"></textarea>
</p>
<mwc-button ?disabled="${this.isLoading}" slot="primaryAction" @click=${this._sendMessage}>${translate("welcomepage.wcchange6")}</mwc-button>
<mwc-button
?disabled="${this.isLoading}"
slot="secondaryAction"
@click="${() => this.myMenu()}"
class="block red"
>
${translate("general.close")}
</mwc-button>
</mwc-dialog>
`
}
firstUpdated() {
this.changeLanguage()
this.getChatBlockedAdresses()
setInterval(() => {
this.getChatBlockedAdresses();
}, 60000)
window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage')
use(checkLanguage)
})
window.onclick = function(event) {
if (!event.target.matches('.block')) {
var dropdowns = document.getElementsByClassName('dropdown-content');
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('showList')) {
openDropdown.classList.remove('showList');
}
}
}
}
const stopKeyEventPropagation = (e) => {
e.stopPropagation();
return false;
}
this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation);
this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation);
const getDataFromURL = () => {
let tempUrl = document.location.href
let splitedUrl = decodeURI(tempUrl).split('?')
let urlData = splitedUrl[1]
if (urlData !== undefined) {
this.chatId = urlData
}
}
let configLoaded = false
parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {}
selectedAddress = JSON.parse(selectedAddress)
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
this.selectedAddress = selectedAddress
})
parentEpml.request('apiCall', {
url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}`
}).then(res => {
this.balance = res
})
})
parentEpml.imReady()
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
}
}
myMenu() {
this.shadowRoot.getElementById('myDropdown').classList.toggle('showList')
this.shadowRoot.querySelector('#blockNameDialog').close()
this.shadowRoot.querySelector('#startPmDialog').close()
}
closeMenu() {
this.shadowRoot.getElementById('myDropdown').classList.toggle('showList')
var dropdowns = document.getElementsByClassName('dropdown-content');
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('showList')) {
openDropdown.classList.remove('showList');
}
}
}
async copyToClipboard(text) {
try {
let copyString1 = get("walletpage.wchange4")
await navigator.clipboard.writeText(text)
parentEpml.request('showSnackBar', `${copyString1}`)
this.closeMenu()
} catch (err) {
let copyString2 = get("walletpage.wchange39")
parentEpml.request('showSnackBar', `${copyString2}`)
console.error('Copy to clipboard error:', err)
this.closeMenu()
}
}
async getChatBlockedAdresses() {
const chatBlockedAdresses = await parentEpml.request('apiCall', {
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`
})
this.chatBlockedAdresses = chatBlockedAdresses
}
async chatBlockAddress() {
let address = this.toblockaddress
let items = [
address
]
let addressJsonString = JSON.stringify({ "items": items })
let ret = await parentEpml.request('apiCall', {
url: `/lists/blockedAddresses?apiKey=${this.getApiKey()}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: `${addressJsonString}`
})
if (ret === true) {
this.chatBlockedAdresses = this.chatBlockedAdresses.filter(item => item != address)
this.chatBlockedAdresses.push(address)
this.getChatBlockedList()
this.closeMenu()
this.shadowRoot.querySelector('#blockNameDialog').close()
let err1string = get("blockpage.bcchange2")
snackbar.add({
labelText: `${err1string}`,
dismiss: true
})
} else {
this.closeMenu()
this.shadowRoot.querySelector('#blockNameDialog').close()
let err2string = get("blockpage.bcchange2")
snackbar.add({
labelText: `${err2string}`,
dismiss: true
})
}
return ret
}
getChatBlockedList() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const blockedAddressesUrl = `${nodeUrl}/lists/blockedAddresses?apiKey=${this.getApiKey()}`
const err3string = 'No regitered name'
localStorage.removeItem("ChatBlockedAddresses")
var obj = [];
fetch(blockedAddressesUrl).then(response => {
return response.json()
}).then(data => {
return data.map(item => {
const noName = {
name: err3string,
owner: item
}
fetch(`${nodeUrl}/names/address/${item}?limit=0&reverse=true`).then(res => {
return res.json()
}).then(jsonRes => {
if(jsonRes.length) {
jsonRes.map (item => {
obj.push(item)
})
} else {
obj.push(noName)
}
localStorage.setItem("ChatBlockedAddresses", JSON.stringify(obj))
})
})
})
}
_sendMessage() {
this.isLoading = true
const recipient = this.shadowRoot.getElementById('sendTo').value
const messageBox = this.shadowRoot.getElementById('messageBox')
const messageText = messageBox.value
if (recipient.length === 0) {
this.isLoading = false
} else if (messageText.length === 0) {
this.isLoading = false
} else {
this.sendMessage()
}
}
async sendMessage(e) {
this.isLoading = true
const _recipient = this.shadowRoot.getElementById('sendTo').value
const messageBox = this.shadowRoot.getElementById('messageBox')
const messageText = messageBox.value
let recipient
const validateName = async (receiverName) => {
let myRes
let myNameRes = await parentEpml.request('apiCall', {
type: 'api',
url: `/names/${receiverName}`
})
if (myNameRes.error === 401) {
myRes = false
} else {
myRes = myNameRes
}
return myRes
}
const myNameRes = await validateName(_recipient)
if (!myNameRes) {
recipient = _recipient
} else {
recipient = myNameRes.owner
}
let _reference = new Uint8Array(64);
window.crypto.getRandomValues(_reference);
let sendTimestamp = Date.now()
let reference = window.parent.Base58.encode(_reference)
const getAddressPublicKey = async () => {
let isEncrypted
let _publicKey
let addressPublicKey = await parentEpml.request('apiCall', {
type: 'api',
url: `/addresses/publickey/${recipient}`
})
if (addressPublicKey.error === 102) {
_publicKey = false
// Do something here...
let err1string = get("welcomepage.wcchange7")
parentEpml.request('showSnackBar', `${err1string}`)
this.isLoading = false
} else if (addressPublicKey !== false) {
isEncrypted = 1
_publicKey = addressPublicKey
sendMessageRequest(isEncrypted, _publicKey)
} else {
isEncrypted = 0
_publicKey = this.selectedAddress.address
sendMessageRequest(isEncrypted, _publicKey)
}
};
const sendMessageRequest = async (isEncrypted, _publicKey) => {
let chatResponse = await parentEpml.request('chat', {
type: 18,
nonce: this.selectedAddress.nonce,
params: {
timestamp: sendTimestamp,
recipient: recipient,
recipientPublicKey: _publicKey,
message: messageText,
lastReference: reference,
proofOfWorkNonce: 0,
isEncrypted: isEncrypted,
isText: 1
}
})
_computePow(chatResponse)
}
const _computePow = async (chatBytes) => {
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
const chatBytesArray = new Uint8Array(_chatBytesArray)
const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result
const hashPtr = window.parent.sbrk(32, window.parent.heap);
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
hashAry.set(chatBytesHash);
const difficulty = this.balance === 0 ? 12 : 8;
const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce,
chatBytesArray: chatBytesArray,
chatNonce: nonce
})
getSendChatResponse(_response)
}
const getSendChatResponse = (response) => {
if (response === true) {
messageBox.value = ""
let err2string = get("welcomepage.wcchange8")
parentEpml.request('showSnackBar', `${err2string}`)
this.isLoading = false
this.closeMenu()
} else if (response.error) {
parentEpml.request('showSnackBar', response.message)
this.isLoading = false
this.closeMenu()
} else {
let err3string = get("welcomepage.wcchange9")
parentEpml.request('showSnackBar', `${err3string}`)
this.isLoading = false
this.closeMenu()
}
}
getAddressPublicKey()
}
_textMenu(event) {
const getSelectedText = () => {
var text = "";
if (typeof window.getSelection != "undefined") {
text = window.getSelection().toString();
} else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") {
text = this.shadowRoot.selection.createRange().text;
}
return text;
}
const checkSelectedTextAndShowMenu = () => {
let selectedText = getSelectedText();
if (selectedText && typeof selectedText === 'string') {
let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
parentEpml.request('openCopyTextMenu', textMenuObject)
}
}
checkSelectedTextAndShowMenu()
}
_textArea(e) {
if (e.keyCode === 13 && !e.shiftKey) this._sendMessage()
}
isEmptyArray(arr) {
if (!arr) { return true }
return arr.length === 0
}
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey;
return apiKey;
}
}
window.customElements.define('name-menu', NameMenu)

1
qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js

@ -904,7 +904,6 @@ class Chat extends LitElement {
}
scrollToBottom() {
const viewElement = this.shadowRoot.querySelector('chat-page').shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement');
viewElement.scroll({ top: viewElement.scrollHeight, left: 0, behavior: 'smooth' })
}

24
qortal-ui-plugins/plugins/core/minting/minting-info.src.js

@ -233,26 +233,9 @@ class MintingInfo extends LitElement {
<span class="title">${translate("mintingpage.mchange5")}</span>
<hr style="color: #eee; border-radius: 90%; margin-bottom: 1rem;">
<h4>${this._dayReward()} QORT</h4>
</div><br><br><br>
<div>
<span class="level-black">${this.renderActivateHelp()}</span>
<hr style="width: 50%;color: #eee; border-radius: 80%; margin-bottom: 2rem;">
</div><br>
</div>
</div>
<!-- Activate Account Dialog -->
<mwc-dialog id="activateAccountDialog">
<div style="text-align:center">
<h2>${translate("mintingpage.mchange12")}</h2>
<hr>
</div>
<div>
<h3>${translate("mintingpage.mchange13")}</h3><br />
${translate("mintingpage.mchange14")}
</div>
<mwc-button slot="primaryAction" dialogAction="cancel" class="red-button">${translate("general.close")}</mwc-button>
</mwc-dialog>
</div>
`} else {
return html`
@ -474,13 +457,6 @@ class MintingInfo extends LitElement {
}
}
renderActivateHelp() {
if (this.renderMintingPage() === "false") {
return html`${translate("mintingpage.mchange10")} <div class="level-blue">==></div> ${translate("mintingpage.mchange11")}<br><mwc-button class="red-button" @click=${() => this.shadowRoot.querySelector("#activateAccountDialog").show()}><mwc-icon class="help-icon">help_outline</mwc-icon>&nbsp;${translate("mintingpage.mchange31")}</mwc-button>`;
} else {
return "No Details";
}
}
_averageBlockTime() {
let avgBlockString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString();
let averageTimeString = ((avgBlockString / 1000) / 1440).toFixed(2);

180
qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js

@ -13,6 +13,7 @@ import '@material/mwc-checkbox'
import '@material/mwc-dialog'
import '@material/mwc-formfield'
import '@material/mwc-icon'
import '@material/mwc-icon-button'
import '@material/mwc-textfield'
import '@polymer/paper-progress/paper-progress.js'
import '@polymer/paper-slider/paper-slider.js'
@ -467,6 +468,16 @@ class MultiWallet extends LitElement {
position: relative;
}
.btn-clear-success {
--mdc-icon-button-size: 32px;
color: red;
}
.btn-clear-error {
--mdc-icon-button-size: 32px;
color: green;
}
@keyframes fade-in {
0% {
opacity: 0;
@ -476,6 +487,26 @@ class MultiWallet extends LitElement {
}
}
.successBox {
height: 34px;
min-width: 300px;
width: 100%;
border: 1px solid green;
border-radius: 5px;
background-color: transparent;
margin-top: 15px;
}
.errorBox {
height: 34px;
min-width: 300px;
width: 100%;
border: 1px solid red;
border-radius: 5px;
background-color: transparent;
margin-top: 15px;
}
@media (max-width: 863px) {
.wallet {
width: 100%;
@ -583,7 +614,7 @@ class MultiWallet extends LitElement {
this.sendMoneyLoading = false
this.isValidAmount = false
this.btnDisable = false
this.balance = 0
this.balance = 0
this.amount = 0
this.btcAmount = 0
this.ltcAmount = 0
@ -600,9 +631,9 @@ class MultiWallet extends LitElement {
this.dogeFeePerByte = 1000
this.dogeSatMinFee = 100
this.dogeSatMaxFee = 10000
this.dgbFeePerByte = 100
this.dgbSatMinFee = 10
this.dgbSatMaxFee = 1000
this.dgbFeePerByte = 10
this.dgbSatMinFee = 1
this.dgbSatMaxFee = 100
this.rvnFeePerByte = 1125
this.rvnSatMinFee = 1000
this.rvnSatMaxFee = 10000
@ -641,6 +672,7 @@ class MultiWallet extends LitElement {
this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet
this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet
this.wallets.get('dgb').wallet = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet
this.wallets.get('rvn').wallet = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet
this.wallets.get('arrr').wallet = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet
})
@ -1102,11 +1134,11 @@ class MultiWallet extends LitElement {
>
</mwc-textfield>
</p>
<div style="margin-bottom: 0;">
<div style="margin-bottom: 10px;">
<p style="margin-bottom: 0;">${translate("walletpage.wchange21")} <span style="font-weight: bold;">0.001 QORT<span></p>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1119,7 +1151,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeQortDialog()}"
class="red"
>
${translate("general.close")}
@ -1179,8 +1211,8 @@ class MultiWallet extends LitElement {
>
</paper-slider>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1193,7 +1225,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeBtcDialog()}"
class="red"
>
${translate("general.close")}
@ -1253,8 +1285,8 @@ class MultiWallet extends LitElement {
>
</paper-slider>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1267,7 +1299,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeLtcDialog()}"
class="red"
>
${translate("general.close")}
@ -1315,7 +1347,7 @@ class MultiWallet extends LitElement {
</p>
<div style="margin-bottom: 0;">
<p style="margin-bottom: 0;">
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.dogeFeePerByte / 1e8).toFixed(8)} DOGE</span><br>L${translate("walletpage.wchange25")}
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.dogeFeePerByte / 1e8).toFixed(8)} DOGE</span><br>${translate("walletpage.wchange25")}
</p>
<paper-slider
class="blue"
@ -1329,8 +1361,8 @@ class MultiWallet extends LitElement {
>
</paper-slider>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1343,7 +1375,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeDogeDialog()}"
class="red"
>
${translate("general.close")}
@ -1391,7 +1423,7 @@ class MultiWallet extends LitElement {
</p>
<div style="margin-bottom: 0;">
<p style="margin-bottom: 0;">
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.dgbFeePerByte / 1e8).toFixed(8)} DGB</span><br>L${translate("walletpage.wchange25")}
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.dgbFeePerByte / 1e8).toFixed(8)} DGB</span><br>${translate("walletpage.wchange25")}
</p>
<paper-slider
class="blue"
@ -1405,8 +1437,8 @@ class MultiWallet extends LitElement {
>
</paper-slider>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1419,7 +1451,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeDgbDialog()}"
class="red"
>
${translate("general.close")}
@ -1467,7 +1499,7 @@ class MultiWallet extends LitElement {
</p>
<div style="margin-bottom: 0;">
<p style="margin-bottom: 0;">
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.rvnFeePerByte / 1e8).toFixed(8)} RVN</span><br>L${translate("walletpage.wchange25")}
${translate("walletpage.wchange24")}: <span style="font-weight: bold;">${(this.rvnFeePerByte / 1e8).toFixed(8)} RVN</span><br>${translate("walletpage.wchange25")}
</p>
<paper-slider
class="blue"
@ -1481,8 +1513,8 @@ class MultiWallet extends LitElement {
>
</paper-slider>
</div>
<p style="color: red;">${this.errorMessage}</p>
<p style="color: green;">${this.successMessage}</p>
${this.renderClearSuccess()}
${this.renderClearError()}
${this.sendMoneyLoading ? html` <paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress> ` : ''}
<div class="buttons">
<div>
@ -1495,7 +1527,7 @@ class MultiWallet extends LitElement {
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click="${() => this.closeRvnDialog()}"
class="red"
>
${translate("general.close")}
@ -1570,14 +1602,6 @@ class MultiWallet extends LitElement {
this.changeTheme()
this.changeLanguage()
setInterval(() => {
this.errorMessage = '';
}, 10000)
setInterval(() => {
this.successMessage = '';
}, 10000)
this.currencyBoxes = this.shadowRoot.querySelectorAll('.currency-box')
this.transactionsDOM = this.shadowRoot.getElementById('transactionsDOM')
@ -1863,7 +1887,7 @@ class MultiWallet extends LitElement {
let selectedText = getSelectedText()
if (selectedText && typeof selectedText === 'string') {
} else {
this.pasteMenu(event, 'rvnAmountInput')
this.pasteMenu(event, 'dgbRecipient')
this.isPasteMenuOpen = true
event.preventDefault()
event.stopPropagation()
@ -1872,7 +1896,7 @@ class MultiWallet extends LitElement {
checkSelectedTextAndShowMenu()
})
this.shadowRoot.getElementById('rvnRecipient').addEventListener('contextmenu', (event) => {
this.shadowRoot.getElementById('rvnAmountInput').addEventListener('contextmenu', (event) => {
const getSelectedText = () => {
var text = ''
if (typeof window.getSelection != 'undefined') {
@ -1886,7 +1910,7 @@ class MultiWallet extends LitElement {
let selectedText = getSelectedText()
if (selectedText && typeof selectedText === 'string') {
} else {
this.pasteMenu(event, 'rvnRecipient')
this.pasteMenu(event, 'rvnAmountInput')
this.isPasteMenuOpen = true
event.preventDefault()
event.stopPropagation()
@ -1942,6 +1966,76 @@ class MultiWallet extends LitElement {
})
}
renderClearSuccess() {
let strSuccessValue = this.successMessage
if (strSuccessValue === "") {
return html``
} else {
return html`
<div class="successBox">
<span style="color: green; float: left; padding-top: 4px; padding-left: 7px;">${this.successMessage}</span>
<span style="padding-top: 4px: padding-right: 7px; float: right;"><mwc-icon-button class="btn-clear-success" title="${translate("general.close")}" icon="close" @click="${() => this.successMessage = ''}"></mwc-icon-button></span>
</div>
<div style="margin-bottom: 15px;">
<p style="margin-bottom: 0;">${translate("walletpage.wchange43")}</p>
</div>
`
}
}
renderClearError() {
let strErrorValue = this.errorMessage
if (strErrorValue === "") {
return html``
} else {
return html`
<div class="errorBox">
<span style="color: red; float: left; padding-top: 4px; padding-left: 7px;">${this.errorMessage}</span>
<span style="padding-top: 4px: padding-right: 7px; float: right;"><mwc-icon-button class="btn-clear-error" title="${translate("general.close")}" icon="close" @click="${() => this.errorMessage = ''}"></mwc-icon-button></span>
</div>
<div style="margin-bottom: 15px;">
<p style="margin-bottom: 0;">${translate("walletpage.wchange44")}</p>
</div>
`
}
}
closeQortDialog() {
this.shadowRoot.querySelector('#sendQortDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
closeBtcDialog() {
this.shadowRoot.querySelector('#sendBtcDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
closeLtcDialog() {
this.shadowRoot.querySelector('#sendLtcDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
closeDogeDialog() {
this.shadowRoot.querySelector('#sendDogeDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
closeDgbDialog() {
this.shadowRoot.querySelector('#sendDgbDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
closeRvnDialog() {
this.shadowRoot.querySelector('#sendRvnDialog').close()
this.successMessage = ''
this.errorMessage = ''
}
renderFetchText() {
return html`${translate("walletpage.wchange1")}`
}
@ -2755,7 +2849,17 @@ class MultiWallet extends LitElement {
},
{ passive: true }
)
} else if (coin === 'arrr') {
} else if (coin === 'rvn') {
this.transactionsGrid.addEventListener(
'click',
(e) => {
let rvnItem = this.transactionsGrid.getEventContext(e).item
this.showRvnTransactionDetails(rvnItem, this.wallets.get(this._selectedWallet).transactions)
},
{ passive: true }
)
}
else if (coin === 'arrr') {
this.transactionsGrid.addEventListener(
'click',
(e) => {

Loading…
Cancel
Save