Compare commits

...

48 Commits

Author SHA1 Message Date
AlphaX
94835b5118
Merge pull request #365 from Qortal/feature/add-support-base64-field-qr
add support for base64 field
2025-04-27 10:10:05 +02:00
1287d0feed remove unused component 2025-04-14 22:36:38 +03:00
d51216516d fix display name 2025-04-12 07:40:41 +03:00
3c3e1d6e38 allow no name for qr- use default in ui 2025-04-12 07:14:15 +03:00
e9a0da9fda add support for base64 field 2025-04-10 00:45:29 +03:00
AlphaX
747b555edb
Merge pull request #364 from AlphaX-Qortal/master
Fix copy to clipboard in iframe
2025-03-20 11:52:49 +01:00
AlphaX
36e7bd8ba6
Fix copy to clipboard in iframe 2025-03-20 11:51:59 +01:00
AlphaX
29965500fc
Update browser.src.js 2025-03-20 11:28:17 +01:00
AlphaX
75f923e025
Merge pull request #363 from AlphaX-Qortal/master
Update dependencies
2025-03-19 17:31:12 +01:00
AlphaX-Qortal
f12b0c9bf8 Update dependencies 2025-03-19 17:30:04 +01:00
AlphaX
0e3220eed0
Merge pull request #362 from AlphaX-Qortal/master
Update entitlements.mac.plist
2025-03-19 17:06:01 +01:00
AlphaX
f0a5eeebc8
Update entitlements.mac.plist 2025-03-19 17:02:57 +01:00
AlphaX
2ed1b08cd8
Merge pull request #361 from AlphaX-Qortal/master
Added qortal requests for wallet app
2025-03-19 09:24:23 +01:00
AlphaX-Qortal
e4eede5087 Fix response 2025-03-19 09:19:54 +01:00
AlphaX
9dbc4b085b
Fix typo 2025-03-18 19:19:00 +01:00
AlphaX-Qortal
7ca9acaf3a Added qortal requests 2025-03-18 17:20:46 +01:00
AlphaX-Qortal
e3ef24dc5e Fix parsing use-embed 2025-02-26 09:37:46 +01:00
AlphaX
9d72f4539d
Merge pull request #360 from AlphaX-Qortal/master
Fix typo and update dependencies
2025-02-25 11:52:51 +01:00
AlphaX-Qortal
060390da23 Update dependencies 2025-02-25 11:51:10 +01:00
AlphaX-Qortal
2547025d9e Fix typo 2025-02-25 10:24:18 +01:00
AlphaX
665d708563
Merge pull request #359 from AlphaX-Qortal/master
Fix sign tx json output
2025-02-18 18:06:48 +01:00
AlphaX-Qortal
c686a12c3a Fix sign tx json output 2025-02-18 18:05:57 +01:00
AlphaX
e2d6d83fd8
Merge pull request #358 from AlphaX-Qortal/master
Fixed view chat timestamp and reworked view chat dialog
2025-02-18 10:44:07 +01:00
AlphaX-Qortal
78f25607e2 Fixed view chat timestamp and reworked view chat dialog 2025-02-18 10:40:51 +01:00
AlphaX
502952550c
Merge pull request #357 from kennycud/master
Language Support for Level 0 Self Share Allowance
2025-02-15 10:26:48 +01:00
kennycud
7cae21d8ed
Merge branch 'Qortal:master' into master 2025-02-14 11:27:46 -08:00
AlphaX-Qortal
6e648ece9d Update dependencies 2025-02-14 16:52:58 +01:00
AlphaX
b74cd40cd3
Merge pull request #356 from AlphaX-Qortal/master
Fixes
2025-02-14 16:19:45 +01:00
AlphaX-Qortal
d7708259de Fixes
- Fixed reply to encrypted messages
- Fixed show replied encrypted messages
- Fixed edit encrypted messages
- Added MINTER group logo
2025-02-14 16:17:23 +01:00
AlphaX-Qortal
3837973ba8 Bump version 4.6.1 2025-02-13 17:58:44 +01:00
AlphaX
af8dcae748
Merge pull request #355 from AlphaX-Qortal/master
Various updates
2025-02-13 17:24:28 +01:00
AlphaX-Qortal
8b64c80019 Various updates
- Added level 0 can create selfshare
- Added Q-Mintership to default Q-Apps
- Changed chat lock icons
- Fixed encryption icon in PM
2025-02-13 17:23:15 +01:00
kennycud
1ded359b7a
Merge branch 'Qortal:master' into master 2025-02-13 08:15:02 -08:00
AlphaX
2e3a02458d
Merge pull request #354 from AlphaX-Qortal/master
Remove preview chat
2025-02-13 10:39:33 +01:00
AlphaX-Qortal
8b8ad3015f Remove preview chat 2025-02-13 10:37:15 +01:00
AlphaX
d16781e73b
Merge pull request #353 from AlphaX-Qortal/master
Change protocol check in trade portal and auto buy
2025-02-13 08:39:40 +01:00
AlphaX-Qortal
d6e0846d58 Change protocol check in trade portal and auto buy 2025-02-13 08:38:14 +01:00
AlphaX
003eb5c45a
Merge pull request #352 from AlphaX-Qortal/master
Change protocol check
2025-02-12 22:27:52 +01:00
AlphaX-Qortal
f7971f7026 Change protocol check 2025-02-12 22:26:49 +01:00
AlphaX
d3f9e0878b
Merge pull request #351 from AlphaX-Qortal/master
Fix message decoding
2025-02-12 21:34:23 +01:00
AlphaX-Qortal
585d133143 Fix message decoding 2025-02-12 21:33:36 +01:00
AlphaX
4457215a0e
Merge pull request #350 from AlphaX-Qortal/master
Various updates
2025-02-11 20:31:31 +01:00
AlphaX-Qortal
d915b25b47 Various updates
- Add display private messages from Qortal-Hub
- Re-add accidentally deleted qortal request SAVE_FILE
- Reworked decoding Qortal-Hub messages
- Update languages files
2025-02-11 20:29:22 +01:00
kennycud
80d4ce82f1
Merge branch 'Qortal:master' into master 2025-02-07 04:58:39 -08:00
kennycud
6ad91d6934
Merge branch 'Qortal:master' into master 2025-02-04 10:32:02 -08:00
kennycud
4fa85d4923
Merge branch 'Qortal:master' into master 2025-01-30 13:33:18 -08:00
kennycud
eade77c98b language update for dropped minimum level 1 constraint for reward share to self, self share 2025-01-12 16:26:06 -08:00
kennycud
79e9080f6e dropped minimum level 1 constraint for reward share to self 2025-01-12 14:13:44 -08:00
54 changed files with 1596 additions and 2629 deletions

View File

@ -26,8 +26,8 @@ Easiest way to install the lastest required packages on Linux is via nvm.
``` source ~/.profile ``` (For Debian based distro) <br/> ``` source ~/.profile ``` (For Debian based distro) <br/>
``` source ~/.bashrc ``` (For Fedora / CentOS) <br/> ``` source ~/.bashrc ``` (For Fedora / CentOS) <br/>
``` nvm ls-remote ``` (Fetch list of available versions) <br/> ``` nvm ls-remote ``` (Fetch list of available versions) <br/>
``` nvm install v20.18.1 ``` (Latest LTS: Iron supported by Electron V34) <br/> ``` nvm install v20.16.0 ``` (Latest LTS: Iron supported by Electron V32) <br/>
``` npm --location=global install npm@11.1.0 ``` <br/> ``` npm --location=global install npm@10.9.2 ``` <br/>
Adding via binary package mirror will only work if you have set the package path. You can do a node or java build via ports instead by downloading ports with portsnap fetch method. Adding via binary package mirror will only work if you have set the package path. You can do a node or java build via ports instead by downloading ports with portsnap fetch method.

View File

@ -2,7 +2,23 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key> <key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/> <true/>
</dict> </dict>
</plist> </plist>

View File

@ -468,7 +468,7 @@
"rchange6": "Empfänger", "rchange6": "Empfänger",
"rchange7": "Aktion", "rchange7": "Aktion",
"rchange8": "Typ", "rchange8": "Typ",
"rchange9": "Die Stufen 14 können nur Self-Share-(Minting-)Schlüssel erstellen. Nur Level 5 oder höher kann einen Prämienanteil erstellen!", "rchange9": "Die Stufen 04 können nur Self-Share-(Minting-)Schlüssel erstellen. Nur Level 5 oder höher kann einen Prämienanteil erstellen!",
"rchange10": "Öffentlicher Schlüssel des Empfängers", "rchange10": "Öffentlicher Schlüssel des Empfängers",
"rchange11": "Belohnungsanteil in Prozent", "rchange11": "Belohnungsanteil in Prozent",
"rchange12": "Angeforderter Befehl wird ausgeführt...", "rchange12": "Angeforderter Befehl wird ausgeführt...",
@ -1417,6 +1417,7 @@
"mpchange83": "ABGELEHNT", "mpchange83": "ABGELEHNT",
"mpchange84": "FEHLER", "mpchange84": "FEHLER",
"mpchange85": "ERFOLGREICH", "mpchange85": "ERFOLGREICH",
"mpchange86": "Immer automatisches Abrufen des Wallet-Guthabens zulassen" "mpchange86": "Immer automatisches Abrufen des Wallet-Guthabens zulassen",
"mpchange87": "Bitte geben Sie die Gruppen-ID ein"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Receptor", "rchange6": "Receptor",
"rchange7": "Acción", "rchange7": "Acción",
"rchange8": "Tipo", "rchange8": "Tipo",
"rchange9": "Los niveles 1 a 4 solo pueden crear claves Self-Share (acuñación). ¡Solo el nivel 5 o superior puede crear una recompensa compartida!", "rchange9": "Los niveles 0 a 4 solo pueden crear claves Self-Share (acuñación). ¡Solo el nivel 5 o superior puede crear una recompensa compartida!",
"rchange10": "Clave pública del receptor", "rchange10": "Clave pública del receptor",
"rchange11": "Porcentaje de Reward share", "rchange11": "Porcentaje de Reward share",
"rchange12": "Ejecutando el comando solicitado", "rchange12": "Ejecutando el comando solicitado",
@ -1417,6 +1417,7 @@
"mpchange83": "RECHAZADO", "mpchange83": "RECHAZADO",
"mpchange84": "ERROR", "mpchange84": "ERROR",
"mpchange85": "ÉXITO", "mpchange85": "ÉXITO",
"mpchange86": "Permitir siempre obtener el saldo de la billetera automáticamente" "mpchange86": "Permitir siempre obtener el saldo de la billetera automáticamente",
"mpchange87": "Por favor, introduzca el ID del grupo"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Saaja", "rchange6": "Saaja",
"rchange7": "Tegevus", "rchange7": "Tegevus",
"rchange8": "Tüüp", "rchange8": "Tüüp",
"rchange9": "Tase 1 - 4 saab luua iseseiseva jagamise. Tase 5 või kõrgem saab luua Preemiajagamise!", "rchange9": "Tase 0 - 4 saab luua iseseiseva jagamise. Tase 5 või kõrgem saab luua Preemiajagamise!",
"rchange10": "Saaja avalik võti", "rchange10": "Saaja avalik võti",
"rchange11": "Preemiajagamise protsent", "rchange11": "Preemiajagamise protsent",
"rchange12": "Teeb midagi maitsvat", "rchange12": "Teeb midagi maitsvat",
@ -1417,6 +1417,7 @@
"mpchange83": "DECLINED", "mpchange83": "DECLINED",
"mpchange84": "FAILURE", "mpchange84": "FAILURE",
"mpchange85": "EDU", "mpchange85": "EDU",
"mpchange86": "Luba alati rahakoti saldo automaatne hankimine" "mpchange86": "Luba alati rahakoti saldo automaatne hankimine",
"mpchange87": "Palun sisestage grupi ID"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Vastaanottaja", "rchange6": "Vastaanottaja",
"rchange7": "Toiminta", "rchange7": "Toiminta",
"rchange8": "Tyyppi", "rchange8": "Tyyppi",
"rchange9": "Tasot 1 - 4 voivat luoda erillisen jaon. Taso 5 tai korkeampi voi luoda palkintoosuuden!", "rchange9": "Tasot 0 - 4 voivat luoda erillisen jaon. Taso 5 tai korkeampi voi luoda palkintoosuuden!",
"rchange10": "Vastaanottajan julkinen avain", "rchange10": "Vastaanottajan julkinen avain",
"rchange11": "Palkintojen jakoprosentti", "rchange11": "Palkintojen jakoprosentti",
"rchange12": "Tekee jotain herkullista", "rchange12": "Tekee jotain herkullista",
@ -1417,6 +1417,7 @@
"mpchange83": "hylätty", "mpchange83": "hylätty",
"mpchange84": "FAILURE", "mpchange84": "FAILURE",
"mpchange85": "SUCCESS", "mpchange85": "SUCCESS",
"mpchange86": "Salli aina saada lompakon saldo automaattisesti" "mpchange86": "Salli aina saada lompakon saldo automaattisesti",
"mpchange87": "Anna ryhmän tunnus"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Destinataire", "rchange6": "Destinataire",
"rchange7": "Action", "rchange7": "Action",
"rchange8": "Type", "rchange8": "Type",
"rchange9": "Niveau 1 - 4 peuvent créer un autopartage et niveau 5 et supérieur peuvent créer un partage de récompense!", "rchange9": "Niveau 0 - 4 peuvent créer un autopartage et niveau 5 et supérieur peuvent créer un partage de récompense!",
"rchange10": "Clé publique du bénéficiaire", "rchange10": "Clé publique du bénéficiaire",
"rchange11": "Pourcentage du partage de récompense", "rchange11": "Pourcentage du partage de récompense",
"rchange12": "Faire quelque chose de délicieux", "rchange12": "Faire quelque chose de délicieux",
@ -1417,6 +1417,7 @@
"mpchange83": "REFUSÉ", "mpchange83": "REFUSÉ",
"mpchange84": "ÉCHEC", "mpchange84": "ÉCHEC",
"mpchange85": "SUCCÈS", "mpchange85": "SUCCÈS",
"mpchange86": "Toujours autoriser l'obtention automatique du solde du portefeuille" "mpchange86": "Toujours autoriser l'obtention automatique du solde du portefeuille",
"mpchange87": "Veuillez saisir l'ID du groupe"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "प्राप्तकर्ता", "rchange6": "प्राप्तकर्ता",
"rchange7": "कार्रवाई", "rchange7": "कार्रवाई",
"rchange8": "टाइप", "rchange8": "टाइप",
"rchange9": "लेवल 1 - 4 एक सेल्फ शेयर बना सकता है और लेवल 5 या उससे ऊपर एक रिवॉर्ड शेयर बना सकता है!", "rchange9": "लेवल 0 - 4 एक सेल्फ शेयर बना सकता है और लेवल 5 या उससे ऊपर एक रिवॉर्ड शेयर बना सकता है!",
"rchange10": "प्राप्तकर्ता सार्वजनिक कुंजी", "rchange10": "प्राप्तकर्ता सार्वजनिक कुंजी",
"rchange11": "रिवॉर्ड शेयर प्रतिशत", "rchange11": "रिवॉर्ड शेयर प्रतिशत",
"rchange12": "कुछ स्वादिष्ट करना", "rchange12": "कुछ स्वादिष्ट करना",
@ -1417,6 +1417,7 @@
"mpchange83": "अस्वीकृत", "mpchange83": "अस्वीकृत",
"mpchange84": "विफल", "mpchange84": "विफल",
"mpchange85": "सफल", "mpchange85": "सफल",
"mpchange86": "हमेशा वॉलेट बैलेंस को स्वचालित रूप से प्राप्त करने की अनुमति दें" "mpchange86": "हमेशा वॉलेट बैलेंस को स्वचालित रूप से प्राप्त करने की अनुमति दें",
"mpchange87": "कृपया ग्रुप आईडी दर्ज करें"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Primatelj", "rchange6": "Primatelj",
"rchange7": "Akcija", "rchange7": "Akcija",
"rchange8": "Vrsta", "rchange8": "Vrsta",
"rchange9": "Level 1 - 4 može stvoriti samo vlastiti udio a level 5 ili više može stvoriti nagradni udio!", "rchange9": "Level 0 - 4 može stvoriti samo vlastiti udio a level 5 ili više može stvoriti nagradni udio!",
"rchange10": "Primateljov javni ključ", "rchange10": "Primateljov javni ključ",
"rchange11": "Nagradni udio postotak", "rchange11": "Nagradni udio postotak",
"rchange12": "Radiš nešto ukusno :-)", "rchange12": "Radiš nešto ukusno :-)",
@ -1417,6 +1417,7 @@
"mpchange83": "ODBIJENO", "mpchange83": "ODBIJENO",
"mpchange84": "GREŠKA", "mpchange84": "GREŠKA",
"mpchange85": "USPJEH", "mpchange85": "USPJEH",
"mpchange86": "Uvijek dopusti automatsko dobivanje stanja novčanika" "mpchange86": "Uvijek dopusti automatsko dobivanje stanja novčanika",
"mpchange87": "Molimo unesite ID grupe"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Címzett", "rchange6": "Címzett",
"rchange7": "Akció", "rchange7": "Akció",
"rchange8": "Típus", "rchange8": "Típus",
"rchange9": "Az 1- 4. szint létrehozhat egy önmegosztást, és az 5. vagy annál magasabb szint jutalommegosztást hozhat létre!", "rchange9": "Az 0- 4. szint létrehozhat egy önmegosztást, és az 5. vagy annál magasabb szint jutalommegosztást hozhat létre!",
"rchange10": "Címzett Nyilvános Kulcsa", "rchange10": "Címzett Nyilvános Kulcsa",
"rchange11": "Jutalomrészesedési Százalék", "rchange11": "Jutalomrészesedési Százalék",
"rchange12": "Valami Finomat Csinálni", "rchange12": "Valami Finomat Csinálni",
@ -1417,6 +1417,7 @@
"mpchange83": "Elutasítva", "mpchange83": "Elutasítva",
"mpchange84": "FAILURE", "mpchange84": "FAILURE",
"mpchange85": "SIKER", "mpchange85": "SIKER",
"mpchange86": "Mindig engedélyezze a pénztárcaegyenleg automatikus lekérését" "mpchange86": "Mindig engedélyezze a pénztárcaegyenleg automatikus lekérését",
"mpchange87": "Kérjük, adja meg a csoport azonosítóját"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Destinatario", "rchange6": "Destinatario",
"rchange7": "Azione", "rchange7": "Azione",
"rchange8": "Tipo", "rchange8": "Tipo",
"rchange9": "Level 1 - 4 can create a Self Share and Level 5 or above can create a Reward Share!", "rchange9": "Level 0 - 4 can create a Self Share and Level 5 or above can create a Reward Share!",
"rchange10": "Chiave pubblica del destinatario", "rchange10": "Chiave pubblica del destinatario",
"rchange11": "Percentuale di quota premio", "rchange11": "Percentuale di quota premio",
"rchange12": "Fare qualcosa di delizioso", "rchange12": "Fare qualcosa di delizioso",
@ -1417,6 +1417,7 @@
"mpchange83": "RIFIUTATO", "mpchange83": "RIFIUTATO",
"mpchange84": "FALLITO", "mpchange84": "FALLITO",
"mpchange85": "RIUSCITO", "mpchange85": "RIUSCITO",
"mpchange86": "Consenti sempre di ottenere automaticamente il saldo del portafoglio" "mpchange86": "Consenti sempre di ottenere automaticamente il saldo del portafoglio",
"mpchange87": "Inserisci l'ID del gruppo"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "受取人", "rchange6": "受取人",
"rchange7": "アクション", "rchange7": "アクション",
"rchange8": "タイプ", "rchange8": "タイプ",
"rchange9": "レベル 1 4 は自己シェアを、レベル 5 以上は報酬シェアを作成出来ます!", "rchange9": "レベル 0 4 は自己シェアを、レベル 5 以上は報酬シェアを作成出来ます!",
"rchange10": "受取人の公開鍵", "rchange10": "受取人の公開鍵",
"rchange11": "報酬シェア率", "rchange11": "報酬シェア率",
"rchange12": "おいしいことをしています", "rchange12": "おいしいことをしています",
@ -1417,6 +1417,7 @@
"mpchange83": "拒否されました", "mpchange83": "拒否されました",
"mpchange84": "失敗", "mpchange84": "失敗",
"mpchange85": "成功", "mpchange85": "成功",
"mpchange86": "ウォレット残高の自動取得を常に許可する" "mpchange86": "ウォレット残高の自動取得を常に許可する",
"mpchange87": "グループ ID を入力してください"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "받는사람", "rchange6": "받는사람",
"rchange7": "액션", "rchange7": "액션",
"rchange8": "유형", "rchange8": "유형",
"rchange9": "레벨 1 - 4는 자체 공유를 생성할 수 있으며 레벨 5 이상은 보상 공유를 생성할 수 있습니다.", "rchange9": "레벨 0 - 4는 자체 공유를 생성할 수 있으며 레벨 5 이상은 보상 공유를 생성할 수 있습니다.",
"rchange10": "수신자 공개 키", "rchange10": "수신자 공개 키",
"rchange11": "보상공유율", "rchange11": "보상공유율",
"rchange12": "맛있는 거 하기", "rchange12": "맛있는 거 하기",
@ -1417,6 +1417,7 @@
"mpchange83": "거부됨", "mpchange83": "거부됨",
"mpchange84": "실패", "mpchange84": "실패",
"mpchange85": "성공", "mpchange85": "성공",
"mpchange86": "항상 지갑 잔액을 자동으로 가져오도록 허용" "mpchange86": "항상 지갑 잔액을 자동으로 가져오도록 허용",
"mpchange87": "그룹 ID를 입력하세요"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Ontvanger", "rchange6": "Ontvanger",
"rchange7": "Actie", "rchange7": "Actie",
"rchange8": "Type", "rchange8": "Type",
"rchange9": "Level 1 - 4 kunnen een zelf-beloning aanmaken en Level 5 en hoger kunnen een belonings-deel toekennen!", "rchange9": "Level 0 - 4 kunnen een zelf-beloning aanmaken en Level 5 en hoger kunnen een belonings-deel toekennen!",
"rchange10": "Publieke sleutel van de ontvanger", "rchange10": "Publieke sleutel van de ontvanger",
"rchange11": "Belonings-deel in procent", "rchange11": "Belonings-deel in procent",
"rchange12": "Doe iets heerlijk", "rchange12": "Doe iets heerlijk",
@ -1417,6 +1417,7 @@
"mpchange83": "GEWEIGERD", "mpchange83": "GEWEIGERD",
"mpchange84": "MISLUKT", "mpchange84": "MISLUKT",
"mpchange85": "SUCCES", "mpchange85": "SUCCES",
"mpchange86": "Altijd toestaan om automatisch saldo in portemonnee op te halen" "mpchange86": "Altijd toestaan om automatisch saldo in portemonnee op te halen",
"mpchange87": "Voer de groeps-ID in"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Mottaker", "rchange6": "Mottaker",
"rchange7": "Handling", "rchange7": "Handling",
"rchange8": "Type", "rchange8": "Type",
"rchange9": "Nivå 1 - 4 kan opprette en selvdel og nivå 5 eller høyere kan opprette en belønningsdel!", "rchange9": "Nivå 0 - 4 kan opprette en selvdel og nivå 5 eller høyere kan opprette en belønningsdel!",
"rchange10": "Mottaker offentlig nøkkel", "rchange10": "Mottaker offentlig nøkkel",
"rchange11": "Belønningsdel prosent", "rchange11": "Belønningsdel prosent",
"rchange12": "Gjøre noe nydelig", "rchange12": "Gjøre noe nydelig",
@ -1417,6 +1417,7 @@
"mpchange83": "AVSLAGT", "mpchange83": "AVSLAGT",
"mpchange84": "FEIL", "mpchange84": "FEIL",
"mpchange85": "SUKSESS", "mpchange85": "SUKSESS",
"mpchange86": "Tillat alltid få lommeboksaldo automatisk" "mpchange86": "Tillat alltid få lommeboksaldo automatisk",
"mpchange87": "Vennligst skriv inn gruppe-ID"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Odbiorca", "rchange6": "Odbiorca",
"rchange7": "Akcja", "rchange7": "Akcja",
"rchange8": "Typ", "rchange8": "Typ",
"rchange9": "Poziomy 1 - 4 mogą tworzyć Self Share, a poziom 5 lub wyższy może tworzyć Reward Share!", "rchange9": "Poziomy 0 - 4 mogą tworzyć Self Share, a poziom 5 lub wyższy może tworzyć Reward Share!",
"rchange10": "Publiczny klucz odbiorcy", "rchange10": "Publiczny klucz odbiorcy",
"rchange11": "Procent udziału w nagrodzie", "rchange11": "Procent udziału w nagrodzie",
"rchange12": "Robimy coś pysznego", "rchange12": "Robimy coś pysznego",
@ -1417,6 +1417,7 @@
"mpchange83": "ODRZUCONE", "mpchange83": "ODRZUCONE",
"mpchange84": "NIEPOWODZENIE", "mpchange84": "NIEPOWODZENIE",
"mpchange85": "POWODZENIE", "mpchange85": "POWODZENIE",
"mpchange86": "Zawsze zezwalaj na automatyczne pobieranie salda portfela" "mpchange86": "Zawsze zezwalaj na automatyczne pobieranie salda portfela",
"mpchange87": "Wprowadź identyfikator grupy"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Recipiente", "rchange6": "Recipiente",
"rchange7": "Ação", "rchange7": "Ação",
"rchange8": "Tipo", "rchange8": "Tipo",
"rchange9": "Nível 1 - 4 podem criar Auto Ações e nível 5 ou superior podem criar Ações de Recompensa!", "rchange9": "Nível 0 - 4 podem criar Auto Ações e nível 5 ou superior podem criar Ações de Recompensa!",
"rchange10": "Chave Pública do Destinatário", "rchange10": "Chave Pública do Destinatário",
"rchange11": "Porcentagem das ações de recompensa", "rchange11": "Porcentagem das ações de recompensa",
"rchange12": "Fazendo algo delicioso", "rchange12": "Fazendo algo delicioso",
@ -1417,6 +1417,7 @@
"mpchange83": "RECLINADO", "mpchange83": "RECLINADO",
"mpchange84": "FALHA", "mpchange84": "FALHA",
"mpchange85": "SUCESSO", "mpchange85": "SUCESSO",
"mpchange86": "Permitir sempre obter saldo da carteira automaticamente" "mpchange86": "Permitir sempre obter saldo da carteira automaticamente",
"mpchange87": "Por favor introduza o ID do grupo"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Destinatar", "rchange6": "Destinatar",
"rchange7": "Actiune", "rchange7": "Actiune",
"rchange8": "Tip", "rchange8": "Tip",
"rchange9": "Nivelurile 1 - 4 pot crea un cota personala de recompensare, iar nivelul 5 sau mai sus pot crea o Cota de Recompensare!", "rchange9": "Nivelurile 0 - 4 pot crea un cota personala de recompensare, iar nivelul 5 sau mai sus pot crea o Cota de Recompensare!",
"rchange10": "Cheia publica a destinatarului", "rchange10": "Cheia publica a destinatarului",
"rchange11": "Procentul cotei de recompensa", "rchange11": "Procentul cotei de recompensa",
"rchange12": "Se produce ceva delicios", "rchange12": "Se produce ceva delicios",
@ -1417,6 +1417,7 @@
"mpchange83": "RESFUS", "mpchange83": "RESFUS",
"mpchange84": "Eșec", "mpchange84": "Eșec",
"mpchange85": "SUCCES", "mpchange85": "SUCCES",
"mpchange86": "Permiteți întotdeauna obținerea automată a soldului portofelului" "mpchange86": "Permiteți întotdeauna obținerea automată a soldului portofelului",
"mpchange87": "Vă rugăm să introduceți ID-ul grupului"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Primalac", "rchange6": "Primalac",
"rchange7": "Akcija", "rchange7": "Akcija",
"rchange8": "Tip", "rchange8": "Tip",
"rchange9": "Nivoi 1 - 4 mogu napraviti samostalni udeo a nivoi 5 i više mogu napraviti udeo u nagradi!", "rchange9": "Nivoi 0 - 4 mogu napraviti samostalni udeo a nivoi 5 i više mogu napraviti udeo u nagradi!",
"rchange10": "Primalac Javnog Ključa", "rchange10": "Primalac Javnog Ključa",
"rchange11": "Procenat Udela u Nagradi", "rchange11": "Procenat Udela u Nagradi",
"rchange12": "Rađenje nečeg slasnog", "rchange12": "Rađenje nečeg slasnog",
@ -1417,6 +1417,7 @@
"mpchange83": "ODBIJENO", "mpchange83": "ODBIJENO",
"mpchange84": "GREŠKA", "mpchange84": "GREŠKA",
"mpchange85": "USPEH", "mpchange85": "USPEH",
"mpchange86": "Uvek dozvoli automatsko dobijanje stanja novčanika" "mpchange86": "Uvek dozvoli automatsko dobijanje stanja novčanika",
"mpchange87": "Unesite ID grupe"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Получатель", "rchange6": "Получатель",
"rchange7": "Действие", "rchange7": "Действие",
"rchange8": "Тип", "rchange8": "Тип",
"rchange9": "Уровень 14 может создать акцию для самого себя, а уровень 5 или выше может создать акцию для других!", "rchange9": "Уровень 04 может создать акцию для самого себя, а уровень 5 или выше может создать акцию для других!",
"rchange10": "Открытый ключ получателя", "rchange10": "Открытый ключ получателя",
"rchange11": "Процент доли вознаграждения", "rchange11": "Процент доли вознаграждения",
"rchange12": "Делаю что-нибудь вкусненькое", "rchange12": "Делаю что-нибудь вкусненькое",
@ -1417,6 +1417,7 @@
"mpchange83": "ОТКЛОНЕНО", "mpchange83": "ОТКЛОНЕНО",
"mpchange84": "НЕУДАЧА", "mpchange84": "НЕУДАЧА",
"mpchange85": "УСПЕШНО", "mpchange85": "УСПЕШНО",
"mpchange86": "Всегда разрешать автоматически получать баланс кошелька" "mpchange86": "Всегда разрешать автоматически получать баланс кошелька",
"mpchange87": "Пожалуйста, введите идентификатор группы"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "Recipient", "rchange6": "Recipient",
"rchange7": "Action", "rchange7": "Action",
"rchange8": "Type", "rchange8": "Type",
"rchange9": "Levels 1 - 4 can only create a Self-Share (minting) keys. Only Level 5 or above can create a Reward Share!", "rchange9": "Levels 0 - 4 can only create a Self-Share (minting) keys. Only Level 5 or above can create a Reward Share!",
"rchange10": "Recipient's Public Key", "rchange10": "Recipient's Public Key",
"rchange11": "Reward Share percentage", "rchange11": "Reward Share percentage",
"rchange12": "Executing Requested Command...", "rchange12": "Executing Requested Command...",
@ -1417,6 +1417,7 @@
"mpchange83": "DECLINED", "mpchange83": "DECLINED",
"mpchange84": "FAILURE", "mpchange84": "FAILURE",
"mpchange85": "SUCCESS", "mpchange85": "SUCCESS",
"mpchange86": "Always allow get wallet balance automatically" "mpchange86": "Always allow get wallet balance automatically",
"mpchange87": "Please Enter The Group ID"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "接收者", "rchange6": "接收者",
"rchange7": "操作", "rchange7": "操作",
"rchange8": "类型", "rchange8": "类型",
"rchange9": "等级1-4只能创建个人铸币密钥等级5或以上可以创建赞助码!", "rchange9": "等级0-4只能创建个人铸币密钥等级5或以上可以创建赞助码!",
"rchange10": "接收者的公共密钥", "rchange10": "接收者的公共密钥",
"rchange11": "奖励分享百分比", "rchange11": "奖励分享百分比",
"rchange12": "正在添加中...", "rchange12": "正在添加中...",
@ -1417,6 +1417,7 @@
"mpchange83": "拒绝", "mpchange83": "拒绝",
"mpchange84": "失败", "mpchange84": "失败",
"mpchange85": "成功", "mpchange85": "成功",
"mpchange86": "始终允许自动获取钱包余额" "mpchange86": "始终允许自动获取钱包余额",
"mpchange87": "请输入群组ID"
} }
} }

View File

@ -468,7 +468,7 @@
"rchange6": "接收者", "rchange6": "接收者",
"rchange7": "操作", "rchange7": "操作",
"rchange8": "類型", "rchange8": "類型",
"rchange9": "等級1-4只能創建個人鑄幣密鑰等級5或以上可以創建贊助碼!", "rchange9": "等級0-4只能創建個人鑄幣密鑰等級5或以上可以創建贊助碼!",
"rchange10": "接收者的公共密鑰", "rchange10": "接收者的公共密鑰",
"rchange11": "獎勵分享百分比", "rchange11": "獎勵分享百分比",
"rchange12": "正在添加中...", "rchange12": "正在添加中...",
@ -1417,6 +1417,7 @@
"mpchange83": "拒絕", "mpchange83": "拒絕",
"mpchange84": "失敗", "mpchange84": "失敗",
"mpchange85": "成功", "mpchange85": "成功",
"mpchange86": "隨時允許自動取得錢包餘額" "mpchange86": "隨時允許自動取得錢包餘額",
"mpchange87": "請輸入群組 ID"
} }
} }

View File

@ -20,7 +20,9 @@ import {
setSideEffectAction, setSideEffectAction,
setTabNotifications, setTabNotifications,
allowQAPPAutoBalance, allowQAPPAutoBalance,
removeQAPPAutoBalance removeQAPPAutoBalance,
allowQAPPAutoTransactions,
removeQAPPAutoTransactions
} from '../../redux/app/app-actions' } from '../../redux/app/app-actions'
import settings from '../../functional-components/settings-page' import settings from '../../functional-components/settings-page'
import './welcome-page' import './welcome-page'
@ -56,7 +58,9 @@ window.reduxAction = {
allowShowSyncIndicator: allowShowSyncIndicator, allowShowSyncIndicator: allowShowSyncIndicator,
removeShowSyncIndicator: removeShowSyncIndicator, removeShowSyncIndicator: removeShowSyncIndicator,
allowQAPPAutoBalance: allowQAPPAutoBalance, allowQAPPAutoBalance: allowQAPPAutoBalance,
removeQAPPAutoBalance: removeQAPPAutoBalance removeQAPPAutoBalance: removeQAPPAutoBalance,
allowQAPPAutoTransactions: allowQAPPAutoTransactions,
removeQAPPAutoTransactions: removeQAPPAutoTransactions
} }
const animationDuration = 0.7 // Seconds const animationDuration = 0.7 // Seconds

View File

@ -10,7 +10,9 @@ import {
removeQAPPAutoLists, removeQAPPAutoLists,
setIsOpenDevDialog, setIsOpenDevDialog,
allowQAPPAutoBalance, allowQAPPAutoBalance,
removeQAPPAutoBalance removeQAPPAutoBalance,
allowQAPPAutoTransactions,
removeQAPPAutoTransactions
} from '../../redux/app/app-actions' } from '../../redux/app/app-actions'
import { securityViewStyles } from '../../styles/core-css' import { securityViewStyles } from '../../styles/core-css'
import FileSaver from 'file-saver' import FileSaver from 'file-saver'
@ -87,6 +89,12 @@ class SecurityView extends connect(store)(LitElement) {
</label> </label>
<mwc-checkbox style="margin-right: -15px;" id="balanceButton" @click=${(e) => this.checkForBalance(e)} ?checked=${store.getState().app.qAPPAutoBalance}></mwc-checkbox> <mwc-checkbox style="margin-right: -15px;" id="balanceButton" @click=${(e) => this.checkForBalance(e)} ?checked=${store.getState().app.qAPPAutoBalance}></mwc-checkbox>
</div> </div>
<div class="checkbox-row">
<label for="transactionsButton" id="transactionsButtonLabel" style="color: var(--black);">
Always allow wallet txs to be retrieved automatically
</label>
<mwc-checkbox style="margin-right: -15px;" id="transactionsButton" @click=${(e) => this.checkForTransactions(e)} ?checked=${store.getState().app.qAPPAutoTransactions}></mwc-checkbox>
</div>
<div class="checkbox-row"> <div class="checkbox-row">
<label for="authButton" id="authButtonLabel" style="color: var(--black);"> <label for="authButton" id="authButtonLabel" style="color: var(--black);">
${get('browserpage.bchange39')} ${get('browserpage.bchange39')}
@ -124,6 +132,14 @@ class SecurityView extends connect(store)(LitElement) {
} }
} }
checkForTransactions(e) {
if (e.target.checked) {
store.dispatch(removeQAPPAutoTransactions(false))
} else {
store.dispatch(allowQAPPAutoTransactions(true))
}
}
checkForLists(e) { checkForLists(e) {
if (e.target.checked) { if (e.target.checked) {
store.dispatch(removeQAPPAutoLists(false)) store.dispatch(removeQAPPAutoLists(false))

View File

@ -86,5 +86,16 @@ export const defaultQappsTabs = [
"pluginNumber": "plugin-GGHiHzW6pe", "pluginNumber": "plugin-GGHiHzW6pe",
"menus": [], "menus": [],
"parent": false "parent": false
},
{
"url": "myapp",
"domain": "core",
"page": "qdn/browser/index.html?name=Q-Mintership&service=APP",
"title": "Q-Mintership",
"icon": "vaadin:external-browser",
"mwcicon": "apps",
"pluginNumber": "plugin-GGJJPqW6pe",
"menus": [],
"parent": false
} }
] ]

View File

@ -26,7 +26,9 @@ import {
ALLOW_SHOW_SYNC_INDICATOR, ALLOW_SHOW_SYNC_INDICATOR,
REMOVE_SHOW_SYNC_INDICATOR, REMOVE_SHOW_SYNC_INDICATOR,
ALLOW_QAPP_AUTO_BALANCE, ALLOW_QAPP_AUTO_BALANCE,
REMOVE_QAPP_AUTO_BALANCE REMOVE_QAPP_AUTO_BALANCE,
ALLOW_QAPP_AUTO_TRANSACTIONS,
REMOVE_QAPP_AUTO_TRANSACTIONS
} from '../app-action-types' } from '../app-action-types'
export const doUpdateBlockInfo = (blockObj) => { export const doUpdateBlockInfo = (blockObj) => {
@ -136,6 +138,20 @@ export const removeQAPPAutoBalance = (payload) => {
} }
} }
export const allowQAPPAutoTransactions = (payload) => {
return {
type: ALLOW_QAPP_AUTO_TRANSACTIONS,
payload
}
}
export const removeQAPPAutoTransactions = (payload) => {
return {
type: REMOVE_QAPP_AUTO_TRANSACTIONS,
payload
}
}
export const allowQAPPAutoLists = (payload) => { export const allowQAPPAutoLists = (payload) => {
return { return {
type: ALLOW_QAPP_AUTO_LISTS, type: ALLOW_QAPP_AUTO_LISTS,

View File

@ -41,3 +41,5 @@ export const ALLOW_SHOW_SYNC_INDICATOR = 'ALLOW_SHOW_SYNC_INDICATOR'
export const REMOVE_SHOW_SYNC_INDICATOR = 'REMOVE_SHOW_SYNC_INDICATOR' export const REMOVE_SHOW_SYNC_INDICATOR = 'REMOVE_SHOW_SYNC_INDICATOR'
export const ALLOW_QAPP_AUTO_BALANCE = 'ALLOW_QAPP_AUTO_BALANCE' export const ALLOW_QAPP_AUTO_BALANCE = 'ALLOW_QAPP_AUTO_BALANCE'
export const REMOVE_QAPP_AUTO_BALANCE = 'REMOVE_QAPP_AUTO_BALANCE' export const REMOVE_QAPP_AUTO_BALANCE = 'REMOVE_QAPP_AUTO_BALANCE'
export const ALLOW_QAPP_AUTO_TRANSACTIONS = 'ALLOW_QAPP_AUTO_TRANSACTIONS'
export const REMOVE_QAPP_AUTO_TRANSACTIONS = 'REMOVE_QAPP_AUTO_TRANSACTIONS'

View File

@ -42,7 +42,9 @@ import {
ALLOW_SHOW_SYNC_INDICATOR, ALLOW_SHOW_SYNC_INDICATOR,
REMOVE_SHOW_SYNC_INDICATOR, REMOVE_SHOW_SYNC_INDICATOR,
ALLOW_QAPP_AUTO_BALANCE, ALLOW_QAPP_AUTO_BALANCE,
REMOVE_QAPP_AUTO_BALANCE REMOVE_QAPP_AUTO_BALANCE,
ALLOW_QAPP_AUTO_TRANSACTIONS,
REMOVE_QAPP_AUTO_TRANSACTIONS
} from './app-action-types' } from './app-action-types'
import { initWorkersReducer } from './reducers/init-workers' import { initWorkersReducer } from './reducers/init-workers'
import { loginReducer } from './reducers/login-reducer' import { loginReducer } from './reducers/login-reducer'
@ -92,6 +94,7 @@ const INITIAL_STATE = {
qAPPFriendsList: loadStateFromLocalStorage('qAPPFriendsList') || false, qAPPFriendsList: loadStateFromLocalStorage('qAPPFriendsList') || false,
showSyncIndicator: loadStateFromLocalStorage('showSyncIndicator') || false, showSyncIndicator: loadStateFromLocalStorage('showSyncIndicator') || false,
qAPPAutoBalance: loadStateFromLocalStorage('qAPPAutoBalance') || false, qAPPAutoBalance: loadStateFromLocalStorage('qAPPAutoBalance') || false,
qAPPAutoTransactions: loadStateFromLocalStorage('qAPPAutoTransactions') || false,
chatLastSeen: [], chatLastSeen: [],
newTab: null, newTab: null,
tabInfo: {}, tabInfo: {},
@ -270,6 +273,22 @@ export default (state = INITIAL_STATE, action) => {
} }
} }
case ALLOW_QAPP_AUTO_TRANSACTIONS: {
saveStateToLocalStorage("qAPPAutoTransactions", true)
return {
...state,
qAPPAutoTransactions: action.payload
}
}
case REMOVE_QAPP_AUTO_TRANSACTIONS: {
saveStateToLocalStorage("qAPPAutoTransactions", false)
return {
...state,
qAPPAutoTransactions: action.payload
}
}
case ALLOW_QAPP_AUTO_LISTS: { case ALLOW_QAPP_AUTO_LISTS: {
saveStateToLocalStorage("qAPPAutoLists", true) saveStateToLocalStorage("qAPPAutoLists", true)
return { return {

View File

@ -14,6 +14,15 @@ import {
const Base64Message = {} const Base64Message = {}
Base64Message.decode = function (string, keys, ref) { Base64Message.decode = function (string, keys, ref) {
let repliedToStr = ''
let hubSpecialId = ''
let hubMessageStr = ''
let newMessageObject = ''
let reactionStr = ''
let messageUseEmbed = {}
let editStr = false
let embedFileStr = '"images":[""]'
const binaryString = atob(string) const binaryString = atob(string)
const binaryLength = binaryString.length const binaryLength = binaryString.length
const bytes = new Uint8Array(binaryLength) const bytes = new Uint8Array(binaryLength)
@ -34,88 +43,49 @@ Base64Message.decode = function (string, keys, ref) {
return decodedString return decodedString
} }
} else { } else {
let repliedToStr = ''
let addedFileStr = ''
let messageStr = ''
let hubString = ''
let messageRep = ''
let messageUseEmbed = {}
const res = decryptSingle(string, keys, false) const res = decryptSingle(string, keys, false)
if (res === 'noKey' || res === 'decryptionFailed') { if (res === 'noKey' || res === 'decryptionFailed') {
return '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"This message could not be decrypted"}]}]}' + addedFileStr + ',"repliedTo":"","version":3,"isFromHub":true}' return '{"specialId":"","message":"<p>This message could not be decrypted</p>","repliedTo":"","isEdited":false,"isFromHub":true,"version": 3}'
} }
const decryptToUnit8Array = base64ToUint8Array(res) const decryptToUnit8Array = base64ToUint8Array(res)
const responseData = uint8ArrayToObject(decryptToUnit8Array) const responseData = uint8ArrayToObject(decryptToUnit8Array)
if (responseData.type === "notification") { if (responseData.type === "edit") {
const messageStrRaw = responseData.data.message editStr = true
messageStr = messageStrRaw.trim()
}
if (ref !== "noref") {
if (responseData.type === "reaction") {
repliedToStr = ref
messageStr = responseData.content
}
}
if (responseData.hasOwnProperty('message') && typeof responseData['message'] === 'string' && responseData['message'].length) {
if (responseData.message.includes('qortal://use-embed/')) {
const useEmbed1 = extensionToPointer(responseData.message)
const useEmbed2 = /<newpointer>(.*?)<\/newpointer>/g.exec(useEmbed1)
const useEmbed3 = encodedToChar(useEmbed2[1])
messageUseEmbed = parseQortalLink(useEmbed3)
addedFileStr = embedToString(messageUseEmbed)
const useEmbed4 = responseData.message.split(useEmbed2[1]).join('')
if (useEmbed4 === "<p></p>") {
messageRep = useEmbed4.split('<p></p>').join('<p>Qortal-Hub embed link</p>')
} else {
messageRep = useEmbed4
}
} else {
messageRep = responseData.message
addedFileStr = ',"images":[""]'
}
const messageRep1 = messageRep.split('"').join('<upvote>')
const messageRep2 = messageRep1.split('</p><p></p><p></p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep3 = messageRep2.split('</p><p></p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep4 = messageRep3.split('</p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep5 = messageRep4.replace('</p><p>', '')
const messageRep6 = messageRep5.replace('<p></p>', '')
const messageRep7 = messageRep6.replace('<p>', '')
const messageRep8 = messageRep7.replace('<br></p>', '')
const messageRep9 = messageRep8.replace('</p>', '')
const messageRep10 = messageRep9.trim()
const messageRep11 = messageRep10.split('<br><br><br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep12 = messageRep11.split('<br><br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep13 = messageRep12.split('<br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep14 = messageRep13.split('<br>').join('"},{"type":"hardBreak"},{"type":"text","text":"')
messageStr = messageRep14
} }
if (responseData.repliedTo) { if (responseData.repliedTo) {
repliedToStr = responseData.repliedTo repliedToStr = responseData.repliedTo
} }
if (responseData.type === "edit") { if (responseData.specialId) {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isEdited":true,"isFromHub":true}' hubSpecialId = responseData.specialId
} else if (responseData.type === "reaction") {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isReaction":true,"isFromHub":true}'
} else {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isFromHub":true}'
} }
const preparedString = hubString.split('<upvote>').join('\\"') if (responseData.type === "notification") {
const finalString = preparedString.replace(/<\/?[^>]+(>|$)/g, '') hubMessageStr = responseData.data.message
} else if (ref !== "noref" && responseData.type === "reaction") {
reactionStr = '"isReaction":true,'
repliedToStr = ref
hubMessageStr = responseData.content
} else if (responseData.message.includes('qortal://use-embed/')) {
const useEmbed1 = extensionToPointer(responseData.message)
const useEmbed2 = /<newpointer>(.*?)<\/newpointer>/g.exec(useEmbed1)
const useEmbed3 = encodedToChar(useEmbed2[1])
messageUseEmbed = parseQortalLink(useEmbed3)
embedFileStr = embedToString(messageUseEmbed)
hubMessageStr = responseData.message.split(useEmbed2[1]).join('')
} else {
hubMessageStr = responseData.message
}
return finalString const hubMessageFinal = hubMessageStr.split('"').join('&quot;')
newMessageObject = '{"specialId":"' + hubSpecialId + '","message":"' + hubMessageFinal + '",' + embedFileStr + ',"repliedTo":"' + repliedToStr + '","isEdited":' + editStr + ',"isFromHub":true,' + reactionStr + '"version": 3}'
return newMessageObject
} }
} }

View File

@ -50,5 +50,13 @@ export const decryptChatMessageBase64 = (encryptedMessage, privateKey, recipient
return _decryptedMessage return _decryptedMessage
} }
let decrypted1 = new TextDecoder('utf-8').decode(_decryptedMessage)
if (decrypted1.includes('messageText')) {
let decrypted2 = JSON.parse(decrypted1)
let decrypted3 = Object.assign(decrypted2, {isPrivate: true})
return JSON.stringify(decrypted3)
}
return new TextDecoder('utf-8').decode(_decryptedMessage) return new TextDecoder('utf-8').decode(_decryptedMessage)
} }

View File

@ -38,16 +38,16 @@ crashReporter.start({
}) })
if (myMemory > 16000000000) { if (myMemory > 16000000000) {
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=8192', '--max-semi-space-size=2') app.commandLine.appendSwitch('js-flags', '--max-old-space-size=8192')
log.info("Memory Size Is 16GB Using JS Memory Heap Size 8GB") log.info("Memory Size Is 16GB Using JS Memory Heap Size 8GB")
} else if (myMemory > 12000000000) { } else if (myMemory > 12000000000) {
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=6144', '--max-semi-space-size=2') app.commandLine.appendSwitch('js-flags', '--max-old-space-size=6144')
log.info("Memory Size Is 12GB Using JS Memory Heap Size 6GB") log.info("Memory Size Is 12GB Using JS Memory Heap Size 6GB")
} else if (myMemory > 7000000000) { } else if (myMemory > 7000000000) {
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=4096', '--max-semi-space-size=2') app.commandLine.appendSwitch('js-flags', '--max-old-space-size=4096')
log.info("Memory Size Is 8GB Using JS Memory Heap Size 4GB") log.info("Memory Size Is 8GB Using JS Memory Heap Size 4GB")
} else { } else {
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=2048', '--max-semi-space-size=2') app.commandLine.appendSwitch('js-flags', '--max-old-space-size=2048')
log.info("Memory Size Is 4GB Using JS Memory Heap Size 2GB") log.info("Memory Size Is 4GB Using JS Memory Heap Size 2GB")
} }
@ -69,8 +69,6 @@ if (process.arch === 'arm') {
} else { } else {
app.commandLine.appendSwitch('enable-experimental-web-platform-features') app.commandLine.appendSwitch('enable-experimental-web-platform-features')
app.commandLine.appendSwitch('disable-renderer-backgrounding') app.commandLine.appendSwitch('disable-renderer-backgrounding')
app.commandLine.appendSwitch('disable-http-cache')
app.commandLine.appendSwitch('disable-software-rasterizer')
app.commandLine.appendSwitch('in-process-gpu') app.commandLine.appendSwitch('in-process-gpu')
log.info('We are on 64bit. Hardware Acceleration is enabled !') log.info('We are on 64bit. Hardware Acceleration is enabled !')
} }

BIN
img/minter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

673
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "qortal-ui", "name": "qortal-ui",
"version": "4.6.0", "version": "4.6.1",
"description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet", "description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet",
"keywords": [ "keywords": [
"QORT", "QORT",
@ -30,7 +30,7 @@
"publish": "electron-builder -p always" "publish": "electron-builder -p always"
}, },
"dependencies": { "dependencies": {
"@hapi/hapi": "21.3.12", "@hapi/hapi": "21.4.0",
"@hapi/inert": "7.1.0", "@hapi/inert": "7.1.0",
"@lit-labs/motion": "1.0.6", "@lit-labs/motion": "1.0.6",
"@popperjs/core": "2.11.8", "@popperjs/core": "2.11.8",
@ -50,7 +50,7 @@
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"driver.js": "1.3.5", "driver.js": "1.3.5",
"electron-dl": "3.5.2", "electron-dl": "3.5.2",
"electron-log": "5.3.0", "electron-log": "5.3.2",
"electron-store": "8.2.0", "electron-store": "8.2.0",
"electron-updater": "6.3.9", "electron-updater": "6.3.9",
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
@ -59,22 +59,23 @@
"localforage": "1.10.0", "localforage": "1.10.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"os-locale": "5.0.0", "os-locale": "5.0.0",
"prosemirror-commands": "1.6.2", "prosemirror-commands": "1.7.0",
"prosemirror-dropcursor": "1.8.1", "prosemirror-dropcursor": "1.8.1",
"prosemirror-gapcursor": "1.3.2", "prosemirror-gapcursor": "1.3.2",
"prosemirror-history": "1.4.1", "prosemirror-history": "1.4.1",
"prosemirror-keymap": "1.2.2", "prosemirror-keymap": "1.2.2",
"prosemirror-model": "1.24.1", "prosemirror-model": "1.25.0",
"prosemirror-schema-list": "1.5.0", "prosemirror-schema-list": "1.5.1",
"prosemirror-state": "1.4.3", "prosemirror-state": "1.4.3",
"prosemirror-transform": "1.10.2", "prosemirror-transform": "1.10.3",
"prosemirror-view": "1.37.2", "prosemirror-view": "1.38.1",
"sass": "1.77.6", "sass": "1.77.6",
"short-unique-id": "5.2.0", "short-unique-id": "5.2.0",
"xhr2": "0.2.1" "xhr2": "0.2.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.26.8", "@babel/core": "7.26.10",
"@electron/notarize": "2.5.0",
"@electron/packager": "18.3.6", "@electron/packager": "18.3.6",
"@material/mwc-button": "0.27.0", "@material/mwc-button": "0.27.0",
"@material/mwc-checkbox": "0.27.0", "@material/mwc-checkbox": "0.27.0",
@ -114,8 +115,8 @@
"@qortal/rollup-plugin-web-worker-loader": "1.6.5", "@qortal/rollup-plugin-web-worker-loader": "1.6.5",
"@rollup/plugin-alias": "5.1.1", "@rollup/plugin-alias": "5.1.1",
"@rollup/plugin-babel": "6.0.4", "@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "28.0.2", "@rollup/plugin-commonjs": "28.0.3",
"@rollup/plugin-node-resolve": "16.0.0", "@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-replace": "6.0.2", "@rollup/plugin-replace": "6.0.2",
"@rollup/plugin-terser": "0.4.4", "@rollup/plugin-terser": "0.4.4",
"@vaadin/avatar": "24.2.9", "@vaadin/avatar": "24.2.9",
@ -127,8 +128,8 @@
"@vaadin/tabsheet": "24.2.9", "@vaadin/tabsheet": "24.2.9",
"@vaadin/tooltip": "24.2.9", "@vaadin/tooltip": "24.2.9",
"@zip.js/zip.js": "2.7.57", "@zip.js/zip.js": "2.7.57",
"axios": "1.7.9", "axios": "1.8.3",
"electron": "34.1.1", "electron": "32.3.1",
"electron-builder": "25.1.8", "electron-builder": "25.1.8",
"epml": "0.3.3", "epml": "0.3.3",
"file-saver": "2.0.5", "file-saver": "2.0.5",
@ -140,13 +141,13 @@
"pwa-helpers": "0.9.1", "pwa-helpers": "0.9.1",
"redux": "5.0.1", "redux": "5.0.1",
"redux-thunk": "3.1.0", "redux-thunk": "3.1.0",
"rollup": "4.34.6", "rollup": "4.36.0",
"rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2", "rollup-plugin-progress": "1.1.2",
"rollup-plugin-scss": "3.0.0", "rollup-plugin-scss": "3.0.0",
"shelljs": "0.8.5" "shelljs": "0.9.2"
}, },
"engines": { "engines": {
"node": ">=20.18.1" "node": ">=20.16.0"
} }
} }

View File

@ -1,299 +0,0 @@
import { html, LitElement } from 'lit'
import { Epml } from '../../../epml'
import { chatGroupStyles } from './plugins-css'
import './WrapperModal'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@polymer/paper-spinner/paper-spinner-lite.js'
// Multi language support
import { translate } from '../../../../core/translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatGroupInvites extends LitElement {
static get properties() {
return {
isLoading: { type: Boolean },
isOpenLeaveModal: { type: Boolean },
leaveGroupObj: { type: Object },
error: { type: Boolean },
message: { type: String },
chatHeads: { type: Array },
groupAdmin: { attribute: false },
groupMembers: { attribute: false },
selectedHead: { type: Object }
}
}
static get styles() {
return [chatGroupStyles]
}
constructor() {
super()
this.isLoading = false
this.isOpenLeaveModal = false
this.leaveGroupObj = {}
this.leaveFee = 0.001
this.error = false
this.message = ''
this.chatHeads = []
this.groupAdmin = []
this.groupMembers = []
}
render() {
return html`
<vaadin-icon @click=${() => {this.isOpenLeaveModal = true}} class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:users" slot="icon"></vaadin-icon>
<wrapper-modal
.removeImage=${() => {
if (this.isLoading) return
this.isOpenLeaveModal = false
}}
style=${this.isOpenLeaveModal ? "display: block" : "display: none"}
>
<div style="text-align:center">
<h1>${translate("grouppage.gchange35")}</h1>
<hr>
</div>
<button @click=${() => this._addAdmin(this.leaveGroupObj.groupId)}>Promote to Admin</button>
<button @click=${() => this._removeAdmin(this.leaveGroupObj.groupId)}>Remove as Admin</button>
<div style="text-align:right; height:36px;">
<span ?hidden="${!this.isLoading}">
<!-- loading message -->
${translate("grouppage.gchange36")} &nbsp;
<paper-spinner-lite style="margin-top:12px;" ?active="${this.isLoading}" alt="Leaving"></paper-spinner-lite>
</span>
<span ?hidden=${this.message === ""} style="${this.error ? "color:red;" : ""}">${this.message}</span>
</div>
<button @click=${() => {this.isOpenLeaveModal = false}} class="modal-button" ?disabled="${this.isLoading}">${translate("general.close")}</button>
</wrapper-modal>
`
}
firstUpdated() {
// ...
}
timeIsoString(timestamp) {
let myTimestamp = timestamp === undefined ? 1587560082346 : timestamp
let time = new Date(myTimestamp)
return time.toISOString()
}
resetDefaultSettings() {
this.error = false
this.message = ''
this.isLoading = false
}
renderErr9Text() {
return html`${translate("grouppage.gchange49")}`
}
async confirmRelationship(reference) {
let interval = null
let stop = false
const getAnswer = async () => {
if (!stop) {
stop = true
try {
let myRef = await parentEpml.request("apiCall", {
type: "api",
url: `/transactions/reference/${reference}`
})
if (myRef && myRef.type) {
clearInterval(interval)
this.isLoading = false
this.isOpenLeaveModal = false
}
} catch (error) { }
stop = false
}
}
interval = setInterval(getAnswer, 5000)
}
async getLastRef() {
return await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/lastreference/${this.selectedAddress.address}`
})
}
getTxnRequestResponse(txnResponse, reference) {
if (txnResponse === true) {
this.message = this.renderErr9Text()
this.error = false
this.confirmRelationship(reference)
} else {
this.error = true
this.message = ''
throw new Error(txnResponse)
}
}
async convertBytesForSigning(transactionBytesBase58) {
return await parentEpml.request("apiCall", {
type: "api",
method: "POST",
url: `/transactions/convert`,
body: `${transactionBytesBase58}`
})
}
async signTx(body) {
return await parentEpml.request("apiCall", {
type: "api",
method: "POST",
url: `/transactions/sign`,
body: body,
headers: {
'Content-Type': 'application/json'
}
})
}
async process(body) {
return await parentEpml.request("apiCall", {
type: "api",
method: "POST",
url: `/transactions/process`,
body: body
})
}
async _addAdmin(groupId) {
// Reset Default Settings...
this.resetDefaultSettings()
const leaveFeeInput = this.leaveFee
this.isLoading = true
// Get Last Ref
const validateReceiver = async () => {
let lastRef = await this.getLastRef()
let myTransaction = await makeTransactionRequest(lastRef)
this.getTxnRequestResponse(myTransaction, lastRef)
}
// Make Transaction Request
const makeTransactionRequest = async (lastRef) => {
const body = {
timestamp: Date.now(),
reference: lastRef,
fee: leaveFeeInput,
ownerPublicKey: window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey),
groupId: groupId,
member: this.selectedHead.address
}
const bodyToString = JSON.stringify(body)
let transactionBytes = await parentEpml.request("apiCall", {
type: "api",
method: "POST",
url: `/groups/addadmin`,
body: bodyToString,
headers: {
"Content-Type": "application/json"
}
})
const readforsign = await this.convertBytesForSigning(transactionBytes)
const body2 = {
privateKey: window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey),
transactionBytes: readforsign
}
const bodyToString2 = JSON.stringify(body2)
let signTransaction = await this.signTx(bodyToString2)
return await this.process(signTransaction)
}
await validateReceiver()
}
async _removeAdmin(groupId) {
// Reset Default Settings...
this.resetDefaultSettings()
const leaveFeeInput = this.leaveFee
this.isLoading = true
// Get Last Ref
const validateReceiver = async () => {
let lastRef = await this.getLastRef()
let myTransaction = await makeTransactionRequest(lastRef)
this.getTxnRequestResponse(myTransaction, lastRef)
}
// Make Transaction Request
const makeTransactionRequest = async (lastRef) => {
const body = {
timestamp: Date.now(),
reference: lastRef,
fee: leaveFeeInput,
ownerPublicKey: window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey),
groupId: groupId,
admin: this.selectedHead.address
}
const bodyToString = JSON.stringify(body)
let transactionBytes = await parentEpml.request("apiCall", {
type: "api",
method: "POST",
url: `/groups/removeadmin`,
body: bodyToString,
headers: {
"Content-Type": "application/json"
}
})
const readforsign = await this.convertBytesForSigning(
transactionBytes
)
const body2 = {
privateKey: window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey),
transactionBytes: readforsign
}
const bodyToString2 = JSON.stringify(body2)
let signTransaction = await this.signTx(bodyToString2)
return await this.process(signTransaction)
}
await validateReceiver()
}
// Standard functions
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
return myNode.apiKey
}
isEmptyArray(arr) {
if (!arr) { return true }
return arr.length === 0
}
round(number) {
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
}
}
window.customElements.define('chat-group-invites', ChatGroupInvites)

View File

@ -5,7 +5,7 @@ import localForage from 'localforage'
import '@material/mwc-icon' import '@material/mwc-icon'
// Multi language support // Multi language support
import { translate } from '../../../../core/translate' import { get, translate } from '../../../../core/translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -66,6 +66,9 @@ class ChatHead extends LitElement {
} else if (groupString === 'Group_1') { } else if (groupString === 'Group_1') {
const avatarUrl = `/img/qdcgroup.png` const avatarUrl = `/img/qdcgroup.png`
this.avatarImg = this.createImage(avatarUrl) this.avatarImg = this.createImage(avatarUrl)
} else if (groupString === 'Group_694') {
const avatarUrl = `/img/minter.png`
this.avatarImg = this.createImage(avatarUrl)
} else if (this.chatInfo.name) { } else if (this.chatInfo.name) {
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true` const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true`
this.avatarImg = this.createImage(avatarUrl) this.avatarImg = this.createImage(avatarUrl)
@ -129,12 +132,24 @@ class ChatHead extends LitElement {
> >
${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} ${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)}
</span> </span>
<mwc-icon style="font-size:18px; color: var(--chat-group);">${this.chatInfo.groupId !== undefined ? 'lock_open' : 'lock'}</mwc-icon> <mwc-icon
style="font-size:18px; color:${
this.chatInfo.groupId === undefined ? '#f0ad4e' :
this.chatInfo.isOpen === false ? '#C6011F' :
this.chatInfo.isOpen === true ? '#198754' : '#198754'}"
>
${
this.chatInfo.groupId === undefined ? 'private_connectivity' :
this.chatInfo.isOpen === false ? 'lock_outline' :
this.chatInfo.isOpen === true ? 'lock_open' :
'lock_open'
}
</mwc-icon>
</div> </div>
</div> </div>
<div class="about" style="margin-top:7px"> <div class="about" style="margin-top:7px">
<div class="name"> <div class="name">
<span style="float:left; padding-left: 8px; color: var(--chat-group);font-size:12px">${this.chatInfo.groupId !== undefined ? 'id: ' + this.chatInfo.groupId : ''}</span> <span style="float:left; padding-left: 8px; color: var(--chat-group);font-size:12px">${this.chatInfo.groupId !== undefined ? 'id: ' + this.chatInfo.groupId : 'Private Chat'}</span>
<div style="color: var(--black); display: flex;font-size: 12px; align-items:center"> <div style="color: var(--black); display: flex;font-size: 12px; align-items:center">
<div style="width: 8px; height: 8px;border-radius: 50%;background: ${isUnread ? 'var(--error)' : 'none'} ; margin-right:5px;"></div> <div style="width: 8px; height: 8px;border-radius: 50%;background: ${isUnread ? 'var(--error)' : 'none'} ; margin-right:5px;"></div>
<message-time style="display: ${(this.chatInfo.timestamp && this.chatInfo.timestamp > 100000) ? 'block' : 'none'}" timestamp=${this.chatInfo.timestamp}></message-time> <message-time style="display: ${(this.chatInfo.timestamp && this.chatInfo.timestamp > 100000) ? 'block' : 'none'}" timestamp=${this.chatInfo.timestamp}></message-time>

View File

@ -3,7 +3,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'
import { unsafeHTML } from 'lit/directives/unsafe-html.js' import { unsafeHTML } from 'lit/directives/unsafe-html.js'
import { animate } from '@lit-labs/motion' import { animate } from '@lit-labs/motion'
import { Epml } from '../../../epml' import { Epml } from '../../../epml'
import { Editor, Extension, generateHTML } from '@tiptap/core' import { Editor, Extension, generateHTML, generateJSON } from '@tiptap/core'
import { escape } from 'html-escaper' import { escape } from 'html-escaper'
import { inputKeyCodes, replaceMessagesEdited, generateIdFromAddresses } from '../../utils/functions' import { inputKeyCodes, replaceMessagesEdited, generateIdFromAddresses } from '../../utils/functions'
import { publishData, modalHelper, RequestQueue } from '../../utils/classes' import { publishData, modalHelper, RequestQueue } from '../../utils/classes'
@ -345,7 +345,12 @@ class ChatPage extends LitElement {
} }
${+this.repliedToMessageObj.version > 1 ? ${+this.repliedToMessageObj.version > 1 ?
html` html`
<span style="color: var(--black);">${unsafeHTML(generateHTML(this.repliedToMessageObj.message, [StarterKit, Underline, Highlight, Mention]))}</span> <span style="color: var(--black);">
${this.repliedToMessageObj.decodedMessage.includes('specialId') ?
this.convertHubMessageToJson(this.repliedToMessageObj.message) :
unsafeHTML(generateHTML(this.repliedToMessageObj.message, [StarterKit, Underline, Highlight, Mention]))
}
</span>
` `
: '' : ''
} }
@ -362,7 +367,12 @@ class ChatPage extends LitElement {
<vaadin-icon class="reply-icon" icon="vaadin:pencil" slot="icon"></vaadin-icon> <vaadin-icon class="reply-icon" icon="vaadin:pencil" slot="icon"></vaadin-icon>
<div class="repliedTo-message"> <div class="repliedTo-message">
<p class="senderName">${translate("chatpage.cchange25")}</p> <p class="senderName">${translate("chatpage.cchange25")}</p>
<span style="color: var(--black);">${unsafeHTML(generateHTML(this.editedMessageObj.message, [StarterKit, Underline, Highlight, Mention]))}</span> <span style="color: var(--black);">
${this.editedMessageObj.decodedMessage.includes('specialId') && !this.editedMessageObj.decodedMessage.includes('messageText') ?
this.convertHubMessageToJson(this.editedMessageObj.message) :
unsafeHTML(generateHTML(this.editedMessageObj.message, [StarterKit, Underline, Highlight, Mention]))
}
</span>
</div> </div>
<vaadin-icon class="close-icon" icon="vaadin:close-big" slot="icon" @click=${() => this.closeEditMessageContainer()}></vaadin-icon> <vaadin-icon class="close-icon" icon="vaadin:close-big" slot="icon" @click=${() => this.closeEditMessageContainer()}></vaadin-icon>
</div> </div>
@ -845,7 +855,12 @@ class ChatPage extends LitElement {
if (isEnabledChatEnter) { if (isEnabledChatEnter) {
this.isEnabledChatEnter = isEnabledChatEnter === 'false' ? false : true this.isEnabledChatEnter = isEnabledChatEnter === 'false' ? false : true
} }
}
convertHubMessageToJson(message) {
let newJson = generateJSON(`${message}`, [StarterKit, Underline, Highlight, Mention])
return unsafeHTML(generateHTML(newJson, [StarterKit, Underline, Highlight, Mention]))
} }
getNodeUrl() { getNodeUrl() {
@ -1666,7 +1681,7 @@ class ChatPage extends LitElement {
const getMembersAdmins = await parentEpml.request("apiCall", { const getMembersAdmins = await parentEpml.request("apiCall", {
type: "api", type: "api",
url: `/groups/members/${groupId}?onlyAdmins=true&limit=20` url: `/groups/members/${groupId}?onlyAdmins=true&limit=0`
}) })
const getGroupInfo = await parentEpml.request("apiCall", { const getGroupInfo = await parentEpml.request("apiCall", {
@ -2551,15 +2566,13 @@ class ChatPage extends LitElement {
const initDirect = async (cid, noInitial) => { const initDirect = async (cid, noInitial) => {
let timeoutId let timeoutId
let initial = 0 let initial = 0
let directSocketTimeout let directSocketTimeout
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let nodeProtocol = myNode.protocol
let directSocketLink let directSocketLink
if (window.parent.location.protocol === "https:") { if (nodeProtocol === "https") {
directSocketLink = `wss://${nodeUrl}/websockets/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&encoding=BASE64&limit=1` directSocketLink = `wss://${nodeUrl}/websockets/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&encoding=BASE64&limit=1`
} else { } else {
// Fallback to http // Fallback to http
@ -2587,12 +2600,17 @@ class ChatPage extends LitElement {
let getInitialMessages = [] let getInitialMessages = []
let count = 0 let count = 0
let isUnread = false let isUnread = false
let chatInfoTimestamp
const chatId = this.chatId const chatId = this.chatId
const findContent = this.chatHeads.find((item) => item.url === chatId) const findContent = this.chatHeads.find((item) => item.url === chatId)
const chatInfoTimestamp = findContent.timestamp || 0
const lastReadMessageTimestamp = this.lastReadMessageTimestamp const lastReadMessageTimestamp = this.lastReadMessageTimestamp
if (findContent === undefined) {
chatInfoTimestamp = 0
} else {
chatInfoTimestamp = findContent.timestamp || 0
}
if (lastReadMessageTimestamp && chatInfoTimestamp) { if (lastReadMessageTimestamp && chatInfoTimestamp) {
if (lastReadMessageTimestamp < chatInfoTimestamp) { if (lastReadMessageTimestamp < chatInfoTimestamp) {
@ -2675,17 +2693,15 @@ class ChatPage extends LitElement {
const initGroup = (gId, noInitial) => { const initGroup = (gId, noInitial) => {
let timeoutId let timeoutId
let groupId = Number(gId) let groupId = Number(gId)
let initial = 0 let initial = 0
let count = 0 let count = 0
let groupSocketTimeout let groupSocketTimeout
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let nodeProtocol = myNode.protocol
let groupSocketLink let groupSocketLink
if (window.parent.location.protocol === "https:") { if (nodeProtocol === "https") {
groupSocketLink = `wss://${nodeUrl}/websockets/chat/messages?txGroupId=${groupId}&encoding=BASE64&limit=1` groupSocketLink = `wss://${nodeUrl}/websockets/chat/messages?txGroupId=${groupId}&encoding=BASE64&limit=1`
} else { } else {
// Fallback to http // Fallback to http
@ -2710,13 +2726,18 @@ class ChatPage extends LitElement {
this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatId) || 0 this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatId) || 0
if (noInitial) return if (noInitial) return
let getInitialMessages = [] let getInitialMessages = []
const lastReadMessageTimestamp = this.lastReadMessageTimestamp
let isUnread = false let isUnread = false
let chatInfoTimestamp
const chatId = this.chatId const chatId = this.chatId
const findContent = this.chatHeads.find((item) => item.url === chatId) const findContent = this.chatHeads.find((item) => item.url === chatId)
const chatInfoTimestamp = findContent.timestamp || 0 const lastReadMessageTimestamp = this.lastReadMessageTimestamp
if (findContent === undefined) {
chatInfoTimestamp = 0
} else {
chatInfoTimestamp = findContent.timestamp || 0
}
if (lastReadMessageTimestamp && chatInfoTimestamp) { if (lastReadMessageTimestamp && chatInfoTimestamp) {
if (lastReadMessageTimestamp < chatInfoTimestamp) { if (lastReadMessageTimestamp < chatInfoTimestamp) {

View File

@ -3,7 +3,7 @@ import { repeat } from 'lit/directives/repeat.js'
import { unsafeHTML } from 'lit/directives/unsafe-html.js' import { unsafeHTML } from 'lit/directives/unsafe-html.js'
import { Epml } from '../../../epml' import { Epml } from '../../../epml'
import { cropAddress, roundToNearestDecimal } from '../../utils/functions' import { cropAddress, roundToNearestDecimal } from '../../utils/functions'
import { generateHTML } from '@tiptap/core' import { generateHTML, generateJSON } from '@tiptap/core'
import { chatLimit, totalMsgCount } from './ChatPage' import { chatLimit, totalMsgCount } from './ChatPage'
import { chatStyles } from './plugins-css' import { chatStyles } from './plugins-css'
import isElectron from 'is-electron' import isElectron from 'is-electron'
@ -280,6 +280,7 @@ class ChatScroller extends LitElement {
render() { render() {
let formattedMessages = this.messagesToRender let formattedMessages = this.messagesToRender
return html` return html`
${this.isLoadingBefore ${this.isLoadingBefore
? html` ? html`
@ -1081,17 +1082,22 @@ class MessageTemplate extends LitElement {
let version = 0 let version = 0
let isForwarded = false let isForwarded = false
let isEdited = false let isEdited = false
let isFromHub = false let isEncrypted = false
try { try {
const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage) const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage)
if (+parsedMessageObj.version > 1 && parsedMessageObj.messageText) { if (parsedMessageObj.version > 1 && parsedMessageObj.messageText) {
messageVersion2 = generateHTML(parsedMessageObj.messageText, [StarterKit, Underline, Highlight, Mention]) messageVersion2 = generateHTML(parsedMessageObj.messageText, [StarterKit, Underline, Highlight, Mention])
messageVersion2WithLink = processText(messageVersion2) messageVersion2WithLink = processText(messageVersion2)
} }
message = parsedMessageObj.messageText if (parsedMessageObj.version > 1 && parsedMessageObj.message && !parsedMessageObj.messageText) {
messageVersion2 = parsedMessageObj.message
messageVersion2WithLink = processText(messageVersion2)
}
message = parsedMessageObj.messageText ? parsedMessageObj.messageText : parsedMessageObj.message
repliedToData = this.messageObj.repliedToData repliedToData = this.messageObj.repliedToData
isImageDeleted = parsedMessageObj.isImageDeleted isImageDeleted = parsedMessageObj.isImageDeleted
isGifDeleted = parsedMessageObj.isGifDeleted isGifDeleted = parsedMessageObj.isGifDeleted
@ -1101,7 +1107,7 @@ class MessageTemplate extends LitElement {
version = parsedMessageObj.version version = parsedMessageObj.version
isForwarded = parsedMessageObj.type === 'forward' isForwarded = parsedMessageObj.type === 'forward'
isEdited = parsedMessageObj.isEdited && true isEdited = parsedMessageObj.isEdited && true
isFromHub = parsedMessageObj.isFromHub && true isEncrypted = parsedMessageObj.isFromHub || parsedMessageObj.isPrivate || parsedMessageObj.message ? true : false
if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) { if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) {
image = parsedMessageObj.images[0] image = parsedMessageObj.images[0]
@ -1133,8 +1139,8 @@ class MessageTemplate extends LitElement {
let hideit = hidemsg.includes(this.messageObj.sender) let hideit = hidemsg.includes(this.messageObj.sender)
let forwarded = '' let forwarded = ''
let edited = '' let edited = ''
let fromHubOk = '' let encrypted = ''
let fromHubNo = '' let decrypted = ''
levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>` levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>`
@ -1250,9 +1256,9 @@ class MessageTemplate extends LitElement {
</span> </span>
` `
fromHubOk = html`&nbsp;&nbsp;&nbsp;<mwc-icon style="font-size:16px; color: var(--chat-group);">key</mwc-icon>&nbsp;&nbsp;&nbsp;` encrypted = html`&nbsp;&nbsp;&nbsp;<mwc-icon style="font-size:16px; color: var(--chat-group);">key</mwc-icon>&nbsp;&nbsp;&nbsp;`
fromHubNo = html`&nbsp;&nbsp;&nbsp;<mwc-icon style="font-size:16px; color: var(--chat-group);">key_off</mwc-icon>&nbsp;&nbsp;&nbsp;` decrypted = html`&nbsp;&nbsp;&nbsp;<mwc-icon style="font-size:16px; color: var(--chat-group);">key_off</mwc-icon>&nbsp;&nbsp;&nbsp;`
if (repliedToData) { if (repliedToData) {
try { try {
@ -1266,6 +1272,10 @@ class MessageTemplate extends LitElement {
try { try {
repliedToMessageText = generateHTML(repliedToData.decodedMessage.messageText, [StarterKit, Underline, Highlight, Mention]) repliedToMessageText = generateHTML(repliedToData.decodedMessage.messageText, [StarterKit, Underline, Highlight, Mention])
} catch (error) { /* empty */ } } catch (error) { /* empty */ }
} else if (repliedToData && repliedToData.decodedMessage && repliedToData.decodedMessage.message) {
try {
repliedToMessageText = this.convertHubMessageToJson(repliedToData.decodedMessage.message)
} catch (error) { /* empty */ }
} }
let replacedMessage = '' let replacedMessage = ''
@ -1672,7 +1682,7 @@ class MessageTemplate extends LitElement {
` : this.isAgo ? html` ` : this.isAgo ? html`
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<div style="margin-top: 4px;"> <div style="margin-top: 4px;">
${isFromHub ? html`${fromHubOk}` : html`${fromHubNo}`} ${isEncrypted ? html`${encrypted}` : html`${decrypted}`}
</div> </div>
<div id="timeformat"> <div id="timeformat">
<span> <span>
@ -1683,7 +1693,7 @@ class MessageTemplate extends LitElement {
` : this.isIso ? html` ` : this.isIso ? html`
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<div style="margin-top: 4px;"> <div style="margin-top: 4px;">
${isFromHub ? html`${fromHubOk}` : html`${fromHubNo}`} ${isEncrypted ? html`${encrypted}` : html`${decrypted}`}
</div> </div>
<div id="timeformat"> <div id="timeformat">
<span> <span>
@ -1694,7 +1704,7 @@ class MessageTemplate extends LitElement {
` : this.isBoth ? html` ` : this.isBoth ? html`
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<div style="margin-top: 4px;"> <div style="margin-top: 4px;">
${isFromHub ? html`${fromHubOk}` : html`${fromHubNo}`} ${isEncrypted ? html`${encrypted}` : html`${decrypted}`}
</div> </div>
<div id="timeformat"> <div id="timeformat">
<span> <span>
@ -2067,6 +2077,11 @@ class MessageTemplate extends LitElement {
}, 60000) }, 60000)
} }
convertHubMessageToJson(message) {
let newJson = generateJSON(`${message}`, [StarterKit, Underline, Highlight, Mention])
return generateHTML(newJson, [StarterKit, Underline, Highlight, Mention])
}
async closeDownloadProgressDialog() { async closeDownloadProgressDialog() {
const closeDelay = ms => new Promise(res => setTimeout(res, ms)) const closeDelay = ms => new Promise(res => setTimeout(res, ms))
this.shadowRoot.getElementById('downloadProgressDialog').close() this.shadowRoot.getElementById('downloadProgressDialog').close()
@ -2350,7 +2365,13 @@ class ChatMenu extends LitElement {
<div <div
class=${`menu-icon ${!this.firstMessageInChat ? 'tooltip' : ''}`} class=${`menu-icon ${!this.firstMessageInChat ? 'tooltip' : ''}`}
data-text="${translate('blockpage.bcchange12')}" data-text="${translate('blockpage.bcchange12')}"
@click=${() => {if (this.version === '0') {this.versionErrorSnack(); return;} this.setEditedMessageObj(this.originalMessage);}} @click=${() => {
if (this.version === '0') {
this.versionErrorSnack();
return;
}
this.setEditedMessageObj(this.originalMessage);
}}
> >
<vaadin-icon icon="vaadin:pencil" slot="icon"></vaadin-icon> <vaadin-icon icon="vaadin:pencil" slot="icon"></vaadin-icon>
</div> </div>

View File

@ -1649,7 +1649,7 @@ export const chatStyles = css`
position: absolute; position: absolute;
top: 5px; top: 5px;
left: 10px; left: 10px;
height: 75%; height: 85%;
width: 2.6px; width: 2.6px;
background-color: var(--mdc-theme-primary); background-color: var(--mdc-theme-primary);
} }
@ -1669,7 +1669,7 @@ export const chatStyles = css`
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 500px; max-width: 500px;
max-height: 40px; max-height: 80px;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -2014,8 +2014,13 @@ export const chatStyles = css`
} }
#messageContent code { #messageContent code {
background-color: rgba(#616161, 0.1); background: #0D0D0D;
color: #616161; color: #FFF;
font-family: 'JetBrainsMono', monospace;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
white-space: pre-wrap;
margin-top: 10px;
} }
#messageContent pre { #messageContent pre {
@ -2034,12 +2039,10 @@ export const chatStyles = css`
font-size: 0.8rem; font-size: 0.8rem;
} }
#messageContent img { #messageContent img {
width: 1.7em; width: 1.7em;
height: 1.5em; height: 1.5em;
margin: 0px; margin: 0px;
} }
#messageContent blockquote { #messageContent blockquote {
@ -2078,8 +2081,13 @@ export const chatStyles = css`
} }
.replied-message code { .replied-message code {
background-color: rgba(#616161, 0.1); background: #0D0D0D;
color: #616161; color: #FFF;
font-family: 'JetBrainsMono', monospace;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
white-space: pre-wrap;
margin: 0px;
} }
.replied-message pre { .replied-message pre {
@ -7138,18 +7146,28 @@ export const qchatStyles = css`
* { * {
--mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary); --mdc-theme-secondary: var(--mdc-theme-primary);
--paper-input-container-focus-color: var(--mdc-theme-primary);
--mdc-theme-surface: var(--white); --mdc-theme-surface: var(--white);
--mdc-dialog-content-ink-color: var(--black); --mdc-dialog-content-ink-color: var(--black);
--mdc-dialog-min-width: 750px;
--lumo-primary-text-color: rgb(0, 167, 245); --lumo-primary-text-color: rgb(0, 167, 245);
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5); --lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1); --lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
--lumo-primary-color: hsl(199, 100%, 48%); --lumo-primary-color: hsl(199, 100%, 48%);
--lumo-secondary-text-color: var(--sectxt);
--lumo-contrast-60pct: var(--vdicon);
--item-selected-color: var(--nav-selected-color);
--lumo-base-color: var(--white); --lumo-base-color: var(--white);
--lumo-body-text-color: var(--black); --lumo-body-text-color: var(--black);
--_lumo-grid-border-color: var(--border); --_lumo-grid-border-color: var(--border);
--_lumo-grid-secondary-border-color: var(--border2); --_lumo-grid-secondary-border-color: var(--border2);
--mdc-dialog-min-width: 750px; --item-selected-color-text: var(--nav-selected-color-text);
--item-color-active: var(--nav-color-active);
--item-color-hover: var(--nav-color-hover);
--item-text-color: var(--nav-text-color);
--item-icon-color: var(--nav-icon-color);
--item-border-color: var(--nav-border-color);
--item-border-selected-color: var(--nav-border-selected-color);
--paper-input-container-focus-color: var(--mdc-theme-primary);
} }
paper-spinner-lite { paper-spinner-lite {
@ -7647,109 +7665,108 @@ export const qchatStyles = css`
overflow: hidden; overflow: hidden;
} }
.check-roller { .view-grid {
display: inline-block; width: 120px;
position: relative; height: 120px;
width: 80px;
height: 80px;
}
.check-roller div {
animation: check-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
transform-origin: 40px 40px;
}
.check-roller div:after {
content: " ";
display: block;
position: absolute; position: absolute;
width: 7px; left: 50%;
height: 7px; top: 50%;
}
.view-grid div {
position: absolute;
width: 34px;
height: 34px;
border-radius: 50%; border-radius: 50%;
background: var(--black); background: #03a9f4;
margin: -4px 0 0 -4px; animation: view-grid 1.2s linear infinite;
} }
.check-roller div:nth-child(1) { .view-grid div:nth-child(1) {
animation-delay: -0.036s; top: 4px;
left: 4px;
animation-delay: 0s;
} }
.check-roller div:nth-child(1):after { .view-grid div:nth-child(2) {
top: 63px; top: 4px;
left: 63px;
}
.check-roller div:nth-child(2) {
animation-delay: -0.072s;
}
.check-roller div:nth-child(2):after {
top: 68px;
left: 56px;
}
.check-roller div:nth-child(3) {
animation-delay: -0.108s;
}
.check-roller div:nth-child(3):after {
top: 71px;
left: 48px; left: 48px;
animation-delay: -0.4s;
} }
.check-roller div:nth-child(4) { .view-grid div:nth-child(3) {
animation-delay: -0.144s; top: 4px;
left: 90px;
animation-delay: -0.8s;
} }
.check-roller div:nth-child(4):after { .view-grid div:nth-child(4) {
top: 72px; top: 50px;
left: 40px; left: 4px;
animation-delay: -0.4s;
} }
.check-roller div:nth-child(5) { .view-grid div:nth-child(5) {
animation-delay: -0.18s; top: 50px;
left: 48px;
animation-delay: -0.8s;
} }
.check-roller div:nth-child(5):after { .view-grid div:nth-child(6) {
top: 71px; top: 50px;
left: 32px; left: 90px;
animation-delay: -1.2s;
} }
.check-roller div:nth-child(6) { .view-grid div:nth-child(7) {
animation-delay: -0.216s; top: 95px;
left: 4px;
animation-delay: -0.8s;
} }
.check-roller div:nth-child(6):after { .view-grid div:nth-child(8) {
top: 68px; top: 95px;
left: 24px; left: 48px;
animation-delay: -1.2s;
} }
.check-roller div:nth-child(7) { .view-grid div:nth-child(9) {
animation-delay: -0.252s; top: 95px;
left: 90px;
animation-delay: -1.6s;
} }
.check-roller div:nth-child(7):after { @keyframes view-grid {
top: 63px;
left: 17px;
}
.check-roller div:nth-child(8) {
animation-delay: -0.288s;
}
.check-roller div:nth-child(8):after {
top: 56px;
left: 12px;
}
@keyframes check-roller {
0% {
transform: rotate(0deg);
}
0%,
100% { 100% {
transform: rotate(360deg); opacity: 1;
} }
50% {
opacity: 0.5;
}
}
paper-dialog.viewSettings {
min-width: 525px;
max-width: 525px;
min-height: auto;
max-height: 150px;
background-color: var(--white);
color: var(--black);
line-height: 1.6;
overflow: hidden;
border: 1px solid var(--black);
border-radius: 10px;
padding: 15px;
box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.1);
}
.view {
display: inline;
width: 50%;
align-items: center;
} }
` `
@ -8516,7 +8533,7 @@ export const groupManagementStyles = css`
position: absolute; position: absolute;
top: 5px; top: 5px;
left: 10px; left: 10px;
height: 75%; height: 85%;
width: 2.6px; width: 2.6px;
background-color: var(--mdc-theme-primary); background-color: var(--mdc-theme-primary);
} }
@ -8540,7 +8557,7 @@ export const groupManagementStyles = css`
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 500px; max-width: 500px;
max-height: 40px; max-height: 80px;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }

View File

@ -122,8 +122,9 @@ export const extensionToPointer = (repString) => {
const replace36 = replace35.split('.7z').join('.7z</newpointer>') const replace36 = replace35.split('.7z').join('.7z</newpointer>')
const replace37 = replace36.split('.gz').join('.gz</newpointer>') const replace37 = replace36.split('.gz').join('.gz</newpointer>')
const replace38 = replace37.split('.bz2').join('.bz2</newpointer>') const replace38 = replace37.split('.bz2').join('.bz2</newpointer>')
const replace39 = replace38.split('service=QCHAT_IMAGE</p>').join('service=QCHAT_IMAGE</newpointer></p>')
return replace38 return replace39
} }
export const encodedToChar = (encodedString) => { export const encodedToChar = (encodedString) => {
@ -159,15 +160,15 @@ export const embedToString = (embed) => {
embedService = embed.service embedService = embed.service
embedName = embed.name embedName = embed.name
embedIdentifier = embed.identifier embedIdentifier = embed.identifier
embedString = ',"images":[{"service":"' + embedService + '","name":"' + embedName + '","identifier":"' + embedIdentifier + '"}],"isImageDeleted":false' embedString = '"images":[{"service":"' + embedService + '","name":"' + embedName + '","identifier":"' + embedIdentifier + '"}],"isImageDeleted":false'
} else if (embed.type === "ATTACHMENT") { } else if (embed.type === "ATTACHMENT") {
embedService = embed.service embedService = embed.service
embedName = embed.name embedName = embed.name
embedIdentifier = embed.identifier embedIdentifier = embed.identifier
embedAttachmentName = embed.fileName embedAttachmentName = embed.fileName
embedString = ',"attachments":[{"service":"' + embedService + '","name":"' + embedName + '","identifier":"' + embedIdentifier + '","attachmentName":"' + embedAttachmentName + '","attachmentSize":0}],"isAttachmentDeleted":false' embedString = '"attachments":[{"service":"' + embedService + '","name":"' + embedName + '","identifier":"' + embedIdentifier + '","attachmentName":"' + embedAttachmentName + '","attachmentSize":0}],"isAttachmentDeleted":false'
} else { } else {
embedString = ',"images":[""]' embedString = '"images":[""]'
} }
return embedString return embedString

View File

@ -1,6 +1,15 @@
// IS_USING_PUBLIC_NODE // IS_USING_PUBLIC_NODE
export const IS_USING_PUBLIC_NODE = 'IS_USING_PUBLIC_NODE' export const IS_USING_PUBLIC_NODE = 'IS_USING_PUBLIC_NODE'
// GET_ARRR_SYNC_STATUS
export const GET_ARRR_SYNC_STATUS = 'GET_ARRR_SYNC_STATUS'
// GET_NODE_INFO
export const GET_NODE_INFO = 'GET_NODE_INFO'
// GET_NODE_STATUS
export const GET_NODE_STATUS = 'GET_NODE_STATUS'
// ADMIN_ACTION // ADMIN_ACTION
export const ADMIN_ACTION = 'ADMIN_ACTION' export const ADMIN_ACTION = 'ADMIN_ACTION'
@ -123,6 +132,9 @@ export const OPEN_PROFILE = 'OPEN_PROFILE'
// GET_USER_WALLET // GET_USER_WALLET
export const GET_USER_WALLET = 'GET_USER_WALLET' export const GET_USER_WALLET = 'GET_USER_WALLET'
// GET_USER_WALLET_TRANSACTIONS
export const GET_USER_WALLET_TRANSACTIONS = 'GET_USER_WALLET_TRANSACTIONS'
// GET_WALLET_BALANCE // GET_WALLET_BALANCE
export const GET_WALLET_BALANCE = 'GET_WALLET_BALANCE' export const GET_WALLET_BALANCE = 'GET_WALLET_BALANCE'

View File

@ -2767,6 +2767,15 @@ self.addEventListener('message', async (e) => {
}) })
const decode = (string, keys, ref) => { const decode = (string, keys, ref) => {
let repliedToStr = ''
let hubSpecialId = ''
let hubMessageStr = ''
let newMessageObject = ''
let reactionStr = ''
let messageUseEmbed = {}
let editStr = false
let embedFileStr = '"images":[""]'
const binaryString = atob(string) const binaryString = atob(string)
const binaryLength = binaryString.length const binaryLength = binaryString.length
const bytes = new Uint8Array(binaryLength) const bytes = new Uint8Array(binaryLength)
@ -2787,88 +2796,49 @@ const decode = (string, keys, ref) => {
return decodedString return decodedString
} }
} else { } else {
let repliedToStr = ''
let addedFileStr = ''
let messageStr = ''
let hubString = ''
let messageRep = ''
let messageUseEmbed = {}
const res = decryptSingle(string, keys, false) const res = decryptSingle(string, keys, false)
if (res === 'noKey' || res === 'decryptionFailed') { if (res === 'noKey' || res === 'decryptionFailed') {
return '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"This message could not be decrypted"}]}]}' + addedFileStr + ',"repliedTo":"","version":3,"isFromHub":true}' return '{"specialId":"","message":"<p>This message could not be decrypted</p>","repliedTo":"","isEdited":false,"isFromHub":true,"version": 3}'
} }
const decryptToUnit8Array = base64ToUint8Array(res) const decryptToUnit8Array = base64ToUint8Array(res)
const responseData = uint8ArrayToObject(decryptToUnit8Array) const responseData = uint8ArrayToObject(decryptToUnit8Array)
if (responseData.type === "notification") { if (responseData.type === "edit") {
const messageStrRaw = responseData.data.message editStr = true
messageStr = messageStrRaw.trim()
}
if (ref !== "noref") {
if (responseData.type === "reaction") {
repliedToStr = ref
messageStr = responseData.content
}
}
if (responseData.hasOwnProperty('message') && typeof responseData['message'] === 'string' && responseData['message'].length) {
if (responseData.message.includes('qortal://use-embed/')) {
const useEmbed1 = extensionToPointer(responseData.message)
const useEmbed2 = /<newpointer>(.*?)<\/newpointer>/g.exec(useEmbed1)
const useEmbed3 = encodedToChar(useEmbed2[1])
messageUseEmbed = parseQortalLink(useEmbed3)
addedFileStr = embedToString(messageUseEmbed)
const useEmbed4 = responseData.message.split(useEmbed2[1]).join('')
if (useEmbed4 === "<p></p>") {
messageRep = useEmbed4.split('<p></p>').join('<p>Qortal-Hub embed link</p>')
} else {
messageRep = useEmbed4
}
} else {
messageRep = responseData.message
addedFileStr = ',"images":[""]'
}
const messageRep1 = messageRep.split('"').join('<upvote>')
const messageRep2 = messageRep1.split('</p><p></p><p></p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep3 = messageRep2.split('</p><p></p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep4 = messageRep3.split('</p><p></p><p>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep5 = messageRep4.replace('</p><p>', '')
const messageRep6 = messageRep5.replace('<p></p>', '')
const messageRep7 = messageRep6.replace('<p>', '')
const messageRep8 = messageRep7.replace('<br></p>', '')
const messageRep9 = messageRep8.replace('</p>', '')
const messageRep10 = messageRep9.trim()
const messageRep11 = messageRep10.split('<br><br><br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep12 = messageRep11.split('<br><br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep13 = messageRep12.split('<br><br>').join('"},{"type":"hardBreak"},{"type":"hardBreak"},{"type":"text","text":"')
const messageRep14 = messageRep13.split('<br>').join('"},{"type":"hardBreak"},{"type":"text","text":"')
messageStr = messageRep14
} }
if (responseData.repliedTo) { if (responseData.repliedTo) {
repliedToStr = responseData.repliedTo repliedToStr = responseData.repliedTo
} }
if (responseData.type === "edit") { if (responseData.specialId) {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isEdited":true,"isFromHub":true}' hubSpecialId = responseData.specialId
} else if (responseData.type === "reaction") {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isReaction":true,"isFromHub":true}'
} else {
hubString = '{"messageText":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"' + messageStr + '"}]}]}' + addedFileStr + ',"repliedTo":"' + repliedToStr + '","version":3,"isFromHub":true}'
} }
const preparedString = hubString.split('<upvote>').join('\\"') if (responseData.type === "notification") {
const finalString = preparedString.replace(/<\/?[^>]+(>|$)/g, '') hubMessageStr = responseData.data.message
} else if (ref !== "noref" && responseData.type === "reaction") {
reactionStr = '"isReaction":true,'
repliedToStr = ref
hubMessageStr = responseData.content
} else if (responseData.message.includes('qortal://use-embed/')) {
const useEmbed1 = extensionToPointer(responseData.message)
const useEmbed2 = /<newpointer>(.*?)<\/newpointer>/g.exec(useEmbed1)
const useEmbed3 = encodedToChar(useEmbed2[1])
messageUseEmbed = parseQortalLink(useEmbed3)
embedFileStr = embedToString(messageUseEmbed)
hubMessageStr = responseData.message.split(useEmbed2[1]).join('')
} else {
hubMessageStr = responseData.message
}
return finalString const hubMessageFinal = hubMessageStr.split('"').join('&quot;')
newMessageObject = '{"specialId":"' + hubSpecialId + '","message":"' + hubMessageFinal + '",' + embedFileStr + ',"repliedTo":"' + repliedToStr + '","isEdited":' + editStr + ',"isFromHub":true,' + reactionStr + '"version": 3}'
return newMessageObject
} }
} }
@ -2923,6 +2893,14 @@ export const decryptChatMessageBase64 = (encryptedMessage, privateKey, recipient
return _decryptedMessage return _decryptedMessage
} }
let decrypted1 = new TextDecoder('utf-8').decode(_decryptedMessage)
if (decrypted1.includes('messageText')) {
let decrypted2 = JSON.parse(decrypted1)
let decrypted3 = Object.assign(decrypted2, {isPrivate: true})
return JSON.stringify(decrypted3)
}
return new TextDecoder('utf-8').decode(_decryptedMessage) return new TextDecoder('utf-8').decode(_decryptedMessage)
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@ import '@vaadin/grid'
// Multi language support // Multi language support
import { get, registerTranslateConfig, translate, use } from '../../../../core/translate' import { get, registerTranslateConfig, translate, use } from '../../../../core/translate'
registerTranslateConfig({ registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
}) })
@ -427,7 +428,9 @@ class NodeManagement extends LitElement {
async addPeer() { async addPeer() {
this.addPeerLoading = true this.addPeerLoading = true
const addPeerAddress = this.shadowRoot.getElementById('addPeerAddress').value const addPeerAddress = this.shadowRoot.getElementById('addPeerAddress').value
await parentEpml.request('apiCall', { await parentEpml.request('apiCall', {
url: `/peers?apiKey=${this.getApiKey()}`, url: `/peers?apiKey=${this.getApiKey()}`,
method: 'POST', method: 'POST',
@ -456,7 +459,6 @@ class NodeManagement extends LitElement {
addMintingAccount() { addMintingAccount() {
this.addMintingAccountLoading = true this.addMintingAccountLoading = true
this.addMintingAccountMessage = 'Loading...' this.addMintingAccountMessage = 'Loading...'
this.addMintingAccountKey = this.shadowRoot.querySelector('#addMintingAccountKey').value this.addMintingAccountKey = this.shadowRoot.querySelector('#addMintingAccountKey').value
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
@ -479,6 +481,7 @@ class NodeManagement extends LitElement {
updateMintingAccounts() { updateMintingAccounts() {
this.mintingAccounts = [] this.mintingAccounts = []
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`, url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`,
method: 'GET' method: 'GET'
@ -518,10 +521,6 @@ class NodeManagement extends LitElement {
if (!arr) { return true } if (!arr) { return true }
return arr.length === 0 return arr.length === 0
} }
round(number) {
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
}
} }
window.customElements.define('node-management', NodeManagement) window.customElements.define('node-management', NodeManagement)

View File

@ -10,6 +10,7 @@ import '@vaadin/button'
// Multi language support // Multi language support
import { get, registerTranslateConfig, translate, use } from '../../../../core/translate' import { get, registerTranslateConfig, translate, use } from '../../../../core/translate'
registerTranslateConfig({ registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
}) })
@ -144,7 +145,6 @@ class OverviewPage extends LitElement {
async firstUpdated() { async firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig
this.accountInfo = window.parent.reduxStore.getState().app.accountInfo this.accountInfo = window.parent.reduxStore.getState().app.accountInfo
@ -199,11 +199,13 @@ class OverviewPage extends LitElement {
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark' this.theme = 'dark'
} else { } else {
this.theme = 'light' this.theme = 'light'
} }
document.querySelector('html').setAttribute('theme', this.theme) document.querySelector('html').setAttribute('theme', this.theme)
} }
@ -225,6 +227,7 @@ class OverviewPage extends LitElement {
async refreshItems() { async refreshItems() {
this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig
this.accountInfo = window.parent.reduxStore.getState().app.accountInfo this.accountInfo = window.parent.reduxStore.getState().app.accountInfo
await this.getNodeInfo() await this.getNodeInfo()
await this.getCoreInfo() await this.getCoreInfo()
await this.getBalanceInfo() await this.getBalanceInfo()
@ -234,12 +237,14 @@ class OverviewPage extends LitElement {
async getMintingKeysList() { async getMintingKeysList() {
this.check1 = false this.check1 = false
this.check2 = false this.check2 = false
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeStatus = myNode.protocol + '://' + myNode.domain + ':' + myNode.port const nodeStatus = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const statusUrl = `${nodeStatus}/admin/mintingaccounts` const statusUrl = `${nodeStatus}/admin/mintingaccounts?apiKey=${this.getApiKey()}`
try { try {
const res = await fetch(statusUrl) const res = await fetch(statusUrl)
this.listAccounts = await res.json() this.listAccounts = await res.json()
const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo
@ -249,7 +254,6 @@ class OverviewPage extends LitElement {
const findRemovedSponsorsKey = this.listAccounts.filter((my) => my.address) const findRemovedSponsorsKey = this.listAccounts.filter((my) => my.address)
this.check1 = findMyMintingAccount !== undefined this.check1 = findMyMintingAccount !== undefined
this.check2 = findMyMintingRecipient !== undefined this.check2 = findMyMintingRecipient !== undefined
if (findRemovedSponsorsKey.length > 0) { if (findRemovedSponsorsKey.length > 0) {
@ -285,8 +289,7 @@ class OverviewPage extends LitElement {
this.cssStatus = '' this.cssStatus = ''
return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>` return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>`
} else if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === false && this.check1 === false && this.check2 === true && addressInfo.level == 0 && addressInfo.blocksMinted < 7200) { } else if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === false && this.check1 === false && this.check2 === true && addressInfo.level == 0 && addressInfo.blocksMinted < 7200) {
this.cssStatus = '' return html`<span class="float-right"><start-minting-now></start-minting-now></span>`
return html`<span class="btn btn-sm btn-info float-right">${translate("becomeMinterPage.bchange12")}</span>`
} else if (this.check1 === false && this.check2 === false && myMintingKey === true) { } else if (this.check1 === false && this.check2 === false && myMintingKey === true) {
return html`<span class="float-right"><start-minting-now></start-minting-now></span>` return html`<span class="float-right"><start-minting-now></start-minting-now></span>`
} else if (myMintingKey === false) { } else if (myMintingKey === false) {
@ -319,6 +322,7 @@ class OverviewPage extends LitElement {
const infoNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const infoNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const infoNodeUrl = infoNode.protocol + '://' + infoNode.domain + ':' + infoNode.port const infoNodeUrl = infoNode.protocol + '://' + infoNode.domain + ':' + infoNode.port
const nodeUrl = `${infoNodeUrl}/admin/status` const nodeUrl = `${infoNodeUrl}/admin/status`
await fetch(nodeUrl).then(response => { await fetch(nodeUrl).then(response => {
return response.json() return response.json()
}).then(data => { }).then(data => {
@ -332,6 +336,7 @@ class OverviewPage extends LitElement {
const infoCore = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const infoCore = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const infoCoreUrl = infoCore.protocol + '://' + infoCore.domain + ':' + infoCore.port const infoCoreUrl = infoCore.protocol + '://' + infoCore.domain + ':' + infoCore.port
const coreUrl = `${infoCoreUrl}/admin/info` const coreUrl = `${infoCoreUrl}/admin/info`
await fetch(coreUrl).then(response => { await fetch(coreUrl).then(response => {
return response.json() return response.json()
}).then(data => { }).then(data => {
@ -344,6 +349,7 @@ class OverviewPage extends LitElement {
const infoBalance = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const infoBalance = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const infoBalanceUrl = infoBalance.protocol + '://' + infoBalance.domain + ':' + infoBalance.port const infoBalanceUrl = infoBalance.protocol + '://' + infoBalance.domain + ':' + infoBalance.port
const balanceUrl = `${infoBalanceUrl}/addresses/balance/${this.accountInfo.addressInfo.address}` const balanceUrl = `${infoBalanceUrl}/addresses/balance/${this.accountInfo.addressInfo.address}`
await fetch(balanceUrl).then(response => { await fetch(balanceUrl).then(response => {
return response.json() return response.json()
}).then(data => { }).then(data => {
@ -422,7 +428,7 @@ class StartMintingNow extends LitElement {
async getMintingAcccounts() { async getMintingAcccounts() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] 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 nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const url = `${nodeUrl}/admin/mintingaccounts` const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${this.getApiKey()}`
try { try {
const res = await fetch(url) const res = await fetch(url)
this.mintingAccountData = await res.json() this.mintingAccountData = await res.json()
@ -484,7 +490,9 @@ class StartMintingNow extends LitElement {
let interval = null let interval = null
let stop = false let stop = false
this.status = 2 this.status = 2
const getAnswer = async () => { const getAnswer = async () => {
const rewardShares = async (minterAddr) => { const rewardShares = async (minterAddr) => {
const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}` const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}`
@ -508,6 +516,7 @@ class StartMintingNow extends LitElement {
stop = false stop = false
} }
} }
interval = setInterval(getAnswer, 5000) interval = setInterval(getAnswer, 5000)
} }

View File

@ -39,6 +39,7 @@ import '@polymer/paper-icon-button/paper-icon-button.js'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/grid' import '@vaadin/grid'
import '@vaadin/tooltip' import '@vaadin/tooltip'
import '@vaadin/text-field'
// Multi language support // Multi language support
import { get, registerTranslateConfig, translate, use } from '../../../../core/translate' import { get, registerTranslateConfig, translate, use } from '../../../../core/translate'
@ -62,6 +63,7 @@ class Chat extends LitElement {
messages: { type: Array }, messages: { type: Array },
btnDisable: { type: Boolean }, btnDisable: { type: Boolean },
isLoading: { type: Boolean }, isLoading: { type: Boolean },
isViewOpen: { type: Boolean },
balance: { type: Number }, balance: { type: Number },
theme: { type: String, reflect: true }, theme: { type: String, reflect: true },
blockedUsers: { type: Array }, blockedUsers: { type: Array },
@ -69,6 +71,7 @@ class Chat extends LitElement {
privateMessagePlaceholder: { type: String }, privateMessagePlaceholder: { type: String },
imageFile: { type: Object }, imageFile: { type: Object },
activeChatHeadUrl: { type: String }, activeChatHeadUrl: { type: String },
switchChatHeadUrl: { type: String },
openPrivateMessage: { type: Boolean }, openPrivateMessage: { type: Boolean },
userFound: { type: Array }, userFound: { type: Array },
userFoundModalOpen: { type: Boolean }, userFoundModalOpen: { type: Boolean },
@ -102,6 +105,7 @@ class Chat extends LitElement {
this.messages = [] this.messages = []
this.btnDisable = false this.btnDisable = false
this.isLoading = false this.isLoading = false
this.isViewOpen = false
this.showNewMessageBar = this.showNewMessageBar.bind(this) this.showNewMessageBar = this.showNewMessageBar.bind(this)
this.hideNewMessageBar = this.hideNewMessageBar.bind(this) this.hideNewMessageBar = this.hideNewMessageBar.bind(this)
this.setOpenPrivateMessage = this.setOpenPrivateMessage.bind(this) this.setOpenPrivateMessage = this.setOpenPrivateMessage.bind(this)
@ -113,6 +117,7 @@ class Chat extends LitElement {
this.privateMessagePlaceholder = '' this.privateMessagePlaceholder = ''
this.imageFile = null this.imageFile = null
this.activeChatHeadUrl = '' this.activeChatHeadUrl = ''
this.switchChatHeadUrl = ''
this.openPrivateMessage = false this.openPrivateMessage = false
this.userFound = [] this.userFound = []
this.userFoundModalOpen = false this.userFoundModalOpen = false
@ -140,7 +145,7 @@ class Chat extends LitElement {
</vaadin-tooltip> </vaadin-tooltip>
</div> </div>
<div style="display:flex; align-items:center;gap:10px"> <div style="display:flex; align-items:center;gap:10px">
<div id="viewChat" class="create-chat" @click=${() => { this.shadowRoot.querySelector('#viewChatDialog').show() }}> <div id="viewChat" class="create-chat" @click=${() => { this.openView(this.activeChatHeadUrl) }}>
<mwc-icon style="color: var(--black);">pageview</mwc-icon> <mwc-icon style="color: var(--black);">pageview</mwc-icon>
<vaadin-tooltip <vaadin-tooltip
for="viewChat" for="viewChat"
@ -185,7 +190,11 @@ class Chat extends LitElement {
<span>${translate("chatpage.cchange5")} <mwc-icon style="font-size: 16px; vertical-align: bottom;">keyboard_arrow_down</mwc-icon></span> <span>${translate("chatpage.cchange5")} <mwc-icon style="font-size: 16px; vertical-align: bottom;">keyboard_arrow_down</mwc-icon></span>
</div> </div>
<div class="chat-history"> <div class="chat-history">
${this.activeChatHeadUrl ? html`${this.renderChatPage()}` : html`${this.renderChatWelcomePage()}`} ${this.activeChatHeadUrl ?
html`${this.renderChatPage()}`
: this.isViewOpen ? html`${this.renderChatViewPage()}`
: html`${this.renderChatWelcomePage()}`
}
</div> </div>
</div> </div>
<!-- Start Chatting Dialog --> <!-- Start Chatting Dialog -->
@ -315,43 +324,24 @@ class Chat extends LitElement {
</mwc-button> </mwc-button>
</mwc-dialog> </mwc-dialog>
<!-- View Chat Over ID --> <!-- View Chat Over ID -->
<mwc-dialog id="viewChatDialog"> <paper-dialog id="viewChatDialog" class="viewSettings" modal>
<div style="text-align: center;"> <div style="display: inline;">
<h1>Please Enter The Group ID</h1> <div class="view">
<hr> <vaadin-text-field
<br> style="width: 350px"
id="groupIdInput"
required
allowed-char-pattern="[0-9]"
placeholder="${translate("modals.mpchange87")}"
value=""
@keydown="${this.viewKeyListener}"
clear-button-visible
>
</vaadin-text-field>
<paper-icon-button icon="icons:visibility" @click="${() => this.switchChatID()}" title="${translate("general.view")}"></paper-icon-button>
<paper-icon-button icon="icons:close" @click="${() => this.closeView()}" title="${translate("general.close")}"></paper-icon-button>
</div>
</div> </div>
<div style="display: flex; align-items: center;">
<mwc-textfield
style="width: 100%;"
required
id="groupIdInput"
label="Emter Group ID"
type="number"
auto-validate="false"
value=""
>
</mwc-textfield>
</div>
<mwc-button slot="primaryAction" dialogAction="cancel" class="red">
${translate("general.close")}
</mwc-button>
<mwc-button slot="secondaryAction" class="green" @click=${this.switchChatID}>
${translate("general.view")}
</mwc-button>
</mwc-dialog>
<paper-dialog id="checkIdDialog" class="check" modal>
<div class="check-roller">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<h2>Checking</h2>
</paper-dialog> </paper-dialog>
</div> </div>
` `
@ -499,8 +489,6 @@ class Chat extends LitElement {
viewGroupID = this.shadowRoot.getElementById('groupIdInput').value viewGroupID = this.shadowRoot.getElementById('groupIdInput').value
this.shadowRoot.getElementById('checkIdDialog').open()
await parentEpml.request('apiCall', { await parentEpml.request('apiCall', {
url: `/groups/${viewGroupID}` url: `/groups/${viewGroupID}`
}).then(res => { }).then(res => {
@ -508,25 +496,55 @@ class Chat extends LitElement {
}) })
if (checkTheID.error) { if (checkTheID.error) {
this.shadowRoot.getElementById('checkIdDialog').close()
this.shadowRoot.getElementById('viewChatDialog').close() this.shadowRoot.getElementById('viewChatDialog').close()
this.shadowRoot.getElementById('groupIdInput').value = '' this.shadowRoot.getElementById('groupIdInput').value = ''
this.isViewOpen = false
this.activeChatHeadUrl = this.switchChatHeadUrl
this.switchChatHeadUrl = ''
this.resetChatEditor()
parentEpml.request('showSnackBar', `${notFound}`) parentEpml.request('showSnackBar', `${notFound}`)
} else if (checkTheID.groupId) { } else if (checkTheID.groupId) {
let switchToID = checkTheID.groupName let switchToID = checkTheID.groupName
this.shadowRoot.getElementById('checkIdDialog').close()
this.shadowRoot.getElementById('viewChatDialog').close() this.shadowRoot.getElementById('viewChatDialog').close()
this.shadowRoot.getElementById('groupIdInput').value = '' this.shadowRoot.getElementById('groupIdInput').value = ''
this.switchChatHeadUrl = ''
parentEpml.request('showSnackBar', `${switchToID}`) parentEpml.request('showSnackBar', `${switchToID}`)
this.processChatID(checkTheID.groupId) this.processChatID(checkTheID.groupId)
} else { } else {
this.shadowRoot.getElementById('checkIdDialog').close()
this.shadowRoot.getElementById('viewChatDialog').close() this.shadowRoot.getElementById('viewChatDialog').close()
this.shadowRoot.getElementById('groupIdInput').value = '' this.shadowRoot.getElementById('groupIdInput').value = ''
this.isViewOpen = false
this.activeChatHeadUrl = this.switchChatHeadUrl
this.switchChatHeadUrl = ''
this.resetChatEditor()
parentEpml.request('showSnackBar', `${wentWrong}`) parentEpml.request('showSnackBar', `${wentWrong}`)
} }
} }
openView(currentUrl) {
this.switchChatHeadUrl = currentUrl
this.activeChatHeadUrl = ''
this.isViewOpen = true
this.shadowRoot.getElementById('viewChatDialog').open()
this.shadowRoot.getElementById('groupIdInput').value = ''
this.resetChatEditor()
}
closeView() {
this.shadowRoot.getElementById('viewChatDialog').close()
this.shadowRoot.getElementById('groupIdInput').value = ''
this.isViewOpen = false
this.activeChatHeadUrl = this.switchChatHeadUrl
this.switchChatHeadUrl = ''
this.resetChatEditor()
}
viewKeyListener(e) {
if (e.key === 'Enter') {
this.switchChatID()
}
}
async processChatID(newID) { async processChatID(newID) {
let viewNewUrl = 'group/' + newID let viewNewUrl = 'group/' + newID
this.setActiveChatHeadUrl(viewNewUrl) this.setActiveChatHeadUrl(viewNewUrl)
@ -535,6 +553,7 @@ class Chat extends LitElement {
async setActiveChatHeadUrl(url) { async setActiveChatHeadUrl(url) {
await this.getSymKeyFile(url) await this.getSymKeyFile(url)
this.isViewOpen = false
} }
async getSymKeyFile(url) { async getSymKeyFile(url) {
@ -1153,6 +1172,22 @@ class Chat extends LitElement {
` `
} }
renderChatViewPage() {
return html`
<div class="view-grid">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
`
}
renderChatHead(chatHeadArr) { renderChatHead(chatHeadArr) {
return chatHeadArr.map(eachChatHead => { return chatHeadArr.map(eachChatHead => {
return html`<chat-head activeChatHeadUrl=${this.activeChatHeadUrl} .setActiveChatHeadUrl=${(val) => this.setActiveChatHeadUrl(val)} chatInfo=${JSON.stringify(eachChatHead)}></chat-head>` return html`<chat-head activeChatHeadUrl=${this.activeChatHeadUrl} .setActiveChatHeadUrl=${(val) => this.setActiveChatHeadUrl(val)} chatInfo=${JSON.stringify(eachChatHead)}></chat-head>`
@ -1207,6 +1242,20 @@ class Chat extends LitElement {
} }
} }
async getGroupType(newGroupId) {
try {
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 response = await fetch(`${nodeUrl}/groups/${newGroupId}`)
const data = await response.json()
return data.isOpen
} catch (error) {
console.error('Error fetching group type', error)
throw error
}
}
async setChatHeads(chatObj) { async setChatHeads(chatObj) {
const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : [] const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : []
const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : [] const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : []
@ -1216,12 +1265,14 @@ class Chat extends LitElement {
url: `group/${group.groupId}`, url: `group/${group.groupId}`,
groupName: 'Qortal General Chat', groupName: 'Qortal General Chat',
timestamp: group.timestamp === undefined ? 2 : group.timestamp, timestamp: group.timestamp === undefined ? 2 : group.timestamp,
sender: group.sender sender: group.sender,
isOpen: true
} : { } : {
...group, ...group,
timestamp: group.timestamp === undefined ? 1 : group.timestamp, timestamp: group.timestamp === undefined ? 1 : group.timestamp,
url: `group/${group.groupId}`, url: `group/${group.groupId}`,
ownerName: group.ownerName === undefined ? await this.getOwnerName(group.groupId) : 'undefined' ownerName: group.ownerName === undefined ? await this.getOwnerName(group.groupId) : 'undefined',
isOpen: group.isOpen === undefined ? await this.getGroupType(group.groupId) : true
})) }))
let directList = chatObjDirect.map(dc => { let directList = chatObjDirect.map(dc => {

View File

@ -13,11 +13,14 @@ import {
processTransactionV2, processTransactionV2,
publishData, publishData,
requestQueueGetAtAddresses, requestQueueGetAtAddresses,
tradeBotCreateRequest tradeBotCreateRequest,
getArrrSyncStatus,
getNodeInfo,
getNodeStatus
} from '../../../utils/classes' } from '../../../utils/classes'
import {appendBuffer} from '../../../utils/utilities' import {appendBuffer} from '../../../utils/utilities'
import {QORT_DECIMALS} from '../../../../../crypto/api/constants' import {QORT_DECIMALS} from '../../../../../crypto/api/constants'
import {listOfAllQortalRequests} from '../../components/qdn-action-constants' import {mimeToExtensionMap, listOfAllQortalRequests} from '../../components/qdn-action-constants'
import { import {
createSymmetricKeyAndNonce, createSymmetricKeyAndNonce,
decryptGroupEncryptionWithSharingKey, decryptGroupEncryptionWithSharingKey,
@ -182,6 +185,7 @@ class WebBrowser extends LitElement {
) )
} }
const render = () => { const render = () => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] 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 nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
@ -262,7 +266,7 @@ class WebBrowser extends LitElement {
${this.renderFollowUnfollowButton()} ${this.renderFollowUnfollowButton()}
</div> </div>
<div class="iframe-container"> <div class="iframe-container">
<iframe id="browser-iframe" src="${this.url}" sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen"> <iframe id="browser-iframe" src="${this.url}" sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen; clipboard-read; clipboard-write;">
<span style="color: var(--black);">${translate('browserpage.bchange6')}</span> <span style="color: var(--black);">${translate('browserpage.bchange6')}</span>
</iframe> </iframe>
</div> </div>
@ -319,6 +323,21 @@ class WebBrowser extends LitElement {
} }
break break
case actions.GET_ARRR_SYNC_STATUS: {
response = await getArrrSyncStatus()
}
break
case actions.GET_NODE_INFO: {
response = await getNodeInfo()
}
break
case actions.GET_NODE_STATUS: {
response = await getNodeStatus()
}
break
case actions.ADMIN_ACTION: { case actions.ADMIN_ACTION: {
let type = data.type let type = data.type
let value = data.value let value = data.value
@ -1399,7 +1418,7 @@ class WebBrowser extends LitElement {
case actions.PUBLISH_QDN_RESOURCE: { case actions.PUBLISH_QDN_RESOURCE: {
// optional fields: encrypt:boolean recipientPublicKey:string // optional fields: encrypt:boolean recipientPublicKey:string
const requiredFields = ['service', 'name'] const requiredFields = ['service']
const missingFields = [] const missingFields = []
let dataSentBack = {} let dataSentBack = {}
requiredFields.forEach((field) => { requiredFields.forEach((field) => {
@ -1421,7 +1440,7 @@ class WebBrowser extends LitElement {
response = JSON.stringify(dataSentBack) response = JSON.stringify(dataSentBack)
break break
} }
if (!data.file && !data.data64) { if (!data.file && !data.data64 && !data.base64) {
let myMsg1 = get("modals.mpchange22") let myMsg1 = get("modals.mpchange22")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
@ -1432,9 +1451,13 @@ class WebBrowser extends LitElement {
} }
// Use "default" if user hasn't specified an identifer // Use "default" if user hasn't specified an identifer
const service = data.service const service = data.service
const name = data.name const name = data.name || this.getMyName()
if(!name){
dataSentBack['error'] = `Missing name`
break
}
let identifier = data.identifier let identifier = data.identifier
let data64 = data.data64 let data64 = data.data64 || data.base64
const filename = data.filename const filename = data.filename
const title = data.title const title = data.title
const description = data.description const description = data.description
@ -1611,10 +1634,16 @@ class WebBrowser extends LitElement {
} }
const getArbitraryFee = await this.getArbitraryFee() const getArbitraryFee = await this.getArbitraryFee()
feeAmount = getArbitraryFee.fee feeAmount = getArbitraryFee.fee
const reformatResources = resources.map((resource)=> {
return {
...resource,
name: resource.name || this.getMyName()
}
})
const res2 = await showModalAndWait( const res2 = await showModalAndWait(
actions.PUBLISH_MULTIPLE_QDN_RESOURCES, actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
{ {
resources, resources: reformatResources,
encrypt: data.encrypt, encrypt: data.encrypt,
feeAmount: getArbitraryFee.feeToShow feeAmount: getArbitraryFee.feeToShow
} }
@ -1629,9 +1658,9 @@ class WebBrowser extends LitElement {
} }
let failedPublishesIdentifiers = [] let failedPublishesIdentifiers = []
this.loader.show() this.loader.show()
for (const resource of resources) { for (const resource of reformatResources) {
try { try {
const requiredFields = ['service', 'name'] const requiredFields = ['service']
const missingFields = [] const missingFields = []
requiredFields.forEach((field) => { requiredFields.forEach((field) => {
if (!resource[field]) { if (!resource[field]) {
@ -1647,7 +1676,7 @@ class WebBrowser extends LitElement {
}) })
continue continue
} }
if (!resource.file && !resource.data64) { if (!resource.file && !resource.data64 && !resource.base64) {
const errorMsg = 'No data or file was submitted' const errorMsg = 'No data or file was submitted'
failedPublishesIdentifiers.push({ failedPublishesIdentifiers.push({
reason: errorMsg, reason: errorMsg,
@ -1657,8 +1686,16 @@ class WebBrowser extends LitElement {
} }
const service = resource.service const service = resource.service
const name = resource.name const name = resource.name
if(!name){
const errorMsg = `Missing name`
failedPublishesIdentifiers.push({
reason: errorMsg,
identifier: resource.identifier
})
continue
}
let identifier = resource.identifier let identifier = resource.identifier
let data64 = resource.data64 let data64 = resource.data64 || resource.base64
const filename = resource.filename const filename = resource.filename
const title = resource.title const title = resource.title
const description = resource.description const description = resource.description
@ -2252,6 +2289,108 @@ class WebBrowser extends LitElement {
} }
break break
case actions.SAVE_FILE: {
try {
const requiredFields = ['filename', 'blob']
const missingFields = []
let dataSentBack = {}
requiredFields.forEach((field) => {
if (!data[field]) {
missingFields.push(field)
}
})
if (missingFields.length > 0) {
const missingFieldsString = missingFields.join(', ')
const tryAgain = get("walletpage.wchange44")
await showErrorAndWait(
"MISSING_FIELDS",
{
id1: missingFieldsString,
id2: tryAgain
}
)
dataSentBack['error'] = `Missing fields: ${missingFieldsString}`
response = JSON.stringify(dataSentBack)
break
}
const filename = data.filename
const blob = data.blob
const res = await showModalAndWait(
actions.SAVE_FILE,
{
filename
}
)
if (res.action === 'reject') {
let myMsg1 = get("transactions.declined")
let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 })
response = '{"error": "User declined request"}'
break
}
const mimeType = blob.type || data.mimeType
let backupExention = filename.split('.').pop()
if (backupExention) {
backupExention = '.' + backupExention
}
const fileExtension = mimeToExtensionMap[mimeType] || backupExention
let fileHandleOptions = {}
if (!mimeType) {
const obj = {}
obj['error'] = 'A mimeType could not be derived'
response = JSON.stringify(obj)
break
}
if (!fileExtension) {
const obj = {}
obj['error'] = 'A file extension could not be derived'
response = JSON.stringify(obj)
break
}
if (fileExtension && mimeType) {
fileHandleOptions = {
accept: {
[mimeType]: [fileExtension]
}
}
}
try {
const fileHandle = await self.showSaveFilePicker({
suggestedName: filename,
types: [
{
description: mimeType,
...fileHandleOptions
}
]
})
const writeFile = async (fileHandle, contents) => {
const writable = await fileHandle.createWritable()
await writable.write(contents)
await writable.close()
}
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
} catch (error) {
if (error.name === 'AbortError') {
const obj = {}
obj['error'] = 'User declined the download'
response = JSON.stringify(obj)
break
}
FileSaver.saveAs(blob, filename)
}
response = JSON.stringify(true)
} catch (error) {
let myMsg1 = get("managegroup.mg58")
let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
const obj = {}
obj['error'] = error.message || 'Failed to initiate download'
response = JSON.stringify(obj)
}
}
break
case actions.DEPLOY_AT: { case actions.DEPLOY_AT: {
const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'] const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type']
const missingFields = [] const missingFields = []
@ -2583,6 +2722,7 @@ class WebBrowser extends LitElement {
break break
case 'ARRR': case 'ARRR':
userWallet['address'] = arrrAddress userWallet['address'] = arrrAddress
userWallet['publicKey'] = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
break break
default: default:
break break
@ -2599,12 +2739,121 @@ class WebBrowser extends LitElement {
} }
break break
case actions.GET_USER_WALLET_TRANSACTIONS: {
const requiredFields = ['coin']
const missingFields = []
let dataSentBack = {}
let skipWalletTransactions = false
let resSkipWalletTransactions
requiredFields.forEach((field) => {
if (!data[field]) {
missingFields.push(field)
}
})
if (missingFields.length > 0) {
const missingFieldsString = missingFields.join(', ')
const tryAgain = get("walletpage.wchange44")
await showErrorAndWait(
"MISSING_FIELDS",
{
id1: missingFieldsString,
id2: tryAgain
}
)
dataSentBack['error'] = `Missing fields: ${missingFieldsString}`
response = JSON.stringify(dataSentBack)
break
}
if (window.parent.reduxStore.getState().app.qAPPAutoTransactions) {
skipWalletTransactions = true
}
if (!skipWalletTransactions) {
resSkipWalletTransactions = await showModalAndWait(
actions.GET_USER_WALLET_TRANSACTIONS
)
}
if ((resSkipWalletTransactions && resSkipWalletTransactions.action === 'accept') || skipWalletTransactions) {
let coin = data.coin
if (coin === "QORT") {
let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
try {
response = await parentEpml.request('apiCall', {
url: `/transactions/address/${qortAddress}?limit=0&reverse=true`
})
break
} catch (error) {
let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", {id1: myMsg1, id2: myMsg2})
const data = {}
data['error'] = error.message ? error.message : get("browserpage.bchange21")
response = JSON.stringify(data)
break
}
} else {
let _url = ``
let _body = null
switch (coin) {
case 'BTC':
_url = `/crosschain/btc/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey
break
case 'LTC':
_url = `/crosschain/ltc/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
break
case 'DOGE':
_url = `/crosschain/doge/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
break
case 'DGB':
_url = `/crosschain/dgb/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
break
case 'RVN':
_url = `/crosschain/rvn/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
break
case 'ARRR':
_url = `/crosschain/arrr/wallettransactions?apiKey=${this.getApiKey()}`
_body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
break
default:
break
}
try {
response = await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body
})
break
} catch (error) {
let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
const data = {}
data['error'] = error.message ? error.message : get("browserpage.bchange21")
response = JSON.stringify(data)
break
}
}
} else if (resSkipWalletTransactions.action === 'reject') {
let myMsg1 = get("transactions.declined")
let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 })
response = '{"error": "User declined request"}'
break
}
}
break
case actions.GET_WALLET_BALANCE: { case actions.GET_WALLET_BALANCE: {
const requiredFields = ['coin'] const requiredFields = ['coin']
const missingFields = [] const missingFields = []
let dataSentBack = {} let dataSentBack = {}
let skip = false let skipWalletBalance = false
let res3 let resSkipWalletBalance
requiredFields.forEach((field) => { requiredFields.forEach((field) => {
if (!data[field]) { if (!data[field]) {
missingFields.push(field) missingFields.push(field)
@ -2629,32 +2878,30 @@ class WebBrowser extends LitElement {
// then set the response string from the core to the `response` variable (defined above) // then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
if (window.parent.reduxStore.getState().app.qAPPAutoBalance) { if (window.parent.reduxStore.getState().app.qAPPAutoBalance) {
skip = true skipWalletBalance = true
} }
if (!skip) { if (!skipWalletBalance) {
res3 = await showModalAndWait( resSkipWalletBalance = await showModalAndWait(
actions.GET_WALLET_BALANCE actions.GET_WALLET_BALANCE
) )
} }
if ((res3 && res3.action === 'accept') || skip) { if ((resSkipWalletBalance && resSkipWalletBalance.action === 'accept') || skipWalletBalance) {
let coin = data.coin let coin = data.coin
if (coin === "QORT") { if (coin === "QORT") {
let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
try { try {
this.loader.show()
response = await parentEpml.request('apiCall', { response = await parentEpml.request('apiCall', {
url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}` url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`
}) })
this.loader.hide()
break break
} catch (error) { } catch (error) {
this.loader.hide()
let myMsg1 = get("browserpage.bchange21") let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", {id1: myMsg1, id2: myMsg2}) await showErrorAndWait("ACTION_FAILED", {id1: myMsg1, id2: myMsg2})
const data = {} const data = {}
data['error'] = error.message ? error.message : get("browserpage.bchange21") data['error'] = error.message ? error.message : get("browserpage.bchange21")
response = JSON.stringify(data) response = JSON.stringify(data)
break
} }
} else { } else {
let _url = `` let _url = ``
@ -2688,14 +2935,12 @@ class WebBrowser extends LitElement {
break break
} }
try { try {
this.loader.show()
const res = await parentEpml.request('apiCall', { const res = await parentEpml.request('apiCall', {
url: _url, url: _url,
method: 'POST', method: 'POST',
body: _body body: _body
}) })
if (isNaN(Number(res))) { if (isNaN(Number(res))) {
this.loader.hide()
let myMsg1 = get("browserpage.bchange21") let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
@ -2704,12 +2949,10 @@ class WebBrowser extends LitElement {
response = JSON.stringify(data) response = JSON.stringify(data)
break break
} else { } else {
this.loader.hide()
response = (Number(res) / 1e8).toFixed(8) response = (Number(res) / 1e8).toFixed(8)
break break
} }
} catch (error) { } catch (error) {
this.loader.hide()
let myMsg1 = get("browserpage.bchange21") let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
@ -2719,7 +2962,7 @@ class WebBrowser extends LitElement {
break break
} }
} }
} else if (res3.action === 'reject') { } else if (resSkipWalletBalance.action === 'reject') {
let myMsg1 = get("transactions.declined") let myMsg1 = get("transactions.declined")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 })
@ -2732,7 +2975,9 @@ class WebBrowser extends LitElement {
case actions.GET_USER_WALLET_INFO: { case actions.GET_USER_WALLET_INFO: {
const requiredFields = ['coin'] const requiredFields = ['coin']
const missingFields = [] const missingFields = []
let skipUserWalletInfo = false
let dataSentBack = {} let dataSentBack = {}
let resSkipUserWalletInfo
requiredFields.forEach((field) => { requiredFields.forEach((field) => {
if (!data[field]) { if (!data[field]) {
missingFields.push(field) missingFields.push(field)
@ -2752,16 +2997,20 @@ class WebBrowser extends LitElement {
response = JSON.stringify(dataSentBack) response = JSON.stringify(dataSentBack)
break break
} }
const userWallet = await showModalAndWait( if (window.parent.reduxStore.getState().app.qAPPAutoAuth) {
actions.GET_USER_WALLET skipUserWalletInfo = true
) }
if (userWallet.action === 'accept') { if (!skipUserWalletInfo) {
resSkipUserWalletInfo = await showModalAndWait(
actions.GET_USER_WALLET
)
}
if ((resSkipUserWalletInfo && resSkipUserWalletInfo.action === 'accept') || skipUserWalletInfo) {
let coin = data.coin let coin = data.coin
let walletKeys = this.getUserWallet(coin) let walletKeys = this.getUserWallet(coin)
let _url = `/crosschain/` + data.coin.toLowerCase() + `/addressinfos?apiKey=${this.getApiKey()}` let _url = `/crosschain/` + data.coin.toLowerCase() + `/addressinfos?apiKey=${this.getApiKey()}`
let _body = { xpub58: walletKeys['publicKey'] } let _body = { xpub58: walletKeys['publicKey'] }
try { try {
this.loader.show()
const bodyToString = JSON.stringify(_body) const bodyToString = JSON.stringify(_body)
const res = await parentEpml.request('apiCall', { const res = await parentEpml.request('apiCall', {
url: _url, url: _url,
@ -2774,7 +3023,6 @@ class WebBrowser extends LitElement {
}) })
response = JSON.stringify(res) response = JSON.stringify(res)
} catch (error) { } catch (error) {
this.loader.hide()
let myMsg1 = get("browserpage.bchange21") let myMsg1 = get("browserpage.bchange21")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
@ -2782,10 +3030,8 @@ class WebBrowser extends LitElement {
data['error'] = error.message ? error.message : get("browserpage.bchange21") data['error'] = error.message ? error.message : get("browserpage.bchange21")
response = JSON.stringify(data) response = JSON.stringify(data)
return return
} finally {
this.loader.hide()
} }
} else if (userWallet.action === 'reject') { } else if (resSkipUserWalletInfo.action === 'reject') {
let myMsg1 = get("transactions.declined") let myMsg1 = get("transactions.declined")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("DECLINED_REQUEST", { id1: myMsg1, id2: myMsg2 })
@ -2819,7 +3065,6 @@ class WebBrowser extends LitElement {
} }
let _url = `/crosschain/` + data.coin.toLowerCase() + `/serverinfos` let _url = `/crosschain/` + data.coin.toLowerCase() + `/serverinfos`
try { try {
this.loader.show()
const res = await parentEpml.request('apiCall', { const res = await parentEpml.request('apiCall', {
url: _url, url: _url,
method: 'GET', method: 'GET',
@ -2829,7 +3074,6 @@ class WebBrowser extends LitElement {
}) })
response = JSON.stringify(res.servers) response = JSON.stringify(res.servers)
} catch (error) { } catch (error) {
this.loader.hide()
let myMsg1 = get("modals.mpchange55") let myMsg1 = get("modals.mpchange55")
let myMsg2 = get("walletpage.wchange44") let myMsg2 = get("walletpage.wchange44")
await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 }) await showErrorAndWait("ACTION_FAILED", { id1: myMsg1, id2: myMsg2 })
@ -2837,8 +3081,6 @@ class WebBrowser extends LitElement {
data['error'] = error.message ? error.message : get("modals.mpchange55") data['error'] = error.message ? error.message : get("modals.mpchange55")
response = JSON.stringify(data) response = JSON.stringify(data)
return return
} finally {
this.loader.hide()
} }
} }
break break
@ -3263,10 +3505,11 @@ class WebBrowser extends LitElement {
const signRequest = await showModalAndWait( const signRequest = await showModalAndWait(
actions.SIGN_TRANSACTION, actions.SIGN_TRANSACTION,
{ {
text1: `${shouldProcess ? get("modals.mpchange65") : get("modals.mpchange6")}`, text1: `${shouldProcess ? get("modals.mpchange65") : get("modals.mpchange66")}`,
text2: get("modals.mpchange67"), text2: get("modals.mpchange67"),
text3: `${get("modals.mpchange68")} ${decodedData.type}`, text3: `${get("modals.mpchange68")} ${decodedData.type}`,
json: `${get("modals.mpchange69")} ${decodedData}` txdata: `${get("modals.mpchange69")}`,
txjson: `${JSON.stringify(decodedData)}`
} }
) )
if (signRequest.action === 'accept') { if (signRequest.action === 'accept') {
@ -3297,10 +3540,7 @@ class WebBrowser extends LitElement {
const signedBytes = appendBuffer(arbitraryBytesBuffer, signature) const signedBytes = appendBuffer(arbitraryBytesBuffer, signature)
const signedBytesToBase58 = Base58.encode(signedBytes) const signedBytesToBase58 = Base58.encode(signedBytes)
if(!shouldProcess) { if(!shouldProcess) {
let myMsg1 = get("modals.mpchange70") response = signedBytesToBase58
let myMsg2 = get("modals.mpchange71") + signedBytesToBase58
await showSuccessAndWait("REQUEST_SUCCESS", { id1: myMsg1, id2: myMsg2 })
response = '{"error": "Process transaction was not requested!"}'
break break
} }
try { try {
@ -4186,6 +4426,11 @@ class WebBrowser extends LitElement {
}, 60000) }, 60000)
} }
getMyName(){
const names = window.parent.reduxStore.getState().app.accountInfo.names
if(names.length === 0) return null
return names[0].name
}
renderFullScreen() { renderFullScreen() {
if (window.innerHeight === screen.height) { if (window.innerHeight === screen.height) {
return html` return html`
@ -5126,7 +5371,6 @@ async function showModalAndWait(type, data) {
${type === actions.GET_PROFILE_DATA ? ` ${type === actions.GET_PROFILE_DATA ? `
<div class="modal-subcontainer"> <div class="modal-subcontainer">
<p class="modal-paragraph">${get("browserpage.bchange49")}: <span style="font-weight: bold"> ${data.property}</span></p> <p class="modal-paragraph">${get("browserpage.bchange49")}: <span style="font-weight: bold"> ${data.property}</span></p>
</div> </div>
` : ''} ` : ''}
@ -5163,7 +5407,8 @@ async function showModalAndWait(type, data) {
<p class="modal-paragraph">${data.text1}</p> <p class="modal-paragraph">${data.text1}</p>
<p class="modal-paragraph">${data.text2}</p> <p class="modal-paragraph">${data.text2}</p>
<p class="modal-paragraph">${data.text3}</p> <p class="modal-paragraph">${data.text3}</p>
<p class="modal-paragraph">Transaction: <span>${data.json}</span></p> <p class="modal-paragraph"><span>${data.txdata}</span></p>
<p class="modal-paragraph"><span>${convertJson(data.txjson)}</span></p>
` : ''} ` : ''}
${type === actions.CREATE_TRADE_BUY_ORDER ? ` ${type === actions.CREATE_TRADE_BUY_ORDER ? `
@ -5193,6 +5438,18 @@ async function showModalAndWait(type, data) {
<p class="modal-paragraph">${data.text3}</p> <p class="modal-paragraph">${data.text3}</p>
<p class="modal-paragraph">${get("walletpage.wchange36")}: <span>${data.fee}</span></p> <p class="modal-paragraph">${get("walletpage.wchange36")}: <span>${data.fee}</span></p>
` : ''} ` : ''}
${type === actions.GET_USER_WALLET_TRANSACTIONS ? `
<div class="modal-subcontainer">
<p class="modal-paragraph">Do you give this application permission to retrieve your wallet transactions?</p>
<div class="checkbox-row">
<label for="transactionsButton" id="transactionsButtonLabel" style="color: var(--black);">
Always allow wallet txs to be retrieved automatically
</label>
<mwc-checkbox style="margin-right: -15px;" id="transactionsButton" ?checked=${window.parent.reduxStore.getState().app.qAPPAutoTransactions}></mwc-checkbox>
</div>
</div>
` : ''}
</div> </div>
<div class="modal-buttons"> <div class="modal-buttons">
<button id="cancel-button">${get("browserpage.bchange27")}</button> <button id="cancel-button">${get("browserpage.bchange27")}</button>
@ -5264,7 +5521,7 @@ async function showModalAndWait(type, data) {
}) })
} }
const checkbox1 = modal.querySelector('#abalanceButton') const checkbox1 = modal.querySelector('#balanceButton')
if (checkbox1) { if (checkbox1) {
checkbox1.addEventListener('click', (e) => { checkbox1.addEventListener('click', (e) => {
if (e.target.checked) { if (e.target.checked) {
@ -5293,6 +5550,24 @@ async function showModalAndWait(type, data) {
}) })
} }
const labelButton3 = modal.querySelector('#transactionsButtonLabel')
if (labelButton3) {
labelButton3.addEventListener('click', () => {
this.shadowRoot.getElementById('transactionsButton').click()
})
}
const checkbox3 = modal.querySelector('#transactionsButton')
if (checkbox3) {
checkbox3.addEventListener('click', (e) => {
if (e.target.checked) {
window.parent.reduxStore.dispatch(window.parent.reduxAction.removeQAPPAutoTransacions(false))
return
}
window.parent.reduxStore.dispatch(window.parent.reduxAction.allowQAPPAutoTransacions(true))
})
}
const labelButtonFriendsList = modal.querySelector('#friendsListLabel') const labelButtonFriendsList = modal.querySelector('#friendsListLabel')
if (labelButtonFriendsList) { if (labelButtonFriendsList) {
labelButtonFriendsList.addEventListener('click', () => { labelButtonFriendsList.addEventListener('click', () => {
@ -5313,6 +5588,35 @@ async function showModalAndWait(type, data) {
}) })
} }
function convertJson(jsonStr) {
let regeStr = ''
let f = {
brace: 0
}
regeStr = jsonStr.replace(/({|}[,]*|[^{}:]+:[^{}:,]*[,{]*)/g, function (m, p1) {
const rtnFn = function() {
return '<div style="text-indent: ' + (f['brace'] * 20) + 'px;color: var(--black);">' + p1 + '</div>'
}
let rtnStr = 0
if (p1.lastIndexOf('{') === (p1.length - 1)) {
rtnStr = rtnFn()
f['brace'] += 1
} else if (p1.indexOf('}') === 0) {
f['brace'] -= 1
rtnStr = rtnFn()
} else {
rtnStr = rtnFn()
}
return rtnStr
})
return regeStr
}
async function showErrorAndWait(type, data) { async function showErrorAndWait(type, data) {
// Create the modal and add it to the DOM // Create the modal and add it to the DOM
const modalDelay = ms => new Promise(res => setTimeout(res, ms)) const modalDelay = ms => new Promise(res => setTimeout(res, ms))

View File

@ -13,6 +13,7 @@ import '@vaadin/grid'
// Multi language support // Multi language support
import { get, registerTranslateConfig, translate, use } from '../../../../core/translate' import { get, registerTranslateConfig, translate, use } from '../../../../core/translate'
registerTranslateConfig({ registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
}) })
@ -346,7 +347,7 @@ class RewardShare extends LitElement {
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} }
} else if (accountDetails.address === recipientAddress) { } else if (accountDetails.address === recipientAddress) {
if (accountDetails.level >= 1 && accountDetails.level <= 4) { if (accountDetails.level <= 4) {
this.error = false this.error = false
this.message = '' this.message = ''
let myTransaction = await makeTransactionRequest(lastRef) let myTransaction = await makeTransactionRequest(lastRef)
@ -361,7 +362,6 @@ class RewardShare extends LitElement {
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} }
} else if (accountDetails.level >= 5) { } else if (accountDetails.level >= 5) {
this.error = false this.error = false
this.message = '' this.message = ''
let myTransaction = await makeTransactionRequest(lastRef) let myTransaction = await makeTransactionRequest(lastRef)
@ -504,7 +504,7 @@ class RewardShare extends LitElement {
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} }
} else if (accountDetails.address === recipientAddress) { } else if (accountDetails.address === recipientAddress) {
if (accountDetails.level >= 1 && accountDetails.level <= 4) { if (accountDetails.level <= 4) {
this.error = false this.error = false
this.message = '' this.message = ''
let myTransaction = await makeTransactionRequest(lastRef) let myTransaction = await makeTransactionRequest(lastRef)
@ -519,7 +519,6 @@ class RewardShare extends LitElement {
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} }
} else if (accountDetails.level >= 5) { } else if (accountDetails.level >= 5) {
this.error = false this.error = false
this.message = '' this.message = ''
let myTransaction = await makeTransactionRequest(lastRef) let myTransaction = await makeTransactionRequest(lastRef)

View File

@ -136,9 +136,10 @@ function attemptReconnectNodeStatusSocket() {
const initBlockSocket = () => { const initBlockSocket = () => {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let nodeProtocol = myNode.protocol
let activeBlockSocketLink let activeBlockSocketLink
if (window.parent.location.protocol === "https:") { if (nodeProtocol === "https") {
activeBlockSocketLink = `wss://${nodeUrl}/websockets/blocks` activeBlockSocketLink = `wss://${nodeUrl}/websockets/blocks`
} else { } else {
activeBlockSocketLink = `ws://${nodeUrl}/websockets/blocks` activeBlockSocketLink = `ws://${nodeUrl}/websockets/blocks`
@ -205,9 +206,10 @@ const pingactiveBlockSocket = () => {
const initNodeStatusSocket = () => { const initNodeStatusSocket = () => {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let nodeProtocol = myNode.protocol
let activeNodeStatusSocketLink let activeNodeStatusSocketLink
if (window.parent.location.protocol === "https:") { if (nodeProtocol === "https") {
activeNodeStatusSocketLink = `wss://${nodeUrl}/websockets/admin/status` activeNodeStatusSocketLink = `wss://${nodeUrl}/websockets/admin/status`
} else { } else {
activeNodeStatusSocketLink = `ws://${nodeUrl}/websockets/admin/status` activeNodeStatusSocketLink = `ws://${nodeUrl}/websockets/admin/status`

View File

@ -112,9 +112,10 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
const initChatHeadSocket = () => { const initChatHeadSocket = () => {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let nodeProtocol = myNode.protocol
let activeChatSocketLink let activeChatSocketLink
if (window.parent.location.protocol === "https:") { if (nodeProtocol === "https") {
activeChatSocketLink = `wss://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64` activeChatSocketLink = `wss://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64`
} else { } else {
activeChatSocketLink = `ws://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64` activeChatSocketLink = `ws://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64`

View File

@ -2882,7 +2882,7 @@ class TradeBotPortal extends LitElement {
const initTradeOffersWebSocket = (restarted = false) => { const initTradeOffersWebSocket = (restarted = false) => {
let tradeOffersSocketCounter = 0 let tradeOffersSocketCounter = 0
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -2914,7 +2914,7 @@ class TradeBotPortal extends LitElement {
const initTradeBotWebSocket = (restarted = false) => { const initTradeBotWebSocket = (restarted = false) => {
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -2943,7 +2943,7 @@ class TradeBotPortal extends LitElement {
const initTradePresenceWebSocket = (restarted = false) => { const initTradePresenceWebSocket = (restarted = false) => {
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradepresence` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradepresence`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -3289,10 +3289,19 @@ class TradeBotPortal extends LitElement {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ':' + myNode.port let nodeUrl = myNode.domain + ':' + myNode.port
let nodeProtocol = myNode.protocol
let checkProtocol
if (nodeProtocol === "https") {
checkProtocol = 'wss'
} else {
checkProtocol = 'ws'
}
const modifiers = [ const modifiers = [
{ searchValue: 'PROTOCOL', replaceValue: checkProtocol },
{ searchValue: 'NODEURL', replaceValue: nodeUrl }, { searchValue: 'NODEURL', replaceValue: nodeUrl },
{ searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin }, { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin }
] ]
workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers) workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers)

View File

@ -2181,7 +2181,7 @@ class TradePortal extends LitElement {
const initTradeOffersWebSocket = (restarted = false) => { const initTradeOffersWebSocket = (restarted = false) => {
let tradeOffersSocketCounter = 0 let tradeOffersSocketCounter = 0
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -2213,7 +2213,7 @@ class TradePortal extends LitElement {
const initTradeBotWebSocket = (restarted = false) => { const initTradeBotWebSocket = (restarted = false) => {
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -2242,7 +2242,7 @@ class TradePortal extends LitElement {
const initTradePresenceWebSocket = (restarted = false) => { const initTradePresenceWebSocket = (restarted = false) => {
let socketTimeout let socketTimeout
let socketLink = `ws://NODEURL/websockets/crosschain/tradepresence` let socketLink = `PROTOCOL://NODEURL/websockets/crosschain/tradepresence`
const socket = new WebSocket(socketLink) const socket = new WebSocket(socketLink)
socket.onopen = () => { socket.onopen = () => {
setTimeout(pingSocket, 50) setTimeout(pingSocket, 50)
@ -2726,10 +2726,19 @@ class TradePortal extends LitElement {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ':' + myNode.port let nodeUrl = myNode.domain + ':' + myNode.port
let nodeProtocol = myNode.protocol
let checkProtocol
if (nodeProtocol === "https") {
checkProtocol = 'wss'
} else {
checkProtocol = 'ws'
}
const modifiers = [ const modifiers = [
{ searchValue: 'PROTOCOL', replaceValue: checkProtocol },
{ searchValue: 'NODEURL', replaceValue: nodeUrl }, { searchValue: 'NODEURL', replaceValue: nodeUrl },
{ searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin }, { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin }
] ]
workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers) workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers)
@ -2791,7 +2800,7 @@ class TradePortal extends LitElement {
}) })
const getCompletedTrades = async () => { const getCompletedTrades = async () => {
const url = `http://NODEURL/crosschain/trades?limit=25&reverse=true&foreignBlockchain=FOREIGN_BLOCKCHAIN` const url = `PROTOCOL://NODEURL/crosschain/trades?limit=25&reverse=true&foreignBlockchain=FOREIGN_BLOCKCHAIN`
const res = await fetch(url) const res = await fetch(url)
const historicTrades = await res.json() const historicTrades = await res.json()
const compareFn = (a, b) => { const compareFn = (a, b) => {
@ -2810,7 +2819,7 @@ class TradePortal extends LitElement {
} }
const getOffers = async () => { const getOffers = async () => {
const url = `http://NODEURL/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN` const url = `PROTOCOL://NODEURL/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN`
const res = await fetch(url) const res = await fetch(url)
const openTradeOrders = await res.json() const openTradeOrders = await res.json()
const myOpenTradeOrders = await openTradeOrders.filter((order) => order.mode === 'OFFERING' && order.qortalCreator === 'SELECTED_ADDRESS') const myOpenTradeOrders = await openTradeOrders.filter((order) => order.mode === 'OFFERING' && order.qortalCreator === 'SELECTED_ADDRESS')
@ -2872,11 +2881,20 @@ class TradePortal extends LitElement {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ':' + myNode.port let nodeUrl = myNode.domain + ':' + myNode.port
let nodeProtocol = myNode.protocol
let checkProtocol
if (nodeProtocol === "https") {
checkProtocol = 'https'
} else {
checkProtocol = 'http'
}
const modifiers = [ const modifiers = [
{ searchValue: 'PROTOCOL', replaceValue: checkProtocol },
{ searchValue: 'NODEURL', replaceValue: nodeUrl }, { searchValue: 'NODEURL', replaceValue: nodeUrl },
{ searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address, }, { searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address },
{ searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }, { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }
] ]
workers.get(this.selectedCoin).handleStuckTradesConnectedWorker = this.inlineWorker(this.handleStuckTrades, modifiers) workers.get(this.selectedCoin).handleStuckTradesConnectedWorker = this.inlineWorker(this.handleStuckTrades, modifiers)

View File

@ -1552,3 +1552,99 @@ export const cancelTradeOfferTradeBot = async (body, keyPair) => {
throw new Error("Failed to Cancel Sell Order. Try again!") throw new Error("Failed to Cancel Sell Order. Try again!")
} }
} }
export const getArrrSyncStatus = async () => {
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 myApiKey = myNode.apiKey
const url = `${nodeUrl}/crosschain/arrr/syncstatus?apiKey=${myApiKey}`
const arrrSeed = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
try {
const response = await fetch(url, {
method: "POST",
headers: {
Accept: "*/*"
},
body: arrrSeed
})
let res
try {
res = await response.clone().json()
} catch (e) {
res = await response.text()
}
return res
} catch (error) {
console.error(error.message || "Error in retrieving arrr sync status")
}
}
export const getNodeInfo = async () => {
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 url = `${nodeUrl}/admin/info`
try {
const response = await fetch(url, {
method: "GET",
headers: {
Accept: "*/*"
}
})
if (!response.ok) console.error("Failed to retrieve node info")
let res
try {
res = await response.clone().json()
} catch (e) {
res = await response.text()
}
if (res.error && res.message) {
console.error(res.message)
}
return res
} catch (error) {
console.error(error.message || "Error in retrieving node info")
}
}
export const getNodeStatus = async () => {
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 url = `${nodeUrl}/admin/status`
try {
const response = await fetch(url, {
method: "GET",
headers: {
Accept: "*/*"
}
})
if (!response.ok) console.error("Failed to retrieve node status")
let res
try {
res = await response.clone().json()
} catch (e) {
res = await response.text()
}
if (res.error && res.message) {
console.error(res.message)
}
return res
} catch (error) {
console.error(error.message || "Error in retrieving node status")
}
}