Browse Source

Merge pull request #132 from MyHush/hushchat

Hushchat to denio branch
denio
Denio 4 years ago
committed by GitHub
parent
commit
77981bdfb1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 61
      .gdb_history
  2. 2
      README.md
  3. 72
      application.qrc
  4. 5
      compile.log
  5. 7
      lib/Cargo.lock
  6. 2
      lib/Cargo.toml
  7. 2
      peda-session-SilentDragonLite.txt
  8. BIN
      res/Berg.png
  9. BIN
      res/Denio.png
  10. BIN
      res/Duke.png
  11. BIN
      res/Elsa.png
  12. BIN
      res/Garfield.png
  13. BIN
      res/Mickey.png
  14. BIN
      res/Pinguin.png
  15. BIN
      res/Popey.png
  16. BIN
      res/SDLogo.png
  17. BIN
      res/Sharpee.png
  18. BIN
      res/Snoopy.png
  19. BIN
      res/Stag.png
  20. BIN
      res/Yoda.png
  21. BIN
      res/addContactBlack.png
  22. BIN
      res/addContactWhite.png
  23. BIN
      res/add_contact.png
  24. 9
      res/add_contact.svg
  25. 7
      res/addcontact.svg
  26. 0
      res/css/Blue.css
  27. 4
      res/css/Dark.css
  28. 0
      res/css/Default.css
  29. 0
      res/css/Light.css
  30. 139
      res/css/Midnight.css
  31. BIN
      res/darkwing.png
  32. BIN
      res/getAddrBlack.png
  33. BIN
      res/getAddrWhite.png
  34. BIN
      res/hushdark.png
  35. BIN
      res/loaderblack.gif
  36. BIN
      res/loaderwhite.gif
  37. BIN
      res/lock.png
  38. 7
      res/lock.svg
  39. 7
      res/lock_blue.svg
  40. BIN
      res/lock_green.png
  41. 7
      res/lock_green.svg
  42. BIN
      res/lock_orange.png
  43. 9
      res/message-icon.svg
  44. BIN
      res/notification.png
  45. 10
      res/notification.svg
  46. BIN
      res/rahmen-message.png
  47. BIN
      res/requestBlack.png
  48. BIN
      res/requestWhite.png
  49. BIN
      res/sdlogo2.png
  50. BIN
      res/send-new-white.png
  51. 19
      res/send-new.svg
  52. BIN
      res/send-white.png
  53. BIN
      res/send.png
  54. 6
      res/send.svg
  55. BIN
      res/sendBlack.png
  56. BIN
      res/silentdragonlite-animated-dark.gif
  57. BIN
      res/silentdragonlite-animated-startup-dark.gif
  58. BIN
      res/silentdragonlite-animated-startup.gif
  59. BIN
      res/silentdragonlite-animated.gif
  60. BIN
      res/silentdragonlite_ar.qm
  61. 2651
      res/silentdragonlite_ar.ts
  62. BIN
      res/silentdragonlite_de.qm
  63. 1494
      res/silentdragonlite_de.ts
  64. 1507
      res/silentdragonlite_es.ts
  65. 1499
      res/silentdragonlite_fa.ts
  66. 1500
      res/silentdragonlite_fr.ts
  67. 1498
      res/silentdragonlite_hr.ts
  68. 1488
      res/silentdragonlite_it.ts
  69. 1515
      res/silentdragonlite_pt.ts
  70. 1500
      res/silentdragonlite_sr.ts
  71. 1482
      res/silentdragonlite_tr.ts
  72. 1484
      res/silentdragonlite_zh.ts
  73. BIN
      res/unknownBlack.png
  74. BIN
      res/unknownWhite.png
  75. BIN
      res/unkownBlack.png
  76. BIN
      res/unlocked.png
  77. 38
      silentdragon-lite.pro
  78. 101
      src/Chat/Chat.cpp
  79. 34
      src/Chat/Chat.h
  80. 193
      src/Chat/Helper/ChatDelegator.h
  81. 28
      src/Chat/Helper/ChatIDGenerator.cpp
  82. 18
      src/Chat/Helper/ChatIDGenerator.h
  83. 114
      src/Crypto/FileEncryption.cpp
  84. 24
      src/Crypto/FileEncryption.h
  85. 60
      src/Crypto/passwd.cpp
  86. 14
      src/Crypto/passwd.h
  87. 127
      src/DataStore/ChatDataStore.cpp
  88. 44
      src/DataStore/ChatDataStore.h
  89. 50
      src/DataStore/ContactDataStore.cpp
  90. 34
      src/DataStore/ContactDataStore.h
  91. 0
      src/DataStore/DataStore-deprecated.h
  92. 16
      src/DataStore/DataStore.cpp
  93. 16
      src/DataStore/DataStore.h
  94. 35
      src/DataStore/SietchDataStore.cpp
  95. 31
      src/DataStore/SietchDataStore.h
  96. 127
      src/FileSystem/FileSystem.cpp
  97. 31
      src/FileSystem/FileSystem.h
  98. 11
      src/Logger/LogContext.h
  99. 18
      src/Logger/LogCrtitical.h
  100. 18
      src/Logger/LogDebug.h
  101. 18
      src/Logger/LogError.h
  102. 18
      src/Logger/LogFatal.h
  103. 18
      src/Logger/LogInfo.h
  104. 11
      src/Logger/LogStrategy.h
  105. 18
      src/Logger/LogSuccess.h
  106. 47
      src/Logger/LogType.h
  107. 18
      src/Logger/LogWarning.h
  108. 35
      src/Logger/LogWriter.cpp
  109. 22
      src/Logger/LogWriter.h
  110. 25
      src/Logger/Logger.h
  111. 84
      src/Logger/SimpleLogger.h
  112. 14
      src/Logger/test.cpp
  113. 206
      src/Model/ChatItem.cpp
  114. 60
      src/Model/ChatItem.h
  115. 98
      src/Model/ContactItem.cpp
  116. 40
      src/Model/ContactItem.h
  117. 96
      src/Model/ContactRequest.cpp
  118. 40
      src/Model/ContactRequest.h
  119. 1
      src/Model/ContactRequestChatItem.cpp
  120. 11
      src/Model/ContactRequestChatItem.h
  121. 214
      src/addressbook.cpp
  122. 37
      src/addressbook.h
  123. 324
      src/addressbook.ui
  124. 14
      src/chatbubbleme.cpp
  125. 22
      src/chatbubbleme.h
  126. 57
      src/chatbubbleme.ui
  127. 14
      src/chatbubblepartner.cpp
  128. 22
      src/chatbubblepartner.h
  129. 57
      src/chatbubblepartner.ui
  130. 1018
      src/chatmodel.cpp
  131. 76
      src/chatmodel.h
  132. 114
      src/connection.cpp
  133. 1
      src/connection.h
  134. 27
      src/connection.ui
  135. 159
      src/contactmodel.cpp
  136. 27
      src/contactmodel.h
  137. 491
      src/contactrequest.ui
  138. 746
      src/controller.cpp
  139. 18
      src/controller.h
  140. 132
      src/deposithush.ui
  141. 153
      src/encryption.ui
  142. 60
      src/firsttimewizard.cpp
  143. 12
      src/firsttimewizard.h
  144. 72
      src/fundhushchat.ui
  145. 156
      src/hushrequest.ui
  146. 803
      src/mainwindow.cpp
  147. 75
      src/mainwindow.h
  148. 795
      src/mainwindow.ui
  149. 2
      src/memodialog.ui
  150. 2
      src/mobileappconnector.ui
  151. 28
      src/newseed.ui
  152. 79
      src/newwallet.ui
  153. 2
      src/recurringdialog.ui
  154. 2
      src/recurringmultiple.ui
  155. 2
      src/recurringpayments.ui
  156. 175
      src/removeencryption.ui
  157. 473
      src/requestContactDialog.ui
  158. 252
      src/requestdialog.ui
  159. 2
      src/restoreseed.ui
  160. 267
      src/sendtab.cpp
  161. 13
      src/settings.cpp
  162. 2
      src/settings.h
  163. 39
      src/settings.ui
  164. 129
      src/startupencryption.ui
  165. 2
      src/version.h

61
.gdb_history

@ -0,0 +1,61 @@
b ContactDataStore::dump()
r
n
q
b ContactDataStore::dump()
r
n
c
./build.sh
$(./build.sh)
$(./build.sh)
q
r
q
r
b ContactDataStore::dump()
r
n
b ContactItem::toJson()
r
c
n
q
b ContactItem::toJson()
r
n
c
c
c
c
c
c
c
c
q
b FileSystem::writeContacts(QString file, json j)
b FileSystem::writeContacts
r
q
b FileSystem::writeContacts
r
b ContactDataStore::dump()
r
c
n
q
b FileSystem::writeContacts
r
n
q
r
b FileEncryption::encrypt
r
s
n
q
b FileSystem::readContactsOldFormat
r
n
c
q

2
README.md

@ -26,7 +26,7 @@ SilentDragonLite does automatic note and utxo management, which means it doesn't
## Compiling from source
* SilentDragonLite is written in C++ 14, and can be compiled with g++/clang++/visual c++.
* It also depends on Qt5, which you can get from [here](https://www.qt.io/download).
* You'll need Rust v1.37 +
* You'll need Rust v1.41 +
## Building on Linux

72
application.qrc

@ -8,26 +8,72 @@
<file>res/paymentreq.gif</file>
<file>res/icon.ico</file>
<file>res/mail.png</file>
<file>res/darkwing.png</file>
<file>res/SDLogo.png</file>
<file>res/sdlogo2.png</file>
<file>res/Berg.png</file>
<file>res/Denio.png</file>
<file>res/Duke.png</file>
<file>res/Sharpee.png</file>
<file>res/Yoda.png</file>
<file>res/Mickey.png</file>
<file>res/Snoopy.png</file>
<file>res/Popey.png</file>
<file>res/Garfield.png</file>
<file>res/Pinguin.png</file>
<file>res/Stag.png</file>
<file>res/Elsa.png</file>
<file>res/send.png</file>
<file>res/send.svg</file>
<file>res/addcontact.svg</file>
<file>res/send-new.svg</file>
<file>res/add_contact.svg</file>
<file>res/notification.svg</file>
<file>res/send-new-white.png</file>
<file>res/add_contact.png</file>
<file>res/notification.png</file>
<file>res/rahmen-message.png</file>
<file>res/message-icon.svg</file>
<file>res/lock_green.png</file>
<file>res/lock_orange.png</file>
<file>res/unlocked.png</file>
<file>res/getAddrWhite.png</file>
<file>res/send-white.png</file>
<file>res/requestWhite.png</file>
<file>res/addContactWhite.png</file>
<file>res/getAddrBlack.png</file>
<file>res/sendBlack.png</file>
<file>res/requestBlack.png</file>
<file>res/addContactBlack.png</file>
<file>res/unknownBlack.png</file>
<file>res/unknownWhite.png</file>
</qresource>
<qresource prefix="/img">
<file>res/hushdlogo.gif</file>
<file>res/logobig.gif</file>
<file>res/silentdragonlite-animated.gif</file>
<file>res/silentdragonlite-animated-dark.gif</file>
<file>res/silentdragonlite-animated-startup.gif</file>
<file>res/silentdragonlite-animated-startup-dark.gif</file>
<file>res/loaderblack.gif</file>
<file>res/loaderwhite.gif</file>
</qresource>
<qresource prefix="/translations">
<file>res/silentdragonlite_de.qm</file>
<file>res/silentdragonlite_es.qm</file>
<file>res/silentdragonlite_fr.qm</file>
<file>res/silentdragonlite_pt.qm</file>
<file>res/silentdragonlite_it.qm</file>
<file>res/silentdragonlite_hr.qm</file>
<file>res/silentdragonlite_fa.qm</file>
<file>res/silentdragonlite_id.qm</file>
<file>res/silentdragonlite_de.qm</file>
<file>res/silentdragonlite_es.qm</file>
<file>res/silentdragonlite_fr.qm</file>
<file>res/silentdragonlite_pt.qm</file>
<file>res/silentdragonlite_it.qm</file>
<file>res/silentdragonlite_hr.qm</file>
<file>res/silentdragonlite_fa.qm</file>
<file>res/silentdragonlite_id.qm</file>
<file>res/silentdragonlite_ar.qm</file>
</qresource>
<qresource prefix="/css">
<file>res/css/blue.css</file>
<file>res/css/dark.css</file>
<file>res/css/default.css</file>
<file>res/css/light.css</file>
<file>res/css/Blue.css</file>
<file>res/css/Dark.css</file>
<file>res/css/Default.css</file>
<file>res/css/Light.css</file>
<file>res/css/Midnight.css</file>
</qresource>
<qresource prefix="/images/blue">
<file>res/images/blue/unchecked.png</file>

5
compile.log

@ -0,0 +1,5 @@
Compiling SilentDragonLite 1.2.2 with 4 threads...
g++ -c -include bin/SilentDragonLite -pipe -g -std=gnu++1y -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQAPPLICATION_CLASS=QApplication -D_FORTIFY_SOURCE=2 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_WEBSOCKETS_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -Isrc/3rdparty -Isrc -Isingleapplication -Ires -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtWebSockets -isystem /usr/include/x86_64-linux-gnu/qt5/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -Ibin -Isrc -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o bin/mainwindow.o src/mainwindow.cpp
g++ -c -include bin/SilentDragonLite -pipe -g -std=gnu++1y -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQAPPLICATION_CLASS=QApplication -D_FORTIFY_SOURCE=2 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_WEBSOCKETS_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -Isrc/3rdparty -Isrc -Isingleapplication -Ires -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtWebSockets -isystem /usr/include/x86_64-linux-gnu/qt5/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -Ibin -Isrc -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o bin/sendtab.o src/sendtab.cpp
g++ -c -include bin/SilentDragonLite -pipe -g -std=gnu++1y -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQAPPLICATION_CLASS=QApplication -D_FORTIFY_SOURCE=2 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_WEBSOCKETS_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -Isrc/3rdparty -Isrc -Isingleapplication -Ires -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtWebSockets -isystem /usr/include/x86_64-linux-gnu/qt5/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -Ibin -Isrc -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o bin/addressbook.o src/addressbook.cpp
g++ -c -include bin/SilentDragonLite -pipe -g -std=gnu++1y -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS -DQAPPLICATION_CLASS=QApplication -D_FORTIFY_SOURCE=2 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_WEBSOCKETS_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -Isrc/3rdparty -Isrc -Isingleapplication -Ires -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtWebSockets -isystem /usr/include/x86_64-linux-gnu/qt5/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -Ibin -Isrc -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o bin/addresscombo.o src/addresscombo.cpp

7
lib/Cargo.lock

@ -1177,7 +1177,7 @@ version = "0.1.0"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=7efa024660cbe08e7eadf2524134e153c89c51ad)",
"silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=d2887d07879a93bdd9b2c8bd12504bb977e82fe0)",
]
[[package]]
@ -1640,7 +1640,7 @@ dependencies = [
[[package]]
name = "silentdragonlitelib"
version = "0.1.0"
source = "git+https://github.com/MyHush/silentdragonlite-cli?rev=7efa024660cbe08e7eadf2524134e153c89c51ad#7efa024660cbe08e7eadf2524134e153c89c51ad"
source = "git+https://github.com/MyHush/silentdragonlite-cli?rev=d2887d07879a93bdd9b2c8bd12504bb977e82fe0#d2887d07879a93bdd9b2c8bd12504bb977e82fe0"
dependencies = [
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bellman 0.1.0 (git+https://github.com/MyHush/librustzcash.git?rev=1a0204113d487cdaaf183c2967010e5214ff9e37)",
@ -1652,6 +1652,7 @@ dependencies = [
"http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.14.2 (git+https://github.com/MyHush/librustzcash.git?rev=1a0204113d487cdaaf183c2967010e5214ff9e37)",
@ -2630,7 +2631,7 @@ dependencies = [
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0"
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=7efa024660cbe08e7eadf2524134e153c89c51ad)" = "<none>"
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/MyHush/silentdragonlite-cli?rev=d2887d07879a93bdd9b2c8bd12504bb977e82fe0)" = "<none>"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"

2
lib/Cargo.toml

@ -11,4 +11,4 @@ crate-type = ["staticlib"]
[dependencies]
libc = "0.2.58"
lazy_static = "1.4.0"
silentdragonlitelib = { git = "https://github.com/MyHush/silentdragonlite-cli", rev = "7efa024660cbe08e7eadf2524134e153c89c51ad" }
silentdragonlitelib = { git = "https://github.com/MyHush/silentdragonlite-cli", rev = "d2887d07879a93bdd9b2c8bd12504bb977e82fe0" }

2
peda-session-SilentDragonLite.txt

@ -0,0 +1,2 @@
break FileSystem::readContactsOldFormat

BIN
res/Berg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
res/Denio.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
res/Duke.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
res/Elsa.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
res/Garfield.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
res/Mickey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
res/Pinguin.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
res/Popey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
res/SDLogo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
res/Sharpee.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
res/Snoopy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
res/Stag.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
res/Yoda.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
res/addContactBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
res/addContactWhite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
res/add_contact.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

9
res/add_contact.svg

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 265.7 283.5" style="enable-background:new 0 0 265.7 283.5;" xml:space="preserve">
<g>
<path d="M132.9,0C59.8,0,0,59.8,0,132.9c0,73,59.8,132.9,132.9,132.9c73,0,132.9-59.8,132.9-132.9C265.7,59.8,205.9,0,132.9,0
L132.9,0z M199.3,146.2h-53.1v53.1h-26.6v-53.1H66.4v-26.6h53.1V66.4h26.6v53.1h53.1V146.2z M199.3,146.2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 604 B

7
res/addcontact.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M870.2,797.3l-99.5-2.4l2.4-99.7c0.4-15.7-12.1-28.8-27.8-29.2c-15.7-0.4-28.8,12-29.2,27.8l-2.4,99.7l-99.6-2.4c-15.7-0.4-28.8,12.1-29.2,27.8c-0.4,15.7,12,28.8,27.8,29.2l99.6,2.4l-2.4,99.7c-0.4,15.7,12,28.8,27.8,29.2c15.7,0.4,28.8-12,29.2-27.8l2.4-99.6l99.5,2.4c15.6,0.4,28.8-12,29.2-27.8C898.3,810.8,885.9,797.7,870.2,797.3L870.2,797.3z"/><path d="M515.1,568.6c2.2,15.9,16.9,27.1,32.7,25.1c117.1-14.5,232.6,25.5,316.9,109.9c11.4,11.4,29.8,11.5,41.1,0.3c11.3-11.2,11.2-29.7-0.3-41.1C808.3,565.4,675,519.2,539.9,536C524.4,538,512.9,553.1,515.1,568.6z M113.8,990c15.9,0.5,29.2-12.2,29.7-28.4c6.3-209.1,178.4-374.1,383.6-367.9c158.1,4.8,290.6-122.2,295.5-283.1c4.8-160.9-119.8-295.7-277.9-300.5C386.6,5.4,254.1,132.4,249.2,293.3c-3.2,106.5,52.2,207,142.4,260.6C216.3,608.1,91.5,772.7,85.8,959.9C85.3,976,97.9,989.5,113.8,990z M542.9,68.8c126.3,3.8,225.8,111.5,221.9,240.1C761,437.5,655.2,539,528.9,535.1c-126.2-3.8-225.6-111.5-221.8-240.1C311,166.6,416.8,65.1,542.9,68.8z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

0
res/css/blue.css → res/css/Blue.css

4
res/css/dark.css → res/css/Dark.css

@ -1,5 +1,5 @@
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow, ChatModel, requestDialog
{
background-color: #303335;
color: #ffffff;
@ -25,7 +25,7 @@ QTabWidget QTabBar::tab:hover {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #747577, stop: 1 #3E4244);
color:#fff;
border: 1px ridge #fff;
min-height: 20px
min-height: 20px;
}
QHeaderView { /* Table Header */

0
res/css/default.css → res/css/Default.css

0
res/css/light.css → res/css/Light.css

139
res/css/Midnight.css

@ -0,0 +1,139 @@
/*
Theme: Midnight Qt
Version: 1.0.2
Reference: https://doc.qt.io/qt-5/stylesheet-reference.html
Author: Charles Sharpe
Date: Apr. 23, 2020
Website: https://www.csharpe.me
License: https://opensource.org/licenses/MIT
*/
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QTableView::item, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow
{
background-color: #111;
color: #fff;
}
QPushButton {
padding: 10px 15px;
}
QPushButton:hover {
background: #222;
}
QLineEdit, QRadioButton::indicator::unchecked, QCheckBox::indicator::unchecked {
background: #222;
border: 1px solid #333;
border-radius: 3px;
}
QLineEdit {
font-size: 12px;
}
QLineEdit:focus {
border: 1px solid #9d8400;
}
QWidget QLabel {
font-size: 11pt;
}
QWidget QCheckBox {
font-weight: bold;
}
QTabWidget QTabBar::tab {
min-height: 15px;
padding: 15px 25px;
border: 1px ridge #222;
left: 1px; /* Fix 1px alignment */
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #333, stop: 1 #111);
}
QTabWidget QTabBar::tab:selected {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #555, stop: 1 #111);
color:#fff;
border: 1px ridge #222;
border-bottom: 0px; /* Overwrites border-bottom */
}
QTabWidget QTabBar::tab:hover {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #555, stop: 1 #111);
}
QHeaderView { /* Table Header */
background-color:#111;
}
QHeaderView::section { /* Table Header Sections */
qproperty-alignment:center;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #333, stop: 1 #111);
color:#fff;
min-height:25px;
font-weight:bold;
font-size:12px;
outline:0;
border:1px ridge #222;
padding: 2px 5px;
}
QHeaderView::section:last {
border-right: 0px ridge #222;
}
QScrollArea {
background:transparent;
border:0px;
}
QTableView { /* Table - has to be selected as a class otherwise it throws off QCalendarWidget */
background:#111;
}
QTableView::item { /* Table Item */
background-color:#111;
border:1px solid #222;
font-size:12px;
}
QTableView::item:selected { /* Table Item Selected */
background-color:#fff;
color:#000;
}
QMenuBar {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #222, stop: 1 #111);
color: #fff;
}
QMenuBar::item {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #222, stop: 1 #111);
color: #fff;
padding: 5px 7px;
margin: 0px;
}
QMenuBar::item:selected {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #333, stop: 1 #111);
}
QMenu {
border:1px solid #222;
}
QMenu::item {
padding: 7px 15px;
}
QMenu::item:selected {
background: #222;
}
QMenu::separator {
height: 1px;
margin: 3px 7px 3px 7px; /* space at ends of separator */
background: #222;
}

BIN
res/darkwing.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
res/getAddrBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
res/getAddrWhite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
res/hushdark.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
res/loaderblack.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
res/loaderwhite.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
res/lock.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

7
res/lock.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M500,10C229.4,10,10,229.4,10,500c0,270.6,219.4,490,490,490c270.6,0,490-219.4,490-490C990,229.4,770.6,10,500,10z M500,947.4C252.9,947.4,52.6,747.1,52.6,500C52.6,252.9,252.9,52.6,500,52.6c247.1,0,447.4,200.3,447.4,447.4C947.4,747.1,747.1,947.4,500,947.4z"/><path d="M452.1,392.4c0-24.5,6.4-83.1,69.2-83.1c59.7,0,69.2,52.2,69.2,83.1v18.1h52.2v-18.1c0-81-46.9-133.2-120.4-133.2c-73.5,0-120.4,52.2-120.4,133.2v18.1h52.2v-18.1H452.1z M641.7,427.6H400.9c-28.8,0-52.2,22.4-52.2,51.1V647c0,27.7,23.4,51.1,52.2,51.1h240.7c28.8,0,52.2-22.4,52.2-51.1V478.7C693.9,451,670.4,427.6,641.7,427.6L641.7,427.6z M538.3,575.6V614c0,9.6-7.5,17-17,17c-9.6,0-17-7.5-17-17v-38.3c-10.7-5.3-17-17-17-28.8c0-18.1,14.9-34.1,34.1-34.1s34.1,14.9,34.1,34.1C555.4,558.6,549,569.2,538.3,575.6L538.3,575.6z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

7
res/lock_blue.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#46a2da" width="16px" height="16px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M500,10C229.4,10,10,229.4,10,500c0,270.6,219.4,490,490,490c270.6,0,490-219.4,490-490C990,229.4,770.6,10,500,10z M500,947.4C252.9,947.4,52.6,747.1,52.6,500C52.6,252.9,252.9,52.6,500,52.6c247.1,0,447.4,200.3,447.4,447.4C947.4,747.1,747.1,947.4,500,947.4z"/><path d="M452.1,392.4c0-24.5,6.4-83.1,69.2-83.1c59.7,0,69.2,52.2,69.2,83.1v18.1h52.2v-18.1c0-81-46.9-133.2-120.4-133.2c-73.5,0-120.4,52.2-120.4,133.2v18.1h52.2v-18.1H452.1z M641.7,427.6H400.9c-28.8,0-52.2,22.4-52.2,51.1V647c0,27.7,23.4,51.1,52.2,51.1h240.7c28.8,0,52.2-22.4,52.2-51.1V478.7C693.9,451,670.4,427.6,641.7,427.6L641.7,427.6z M538.3,575.6V614c0,9.6-7.5,17-17,17c-9.6,0-17-7.5-17-17v-38.3c-10.7-5.3-17-17-17-28.8c0-18.1,14.9-34.1,34.1-34.1s34.1,14.9,34.1,34.1C555.4,558.6,549,569.2,538.3,575.6L538.3,575.6z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
res/lock_green.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

7
res/lock_green.svg

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#32dc15" width="16px" height="16px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M500,10C229.4,10,10,229.4,10,500c0,270.6,219.4,490,490,490c270.6,0,490-219.4,490-490C990,229.4,770.6,10,500,10z M500,947.4C252.9,947.4,52.6,747.1,52.6,500C52.6,252.9,252.9,52.6,500,52.6c247.1,0,447.4,200.3,447.4,447.4C947.4,747.1,747.1,947.4,500,947.4z"/><path d="M452.1,392.4c0-24.5,6.4-83.1,69.2-83.1c59.7,0,69.2,52.2,69.2,83.1v18.1h52.2v-18.1c0-81-46.9-133.2-120.4-133.2c-73.5,0-120.4,52.2-120.4,133.2v18.1h52.2v-18.1H452.1z M641.7,427.6H400.9c-28.8,0-52.2,22.4-52.2,51.1V647c0,27.7,23.4,51.1,52.2,51.1h240.7c28.8,0,52.2-22.4,52.2-51.1V478.7C693.9,451,670.4,427.6,641.7,427.6L641.7,427.6z M538.3,575.6V614c0,9.6-7.5,17-17,17c-9.6,0-17-7.5-17-17v-38.3c-10.7-5.3-17-17-17-28.8c0-18.1,14.9-34.1,34.1-34.1s34.1,14.9,34.1,34.1C555.4,558.6,549,569.2,538.3,575.6L538.3,575.6z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
res/lock_orange.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

9
res/message-icon.svg

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g id="XMLID_1_">
<polygon id="XMLID_3_" points="256,371.5 256,379 512,379 512,27.4 0,27.4 0,379 136.3,379 136.3,484.6 261,377.4 256,371.5
256,379 256,371.5 251,364.9 152.1,449.7 152.1,363.2 15.8,363.2 15.8,43.2 496.2,43.2 496.2,363.2 252.7,363.2 251,364.9 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 636 B

BIN
res/notification.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

10
res/notification.svg

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 225.9 283.5" style="enable-background:new 0 0 225.9 283.5;" xml:space="preserve">
<g>
<path d="M113,265.7c14.6,0,26.5-11.9,26.5-26.6H86.4C86.4,253.8,98.4,265.7,113,265.7L113,265.7z M199.3,186v-73
c0-41.2-27.9-74.4-66.4-83.7v-9.4C132.9,9.3,123.6,0,113,0C102.3,0,93,9.3,93,19.9v9.4C54.5,38.5,26.6,71.8,26.6,113v73L0,212.6
v13.3h225.9v-13.3L199.3,186z M199.3,186"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 655 B

BIN
res/rahmen-message.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
res/requestBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
res/requestWhite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
res/sdlogo2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
res/send-new-white.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

19
res/send-new.svg

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 300.2 283.5" style="enable-background:new 0 0 300.2 283.5;" xml:space="preserve">
<!--<style type="text/css">-->
<!--.st0{clip-path:url(#SVGID_2_);}-->
<!--</style>-->
<g>
<!--<g>-->
<!--<defs>-->
<!--<rect id="SVGID_1_" x="2.6" width="297.6" height="265.7"/>-->
<!--</defs>-->
<!--<clipPath id="SVGID_2_">-->
<!--<use xlink:href="#SVGID_1_" style="overflow:visible;"/>-->
<!--</clipPath>-->
<path class="st0" d="M2.6,255.1l297.7-127.5L2.6,0v99.2l212.6,28.3L2.6,155.9V255.1z M2.6,255.1"/>
<!--</g>-->
</g>
</svg>

After

Width:  |  Height:  |  Size: 808 B

BIN
res/send-white.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
res/send.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

6
res/send.svg

@ -0,0 +1,6 @@
<?xml version="1.0" ?><svg id="Layer_1" style="enable-background:new 0 0 137.3 139.3;" version="1.1" viewBox="0 0 137.3 139.3" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style type="text/css">
.st0{fill:#2C8AAA;}
.st1{opacity:0.19;clip-path:url(#XMLID_39_);fill:#070808;}
.st2{fill:#FFFFFF;}
.st3{opacity:0.19;fill:#070808;}
</style><g id="XMLID_2671_"><g id="XMLID_2704_"><circle class="st0" cx="68.5" cy="69.6" id="XMLID_2708_" r="66.2"/><g id="XMLID_2705_"><defs><circle cx="68.7" cy="69.6" id="XMLID_2706_" r="66.2"/></defs><clipPath id="XMLID_39_"><use style="overflow:visible;" xlink:href="#XMLID_2706_"/></clipPath><polyline class="st1" id="XMLID_2707_" points="95.7,41 155.1,91.1 134,135.8 112,146.2 33.3,62.9 "/></g></g></g><g id="XMLID_2719_"><polygon class="st2" id="XMLID_2718_" points="74.3,103.9 95.7,41 33.3,62.9 50.9,76.8 60.4,76.8 60.3,86.1 "/><polygon class="st3" id="XMLID_2713_" points="60.7,84.9 95.7,41 50.9,76.8 60.4,76.8 "/><polygon class="st3" id="XMLID_2703_" points="60.4,76.8 95.7,41 60.3,86.1 "/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
res/sendBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
res/silentdragonlite-animated-dark.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

BIN
res/silentdragonlite-animated-startup-dark.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
res/silentdragonlite-animated-startup.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 KiB

BIN
res/silentdragonlite-animated.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

BIN
res/silentdragonlite_ar.qm

Binary file not shown.

2651
res/silentdragonlite_ar.ts

File diff suppressed because it is too large

BIN
res/silentdragonlite_de.qm

Binary file not shown.

1494
res/silentdragonlite_de.ts

File diff suppressed because it is too large

1507
res/silentdragonlite_es.ts

File diff suppressed because it is too large

1499
res/silentdragonlite_fa.ts

File diff suppressed because it is too large

1500
res/silentdragonlite_fr.ts

File diff suppressed because it is too large

1498
res/silentdragonlite_hr.ts

File diff suppressed because it is too large

1488
res/silentdragonlite_it.ts

File diff suppressed because it is too large

1515
res/silentdragonlite_pt.ts

File diff suppressed because it is too large

1500
res/silentdragonlite_sr.ts

File diff suppressed because it is too large

1482
res/silentdragonlite_tr.ts

File diff suppressed because it is too large

1484
res/silentdragonlite_zh.ts

File diff suppressed because it is too large

BIN
res/unknownBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
res/unknownWhite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
res/unkownBlack.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
res/unlocked.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

38
silentdragon-lite.pro

@ -13,6 +13,7 @@ PRECOMPILED_HEADER = src/precompiled.h
QT += widgets
QT += websockets
TARGET = SilentDragonLite
TEMPLATE = app
@ -33,6 +34,7 @@ mac: LIBS+= -Wl,-bind_at_load
RESOURCES = application.qrc
MOC_DIR = bin
OBJECTS_DIR = bin
UI_DIR = src
@ -65,7 +67,24 @@ SOURCES += \
src/datamodel.cpp \
src/controller.cpp \
src/liteinterface.cpp \
src/camount.cpp
src/camount.cpp \
src/chatbubbleme.cpp \
src/chatbubblepartner.cpp \
src/chatmodel.cpp \
src/contactmodel.cpp \
src/DataStore/DataStore.cpp \
src/DataStore/ChatDataStore.cpp \
src/DataStore/SietchDataStore.cpp \
src/DataStore/ContactDataStore.cpp \
src/Model/ChatItem.cpp \
src/Model/ContactRequestChatItem.cpp \
src/Model/ContactItem.cpp \
src/Model/ContactRequest.cpp \
src/Chat/Helper/ChatIDGenerator.cpp \
src/Chat/Chat.cpp \
src/FileSystem/FileSystem.cpp \
src/Crypto/FileEncryption.cpp \
src/Crypto/passwd.cpp
HEADERS += \
src/firsttimewizard.h \
@ -94,10 +113,17 @@ HEADERS += \
src/controller.h \
src/liteinterface.h \
src/camount.h \
lib/silentdragonlitelib.h
lib/silentdragonlitelib.h \
src/chatbubbleme.h \
src/chatbubblepartner.h \
src/chatmodel.h \
src/contactmodel.h
FORMS += \
src/contactrequest.ui \
src/deposithush.ui \
src/encryption.ui \
src/hushrequest.ui \
src/mainwindow.ui \
src/migration.ui \
src/newseed.ui \
@ -109,15 +135,20 @@ FORMS += \
src/confirm.ui \
src/privkey.ui \
src/memodialog.ui \
src/startupencryption.ui \
src/viewalladdresses.ui \
src/connection.ui \
src/addressbook.ui \
src/mobileappconnector.ui \
src/createhushconfdialog.ui \
src/recurringdialog.ui \
src/requestContactDialog.ui \
src/newrecurring.ui \
src/requestdialog.ui \
src/recurringmultiple.ui
src/removeencryption.ui \
src/recurringmultiple.ui \
src/chatbubbleme.ui \
src/chatbubblepartner.ui
TRANSLATIONS = res/silentdragonlite_es.ts \
@ -130,6 +161,7 @@ TRANSLATIONS = res/silentdragonlite_es.ts \
res/silentdragonlite_sr.ts \
res/silentdragonlite_fa.ts \
res/silentdragonlite_id.ts \
res/silentdragonlite_ar.ts \
res/silentdragonlite_tr.ts
include(singleapplication/singleapplication.pri)

101
src/Chat/Chat.cpp

@ -0,0 +1,101 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "Chat.h"
#include "../addressbook.h"
#include "../DataStore/DataStore.h"
Chat::Chat() {}
ChatMemoEdit::ChatMemoEdit(QWidget* parent) : QTextEdit(parent) {
QObject::connect(this, &QTextEdit::textChanged, this, &ChatMemoEdit::updateDisplayChat);
}
void ChatMemoEdit::updateDisplayChat() {
QString txt = this->toPlainText();
if (lenDisplayLabelchat)
lenDisplayLabelchat->setText(QString::number(txt.toUtf8().size()) + "/" + QString::number(maxlenchat));
if (txt.toUtf8().size() <= maxlenchat) {
// Everything is fine
if (sendChatButton)
sendChatButton->setEnabled(true);
if (lenDisplayLabelchat)
lenDisplayLabelchat->setStyleSheet("");
}
else {
// Overweight
if (sendChatButton)
sendChatButton->setEnabled(false);
if (lenDisplayLabelchat)
lenDisplayLabelchat->setStyleSheet("color: red;");
}
}
void ChatMemoEdit::setMaxLenChat(int len) {
this->maxlenchat = len;
updateDisplayChat();
}
void ChatMemoEdit::SetSendChatButton(QPushButton* button) {
this->sendChatButton = button;
}
void ChatMemoEdit::setLenDisplayLabelChat(QLabel* label) {
this->lenDisplayLabelchat = label;
}
void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label)
{
QStandardItemModel *chat = new QStandardItemModel();
DataStore::getChatDataStore()->dump(); // test to see if the chat items in datastore are correctly dumped to json
for (auto &p : AddressBook::getInstance()->getAllAddressLabels())
{
for (auto &c : DataStore::getChatDataStore()->getAllMemos())
{
if (
(p.getName() == ui->contactNameMemo->text().trimmed()) &&
(p.getPartnerAddress() == c.second.getAddress()) &&
(c.second.isOutgoing() == true))
{
QStandardItem *Items = new QStandardItem(c.second.toChatLine());
Items->setData(OUTGOING, Qt::UserRole + 1);
chat->appendRow(Items);
ui->listChat->setModel(chat);
}
else
{
ui->listChat->setModel(chat);
}
if (
(p.getName() == ui->contactNameMemo->text().trimmed()) &&
(p.getMyAddress() == c.second.getAddress()) &&
(c.second.isOutgoing() == false) &&
(c.second.getCid() == p.getCid())
)
{
QStandardItem *Items1 = new QStandardItem(c.second.toChatLine());
Items1->setData(INCOMING, Qt::UserRole + 1);
chat->appendRow(Items1);
ui->listChat->setModel(chat);
}
else
{
ui->listChat->setModel(chat);
}
}
}
}

34
src/Chat/Chat.h

@ -0,0 +1,34 @@
#ifndef CHAT_H
#define CHAT_H
#include <QString>
#include <QStandardItemModel>
#include <QAbstractItemDelegate>
#include <QPainter>
#include <map>
#include <vector>
#include <QListView>
#include "precompiled.h"
#include "mainwindow.h"
#include "controller.h"
#include "settings.h"
#include "camount.h"
#include "../Model/ChatItem.h"
class Chat // Chat Controller
{
private:
QTableView* parent;
Ui::MainWindow* ui;
MainWindow* main;
std::map<QString, QString> cidMap;
std::map<QString, QString> requestZaddrMap;
public:
Chat();
void renderChatBox(Ui::MainWindow* ui, QListView *view, QLabel *label); // action
};
#endif

193
src/Chat/Helper/ChatDelegator.h

@ -0,0 +1,193 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CHATDELEGATOR_H
#define CHATDELEGATOR_H
#include <QString>
#include <QStandardItemModel>
#include <QAbstractItemDelegate>
#include <QPainter>
enum RenderType
{
OUTGOING=0,
INCOMING=1,
INDATE=2,
OUTDATE=3
};
class ListViewDelegate : public QAbstractItemDelegate
{
int d_radius;
int d_toppadding;
int d_bottompadding;
int d_leftpadding;
int d_rightpadding;
int d_verticalmargin;
int d_horizontalmargin;
int d_pointerwidth;
int d_pointerheight;
float d_widthfraction;
public:
inline ListViewDelegate(QObject *parent = nullptr);
protected:
inline void paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const;
inline QSize sizeHint(QStyleOptionViewItem const &option, QModelIndex const &index) const;
};
inline ListViewDelegate::ListViewDelegate(QObject *parent): QAbstractItemDelegate(parent), d_radius(5), d_toppadding(5), d_bottompadding(3), d_leftpadding(5), d_rightpadding(5), d_verticalmargin(5), d_horizontalmargin(10), d_pointerwidth(4), d_pointerheight(17), d_widthfraction(.6)
{
}
inline void ListViewDelegate::paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const
{
QTextDocument bodydoc;
QTextOption textOption(bodydoc.defaultTextOption());
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
bodydoc.setDefaultTextOption(textOption);
bodydoc.setDefaultFont(QFont("Roboto", 12));
QString bodytext(index.data(Qt::DisplayRole).toString());
bodydoc.setHtml(bodytext);
qreal contentswidth = option.rect.width() * d_widthfraction - d_horizontalmargin - d_pointerwidth - d_leftpadding - d_rightpadding;
bodydoc.setTextWidth(contentswidth);
qreal bodyheight = bodydoc.size().height();
int outgoing = index.data(Qt::UserRole + 1).toInt();
int outdate = index.data(Qt::UserRole + 1).toInt();
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
// uncomment to see the area provided to paint this item
//painter->drawRect(option.rect);
painter->translate(option.rect.left() + d_horizontalmargin, option.rect.top() + ((index.row() == 0) ? d_verticalmargin : 0));
QColor bgcolor("#ffffff");
switch(outgoing)
{
case INDATE:
bgcolor = "transparent";
break;
case OUTDATE:
bgcolor = "transparent";
break;
case OUTGOING:
bgcolor = "#f8f9fa";
break;
default:
case INCOMING:
bgcolor = "#535353";
break;
}
// create chat bubble
QPainterPath pointie;
// left bottom
pointie.moveTo(0, bodyheight + d_toppadding + d_bottompadding);
// right bottom
pointie.lineTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - d_radius,
bodyheight + d_toppadding + d_bottompadding);
pointie.arcTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - 2 * d_radius,
bodyheight + d_toppadding + d_bottompadding - 2 * d_radius,
2 * d_radius, 2 * d_radius, 270, 90);
// right top
pointie.lineTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding, 0 + d_radius);
pointie.arcTo(0 + contentswidth + d_pointerwidth + d_leftpadding + d_rightpadding - 2 * d_radius, 0,
2 * d_radius, 2 * d_radius, 0, 90);
// left top
pointie.lineTo(0 + d_pointerwidth + d_radius, 0);
pointie.arcTo(0 + d_pointerwidth, 0, 2 * d_radius, 2 * d_radius, 90, 90);
// left bottom almost (here is the pointie)
pointie.lineTo(0 + d_pointerwidth, bodyheight + d_toppadding + d_bottompadding - d_pointerheight);
pointie.closeSubpath();
// rotate bubble for outgoing messages
if ((outgoing == OUTGOING) || (outdate == OUTDATE))
{
painter->translate(option.rect.width() - pointie.boundingRect().width() - d_horizontalmargin - d_pointerwidth, 0);
painter->translate(pointie.boundingRect().center());
painter->rotate(180);
painter->translate(-pointie.boundingRect().center());
}
// now paint it!
painter->setPen(QPen(bgcolor));
painter->drawPath(pointie);
painter->fillPath(pointie, QBrush(bgcolor));
// rotate back or painter is going to paint the text rotated...
if ((outgoing == OUTGOING) || (outdate == OUTDATE))
{
painter->translate(pointie.boundingRect().center());
painter->rotate(-180);
painter->translate(-pointie.boundingRect().center());
}
// set text color used to draw message body
QAbstractTextDocumentLayout::PaintContext ctx;
switch(outgoing)
{
case INDATE:
ctx.palette.setColor(QPalette::Text, QColor("Black"));
break;
case OUTDATE:
ctx.palette.setColor(QPalette::Text, QColor("Black"));
break;
case OUTGOING:
ctx.palette.setColor(QPalette::Text, QColor("Black"));
break;
default:
case INCOMING:
ctx.palette.setColor(QPalette::Text, QColor("whitesmoke"));
break;
}
// draw body text
painter->translate((outgoing == OUTGOING ? 0 : d_pointerwidth) + d_leftpadding, 0);
painter->translate((outdate == OUTDATE ? 0 : d_pointerwidth) + d_leftpadding, 0);
bodydoc.documentLayout()->draw(painter, ctx);
painter->restore();
}
inline QSize ListViewDelegate::sizeHint(QStyleOptionViewItem const &option, QModelIndex const &index) const
{
QTextDocument bodydoc;
QTextOption textOption(bodydoc.defaultTextOption());
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
bodydoc.setDefaultTextOption(textOption);
bodydoc.setDefaultFont(QFont("Roboto", 12));
QString bodytext(index.data(Qt::DisplayRole).toString());
bodydoc.setHtml(bodytext);
// the width of the contents are the (a fraction of the window width) minus (margins + padding + width of the bubble's tail)
qreal contentswidth = option.rect.width() * d_widthfraction - d_horizontalmargin - d_pointerwidth - d_leftpadding - d_rightpadding;
// set this available width on the text document
bodydoc.setTextWidth(contentswidth);
QSize size(bodydoc.idealWidth() + d_horizontalmargin + d_pointerwidth + d_leftpadding + d_rightpadding,
bodydoc.size().height() + d_bottompadding + d_toppadding + d_verticalmargin + 1); // I dont remember why +1, haha, might not be necessary
if (index.row() == 0) // have extra margin at top of first item
size += QSize(0, d_verticalmargin);
return size;
}
#endif

28
src/Chat/Helper/ChatIDGenerator.cpp

@ -0,0 +1,28 @@
#include "ChatIDGenerator.h"
ChatIDGenerator* ChatIDGenerator::getInstance()
{
if(ChatIDGenerator::instance == nullptr)
ChatIDGenerator::instance = new ChatIDGenerator();
return ChatIDGenerator::instance;
}
QString ChatIDGenerator::generateID(ChatItem item)
{
QString key = QString::number(item.getTimestamp()) + QString("-");
key += QString(
QCryptographicHash::hash(
QString(
QString::number(item.getTimestamp()) +
item.getAddress() +
item.getContact() +
item.getMemo()
).toUtf8(),
QCryptographicHash::Md5
).toHex()
);
return key;
}
ChatIDGenerator* ChatIDGenerator::instance = nullptr;

18
src/Chat/Helper/ChatIDGenerator.h

@ -0,0 +1,18 @@
#ifndef CHATIDGENERATOR_H
#define CHATIDGENERATOR_H
#include <QString>
#include <QUuid>
#include "../../Model/ChatItem.h"
class ChatIDGenerator
{
private:
static ChatIDGenerator* instance;
public:
static ChatIDGenerator* getInstance();
QString generateID(ChatItem item);
};
#endif

114
src/Crypto/FileEncryption.cpp

@ -0,0 +1,114 @@
#include "FileEncryption.h"
void FileEncryption::showConfig()
{
qInfo() << FILEENCRYPTION_CHUNK_SIZE;
}
int FileEncryption::encrypt(QString target_file, QString source_file, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES])
{
unsigned char plain_data[FILEENCRYPTION_CHUNK_SIZE];
unsigned char cipher_data[FILEENCRYPTION_CHUNK_SIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
crypto_secretstream_xchacha20poly1305_state state;
FILE *target, *source;
unsigned long long cipher_len;
size_t rlen;
int eof;
unsigned char tag;
if(!FileEncryption::exists(source_file.toStdString()))
{
qDebug() << "File not exits" << source_file;
return -1;
}
source = fopen(source_file.toStdString().c_str(), "rb");
target = fopen(target_file.toStdString().c_str(), "wb");
crypto_secretstream_xchacha20poly1305_init_push(&state, header, key);
fwrite(header, 1, sizeof header, target);
do
{
rlen = fread(plain_data, 1, sizeof plain_data, source);
eof = feof(source);
tag = eof ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
crypto_secretstream_xchacha20poly1305_push(
&state,
cipher_data,
&cipher_len,
plain_data,
rlen,
NULL,
0,
tag
);
fwrite(cipher_data, 1, (size_t) cipher_len, target);
}
while (! eof);
fclose(target);
fclose(source);
return 0;
}
int FileEncryption::decrypt(QString target_file, QString source_file, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES])
{
unsigned char buf_in[FILEENCRYPTION_CHUNK_SIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
unsigned char buf_out[FILEENCRYPTION_CHUNK_SIZE];
unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
crypto_secretstream_xchacha20poly1305_state st;
FILE *fp_t, *fp_s;
unsigned long long out_len;
size_t rlen;
int eof;
int ret = -1;
unsigned char tag;
if(!FileEncryption::exists(source_file.toStdString()))
{
qDebug() << "File not exits" << source_file;
return -1;
}
fp_s = fopen(source_file.toStdString().c_str(), "rb");
fp_t = fopen(target_file.toStdString().c_str(), "wb");
fread(header, 1, sizeof header, fp_s);
if (crypto_secretstream_xchacha20poly1305_init_pull(&st, header, key) != 0)
{
goto ret; /* incomplete header */
}
do
{
rlen = fread(buf_in, 1, sizeof buf_in, fp_s);
eof = feof(fp_s);
if (crypto_secretstream_xchacha20poly1305_pull(
&st,
buf_out,
&out_len,
&tag,
buf_in,
rlen,
NULL,
0
) != 0)
{
goto ret; /* corrupted chunk */
}
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && ! eof)
{
goto ret; /* premature end (end of file reached before the end of the stream) */
}
fwrite(buf_out, 1, (size_t) out_len, fp_t);
}
while (! eof);
ret = 0;
ret:
fclose(fp_t);
fclose(fp_s);
return ret;
}

24
src/Crypto/FileEncryption.h

@ -0,0 +1,24 @@
#ifndef FILEENCRYPTION_H
#define FILEENCRYPTION_H
#include <stdio.h>
#include <sodium.h>
#include <QString>
#include <fstream>
#define FILEENCRYPTION_CHUNK_SIZE 4096
class FileEncryption
{
private:
inline static bool exists (const std::string& name) {
std::ifstream f(name.c_str());
return f.good();
}
public:
static void showConfig();
static int encrypt(QString target_file, QString source_file, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]);
static int decrypt(QString target_file, QString source_file, const unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES]);
};
#endif

60
src/Crypto/passwd.cpp

@ -0,0 +1,60 @@
#include "passwd.h"
void PASSWD::show_hex_buff(unsigned char buf[])
{
int i;
for (uint8_t i=0; i < crypto_secretstream_xchacha20poly1305_KEYBYTES; i++)
printf("%02X ", buf[i]);
printf("\n");
}
const unsigned char* PASSWD::key(QString password)
{
int length = password.length();
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, password.toLocal8Bit(), length +1);
#define MESSAGE ((const unsigned char *) sequence)
#define MESSAGE_LEN length
unsigned char hash[crypto_secretstream_xchacha20poly1305_KEYBYTES];
crypto_hash_sha256(hash, MESSAGE, MESSAGE_LEN);
qDebug()<<"Generating SaltHash from password: " <<sequence;
/////////we use the Hash of the Password as Salt, not perfect but still a good solution.
#define PASSWORD sequence
#define KEY_LEN crypto_box_SEEDBYTES
unsigned char key[KEY_LEN];
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
qDebug()<<"Generating cryptographic key from password: " <<sequence;
// crypto_generichash(blacke2hash, sizeof hash, MESSAGE, MESSAGE_LEN, NULL, 0);
//for(uint8_t i = 0; i < crypto_secretstream_xchacha20poly1305_KEYBYTES/2; i++)
// hash[i] = blacke2hash[i];
// for(uint8_t i = crypto_secretstream_xchacha20poly1305_KEYBYTES/2; i < crypto_secretstream_xchacha20poly1305_KEYBYTES; i++)
// hash[i] = sha256hash[i];
// delete[] sha256hash;
//delete[] blacke2hash;
qDebug()<<"secret key generated:\n";
PASSWD::show_hex_buff(key);
return key;
}

14
src/Crypto/passwd.h

@ -0,0 +1,14 @@
#ifndef PASSWD_H
#define PASSWD_H
#include <stdio.h>
#include <sodium.h>
#include <QString>
class PASSWD
{
public:
static void show_hex_buff(unsigned char buf[]);
static const unsigned char* key(QString);
};
#endif

127
src/DataStore/ChatDataStore.cpp

@ -0,0 +1,127 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "ChatDataStore.h"
#include "addressbook.h"
#include "chatmodel.h"
ChatDataStore* ChatDataStore::getInstance()
{
if(!ChatDataStore::instanced)
{
ChatDataStore::instanced = true;
ChatDataStore::instance = new ChatDataStore();
}
return ChatDataStore::instance;
}
void ChatDataStore::clear()
{
this->data.clear();
}
void ChatDataStore::setData(QString key, ChatItem value)
{
this->data[key] = value;
}
ChatItem ChatDataStore::getData(QString key)
{
return this->data[key];
}
QString ChatDataStore::getPassword()
{
return _password;
}
void ChatDataStore::setPassword(QString password)
{
_password = password;
}
QString ChatDataStore::dump()
{
json chats;
chats["count"] = this->data.size();
json j = {};
for (auto &c: this->data)
{
j.push_back(c.second.toJson());
}
chats["chatitems"] = j;
return QString::fromStdString(chats.dump());
}
std::map<QString, ChatItem> ChatDataStore::getAllRawChatItems()
{
return this->data;
}
std::map<QString, ChatItem> ChatDataStore::getAllNewContactRequests()
{
std::map<QString, ChatItem> filteredItems;
for(auto &c: this->data)
{
if (
(c.second.isOutgoing() == false) &&
(c.second.getType() == "Cont") &&
(c.second.isContact() == false) &&
(c.second.getMemo().startsWith("{"))
)
{
filteredItems[c.first] = c.second;
}
}
return filteredItems;
}
std::map<QString, ChatItem> ChatDataStore::getAllOldContactRequests()
{
std::map<QString, ChatItem> filteredItems;
for(auto &c: this->data)
{
if (
(c.second.isOutgoing() == false) &&
(c.second.getType() == "Cont") &&
(c.second.isContact() == true) &&
(c.second.getMemo().startsWith("{"))
)
{
filteredItems[c.first] = c.second;
}
}
return filteredItems;
}
std::map<QString, ChatItem> ChatDataStore::getAllMemos()
{
std::map<QString, ChatItem> filteredItems;
for(auto &c: this->data)
{
if (
(c.second.getMemo().startsWith("{") == false) &&
(c.second.getMemo().isEmpty() == false)
)
{
filteredItems[c.first] = c.second;
}
}
return filteredItems;
}
ChatDataStore* ChatDataStore::instance = nullptr;
bool ChatDataStore::instanced = false;

44
src/DataStore/ChatDataStore.h

@ -0,0 +1,44 @@
#ifndef CHATDATASTORE_H
#define CHATDATASTORE_H
#include "../chatmodel.h"
using json = nlohmann::json;
class ChatDataStore
{
private:
static bool instanced;
static ChatDataStore* instance;
Ui::MainWindow* ui;
MainWindow* main;
std::map<QString, ChatItem> data;
ChatDataStore()
{
}
public:
static ChatDataStore* getInstance();
void clear();
void setData(QString key, ChatItem value);
ChatItem getData(QString key);
std::map<QString, ChatItem> getAllRawChatItems();
std::map<QString, ChatItem> getAllNewContactRequests();
std::map<QString, ChatItem> getAllOldContactRequests();
std::map<QString, ChatItem> getAllMemos();
QString getPassword();
void setPassword(QString Password);
QString _password;
QString dump();
~ChatDataStore()
{
ChatDataStore::instanced = false;
ChatDataStore::instance = nullptr;
}
};
#endif

50
src/DataStore/ContactDataStore.cpp

@ -0,0 +1,50 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "ContactDataStore.h"
#include <string>
ContactDataStore* ContactDataStore::getInstance()
{
if(!ContactDataStore::instanced)
{
ContactDataStore::instanced = true;
ContactDataStore::instance = new ContactDataStore();
}
return ContactDataStore::instance;
}
void ContactDataStore::clear()
{
this->data.clear();
}
void ContactDataStore::setData(QString key, ContactItem value)
{
this->data[key] = value;
}
ContactItem ContactDataStore::getData(QString key)
{
return this->data[key];
}
QString ContactDataStore::dump()
{
json contacts;
contacts["count"] = this->data.size();
json j = {};
for (auto &c: this->data)
{
qDebug() << c.second.toQTString();
c.second.toJson();
j.push_back(c.second.toJson());
}
contacts["contacts"] = j;
return QString::fromStdString(contacts.dump(4));
}
ContactDataStore* ContactDataStore::instance = nullptr;
bool ContactDataStore::instanced = false;

34
src/DataStore/ContactDataStore.h

@ -0,0 +1,34 @@
#ifndef CONTACTDATASTORE_H
#define CONTACTDATASTORE_H
#include "../Model/ContactItem.h"
#include <string>
using json = nlohmann::json;
class ContactDataStore
{
private:
static bool instanced;
static ContactDataStore* instance;
std::map<QString, ContactItem> data;
ContactDataStore()
{
}
public:
static ContactDataStore* getInstance();
void clear();
void setData(QString key, ContactItem value);
ContactItem getData(QString key);
QString dump();
~ContactDataStore()
{
ContactDataStore::instanced = false;
ContactDataStore::instance = nullptr;
}
};
#endif

0
src/DataStore.h → src/DataStore/DataStore-deprecated.h

16
src/DataStore/DataStore.cpp

@ -0,0 +1,16 @@
#include "DataStore.h"
SietchDataStore* DataStore::getSietchDataStore()
{
return SietchDataStore::getInstance();
}
ChatDataStore* DataStore::getChatDataStore()
{
return ChatDataStore::getInstance();
}
ContactDataStore* DataStore::getContactDataStore()
{
return ContactDataStore::getInstance();
}

16
src/DataStore/DataStore.h

@ -0,0 +1,16 @@
#ifndef DATASTORE_H
#define DATASTORE_H
#include "SietchDataStore.h"
#include "ChatDataStore.h"
#include "ContactDataStore.h"
class DataStore
{
public:
static SietchDataStore* getSietchDataStore();
static ChatDataStore* getChatDataStore();
static ContactDataStore* getContactDataStore();
};
#endif

35
src/DataStore/SietchDataStore.cpp

@ -0,0 +1,35 @@
#include "SietchDataStore.h"
SietchDataStore* SietchDataStore::getInstance()
{
if(!SietchDataStore::instanced)
{
SietchDataStore::instanced = true;
SietchDataStore::instance = new SietchDataStore();
}
return SietchDataStore::instance;
}
void SietchDataStore::clear()
{
this->data.clear();
}
void SietchDataStore::setData(QString key, QString value)
{
this->data[key] = value;
}
QString SietchDataStore::getData(QString key)
{
return this->data[key];
}
QString SietchDataStore::dump()
{
return "";
}
SietchDataStore* SietchDataStore::instance = nullptr;
bool SietchDataStore::instanced = false;

31
src/DataStore/SietchDataStore.h

@ -0,0 +1,31 @@
#ifndef SIETCHDATASTORE_H
#define SIETCHDATASTORE_H
using json = nlohmann::json;
class SietchDataStore
{
private:
static bool instanced;
static SietchDataStore* instance;
std::map<QString, QString> data;
SietchDataStore()
{
}
public:
static SietchDataStore* getInstance();
void clear();
void setData(QString key, QString value);
QString getData(QString key);
QString dump();
~SietchDataStore()
{
SietchDataStore::instanced = false;
SietchDataStore::instance = nullptr;
}
};
#endif

127
src/FileSystem/FileSystem.cpp

@ -0,0 +1,127 @@
#include "FileSystem.h"
#include <QString>
#include <QList>
FileSystem::FileSystem()
{
}
FileSystem* FileSystem::getInstance()
{
if(!FileSystem::instanced)
{
FileSystem::instanced = true;
FileSystem::instance = new FileSystem();
FileEncryption::showConfig();
}
return FileSystem::instance;
}
/*QList<ContactItem> FileSystem::readContacts(QString file)
{
//return this->readContactsOldFormat(file); //will be called if addresses are in the old dat-format
QFile _file(file);
if (_file.exists())
{
std::ifstream f(file.toStdString().c_str(), std::ios::binary);
if(f.is_open())
{
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(f), {});
//todo covert to string to use is as json to feed the data store in addressbook
}
f.close();
}
else
{
qInfo() << file << "not exist";
}
}
void FileSystem::writeContacts(QString file, QString data)
{
qDebug() << data;
QFile _file(file);
if (_file.exists())
{
std::ofstream f(file.toStdString().c_str());
if(f.is_open())
{
//ENCRYPT HERE
f << data.toStdString();
}
f.close();
}
else
{
qInfo() << file << "not exist";
}
}
void FileSystem::writeContactsOldFormat(QString file, QList<ContactItem> contacts)
{
QFile _file(file);
_file.open(QIODevice::ReadWrite | QIODevice::Truncate);
QDataStream out(&_file); // we will serialize the data into the file
QList<QList<QString>> _contacts;
for(auto &item: contacts)
{
QList<QString> c;
c.push_back(item.getName());
c.push_back(item.getPartnerAddress());
c.push_back(item.getMyAddress());
c.push_back(item.getCid());
c.push_back(item.getAvatar());
_contacts.push_back(c);
}
out << QString("v0") << _contacts;
_file.close();
}
QList<ContactItem> FileSystem::readContactsOldFormat(QString file)
{
QList<ContactItem> contacts;
QFile _file(file);
if (_file.exists())
{
contacts.clear();
_file.open(QIODevice::ReadOnly);
QDataStream in(&_file); // read the data serialized from the file
QString version;
in >> version;
qDebug() << "Read " << version << " Hush contacts from disk...";
qDebug() << "Detected old addressbook format";
QList<QList<QString>> stuff;
in >> stuff;
//qDebug() << "Stuff: " << stuff;
for (int i=0; i < stuff.size(); i++)
{
ContactItem contact = ContactItem(stuff[i][0],stuff[i][1], stuff[i][2], stuff[i][3],stuff[i][4]);
contacts.push_back(contact);
}
_file.close();
}
else
{
qDebug() << "No Hush contacts found on disk!";
}
return contacts;
}
FileSystem::~FileSystem()
{
this->instance = nullptr;
this->instanced = false;
delete this->instance;
}*/
FileSystem *FileSystem::instance = nullptr;
bool FileSystem::instanced = false;

31
src/FileSystem/FileSystem.h

@ -0,0 +1,31 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <QString>
#include <QList>
#include "../Model/ContactItem.h"
#include "../Crypto/FileEncryption.h"
#include <fstream>
using json = nlohmann::json;
class FileSystem
{
private:
static bool instanced;
static FileSystem* instance;
FileSystem();
public:
static FileSystem* getInstance();
QList<ContactItem> readContacts(QString file);
void writeContacts(QString file, QString data);
//converter
QList<ContactItem> readContactsOldFormat(QString file);
void writeContactsOldFormat(QString file, QList<ContactItem> contacts);
~FileSystem();
};
#endif

11
src/Logger/LogContext.h

@ -0,0 +1,11 @@
#ifndef LOGCONTEXT_H
#define LOGCONTEXT_H
#include <string>
class LogContext
{
public:
virtual void log(std::string message) {};
};
#endif

18
src/Logger/LogCrtitical.h

@ -0,0 +1,18 @@
#ifndef LOGCRITICAL_H
#define LOGCRITICAL_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogCritical : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::CRITICAL, message);
}
};
#endif

18
src/Logger/LogDebug.h

@ -0,0 +1,18 @@
#ifndef LOGDEBUG_H
#define LOGDEBUG_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogDebug : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::DEBUG, message);
}
};
#endif

18
src/Logger/LogError.h

@ -0,0 +1,18 @@
#ifndef LOGERROR_H
#define LOGERROR_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogError : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::ERROR, message);
}
};
#endif

18
src/Logger/LogFatal.h

@ -0,0 +1,18 @@
#ifndef LOGFATAL_H
#define LOGFATAL_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogFatal : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::FATAL, message);
}
};
#endif

18
src/Logger/LogInfo.h

@ -0,0 +1,18 @@
#ifndef LOGINFO_H
#define LOGINFO_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogInfo : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::INFO, message);
}
};
#endif

11
src/Logger/LogStrategy.h

@ -0,0 +1,11 @@
#ifndef LOGSTRATEGY_H
#define LOGSTRATEGY_H
#include <string>
class LogStrategy
{
public:
virtual void log(std::string message) {};
};
#endif

18
src/Logger/LogSuccess.h

@ -0,0 +1,18 @@
#ifndef LOGSUCCESS_H
#define LOGSUCCESS_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogSuccess : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::SUCCESS, message);
}
};
#endif

47
src/Logger/LogType.h

@ -0,0 +1,47 @@
#ifndef LOGTYPE_H
#define LOGTYPE_H
#include <string>
class LogType
{
public:
enum TYPE {
INFO = 0,
DEBUG = 1,
SUCCESS = 2,
WARNING = 3,
ERROR = 4,
FATAL = 5,
CRITICAL = 6
};
static std::string enum2String(int type)
{
switch (type)
{
default:
case 0:
return "INFO";
case 1:
return "DEBUG";
case 2:
return "SUCCESS";
case 3:
return "WARNING";
case 4:
return "ERROR";
case 5:
return "FATAL";
case 6:
return "CRITICAL";
}
}
};
#endif

18
src/Logger/LogWarning.h

@ -0,0 +1,18 @@
#ifndef LOGWARNING_H
#define LOGWARNING_H
#include "LogType.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class LogWarning : public LogStrategy
{
public:
void log(std::string message)
{
LogWriter* lw = LogWriter::getInstance();
lw->write(LogType::WARNING, message);
}
};
#endif

35
src/Logger/LogWriter.cpp

@ -0,0 +1,35 @@
#include "LogWriter.h"
LogWriter* LogWriter::getInstance()
{
if(instance == nullptr)
instance = new LogWriter();
return instance;
}
void LogWriter::setLogFile(std::string file)
{
this->logfile = file;
}
void LogWriter::write(LogType::TYPE type, std::string message)
{
std::ofstream writer(this->logfile, std::ios::out | std::ios::app);
if(writer.good())
{
time_t now = time(0);
tm *ltm = localtime(&now);
std::stringstream ss;
ss << "[" << LogType::enum2String(type) << "] " <<
ltm->tm_mon << "-" <<
ltm->tm_mday << "-" <<
(1900 + ltm->tm_year) << " " <<
ltm->tm_hour << ":" <<
ltm->tm_min << ":" <<
ltm->tm_sec << " > " << message;
writer << ss.str() << "\n";
}
writer.close();
}

22
src/Logger/LogWriter.h

@ -0,0 +1,22 @@
#ifndef LOGWRITER_H
#define LOGWRITER_H
#include <string>
#include <fstream>
#include <sstream>
#include <ctime>
#include "LogType.h"
class LogWriter
{
public:
static LogWriter* getInstance();
std::string logfile = "";
void setLogFile(std::string file);
void write(LogType::TYPE t, std::string message);
private:
static LogWriter* instance;
};
#endif

25
src/Logger/Logger.h

@ -0,0 +1,25 @@
#ifndef LOGGER_H
#define LOGGER_H
#include "LogContext.h"
#include "LogStrategy.h"
#include "LogWriter.h"
class Logger : LogContext
{
private:
LogStrategy * strategy = nullptr;
public:
Logger(LogStrategy * strategy)
{
this->strategy = strategy;
}
void log(std::string message)
{
this->strategy->log(message);
}
};
LogWriter* LogWriter::instance = nullptr;
#endif

84
src/Logger/SimpleLogger.h

@ -0,0 +1,84 @@
#ifndef SIMPLELOGGER_H
#define SIMPLELOGGER_H
#include "Logger.h"
#include "LogInfo.h"
#include "LogDebug.h"
#include "LogSuccess.h"
#include "LogWarning.h"
#include "LogError.h"
#include "LogFatal.h"
#include "LogCrtitical.h"
#include "LogWriter.h"
class SimpleLogger
{
public:
SimpleLogger()
{
LogWriter::getInstance()->setLogFile("log.txt");
}
SimpleLogger(std::string logFile)
{
LogWriter::getInstance()->setLogFile(logFile);
}
void logInfo(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogInfo();
logger = new Logger(li);
logger->log(message);
}
void logDebug(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogDebug();
logger = new Logger(li);
logger->log(message);
}
void logSuccess(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogSuccess();
logger = new Logger(li);
logger->log(message);
}
void logWarning(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogWarning();
logger = new Logger(li);
logger->log(message);
}
void logError(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogError();
logger = new Logger(li);
logger->log(message);
}
void logFatal(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogFatal();
logger = new Logger(li);
logger->log(message);
}
void logCritical(std::string message)
{
Logger* logger = nullptr;
LogStrategy* li = new LogCritical();
logger = new Logger(li);
logger->log(message);
}
};
#endif

14
src/Logger/test.cpp

@ -0,0 +1,14 @@
#include "SimpleLogger.h"
int main(int argc, char** argv)
{
SimpleLogger sl = SimpleLogger("/tmp/simplelog.log");
sl.logInfo("test info");
sl.logDebug("test debug");
sl.logSuccess("test success");
sl.logWarning("test warning");
sl.logError("test error");
sl.logFatal("test fatal");
sl.logCritical("test critical");
return 0;
}

206
src/Model/ChatItem.cpp

@ -0,0 +1,206 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "ChatItem.h"
ChatItem::ChatItem() {}
ChatItem::ChatItem(long timestamp, QString address, QString contact, QString memo, QString requestZaddr, QString type, QString cid, QString txid, int confirmations, bool notarize, bool iscontact)
{
_timestamp = timestamp;
_address = address;
_contact = contact;
_memo = memo;
_requestZaddr = requestZaddr;
_type = type;
_cid = cid;
_txid = txid;
_confirmations = confirmations;
_outgoing = false;
_notarize = notarize;
_iscontact = iscontact;
}
ChatItem::ChatItem(long timestamp, QString address, QString contact, QString memo, QString requestZaddr, QString type, QString cid, QString txid, int confirmations, bool outgoing, bool notarize, bool iscontact)
{
_timestamp = timestamp;
_address = address;
_contact = contact;
_memo = memo;
_requestZaddr = requestZaddr;
_type = type;
_cid = cid;
_txid = txid;
_confirmations = confirmations;
_outgoing = outgoing;
_notarize = notarize;
_iscontact = iscontact;
}
long ChatItem::getTimestamp()
{
return _timestamp;
}
QString ChatItem::getAddress()
{
return _address;
}
QString ChatItem::getContact()
{
return _contact;
}
QString ChatItem::getMemo()
{
return _memo;
}
QString ChatItem::getRequestZaddr()
{
return _requestZaddr;
}
QString ChatItem::getType()
{
return _type;
}
QString ChatItem::getCid()
{
return _cid;
}
QString ChatItem::getTxid()
{
return _txid;
}
int ChatItem::getConfirmations()
{
return _confirmations;
}
bool ChatItem::isOutgoing()
{
return _outgoing;
}
bool ChatItem::isNotarized()
{
return _notarize;
}
bool ChatItem::isContact()
{
return _iscontact;
}
void ChatItem::setTimestamp(long timestamp)
{
_timestamp = timestamp;
}
void ChatItem::setAddress(QString address)
{
_address = address;
}
void ChatItem::setContact(QString contact)
{
_contact = contact;
}
void ChatItem::setMemo(QString memo)
{
_memo = memo;
}
void ChatItem::setRequestZaddr(QString requestZaddr)
{
_requestZaddr = requestZaddr;
}
void ChatItem::setType(QString type)
{
_type = type;
}
void ChatItem::setCid(QString cid)
{
_cid = cid;
}
void ChatItem::setTxid(QString txid)
{
_txid = txid;
}
void ChatItem::setConfirmations(int confirmations)
{
_confirmations = confirmations;
}
void ChatItem::toggleOutgo()
{
_outgoing = true;
}
void ChatItem::notarized()
{
_notarize = false;
}
void ChatItem::contact(bool iscontact)
{
_iscontact = iscontact;
}
QString ChatItem::toChatLine()
{
QDateTime myDateTime;
QString lock;
myDateTime.setTime_t(_timestamp);
if (_notarize == true)
{
lock = "<b> <img src=':/icons/res/lock_orange.png'><b>";
}else{
lock = "<b> <img src=':/icons/res/unlocked.png'><b>";
}
if ((_confirmations > 0) && (_notarize == false))
{
lock = "<b> <img src=':/icons/res/lock_green.png'><b>";
}
QString line = QString("<small>") + myDateTime.toString("yyyy-MM-dd hh:mm");
line += QString(lock) + QString("</small>");
line +=QString("<p>") + _memo.toHtmlEscaped() + QString("</p>");
return line;
}
json ChatItem::toJson()
{
json j;
j["_timestamp"] = _timestamp;
j["_address"] = _address.toStdString();
j["_contact"] = _contact.toStdString();
j["_memo"] = _memo.toStdString();
j["_requestZaddr"] = _requestZaddr.toStdString();
j["_type"] = _type.toStdString();
j["_cid"] = _cid.toStdString();
j["_txid"] = _txid.toStdString();
j["_confirmations"] = _confirmations;
j["_outgoing"] = _outgoing;
return j;
}
ChatItem::~ChatItem()
{
}

60
src/Model/ChatItem.h

@ -0,0 +1,60 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CHATITEM_H
#define CHATITEM_H
#include <QString>
using json = nlohmann::json;
class ChatItem
{
private:
long _timestamp;
QString _address;
QString _contact;
QString _memo;
QString _requestZaddr;
QString _type;
QString _cid;
QString _txid;
int _confirmations;
bool _outgoing = false;
bool _notarize = false;
bool _iscontact = false;
public:
ChatItem();
ChatItem(long timestamp, QString address, QString contact, QString memo,QString requestZaddr, QString type, QString cid, QString txid, int confirmations, bool notarize, bool iscontact);
ChatItem(long timestamp, QString address, QString contact, QString memo, QString requestZaddr, QString type, QString cid, QString txid, int confirmations, bool outgoing, bool notarize, bool iscontact);
long getTimestamp();
QString getAddress();
QString getContact();
QString getMemo();
QString getRequestZaddr();
QString getType();
QString getCid();
QString getTxid();
int getConfirmations();
bool isOutgoing();
bool isdouble();
bool isNotarized();
bool isContact();
void setTimestamp(long timestamp);
void setAddress(QString address);
void setContact(QString contact);
void setMemo(QString memo);
void setRequestZaddr(QString requestZaddr);
void setType(QString type);
void setCid(QString cid);
void setTxid(QString txid);
void setConfirmations(int confirmations);
void toggleOutgo();
void notarized();
void contact(bool iscontact);
QString toChatLine();
json toJson();
~ChatItem();
};
#endif

98
src/Model/ContactItem.cpp

@ -0,0 +1,98 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "ContactItem.h"
#include "chatmodel.h"
#include "Model/ChatItem.h"
#include "controller.h"
ContactItem::ContactItem() {}
ContactItem::ContactItem(QString name, QString partnerAddress)
{
_name = name;
_partnerAddress = partnerAddress;
}
ContactItem::ContactItem(QString name, QString partnerAddress, QString myAddress, QString cid)
{
_name = name;
_myAddress = myAddress;
_partnerAddress = partnerAddress;
_cid = cid;
}
ContactItem::ContactItem(QString name, QString partnerAddress, QString myAddress, QString cid, QString avatar)
{
_name = name;
_myAddress = myAddress;
_partnerAddress = partnerAddress;
_cid = cid;
_avatar = avatar;
}
QString ContactItem::getName() const
{
return _name;
}
QString ContactItem::getMyAddress() const
{
return _myAddress;
}
QString ContactItem::getPartnerAddress() const
{
return _partnerAddress;
}
QString ContactItem::getCid() const
{
return _cid;
}
QString ContactItem::getAvatar() const
{
return _avatar;
}
void ContactItem::setName(QString name)
{
_name = name;
}
void ContactItem::setMyAddress(QString myAddress)
{
_myAddress = myAddress;
}
void ContactItem::setPartnerAddress(QString partnerAddress)
{
_partnerAddress = partnerAddress;
}
void ContactItem::setcid(QString cid)
{
_cid = cid;
}
void ContactItem::setAvatar(QString avatar)
{
_avatar = avatar;
}
QString ContactItem::toQTString()
{
return _name + "|" + _partnerAddress + "|" + _myAddress + "|" + _cid + "|" + _avatar;
}
json ContactItem::toJson()
{
json j;
j["_myAddress"] = _myAddress.toStdString();
j["_partnerAddress"] = _partnerAddress.toStdString();
j["_name"] = _name.toStdString();
j["_cid"] = _cid.toStdString();
j["_avatar"] = _avatar.toStdString();
return j;
}

40
src/Model/ContactItem.h

@ -0,0 +1,40 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CONTACTITEM_H
#define CONTACTITEM_H
#include <vector>
#include <QString>
#include "mainwindow.h"
using json = nlohmann::json;
class ContactItem
{
private:
QString _myAddress;
QString _partnerAddress;
QString _name;
QString _cid;
QString _avatar;
QString _pubkey;
public:
ContactItem();
ContactItem(QString name, QString partnerAddress);
ContactItem(QString name, QString partnerAddress, QString myAddress, QString cid);
ContactItem(QString name, QString partnerAddress, QString myAddress, QString cid, QString avatar);
QString getName() const;
QString getMyAddress() const;
QString getPartnerAddress() const;
QString getCid() const;
QString getAvatar() const;
void setName(QString name);
void setMyAddress(QString myAddress);
void setPartnerAddress(QString partnerAddress);
void setcid(QString cid);
void setAvatar(QString avatar);
QString toQTString();
json toJson();
};
#endif

96
src/Model/ContactRequest.cpp

@ -0,0 +1,96 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "ContactRequest.h"
ContactRequest::ContactRequest() {}
ContactRequest::ContactRequest(QString sender, QString receiver, QString memo, QString cid, QString label, QString avatar)
{
_senderAddress = sender;
_receiverAddress = receiver;
_memo = memo;
_cid = cid;
_label = label;
_avatar = avatar;
}
QString ContactRequest::getSenderAddress()
{
return _senderAddress;
}
QString ContactRequest::getReceiverAddress()
{
return _receiverAddress;
}
QString ContactRequest::getMemo()
{
return _memo;
}
QString ContactRequest::getCid()
{
return _cid;
}
QString ContactRequest::getLabel()
{
return _label;
}
QString ContactRequest::getAvatar()
{
return _avatar;
}
void ContactRequest::setSenderAddress(QString address)
{
_senderAddress = address;
}
void ContactRequest::setReceiverAddress(QString address)
{
_receiverAddress = address;
}
void ContactRequest::setMemo(QString memo)
{
_memo = memo;
}
void ContactRequest::setCid(QString cid)
{
_cid = cid;
}
void ContactRequest::setLabel(QString label)
{
_label = label;
}
void ContactRequest::setAvatar(QString avatar)
{
_avatar = avatar;
}
QString ContactRequest::toString()
{
return "sender: " + _senderAddress + " receiver: " + _receiverAddress + " memo: " + _memo + " cid: " + _cid + " label: " + _label + " avatar: " + _avatar;
}
void ContactRequest::clear()
{
_senderAddress = "";
_receiverAddress = "";
_memo = "";
_cid = "";
_label = "";
_avatar = "";
}
ContactRequest::~ContactRequest()
{
clear();
}

40
src/Model/ContactRequest.h

@ -0,0 +1,40 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CONTACTREQUEST_H
#define CONTACTREQUEST_H
#include <QString>
using json = nlohmann::json;
class ContactRequest
{
private:
QString _senderAddress;
QString _receiverAddress;
QString _memo;
QString _cid;
QString _label;
QString _avatar;
public:
ContactRequest();
ContactRequest(QString sender, QString receiver, QString memo, QString cid, QString label, QString avatar);
QString getSenderAddress();
QString getReceiverAddress();
QString getMemo();
QString getCid();
QString getLabel();
QString getAvatar();
void setSenderAddress(QString address);
void setReceiverAddress(QString contact);
void setMemo(QString memo);
void setCid(QString cid);
void setLabel(QString label);
void setAvatar(QString avatar);
QString toString();
void clear();
~ContactRequest();
};
#endif

1
src/Model/ContactRequestChatItem.cpp

@ -0,0 +1 @@
#include "ContactRequestChatItem.h"

11
src/Model/ContactRequestChatItem.h

@ -0,0 +1,11 @@
#ifdef CONTACTREQUESTCHATITEM_H
#define CONTACTREQUESTCHATITEM_H
#include "ChatItem.h"
class ContactRequestChatItem : ChatItem
{
};
#endif

214
src/addressbook.cpp

@ -1,14 +1,19 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "addressbook.h"
#include "ui_addressbook.h"
#include "ui_mainwindow.h"
#include "settings.h"
#include "mainwindow.h"
#include "controller.h"
#include "DataStore/DataStore.h"
#include "FileSystem/FileSystem.h"
AddressBookModel::AddressBookModel(QTableView *parent) : QAbstractTableModel(parent)
{
headers << tr("Label") << tr("Address");
headers << tr("Avatar")<< tr("Label") << tr("Address") << tr("HushChatAddress") << tr("CID");
this->parent = parent;
loadData();
}
@ -34,14 +39,21 @@ void AddressBookModel::loadData()
parent->horizontalHeader()->restoreState(
QSettings().value(
"addresstablegeometry"
).toByteArray()
).toByteArray()
);
}
void AddressBookModel::addNewLabel(QString label, QString addr)
void AddressBookModel::addNewLabel(QString label, QString addr, QString myAddr, QString cid, QString avatar)
{
//labels.push_back(QPair<QString, QString>(label, addr));
AddressBook::getInstance()->addAddressLabel(label, addr);
AddressBook::getInstance()->addAddressLabel(label, addr, myAddr, cid, avatar);
updateUi();
}
void AddressBookModel::updateUi()
{
labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels();
dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1));
@ -53,22 +65,27 @@ void AddressBookModel::removeItemAt(int row)
if (row >= labels.size())
return;
AddressBook::getInstance()->removeAddressLabel(labels[row].first, labels[row].second);
AddressBook::getInstance()->removeAddressLabel(labels[row].getName(), labels[row].getPartnerAddress(), labels[row].getMyAddress(),labels[row].getCid(),labels[row].getAvatar());
labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels();
dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1));
layoutChanged();
}
QPair<QString, QString> AddressBookModel::itemAt(int row)
ContactItem AddressBookModel::itemAt(int row)
{
if (row >= labels.size())
return QPair<QString, QString>();
if (row >= labels.size())
{
ContactItem item = ContactItem("", "", "", "","");
return item;
}
return labels.at(row);
}
int AddressBookModel::rowCount(const QModelIndex&) const
{
return labels.size();
@ -86,9 +103,14 @@ QVariant AddressBookModel::data(const QModelIndex &index, int role) const
{
switch(index.column())
{
case 0: return labels.at(index.row()).first;
case 1: return labels.at(index.row()).second;
case 0: return labels.at(index.row()).getAvatar();
case 1: return labels.at(index.row()).getName();
case 2: return labels.at(index.row()).getPartnerAddress();
case 3: return labels.at(index.row()).getMyAddress();
case 4: return labels.at(index.row()).getCid();
}
}
return QVariant();
@ -125,6 +147,38 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
// Connect the dialog's closing to updating the label address completor
QObject::connect(&d, &QDialog::finished, [=] (auto) { parent->updateLabels(); });
Controller* rpc = parent->getRPC();
QObject::connect(ab.newZaddr, &QPushButton::clicked, [&] () {
bool sapling = true;
try
{
rpc->createNewZaddr(sapling, [=] (json reply) {
QString myAddr = QString::fromStdString(reply.get<json::array_t>()[0]);
QString message = QString("New Chat Address for your partner: ") + myAddr;
QString cid = QUuid::createUuid().toString(QUuid::WithoutBraces);
rpc->refreshAddresses();
parent->ui->listReceiveAddresses->insertItem(0, myAddr);
parent->ui->listReceiveAddresses->setCurrentIndex(0);
qDebug() << " new Addr in Addressbook" << myAddr;
ab.cid->setText(cid);
ab.addr_chat->setText(myAddr);
});
}
catch(...)
{
qDebug() << QString("Caught something nasty with myZaddr Addressbook");
}
});
// model.updateUi(); //todo fix updating gui after adding
// If there is a target then make it the addr for the "Add to" button
if (target != nullptr && Settings::isValidAddress(target->text()))
{
@ -135,7 +189,12 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
// Add new address button
QObject::connect(ab.addNew, &QPushButton::clicked, [&] () {
auto addr = ab.addr->text().trimmed();
auto myAddr = ab.addr_chat->text().trimmed();
QString newLabel = ab.label->text();
QString cid = ab.cid->text();
QString avatar = QString(":/icons/res/") + ab.comboBoxAvatar->currentText() + QString(".png");
if (addr.isEmpty() || newLabel.isEmpty())
{
@ -170,10 +229,31 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
);
return;
}
model.addNewLabel(newLabel, ab.addr->text());
////// We need a better popup here.
AddressBook::getInstance()->addAddressLabel(newLabel, addr, myAddr, cid,avatar);
QMessageBox::information(
parent,
QObject::tr("Added Contact"),
QObject::tr("successfully added your new contact").arg(newLabel),
QMessageBox::Ok
);
return;
// rpc->refresh(true);
model.updateUi();
rpc->refreshContacts(
parent->ui->listContactWidget
);
});
// AddressBook::getInstance()->addAddressLabel(newLabel, ab.addr->text(), cid);
// Import Button
QObject::connect(ab.btnImport, &QPushButton::clicked, [&] () {
// Get the import file name.
@ -209,7 +289,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
continue;
// Add label, address.
model.addNewLabel(items.at(1), items.at(0));
model.addNewLabel(items.at(1), items.at(0), "", "", "");
numImported++;
}
@ -220,8 +300,8 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
);
});
auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr) {
target->setText(label % "/" % addr);
auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr, QString myAddr, QString cid, QString avatar) {
target->setText(label % "/" % addr % myAddr);
};
// Double-Click picks the item
@ -233,10 +313,13 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
if (index.row() < 0)
return;
QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
QString lbl = model.itemAt(index.row()).getName();
QString addr = model.itemAt(index.row()).getPartnerAddress();
QString myAddr = model.itemAt(index.row()).getMyAddress();
QString cid = model.itemAt(index.row()).getCid();
QString avatar = model.itemAt(index.row()).getCid();
d.accept();
fnSetTargetLabelAddr(target, lbl, addr);
fnSetTargetLabelAddr(target, lbl, addr, myAddr, cid, avatar);
});
// Right-Click
@ -246,15 +329,18 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
if (index.row() < 0)
return;
QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
QString lbl = model.itemAt(index.row()).getName();
QString addr = model.itemAt(index.row()).getPartnerAddress();
QString myAddr = model.itemAt(index.row()).getMyAddress();
QString cid = model.itemAt(index.row()).getCid();
QString avatar = model.itemAt(index.row()).getAvatar();
QMenu menu(parent);
if (target != nullptr)
menu.addAction("Pick", [&] () {
d.accept();
fnSetTargetLabelAddr(target, lbl, addr);
fnSetTargetLabelAddr(target, lbl, addr, myAddr, cid, avatar);
});
menu.addAction(QObject::tr("Copy address"), [&] () {
@ -273,12 +359,13 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target)
auto selection = ab.addresses->selectionModel();
if (selection && selection->hasSelection() && selection->selectedRows().size() > 0) {
auto item = model.itemAt(selection->selectedRows().at(0).row());
fnSetTargetLabelAddr(target, item.first, item.second);
fnSetTargetLabelAddr(target, item.getName(), item.getMyAddress(), item.getPartnerAddress(), item.getCid(), item.getAvatar());
}
};
// Refresh after the dialog is closed to update the labels everywhere.
parent->getRPC()->refresh(true);
model.updateUi(); //todo fix updating gui after adding
}
//=============
@ -307,26 +394,71 @@ void AddressBook::readFromStorage()
file.open(QIODevice::ReadOnly);
QDataStream in(&file); // read the data serialized from the file
QString version;
in >> version >> allLabels;
in >> version;
QList<QList<QString>> stuff;
in >> stuff;
//////////////found old addrbook, and rename it to .bak
if (version != "v2")
{
auto filename = QStringLiteral("addresslabels.dat");
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
QFile address(dir.filePath(filename));
address.rename(dir.filePath("addresslabels.bak"));
}else{
for (int i=0; i < stuff.size(); i++)
{
ContactItem contact = ContactItem(stuff[i][0],stuff[i][1], stuff[i][2], stuff[i][3],stuff[i][4]);
allLabels.push_back(contact);
}
}
// qDebug() << "Read " << version << " Hush contacts from disk...";
file.close();
}
else
{
qDebug() << "No Hush contacts found on disk!";
}
// Special.
// Add the default silentdragon donation address if it isn't already present
// QList<QString> allAddresses;
// std::transform(allLabels.begin(), allLabels.end(),
// std::back_inserter(allAddresses), [=] (auto i) { return i.second; });
// std::back_inserter(allAddresses), [=] (auto i) { return i.getPartnerAddress(); });
// if (!allAddresses.contains(Settings::getDonationAddr(true))) {
// allLabels.append(QPair<QString, QString>("silentdragon donation", Settings::getDonationAddr(true)));
// }
}
void AddressBook::writeToStorage()
{
//FileSystem::getInstance()->writeContacts(AddressBook::writeableFile(), DataStore::getContactDataStore()->dump());
// FileSystem::getInstance()->writeContactsOldFormat(AddressBook::writeableFile(), allLabels);
QFile file(AddressBook::writeableFile());
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
QDataStream out(&file); // we will serialize the data into the file
out << QString("v1") << allLabels;
QList<QList<QString>> contacts;
for(auto &item: allLabels)
{
QList<QString> c;
c.push_back(item.getName());
c.push_back(item.getPartnerAddress());
c.push_back(item.getMyAddress());
c.push_back(item.getCid());
c.push_back(item.getAvatar());
contacts.push_back(c);
}
out << QString("v2") << contacts;
file.close();
}
@ -346,27 +478,27 @@ QString AddressBook::writeableFile()
// Add a new address/label to the database
void AddressBook::addAddressLabel(QString label, QString address)
void AddressBook::addAddressLabel(QString label, QString address, QString myAddr, QString cid, QString avatar)
{
Q_ASSERT(Settings::isValidAddress(address));
// First, remove any existing label
// getName(), remove any existing label
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++)
if (allLabels[i].first == label)
removeAddressLabel(allLabels[i].first, allLabels[i].second);
if (allLabels[i].getName() == label)
removeAddressLabel(allLabels[i].getName(), allLabels[i].getPartnerAddress(),allLabels[i].getMyAddress(), allLabels[i].getCid(), allLabels[i].getAvatar());
allLabels.push_back(QPair<QString, QString>(label, address));
ContactItem item = ContactItem(label, address, myAddr, cid, avatar);
allLabels.push_back(item);
writeToStorage();
}
// Remove a new address/label from the database
void AddressBook::removeAddressLabel(QString label, QString address)
void AddressBook::removeAddressLabel(QString label, QString address, QString myAddr, QString cid, QString avatar)
{
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++)
{
if (allLabels[i].first == label && allLabels[i].second == address)
if (allLabels[i].getName() == label && allLabels[i].getPartnerAddress() == address)
{
allLabels.removeAt(i);
writeToStorage();
@ -380,9 +512,9 @@ void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabe
// Iterate over the list and update the label/address
for (int i = 0; i < allLabels.size(); i++)
{
if (allLabels[i].first == oldlabel && allLabels[i].second == address)
if (allLabels[i].getName() == oldlabel && allLabels[i].getPartnerAddress() == address)
{
allLabels[i].first = newlabel;
allLabels[i].setName(newlabel);
writeToStorage();
return;
}
@ -390,7 +522,7 @@ void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabe
}
// Read all addresses
const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels()
const QList<ContactItem>& AddressBook::getAllAddressLabels()
{
if (allLabels.isEmpty())
readFromStorage();
@ -402,8 +534,8 @@ const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels()
QString AddressBook::getLabelForAddress(QString addr)
{
for (auto i : allLabels)
if (i.second == addr)
return i.first;
if (i.getPartnerAddress() == addr)
return i.getName();
return "";
}
@ -412,8 +544,8 @@ QString AddressBook::getLabelForAddress(QString addr)
QString AddressBook::getAddressForLabel(QString label)
{
for (auto i: allLabels)
if (i.first == label)
return i.second;
if (i.getName() == label)
return i.getPartnerAddress();
return "";
}
@ -428,6 +560,8 @@ QString AddressBook::addLabelToAddress(QString addr)
return addr;
}
QString AddressBook::addressFromAddressLabel(const QString& lblAddr)
{
return lblAddr.trimmed().split("/").last();

37
src/addressbook.h

@ -2,6 +2,8 @@
#define ADDRESSBOOK_H
#include "precompiled.h"
#include "contactmodel.h"
#include "FileSystem/FileSystem.h"
class MainWindow;
@ -10,10 +12,12 @@ class AddressBookModel : public QAbstractTableModel {
public:
AddressBookModel(QTableView* parent);
~AddressBookModel();
void addNewLabel(QString label, QString addr);
void addNewLabel(QString label, QString address, QString myAddr, QString cid, QString avatar);
void updateUi();
void removeItemAt(int row);
QPair<QString, QString> itemAt(int row);
//QPair<QString, QString> itemAt(int row);
ContactItem itemAt(int row);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
@ -25,8 +29,10 @@ private:
void saveData();
QTableView* parent;
QList<QPair<QString, QString>> labels;
QStringList headers;
//QList<QPair<QString, QString>> labels;
QList<ContactItem> labels;
QStringList headers;
};
class AddressBook {
@ -39,21 +45,33 @@ public:
static QString addressFromAddressLabel(const QString& lblAddr);
// Add a new address/label to the database
void addAddressLabel(QString label, QString address);
void addAddressLabel(QString label, QString address, QString myAddr, QString cid, QString avatar);
// Remove a new address/label from the database
void removeAddressLabel(QString label, QString address);
void removeAddressLabel(QString label, QString address, QString myAddr, QString cid, QString avatar);
// Update a label/address
void updateLabel(QString oldlabel, QString address, QString newlabel);
// Read all addresses
const QList<QPair<QString, QString>>& getAllAddressLabels();
const QList<ContactItem>& getAllAddressLabels();
// Get an address's first label
QString getLabelForAddress(QString address);
// Get a Label's address
QString getAddressForLabel(QString label);
QString get_avatar_name();
void set_avatar_name(QString avatar_name);
private:
AddressBook();
@ -61,7 +79,8 @@ private:
void writeToStorage();
QString writeableFile();
QList<QPair<QString, QString>> allLabels;
QList<ContactItem> allLabels;
static AddressBook* instance;
};

324
src/addressbook.ui

@ -13,101 +13,291 @@
<property name="windowTitle">
<string>Address Book</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btnImport">
<property name="text">
<string>Import Address Book</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QTableView" name="addresses">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Add New Address</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Address (z-Addr or t-Addr)</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="addr"/>
</item>
<item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Label</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Nickname :&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<item row="1" column="0">
<widget class="QLineEdit" name="addr">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="label">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maxLength">
<number>40</number>
<number>25</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>HushChat Address - give this Address only to your contact</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLineEdit" name="addr_chat">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Conversation ID:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLineEdit" name="cid">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="addNew">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Add to Address Book</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="comboBoxAvatar">
<item>
<property name="text">
<string>SDLogo</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Duke</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Duke.png</activeon>
</iconset>
</property>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
<property name="text">
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<widget class="QPushButton" name="addNew">
<property name="text">
<string>Add to Address Book</string>
</property>
</widget>
<property name="text">
<string>Berg</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
</iconset>
</property>
</item>
</layout>
<item>
<property name="text">
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garflied</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
</iconset>
</property>
</item>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Avatar :&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="newZaddr">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Create a new HushChat zaddr</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTableView" name="addresses">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btnImport">
<property name="text">
<string>Import Address Book</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

14
src/chatbubbleme.cpp

@ -0,0 +1,14 @@
#include "chatbubbleme.h"
#include "ui_chatbubbleme.h"
ChatBubbleMe::ChatBubbleMe(QWidget *parent) :
QWidget(parent),
ui(new Ui::ChatBubbleMe)
{
ui->setupUi(this);
}
ChatBubbleMe::~ChatBubbleMe()
{
delete ui;
}

22
src/chatbubbleme.h

@ -0,0 +1,22 @@
#ifndef CHATBUBBLEME_H
#define CHATBUBBLEME_H
#include <QWidget>
namespace Ui {
class ChatBubbleMe;
}
class ChatBubbleMe : public QWidget
{
Q_OBJECT
public:
explicit ChatBubbleMe(QWidget *parent = nullptr);
~ChatBubbleMe();
private:
Ui::ChatBubbleMe *ui;
};
#endif // CHATBUBBLEME_H

57
src/chatbubbleme.ui

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ChatBubbleMe</class>
<widget class="QWidget" name="ChatBubbleMe">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>646</width>
<height>76</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget{
background: whitesmoke;
border: 1px solid #afafaf;
border-radius: 3px;
}
QLabel
{
background: none;
border: none;
}</string>
</property>
<widget class="QLabel" name="lblMessage">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>611</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Lorem ipsum dolor sit amet</string>
</property>
</widget>
<widget class="QLabel" name="lblTimestamp">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>611</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>12/03/2020 12:34</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

14
src/chatbubblepartner.cpp

@ -0,0 +1,14 @@
#include "chatbubblepartner.h"
#include "ui_chatbubblepartner.h"
ChatBubblePartner::ChatBubblePartner(QWidget *parent) :
QWidget(parent),
ui(new Ui::ChatBubblePartner)
{
ui->setupUi(this);
}
ChatBubblePartner::~ChatBubblePartner()
{
delete ui;
}

22
src/chatbubblepartner.h

@ -0,0 +1,22 @@
#ifndef CHATBUBBLEPARTNER_H
#define CHATBUBBLEPARTNER_H
#include <QWidget>
namespace Ui {
class ChatBubblePartner;
}
class ChatBubblePartner : public QWidget
{
Q_OBJECT
public:
explicit ChatBubblePartner(QWidget *parent = nullptr);
~ChatBubblePartner();
private:
Ui::ChatBubblePartner *ui;
};
#endif // CHATBUBBLEPARTNER_H

57
src/chatbubblepartner.ui

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ChatBubblePartner</class>
<widget class="QWidget" name="ChatBubblePartner">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>646</width>
<height>76</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget{
background: #c8e1ff;
border: 1px solid #fefefe;
border-radius: 3px;
}
QLabel
{
background: none;
border: none;
}</string>
</property>
<widget class="QLabel" name="lblMessage">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>611</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Lorem ipsum dolor sit amet</string>
</property>
</widget>
<widget class="QLabel" name="lblTimestamp">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>611</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>12/03/2020 12:34</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

1018
src/chatmodel.cpp

File diff suppressed because it is too large

76
src/chatmodel.h

@ -0,0 +1,76 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CHATMODEL_H
#define CHATMODEL_H
#include <QString>
#include <QStandardItemModel>
#include <QAbstractItemDelegate>
#include <QPainter>
#include <map>
#include <vector>
#include <QListView>
#include "precompiled.h"
#include "mainwindow.h"
#include "controller.h"
#include "settings.h"
#include "camount.h"
#include "Model/ChatItem.h"
#include "Model/ContactRequest.h"
#include "Chat/Helper/ChatDelegator.h"
#include "Chat/Helper/ChatIDGenerator.h"
namespace Ui {
class MainWindow;
}
class ChatModel
{
private:
std::map<QString, ChatItem> chatItems;
QTableView* parent;
Ui::MainWindow* ui;
MainWindow* main;
std::map<QString, QString> cidMap;
std::map<QString, QString> requestZaddrMap;
std::map<QString, QString> confirmationsMap;
std::map<int, std::tuple<QString, QString, QString>> sendrequestMap;
std::map<QString, QString> headerMap;
std::map<QString, QString> AddressbyLabelMap;
std::map<QString, QString> OldMemoByTx;
public:
ChatModel() {};
ChatModel(std::map<QString, ChatItem> chatItems);
ChatModel(std::vector<ChatItem> chatItems);
std::map<QString, ChatItem> getItems();
void setItems(std::map<QString, ChatItem> items);
QString zaddr();
void setItems(std::vector<ChatItem> items);
void triggerRequest();
void showMessages();
void clear();
void addAddressbylabel(QString addr, QString label);
void addMessage(ChatItem item);
void addMessage(QString timestamp, ChatItem item);
void addCid(QString tx, QString cid);
void addHeader(QString tx, QString headerbytes);
void addMemo(QString tx, QString memo);
void addrequestZaddr(QString tx, QString requestZaddr);
void addconfirmations(QString tx, int confirmation);
void addSendRequest(int i, QString myAddr, QString cid, QString addr );
QString getCidByTx(QString tx);
QString getHeaderByTx(QString tx);
QString getrequestZaddrByTx(QString tx);
QString getConfirmationByTx(QString tx);
QString getMemoByTx(QString tx);
QString Addressbylabel(QString addr);
void killCidCache();
void killConfirmationCache();
void killrequestZaddrCache();
void killMemoCache();
};
#endif

114
src/connection.cpp

@ -10,73 +10,85 @@
using json = nlohmann::json;
ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc)
{
this->main = main;
this->rpc = rpc;
d = new QDialog(main);
connD = new Ui_ConnectionDialog();
connD->setupUi(d);
QPixmap logo(":/img/res/logobig.gif");
connD->topIcon->setBasePixmap(
logo.scaled(
256,
256,
Qt::KeepAspectRatio,
Qt::SmoothTransformation
)
);
auto theme = Settings::getInstance()->get_theme_name();
qDebug() << theme << "theme has loaded";
auto size = QSize(512,512);
if (theme == "Dark" || theme == "Midnight") {
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");;
movie2->setScaledSize(size);
qDebug() << "Animation dark loaded";
connD->topIcon->setMovie(movie2);
movie2->start();
} else {
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup.gif");;
movie1->setScaledSize(size);
qDebug() << "Animation light loaded";
connD->topIcon->setMovie(movie1);
movie1->start();
}
main->logger->write("Set animation");
qDebug() << "Set animation";
isSyncing = new QAtomicInteger<bool>();
}
ConnectionLoader::~ConnectionLoader()
ConnectionLoader::~ConnectionLoader()
{
delete isSyncing;
delete connD;
delete d;
}
void ConnectionLoader::loadConnection()
void ConnectionLoader::loadConnection()
{
QTimer::singleShot(1, [=]() { this->doAutoConnect(); });
if (!Settings::getInstance()->isHeadless())
d->exec();
}
void ConnectionLoader::doAutoConnect()
void ConnectionLoader::doAutoConnect()
{
qDebug() << "Doing autoconnect";
auto config = std::shared_ptr<ConnectionConfig>(new ConnectionConfig());
config->dangerous = true;
config->dangerous = false;
config->server = Settings::getInstance()->getSettings().server;
// Initialize the library
main->logger->write(QObject::tr("Attempting to initialize library with ") + config->server);
// Check to see if there's an existing wallet
if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str()))
if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str()))
{
main->logger->write(QObject::tr("Using existing wallet."));
char* resp = litelib_initialize_existing(
config->dangerous,
config->dangerous,
config->server.toStdString().c_str()
);
QString response = litelib_process_response(resp);
if (response.toUpper().trimmed() != "OK")
if (response.toUpper().trimmed() != "OK")
{
showError(response);
return;
}
}
}
else
{
main->logger->write(QObject::tr("Create/restore wallet."));
createOrRestore(config->dangerous, config->server);
d->show();
}
}
auto connection = makeConnection(config);
auto me = this;
@ -97,14 +109,14 @@ void ConnectionLoader::doAutoConnect()
// When sync is done, set the connection
this->doRPCSetConnection(connection);
});
// While it is syncing, we'll show the status updates while it is alive.
QObject::connect(syncTimer, &QTimer::timeout, [=]() {
// Check the sync status
if (isSyncing != nullptr && isSyncing->load()) {
// Get the sync status
connection->doRPC("syncstatus", "", [=](json reply) {
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end())
{
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
@ -117,8 +129,8 @@ void ConnectionLoader::doAutoConnect()
qDebug() << "Sync error" << err;
});
}
});
});
syncTimer->setInterval(1* 1000);
syncTimer->start();
@ -127,16 +139,16 @@ void ConnectionLoader::doAutoConnect()
});
}
void ConnectionLoader::createOrRestore(bool dangerous, QString server)
void ConnectionLoader::createOrRestore(bool dangerous, QString server)
{
// Close the startup dialog, since we'll be showing the wizard
d->hide();
// Create a wizard
FirstTimeWizard wizard(dangerous, server);
FirstTimeWizard wizard(dangerous, server);
wizard.exec();
}
void ConnectionLoader::doRPCSetConnection(Connection* conn)
void ConnectionLoader::doRPCSetConnection(Connection* conn)
{
qDebug() << "Connectionloader finished, setting connection";
rpc->setConnection(conn);
@ -144,26 +156,26 @@ void ConnectionLoader::doRPCSetConnection(Connection* conn)
QTimer::singleShot(1, [=]() { delete this; });
}
Connection* ConnectionLoader::makeConnection(std::shared_ptr<ConnectionConfig> config)
Connection* ConnectionLoader::makeConnection(std::shared_ptr<ConnectionConfig> config)
{
return new Connection(main, config);
}
// Update the UI with the status
void ConnectionLoader::showInformation(QString info, QString detail)
void ConnectionLoader::showInformation(QString info, QString detail)
{
connD->status->setText(info);
connD->statusDetail->setText(detail);
}
/**
* Show error will close the loading dialog and show an error.
* Show error will close the loading dialog and show an error.
*/
void ConnectionLoader::showError(QString explanation)
{
void ConnectionLoader::showError(QString explanation)
{
rpc->noConnection();
QMessageBox::critical(
main,
main,
QObject::tr("Connection Error"),
explanation,
QMessageBox::Ok
@ -171,7 +183,7 @@ void ConnectionLoader::showError(QString explanation)
d->close();
}
QString litelib_process_response(char* resp)
QString litelib_process_response(char* resp)
{
char* resp_copy = new char[strlen(resp) + 1];
//a safer version of strcpy
@ -185,15 +197,15 @@ QString litelib_process_response(char* resp)
/***********************************************************************************
* Connection, Executor and Callback Class
************************************************************************************/
void Executor::run()
************************************************************************************/
void Executor::run()
{
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
QString reply = litelib_process_response(resp);
//qDebug() << "RPC Reply=" << reply;
auto parsed = json::parse(
reply.toStdString().c_str(),
nullptr,
reply.toStdString().c_str(),
nullptr,
false
);
if (parsed.is_discarded() || parsed.is_null())
@ -204,14 +216,14 @@ void Executor::run()
}
void Callback::processRPCCallback(json resp)
void Callback::processRPCCallback(json resp)
{
this->cb(resp);
// Destroy self
delete this;
}
void Callback::processError(QString resp)
void Callback::processError(QString resp)
{
this->errCb(resp);
// Destroy self
@ -226,7 +238,7 @@ Connection::Connection(MainWindow* m, std::shared_ptr<ConnectionConfig> conf)
qRegisterMetaType<json>("json");
}
void Connection::doRPC(const QString cmd, const QString args, const std::function<void(json)>& cb, const std::function<void(QString)>& errCb)
void Connection::doRPC(const QString cmd, const QString args, const std::function<void(json)>& cb, const std::function<void(QString)>& errCb)
{
if (shutdownInProgress)
// Ignoring RPC because shutdown in progress
@ -242,26 +254,26 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio
QObject::connect(runner, &Executor::responseReady, c, &Callback::processRPCCallback);
QObject::connect(runner, &Executor::handleError, c, &Callback::processError);
QThreadPool::globalInstance()->start(runner);
QThreadPool::globalInstance()->start(runner);
}
void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function<void(json)>& cb)
void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function<void(json)>& cb)
{
doRPC(cmd, args, cb, [=] (QString err) {
this->showTxError(err);
});
}
}
void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function<void(json)>& cb)
void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function<void(json)>& cb)
{
doRPC(cmd, args, cb, [=] (auto) {
// Ignored error handling
});
}
void Connection::showTxError(const QString& error)
void Connection::showTxError(const QString& error)
{
if (error.isNull())
if (error.isNull())
return;
// Prevent multiple dialog boxes from showing, because they're all called async
@ -271,8 +283,8 @@ void Connection::showTxError(const QString& error)
shown = true;
QMessageBox::critical(
main,
QObject::tr("Transaction Error"),
main,
QObject::tr("Transaction Error"),
QObject::tr("There was an error sending the transaction. The error was:") + "\n\n" + error,
QMessageBox::StandardButton::Ok
);
@ -281,8 +293,8 @@ void Connection::showTxError(const QString& error)
/**
* Prevent all future calls from going through
*/
void Connection::shutdown()
*/
void Connection::shutdown()
{
shutdownInProgress = true;
}

1
src/connection.h

@ -5,6 +5,7 @@
#include "ui_connection.h"
#include "precompiled.h"
using json = nlohmann::json;
class Controller;

27
src/connection.ui

@ -9,10 +9,22 @@
<rect>
<x>0</x>
<y>0</y>
<width>513</width>
<height>201</height>
<width>512</width>
<height>512</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>512</width>
<height>512</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>512</width>
<height>512</height>
</size>
</property>
<property name="windowTitle">
<string>SilentDragonLite</string>
</property>
@ -33,7 +45,7 @@
<number>0</number>
</property>
<item>
<widget class="FilledIconLabel" name="topIcon">
<widget class="QLabel" name="topIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -55,7 +67,7 @@
<item>
<widget class="QLabel" name="status">
<property name="text">
<string>Starting Up</string>
<string>The Dragon Awakens...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -84,13 +96,6 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>FilledIconLabel</class>
<extends>QLabel</extends>
<header>fillediconlabel.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

159
src/contactmodel.cpp

@ -0,0 +1,159 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "contactmodel.h"
#include "addressbook.h"
#include "mainwindow.h"
#include "chatmodel.h"
#include "requestdialog.h"
#include "ui_requestdialog.h"
#include "ui_hushrequest.h"
#include "settings.h"
#include "controller.h"
void ContactModel::addLabel(QString addr, QString label)
{
this->AddressMap[addr] = label;
}
QString ContactModel::getContactbyAddress(QString addr)
{
for(auto& pair : this->AddressMap)
{
}
if(this->AddressMap.count(addr) > 0)
{
return this->AddressMap[addr];
}
return QString("0xdeadbeef");
}
void ContactModel::renderContactList(QListView* view)
{
QStandardItemModel* contact = new QStandardItemModel();
for(auto &c : AddressBook::getInstance()->getAllAddressLabels())
{
QString avatar = c.getAvatar();
QStandardItem* Items1 = new QStandardItem(c.getName());
Items1->setData(QIcon(avatar),Qt::DecorationRole);
contact->appendRow(Items1);
view->setModel(contact);
view->setIconSize(QSize(60,70));
view->setUniformItemSizes(true);
view->setDragDropMode(QAbstractItemView::DropOnly);
view->show();
QString addr = c.getPartnerAddress();
QString label = c.getName();
this->addLabel(addr, label);
}
}
void MainWindow::showRequesthush() {
Ui_hushrequest req;
QDialog d(this);
req.setupUi(&d);
Settings::saveRestore(&d);
QString label = ui->contactNameMemo->text();
for(auto &p : AddressBook::getInstance()->getAllAddressLabels())
{
if (p.getName() == label)
{
QString addr = p.getPartnerAddress();
QString myzaddr = p.getMyAddress();
req.txtFrom->setText(addr);
req.lblAddressInfo->setText(myzaddr);
// Amount textbox
req.txtAmount->setValidator(this->getAmountValidator());
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) {
CAmount amount = CAmount::fromDecimalString(text);
if (Settings::getInstance()->get_currency_name() == "USD") {
req.txtAmountUSD->setText(amount.toDecimalUSDString());
} else if (Settings::getInstance()->get_currency_name() == "EUR") {
req.txtAmountUSD->setText(amount.toDecimalEURString());
} else if (Settings::getInstance()->get_currency_name() == "BTC") {
req.txtAmountUSD->setText(amount.toDecimalBTCString());
} else if (Settings::getInstance()->get_currency_name() == "CNY") {
req.txtAmountUSD->setText(amount.toDecimalCNYString());
} else if (Settings::getInstance()->get_currency_name() == "RUB") {
req.txtAmountUSD->setText(amount.toDecimalRUBString());
} else if (Settings::getInstance()->get_currency_name() == "CAD") {
req.txtAmountUSD->setText(amount.toDecimalCADString());
} else if (Settings::getInstance()->get_currency_name() == "SGD") {
req.txtAmountUSD->setText(amount.toDecimalSGDString());
} else if (Settings::getInstance()->get_currency_name() == "CHF") {
req.txtAmountUSD->setText(amount.toDecimalCHFString());
} else if (Settings::getInstance()->get_currency_name() == "INR") {
req.txtAmountUSD->setText(amount.toDecimalINRString());
} else if (Settings::getInstance()->get_currency_name() == "GBP") {
req.txtAmountUSD->setText(amount.toDecimalGBPString());
} else if (Settings::getInstance()->get_currency_name() == "AUD") {
req.txtAmountUSD->setText(amount.toDecimalBTCString());
}
});
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
if (Settings::getInstance()->get_currency_name() == "USD") {
req.txtAmountUSD->setText(amount.toDecimalUSDString());
} else if (Settings::getInstance()->get_currency_name() == "EUR") {
req.txtAmountUSD->setText(amount.toDecimalEURString());
} else if (Settings::getInstance()->get_currency_name() == "BTC") {
req.txtAmountUSD->setText(amount.toDecimalBTCString());
} else if (Settings::getInstance()->get_currency_name() == "CNY") {
req.txtAmountUSD->setText(amount.toDecimalCNYString());
} else if (Settings::getInstance()->get_currency_name() == "RUB") {
req.txtAmountUSD->setText(amount.toDecimalRUBString());
} else if (Settings::getInstance()->get_currency_name() == "CAD") {
req.txtAmountUSD->setText(amount.toDecimalCADString());
} else if (Settings::getInstance()->get_currency_name() == "SGD") {
req.txtAmountUSD->setText(amount.toDecimalSGDString());
} else if (Settings::getInstance()->get_currency_name() == "CHF") {
req.txtAmountUSD->setText(amount.toDecimalCHFString());
} else if (Settings::getInstance()->get_currency_name() == "INR") {
req.txtAmountUSD->setText(amount.toDecimalINRString());
} else if (Settings::getInstance()->get_currency_name() == "GBP") {
req.txtAmountUSD->setText(amount.toDecimalGBPString());
} else if (Settings::getInstance()->get_currency_name() == "AUD") {
req.txtAmountUSD->setText(amount.toDecimalBTCString());
}
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
req.txtMemo->setLenDisplayLabel(req.lblMemoLen);
req.txtMemo->setMaxLen(400);
req.txtFrom->setFocus();
}
}
if (d.exec() == QDialog::Accepted) {
// Construct a hush Payment URI with the data and pay it immediately.
CAmount amount = CAmount::fromDecimalString(req.txtAmount->text());
QString memoURI = "hush:" + req.lblAddressInfo->text()
+ "?amt=" + amount.toDecimalString()
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
QString sendURI = "hush:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())
+ "?amt=0.0001"
+ "&memo=" + QUrl::toPercentEncoding(memoURI);
// If the disclosed address in the memo doesn't have a balance, it will automatically fallback to the default
// sapling address
this->payhushURI(sendURI, req.lblAddressInfo->text());
}
}

27
src/contactmodel.h

@ -0,0 +1,27 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef CONTACTMODEL_H
#define CONTACTMODEL_H
#include "Model/ContactItem.h"
#include <QListWidget>
#include "mainwindow.h"
class ContactModel
{
public:
MainWindow* main;
std::map<QString, QString> AddressMap;
QString getContactbyAddress(QString addr);
void addLabel(QString addr, QString label);
ContactModel() {}
void renderContactList(QListView* view);
};
#endif

491
src/contactrequest.ui

@ -0,0 +1,491 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>780</width>
<height>351</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>780</width>
<height>351</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>780</width>
<height>351</height>
</size>
</property>
<property name="windowTitle">
<string>Send Contact Request</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Insert a nickname for your contact:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Choose an avatar for your contact:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="8" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Insert a memo for your request:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Your HushChat Address:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="newZaddr">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Create New Address</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0" colspan="6">
<widget class="QLineEdit" name="zaddr">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>650</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Insert the address of your contact:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="5" alignment="Qt::AlignLeft">
<widget class="QLabel" name="myzaddr">
<property name="minimumSize">
<size>
<width>650</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>650</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#d3d7cf;&quot;&gt;Generate your HushChat Address - please wait a second - &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLineEdit" name="labelRequest">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="maxLength">
<number>25</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="comboBoxAvatar">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<item>
<property name="text">
<string>SDLogo</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Duke</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Duke.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Berg</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garfield</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
</iconset>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="11" column="0">
<widget class="QLabel" name="memoSizeChat">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>0/512</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="6">
<widget class="QTextEdit" name="memorequest">
<property name="placeholderText">
<string>Add a memo to your request</string>
</property>
</widget>
</item>
<item row="11" column="3">
<widget class="QPushButton" name="cancel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="11" column="4" colspan="2">
<widget class="QPushButton" name="sendRequestButton">
<property name="text">
<string>Add Contact and Send Request</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>cancel</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>396</x>
<y>262</y>
</hint>
<hint type="destinationlabel">
<x>389</x>
<y>207</y>
</hint>
</hints>
</connection>
<connection>
<sender>sendRequestButton</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>536</x>
<y>262</y>
</hint>
<hint type="destinationlabel">
<x>389</x>
<y>207</y>
</hint>
</hints>
</connection>
</connections>
</ui>

746
src/controller.cpp

@ -1,3 +1,6 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "controller.h"
#include "mainwindow.h"
#include "addressbook.h"
@ -5,11 +8,12 @@
#include "version.h"
#include "camount.h"
#include "websockets.h"
#include "DataStore.h"
template<>
DataStore<QString>* DataStore<QString>::instance = nullptr;
template<>
bool DataStore<QString>::instanced = false;
#include "Model/ChatItem.h"
#include "DataStore/DataStore.h"
ChatModel *chatModel = new ChatModel();
Chat *chat = new Chat();
ContactModel *contactModel = new ContactModel();
using json = nlohmann::json;
@ -87,13 +91,33 @@ void Controller::setConnection(Connection* c)
// Create Sietch zdust addr at startup.
// Using DataStore singelton, to store the data outside of lambda, bing bada boom :D
for(uint8_t i = 0; i < 10; i++)
for(uint8_t i = 0; i < 6; i++)
{
zrpc->createNewSietchZaddr( [=] (json reply) {
QString zdust = QString::fromStdString(reply.get<json::array_t>()[0]);
DataStore<QString>::getInstance()->setData("Sietch" + QString(i), zdust.toUtf8());
DataStore::getSietchDataStore()->setData("Sietch" + QString(i), zdust.toUtf8());
});
}
refreshContacts(
ui->listContactWidget
);
}
std::string Controller::encryptDecrypt(std::string toEncrypt)
{
int radomInteger = rand() % 1000000000 +100000;
char key = radomInteger;
std::string output = toEncrypt;
for (int i = 0; i < toEncrypt.size(); i++)
output[i] = toEncrypt[i] ^ key;
return output;
}
// Build the RPC JSON Parameters for this tx
@ -105,35 +129,72 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx)
json rec = json::object();
//creating the JSON dust parameters in a std::vector to iterate over there during tx
std::vector<json> dust(10);
dust.resize(10, json::object());
std::vector<json> dust(6);
dust.resize(6, json::object());
// Create Sietch zdust addr again to not use it twice.
// Using DataStore singelton, to store the data outside of lambda, bing bada boom :D
for(uint8_t i = 0; i < 10; i++)
for(uint8_t i = 0; i < 6; i++)
{
zrpc->createNewSietchZaddr( [=] (json reply) {
QString zdust = QString::fromStdString(reply.get<json::array_t>()[0]);
DataStore<QString>::getInstance()->setData(QString("Sietch") + QString(i), zdust.toUtf8());
DataStore::getSietchDataStore()->setData(QString("Sietch") + QString(i), zdust.toUtf8());
} );
}
// Set sietch zdust addr to json.
// Using DataStore singelton, to store the data into the dusts, bing bada boom :D
for(uint8_t i = 0; i < 10; i++)
for(uint8_t i = 0; i < 6; i++)
{
dust.at(i)["address"] = DataStore<QString>::getInstance()->getData(QString("Sietch" + QString(i))).toStdString();
dust.at(i)["address"] = DataStore::getSietchDataStore()->getData(QString("Sietch" + QString(i))).toStdString();
}
DataStore<QString>::getInstance()->clear(); // clears the datastore
DataStore::getSietchDataStore()->clear(); // clears the datastore
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
int sizerandomString = rand() % 120 +10;
const int randomStringLength = sizerandomString;
// Dust amt/memo, construct the JSON
for(uint8_t i = 0; i < 10; i++)
QString randomString;
for(int i=0; i<randomStringLength; ++i)
{
dust.at(i)["amount"] = 0;
dust.at(i)["memo"] = "";
int index = qrand() % possibleCharacters.length();
QChar nextChar = possibleCharacters.at(index);
randomString.append(nextChar);
}
for(uint8_t i = 0; i < 6; i++)
{
int length = randomString.length();
int randomSize = rand() % 120 +10;
char *randomHash = NULL;
randomHash = new char[length+1];
strncpy(randomHash, randomString.toLocal8Bit(), length +1);
#define MESSAGE ((const unsigned char *) randomHash)
#define MESSAGE_LEN length
#define MESSAGE_LEN1 length + randomSize
unsigned char hash[crypto_secretstream_xchacha20poly1305_ABYTES];
crypto_generichash(hash, sizeof hash,
MESSAGE, MESSAGE_LEN1,
NULL, 0);
std::string decryptedMemo(reinterpret_cast<char*>(hash),MESSAGE_LEN1);
std::string encrypt = this->encryptDecrypt(decryptedMemo);
QString randomHashafter1 = QByteArray(reinterpret_cast<const char*>(encrypt.c_str()),encrypt.size()).toHex();
dust.at(i)["memo"] = randomHashafter1.toStdString();
}
for(uint8_t i = 0; i < 6; i++)
{
dust.at(i)["amount"] = 0;
}
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
for (int i=0; i < tx.toAddrs.size(); i++)
@ -147,36 +208,15 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx)
allRecepients.push_back(rec) ;
}
int decider = qrand() % ((100 + 1)-1)+ 1;// random int between 1 and 100
//50% chance of adding another zdust, shuffle.
if(decider % 4 == 3)
allRecepients.insert(std::begin(allRecepients), {
dust.at(0),
dust.at(1),
dust.at(2),
dust.at(3),
dust.at(4),
dust.at(5),
dust.at(6),
dust.at(7),
dust.at(8)
dust.at(5)
}) ;
// std::shuffle(allRecepients.begin(),allRecepients.end(),std::random_device());
else
allRecepients.insert(std::begin(allRecepients), {
dust.at(0),
dust.at(1),
dust.at(2),
dust.at(3),
dust.at(4),
dust.at(5),
dust.at(6),
dust.at(7),
dust.at(8),
dust.at(9)
});
// std::shuffle(allRecepients.begin(),allRecepients.end(),std::random_device());
}
void Controller::noConnection()
@ -245,12 +285,15 @@ void Controller::getInfoThenRefresh(bool force)
zrpc->fetchInfo([=] (const json& reply) {
prevCallSucceeded = true;
int curBlock = reply["latest_block_height"].get<json::number_integer_t>();
int longestchain = reply["longestchain"].get<json::number_integer_t>();
int notarized = reply["notarized"].get<json::number_integer_t>();
bool doUpdate = force || (model->getLatestBlock() != curBlock);
int difficulty = reply["difficulty"].get<json::number_integer_t>();
int blocks_until_halving= 340000 - curBlock;
int halving_days = (blocks_until_halving * 150) / (60*60*24) ;
bool doUpdate = force || (model->getLatestBlock() != curBlock);
int longestchain = reply["longestchain"].get<json::number_integer_t>();
int notarized = reply["notarized"].get<json::number_integer_t>();
model->setLatestBlock(curBlock);
if (
Settings::getInstance()->get_currency_name() == "EUR" ||
@ -266,7 +309,11 @@ void Controller::getInfoThenRefresh(bool force)
);
ui->longestchain->setText(
"Block: " + QLocale(QLocale::German).toString(longestchain)
);
ui->difficulty->setText(
QLocale(QLocale::German).toString(difficulty)
);
@ -312,6 +359,7 @@ void Controller::getInfoThenRefresh(bool force)
QString chainName = Settings::getInstance()->isTestnet() ? "test" : "main";
main->statusLabel->setText(chainName + "(" + QString::number(curBlock) + ")");
// use currency ComboBox as input
if (Settings::getInstance()->get_currency_name() == "USD")
@ -329,6 +377,8 @@ void Controller::getInfoThenRefresh(bool force)
" $ " + (QLocale(QLocale::English).toString(cap,'f', 2))
);
}
else if (Settings::getInstance()->get_currency_name() == "EUR")
{
@ -545,8 +595,12 @@ void Controller::getInfoThenRefresh(bool force)
refreshAddresses(); // This calls refreshZSentTransactions() and refreshReceivedZTrans()
refreshTransactions();
}
int lag = longestchain - notarized ;
this->setLag(lag);
}, [=](QString err) {
// hushd has probably disappeared.
this->noConnection();
// Prevent multiple dialog boxes, because these are called async
@ -557,7 +611,7 @@ void Controller::getInfoThenRefresh(bool force)
QMessageBox::critical(
main,
QObject::tr("Connection Error"),
QObject::tr("There was an error connecting to hushd. The error was") + ": \n\n"+ err,
QObject::tr("There was an error connecting to the server. Please check your internet connection. The error was") + ": \n\n"+ err,
QMessageBox::StandardButton::Ok
);
shown = false;
@ -567,6 +621,20 @@ void Controller::getInfoThenRefresh(bool force)
});
}
int Controller::getLag()
{
return _lag;
}
void Controller::setLag(int lag)
{
_lag = lag;
}
void Controller::refreshAddresses()
{
if (!zrpc->haveConnection())
@ -621,7 +689,7 @@ void Controller::processUnspent(const json& reply, QMap<QString, CAmount>* balan
QString txid = QString::fromStdString(it["created_in_txid"]);
CAmount amount = CAmount::fromqint64(it["value"].get<json::number_unsigned_t>());
bool spendable = it["unconfirmed_spent"].is_null() && it["spent"].is_null(); // TODO: Wait for 4 confirmations
bool spendable = it["unconfirmed_spent"].is_null() && it["spent"].is_null(); // TODO: Wait for 1 confirmations
bool pending = !it["unconfirmed_spent"].is_null();
unspentOutputs->push_back(
@ -655,7 +723,9 @@ void Controller::updateUIBalances()
CAmount balAvailable = balT + balVerified;
if (balZ < 0)
balZ = CAmount::fromqint64(0);
double price = (Settings::getInstance()->getBTCPrice() / 1000);
// ui->PriceMemo->setText(" The price of \n one HushChat \n Message is :\n BTC " + (QLocale(QLocale::English).toString(price, 'f',8))
//+ " Messages left :" + ((balTotal.toDecimalhushString()) /0.0001) );
// Balances table
ui->balSheilded->setText(balZ.toDecimalhushString());
ui->balVerified->setText(balVerified.toDecimalhushString());
@ -808,6 +878,7 @@ void Controller::refreshBalances()
CAmount balAvailable = balT + balVerified;
model->setAvailableBalance(balAvailable);
updateUIBalances();
});
// 2. Get the UTXOs
@ -838,115 +909,531 @@ void Controller::refreshBalances()
});
}
void Controller::refreshTransactions()
{
void Controller::refreshTransactions() {
if (!zrpc->haveConnection())
return noConnection();
zrpc->fetchTransactions([=] (json reply) {
QList<TransactionItem> txdata;
for (auto& it : reply.get<json::array_t>())
{
for (auto& it : reply.get<json::array_t>()) {
QString address;
CAmount total_amount;
QList<TransactionItemDetail> items;
long confirmations;
if (it.find("unconfirmed") != it.end() && it["unconfirmed"].get<json::boolean_t>())
if (it.find("unconfirmed") != it.end() && it["unconfirmed"].get<json::boolean_t>()) {
confirmations = 0;
else
} else {
confirmations = model->getLatestBlock() - it["block_height"].get<json::number_integer_t>() + 1;
}
auto txid = QString::fromStdString(it["txid"]);
auto datetime = it["datetime"].get<json::number_integer_t>();
// First, check if there's outgoing metadata
if (!it["outgoing_metadata"].is_null())
{
for (auto o: it["outgoing_metadata"].get<json::array_t>())
{
QString address;
if (!it["outgoing_metadata"].is_null()) {
for (auto o: it["outgoing_metadata"].get<json::array_t>())
{
// if (chatModel->getCidByTx(txid) == QString("0xdeadbeef")){
QString address;
address = QString::fromStdString(o["address"]);
// Sent items are -ve
CAmount amount = CAmount::fromqint64(-1* o["value"].get<json::number_unsigned_t>());
// Check for Memos
if (confirmations == 0) {
chatModel->addconfirmations(txid, confirmations);
}
if ((confirmations == 1) && (chatModel->getConfirmationByTx(txid) != QString("0xdeadbeef"))){
DataStore::getChatDataStore()->clear();
chatModel->killConfirmationCache();
chatModel->killMemoCache();
this->refresh(true);
}
QString memo;
if (!o["memo"].is_null())
memo = QString::fromStdString(o["memo"]);
QString cid;
QString headerbytes;
QString publickey;
if (!o["memo"].is_null()) {
memo = QString::fromStdString(o["memo"].get<json::string_t>());
items.push_back(TransactionItemDetail{address, amount, memo});
total_amount = total_amount + amount;
}
if (memo.startsWith("{")) {
try
{
QJsonDocument headermemo = QJsonDocument::fromJson(memo.toUtf8());
cid = headermemo["cid"].toString();
headerbytes = headermemo["e"].toString();
chatModel->addCid(txid, cid);
chatModel->addHeader(txid, headerbytes);
} catch(...)
{
// Concat all the addresses
QList<QString> addresses;
for (auto item : items)
{
if (item.amount == 0 )
{
}
else
}
}
bool isNotarized;
if (confirmations > getLag())
{
addresses.push_back(item.address);
address = addresses.join(",");
isNotarized = true;
}else{
isNotarized = false;
}
if (chatModel->getCidByTx(txid) != QString("0xdeadbeef")){
cid = chatModel->getCidByTx(txid);
}else{
cid = "";
}
if (chatModel->getHeaderByTx(txid) != QString("0xdeadbeef")){
headerbytes = chatModel->getHeaderByTx(txid);
}else{
headerbytes = "";
}
if (main->getPubkeyByAddress(address) != QString("0xdeadbeef")){
publickey = main->getPubkeyByAddress(address);
}else{
publickey = "";
}
/////We need to filter out Memos smaller then the ciphertext size, or it will dump
if ((memo.startsWith("{") == false) && (headerbytes.length() > 20))
{
QString passphrase = DataStore::getChatDataStore()->getPassword();
QString hashEncryptionKey = passphrase;
int length = hashEncryptionKey.length();
////////////////Generate the secretkey for our message encryption
char *hashEncryptionKeyraw = NULL;
hashEncryptionKeyraw = new char[length+1];
strncpy(hashEncryptionKeyraw, hashEncryptionKey.toLocal8Bit(), length +1);
const QByteArray pubkeyBobArray = QByteArray::fromHex(publickey.toLatin1());
const unsigned char *pubkeyBob = reinterpret_cast<const unsigned char *>(pubkeyBobArray.constData());
#define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw)///////////
#define MESSAGEAS1_LEN length
unsigned char hash1[crypto_kx_SEEDBYTES];
crypto_hash_sha256(hash1,MESSAGEAS1, MESSAGEAS1_LEN);
unsigned char sk[crypto_kx_SECRETKEYBYTES];
unsigned char pk[crypto_kx_PUBLICKEYBYTES];
if (crypto_kx_seed_keypair(pk,sk,
hash1) !=0) {
}
unsigned char server_rx[crypto_kx_SESSIONKEYBYTES], server_tx[crypto_kx_SESSIONKEYBYTES];
////////////////Get the pubkey from Bob, so we can create the share key
/////Create the shared key for sending the message
if (crypto_kx_server_session_keys(server_rx, server_tx,
pk, sk, pubkeyBob) != 0) {
/* Suspicious client public key, bail out */
}
const QByteArray ba = QByteArray::fromHex(memo.toLatin1());
const unsigned char *encryptedMemo = reinterpret_cast<const unsigned char *>(ba.constData());
const QByteArray ba1 = QByteArray::fromHex(headerbytes.toLatin1());
const unsigned char *header = reinterpret_cast<const unsigned char *>(ba1.constData());
int encryptedMemoSize1 = ba.length();
QString memodecrypt;
if (encryptedMemoSize1 > 15)
{
//////unsigned char* as message from QString
#define MESSAGE2 (const unsigned char *) encryptedMemo
///////// length of the encrypted message
#define CIPHERTEXT1_LEN encryptedMemoSize1
///////Message length is smaller then the encrypted message
#define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES
//////Set the length of the decrypted message
unsigned char decrypted[MESSAGE1_LEN];
unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL];
crypto_secretstream_xchacha20poly1305_state state;
/////Our decrypted message is now in decrypted. We need it as QString to render it
/////Only the QString gives weird data, so convert first to std::string
// crypto_secretstream_xchacha20poly1305_keygen(client_rx);
if (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, server_tx) != 0) {
/* Invalid header, no need to go any further */
}
if (crypto_secretstream_xchacha20poly1305_pull
(&state, decrypted, NULL, tag, MESSAGE2, CIPHERTEXT1_LEN, NULL, 0) != 0) {
/* Invalid/incomplete/corrupted ciphertext - abort */
}
txdata.push_back(
TransactionItem{"send", datetime, address, txid,confirmations, items}
);
}
else
{
std::string decryptedMemo(reinterpret_cast<char*>(decrypted),MESSAGE1_LEN);
memodecrypt = QString::fromUtf8( decryptedMemo.data(), decryptedMemo.size());
}else{
memodecrypt = "";
}
/////Now we can convert it to QString
//////////////Give us the output of the decrypted message as debug to see if it was successfully
ChatItem item = ChatItem(
datetime,
address,
QString(""),
memodecrypt,
QString(""),
QString(""),
cid,
txid,
confirmations,
true,
isNotarized,
false
);
DataStore::getChatDataStore()->setData(ChatIDGenerator::getInstance()->generateID(item), item);
updateUIBalances();
}
}
items.push_back(TransactionItemDetail{address, amount, memo});
total_amount = total_amount + amount;
}
{
QList<QString> addresses;
for (auto item : items) {
// Concat all the addresses
addresses.push_back(item.address);
address = addresses.join(",");
}
}
txdata.push_back(TransactionItem{
"send", datetime, address, txid,confirmations, items
});
} else {
// Incoming Transaction
address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"]));
model->markAddressUsed(address);
QString memo;
if (!it["memo"].is_null())
if (!it["memo"].is_null()) {
memo = QString::fromStdString(it["memo"]);
}
items.push_back(
TransactionItemDetail{
address,
CAmount::fromqint64(it["amount"].get<json::number_integer_t>()),
memo
}
);
items.push_back(TransactionItemDetail{
address,
CAmount::fromqint64(it["amount"].get<json::number_integer_t>()),
memo
});
TransactionItem tx{
"Receive",
datetime,
address,
txid,
confirmations,
items
"Receive", datetime, address, txid,confirmations, items
};
txdata.push_back(tx);
QString type;
QString publickey;
QString headerbytes;
QString cid;
QString requestZaddr;
QString contactname;
bool isContact;
if (!it["memo"].is_null()) {
if (memo.startsWith("{")) {
try
{
QJsonDocument headermemo = QJsonDocument::fromJson(memo.toUtf8());
cid = headermemo["cid"].toString();
type = headermemo["t"].toString();
requestZaddr = headermemo["z"].toString();
headerbytes = headermemo["e"].toString();
publickey = headermemo["p"].toString();
chatModel->addCid(txid, cid);
chatModel->addrequestZaddr(txid, requestZaddr);
chatModel->addHeader(txid, headerbytes);
if (publickey.length() > 10){
main->addPubkey(requestZaddr, publickey);
}
} catch(...)
{
}
}
if (chatModel->getCidByTx(txid) != QString("0xdeadbeef")){
cid = chatModel->getCidByTx(txid);
}else{
cid = "";
}
if (chatModel->getrequestZaddrByTx(txid) != QString("0xdeadbeef")){
requestZaddr = chatModel->getrequestZaddrByTx(txid);
}else{
requestZaddr = "";
}
if (chatModel->getHeaderByTx(txid) != QString("0xdeadbeef")){
headerbytes = chatModel->getHeaderByTx(txid);
}else{
headerbytes = "";
}
if (main->getPubkeyByAddress(requestZaddr) != QString("0xdeadbeef")){
publickey = main->getPubkeyByAddress(requestZaddr);
}else{
publickey = "";
}
if (contactModel->getContactbyAddress(requestZaddr) != QString("0xdeadbeef")){
isContact = true;
contactname = contactModel->getContactbyAddress(requestZaddr);
}else{
isContact = false;
contactname = "";
}
bool isNotarized;
if (confirmations > getLag())
{
isNotarized = true;
}else{
isNotarized = false;
}
int position = it["position"].get<json::number_integer_t>();
if ((memo.startsWith("{") == false) && (headerbytes > 0))
{
if (chatModel->getMemoByTx(txid) == QString("0xdeadbeef")){
if (position == 1)
{
chatModel->addMemo(txid, headerbytes);
}else{}
QString passphrase = DataStore::getChatDataStore()->getPassword();
QString hashEncryptionKey = passphrase;
int length = hashEncryptionKey.length();
char *hashEncryptionKeyraw = NULL;
hashEncryptionKeyraw = new char[length+1];
strncpy(hashEncryptionKeyraw, hashEncryptionKey.toLocal8Bit(), length +1);
//const QByteArray ba2 = QByteArray::fromHex(hashEncryptionKey.toLatin1());
// const unsigned char *hashEncryptionKeyraw = reinterpret_cast<const unsigned char *>(ba2.constData());
const QByteArray pubkeyBobArray = QByteArray::fromHex(publickey.toLatin1());
const unsigned char *pubkeyBob = reinterpret_cast<const unsigned char *>(pubkeyBobArray.constData());
#define MESSAGEAS1 ((const unsigned char *) hashEncryptionKeyraw)///////////
#define MESSAGEAS1_LEN length
unsigned char hash1[crypto_kx_SEEDBYTES];
crypto_hash_sha256(hash1,MESSAGEAS1, MESSAGEAS1_LEN);
unsigned char sk[crypto_kx_SECRETKEYBYTES];
unsigned char pk[crypto_kx_PUBLICKEYBYTES];
if (crypto_kx_seed_keypair(pk,sk,
hash1) !=0) {
}
unsigned char client_rx[crypto_kx_SESSIONKEYBYTES], client_tx[crypto_kx_SESSIONKEYBYTES];
////////////////Get the pubkey from Bob, so we can create the share key
/////Create the shared key for sending the message
if (crypto_kx_client_session_keys(client_rx, client_tx,
pk, sk, pubkeyBob) != 0) {
/* Suspicious client public key, bail out */
}
const QByteArray ba = QByteArray::fromHex(memo.toLatin1());
const unsigned char *encryptedMemo = reinterpret_cast<const unsigned char *>(ba.constData());
const QByteArray ba1 = QByteArray::fromHex(headerbytes.toLatin1());
const unsigned char *header = reinterpret_cast<const unsigned char *>(ba1.constData());
int encryptedMemoSize1 = ba.length();
int headersize = ba1.length();
//////unsigned char* as message from QString
#define MESSAGE2 (const unsigned char *) encryptedMemo
///////// length of the encrypted message
#define CIPHERTEXT1_LEN encryptedMemoSize1
///////Message length is smaller then the encrypted message
#define MESSAGE1_LEN encryptedMemoSize1 - crypto_secretstream_xchacha20poly1305_ABYTES
//////Set the length of the decrypted message
unsigned char decrypted[MESSAGE1_LEN];
unsigned char tag[crypto_secretstream_xchacha20poly1305_TAG_FINAL];
crypto_secretstream_xchacha20poly1305_state state;
/////Our decrypted message is now in decrypted. We need it as QString to render it
/////Only the QString gives weird data, so convert first to std::string
// crypto_secretstream_xchacha20poly1305_keygen(client_rx);
if (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, client_rx) != 0) {
/* Invalid header, no need to go any further */
}
if (crypto_secretstream_xchacha20poly1305_pull
(&state, decrypted, NULL, tag, MESSAGE2, CIPHERTEXT1_LEN, NULL, 0) != 0) {
/* Invalid/incomplete/corrupted ciphertext - abort */
}
std::string decryptedMemo(reinterpret_cast<char*>(decrypted),MESSAGE1_LEN);
/////Now we can convert it to QString
QString memodecrypt;
memodecrypt = QString::fromUtf8( decryptedMemo.data(), decryptedMemo.size());
// }
//////////////Give us the output of the decrypted message as debug to see if it was successfully
ChatItem item = ChatItem(
datetime,
address,
contactname,
memodecrypt,
requestZaddr,
type,
cid,
txid,
confirmations,
false,
isNotarized,
isContact
);
DataStore::getChatDataStore()->setData(ChatIDGenerator::getInstance()->generateID(item), item);
}else{
}
}else{
ChatItem item = ChatItem(
datetime,
address,
contactname,
memo,
requestZaddr,
type,
cid,
txid,
confirmations,
false,
isNotarized,
isContact
);
DataStore::getChatDataStore()->setData(ChatIDGenerator::getInstance()->generateID(item), item);
}
}
}
}
}
// Calculate the total unspent amount that's pending. This will need to be
// shown in the UI so the user can keep track of pending funds
CAmount totalPending;
for (auto txitem : txdata)
{
if (txitem.confirmations == 0)
{
for (auto item: txitem.items)
{
for (auto txitem : txdata) {
if (txitem.confirmations == 0) {
for (auto item: txitem.items) {
totalPending = totalPending + item.amount;
}
}
@ -957,9 +1444,26 @@ void Controller::refreshTransactions()
// Update UI Balance
updateUIBalances();
// Update model data, which updates the table view
transactionsTableModel->replaceData(txdata);
});
// Update model data, which updates the table view
transactionsTableModel->replaceData(txdata);
chat->renderChatBox(ui, ui->listChat,ui->memoSizeChat);
ui->listChat->verticalScrollBar()->setValue(
ui->listChat->verticalScrollBar()->maximum());
});
}
void Controller::refreshChat(QListView *listWidget, QLabel *label)
{
chat->renderChatBox(ui, listWidget, label);
ui->listChat->verticalScrollBar()->setValue(
ui->listChat->verticalScrollBar()->maximum());
}
void Controller::refreshContacts(QListView *listWidget)
{
contactModel->renderContactList(listWidget);
}
// If the wallet is encrpyted and locked, we need to unlock it
@ -1523,9 +2027,27 @@ void Controller::shutdownhushd()
QDialog d(main);
Ui_ConnectionDialog connD;
connD.setupUi(&d);
connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256));
auto theme = Settings::getInstance()->get_theme_name();
auto size = QSize(512,512);
if (theme == "Dark" || theme == "Midnight") {
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-startup-dark.gif");;
movie2->setScaledSize(size);
qDebug() << "Animation dark loaded";
connD.topIcon->setMovie(movie2);
movie2->start();
connD.status->setText(QObject::tr("Please wait for SilentDragonLite to exit"));
connD.statusDetail->setText(QObject::tr("Waiting for hushd to exit"));
} else {
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated-startup.gif");;
movie1->setScaledSize(size);
qDebug() << "Animation light loaded";
connD.topIcon->setMovie(movie1);
movie1->start();
connD.status->setText(QObject::tr("Please wait for SilentDragonLite to exit"));
connD.statusDetail->setText(QObject::tr("Waiting for hushd to exit"));
}
bool finished = false;
zrpc->saveWallet([&] (json) {
if (!finished)

18
src/controller.h

@ -1,3 +1,6 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#ifndef RPCCLIENT_H
#define RPCCLIENT_H
@ -11,7 +14,11 @@
#include "mainwindow.h"
#include "liteinterface.h"
#include "connection.h"
#include "chatmodel.h"
#include "Chat/Chat.h"
#include "Model/ContactRequestChatItem.h"
#include "Model/ContactItem.h"
#include "contactmodel.h"
using json = nlohmann::json;
struct WatchedTx {
@ -33,7 +40,11 @@ public:
Connection* getConnection() { return zrpc->getConnection(); }
void setConnection(Connection* c);
void refresh(bool force = false);
void refreshAddresses();
void refreshAddresses();
int getLag();
void setLag(int lag);
int _lag;
std::string encryptDecrypt(std::string);
void checkForUpdate(bool silent = true);
void refreshZECPrice();
@ -71,6 +82,9 @@ public:
void refreshAUDCAP();
void refreshChat(QListView *listWidget, QLabel *label);
void refreshContacts(QListView *listWidget);
void executeStandardUITransaction(Tx tx);
void executeTransaction(Tx tx,

132
src/deposithush.ui

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>deposithush</class>
<widget class="QDialog" name="deposithush">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>792</width>
<height>650</height>
</rect>
</property>
<property name="windowTitle">
<string>Deposit Hush</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QTextBrowser" name="textBrowser">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>71</height>
</size>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:16pt;&quot;&gt;Please use the following hush address to transfer funds to SilentDragonLite. You can either copy the address or use the QR Code. &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;QR Code of your Hush Address&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; text-decoration: underline;&quot;&gt;Your Hush Address &lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="zaddr">
<property name="text">
<string>Hush zaddr</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="CopyAddress">
<property name="text">
<string>Copy Address</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRCodeLabel" name="qrcodeDisplayDeposit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: #fff</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QRCodeLabel</class>
<extends>QLabel</extends>
<header>qrcodelabel.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>deposithush</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>deposithush</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

153
src/encryption.ui

@ -10,80 +10,96 @@
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>Encrypt Your Wallet</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Encryption Password:</string>
<string>Encryption Passphrase:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Confirm Password:</string>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="txtConfirmPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</widget>
</spacer>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="lblPasswordMatch">
<property name="styleSheet">
<string notr="true">color: red;</string>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Passwords don't match</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:14pt; color:#ef2929;&quot;&gt;WARNING:&lt;/span&gt; If you forget your passphrase, the only way to recover the wallet is from the seed phrase. If you don't have a backup of your seed phrase, please do it now!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<item row="10" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>WARNING: If you forget your password, the only way to recover the wallet is from the seed phrase.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<item row="8" column="1" colspan="2">
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Confirm Passphrase:</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<item row="11" column="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -95,7 +111,7 @@
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<item row="0" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -108,18 +124,51 @@
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<spacer name="verticalSpacer">
<item row="4" column="0" rowspan="2" colspan="3">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QLineEdit" name="txtConfirmPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</spacer>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblPasswordMatch">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Passphrase don't match&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;16 letters minimum&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>

60
src/firsttimewizard.cpp

@ -3,6 +3,8 @@
#include "ui_newseed.h"
#include "ui_restoreseed.h"
#include "ui_newwallet.h"
#include "mainwindow.h"
#include "DataStore/DataStore.h"
#include "../lib/silentdragonlitelib.h"
@ -38,31 +40,74 @@ int FirstTimeWizard::nextId() const {
NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent) {
setTitle("Create or Restore wallet.");
QWidget* pageWidget = new QWidget();
Ui_CreateWalletForm form;
form.setupUi(pageWidget);
auto fnPasswordEdited = [=](const QString&) {
// Enable the Finish button if the passwords match.
QString Password = form.txtPassword->text();
if (!form.txtPassword->text().isEmpty() &&
form.txtPassword->text() == form.txtConfirmPassword->text() && Password.size() >= 16) {
form.lblPasswordMatch->setText("");
parent->button(QWizard::CommitButton)->setEnabled(true);
setButtonText(QWizard::CommitButton, "Next");
form.radioRestoreWallet->setEnabled(true);
form.radioNewWallet->setEnabled(true);
form.radioNewWallet->setChecked(true);
// Exclusive buttons
DataStore::getChatDataStore()->setPassword(Password);
//main->setPassword(Password);
//qDebug()<<"Objekt gesetzt";
// Exclusive buttons
QObject::connect(form.radioNewWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
form.radioRestoreWallet->setChecked(false);
}
});
QObject::connect(form.radioRestoreWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
form.radioNewWallet->setChecked(false);
}
});
form.radioNewWallet->setChecked(true);
registerField("intro.new", form.radioNewWallet);
} else {
form.lblPasswordMatch->setText(tr("Passphrase don't match or You have entered too few letters (16 minimum)"));
parent->button(QWizard::CommitButton)->setEnabled(false);
form.radioRestoreWallet->setEnabled(false);
form.radioNewWallet->setEnabled(false);
}
};
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pageWidget);
setLayout(layout);
QObject::connect(form.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited);
QObject::connect(form.txtPassword, &QLineEdit::textChanged, fnPasswordEdited);
registerField("intro.new", form.radioNewWallet);
form.radioRestoreWallet->setEnabled(false);
form.radioNewWallet->setEnabled(false);
setCommitPage(true);
setButtonText(QWizard::CommitButton, "Next");
}
NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
@ -81,6 +126,7 @@ NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
void NewSeedPage::initializePage() {
// Call the library to create a new wallet.
char* resp = litelib_initialize_new(parent->dangerous, parent->server.toStdString().c_str());
QString reply = litelib_process_response(resp);
@ -90,7 +136,11 @@ void NewSeedPage::initializePage() {
} else {
QString seed = QString::fromStdString(parsed["seed"].get<json::string_t>());
form.txtSeed->setPlainText(seed);
}
}
// Will be called just before closing. Make sure we can save the seed in the wallet
@ -175,4 +225,4 @@ bool RestoreSeedPage::validatePage() {
return true;
}
}
}
}

12
src/firsttimewizard.h

@ -5,11 +5,18 @@
#include "ui_newseed.h"
#include "ui_restoreseed.h"
#include "mainwindow.h"
class FirstTimeWizard: public QWizard
{
public:
FirstTimeWizard(bool dangerous, QString server);
protected:
int nextId() const;
@ -27,11 +34,16 @@ private:
friend class NewOrRestorePage;
friend class NewSeedPage;
friend class RestoreSeedPage;
};
class NewOrRestorePage: public QWizardPage {
public:
NewOrRestorePage(FirstTimeWizard* parent);
};

72
src/fundhushchat.ui

@ -0,0 +1,72 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>Dialog</class>
<widget class="QDialog" name="Dialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="geometry" >
<rect>
<x>30</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</widget>
<pixmapfunction></pixmapfunction>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

156
src/hushrequest.ui

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>hushrequest</class>
<widget class="QDialog" name="hushrequest">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>663</width>
<height>529</height>
</rect>
</property>
<property name="windowTitle">
<string>Request Payment</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblPixmap">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblHeader">
<property name="text">
<string>Request payment from a Sapling address. You'll send a hush 0.0001 transaction to the address with a hush payment URI. The memo will be included in the transaction when the address pays you.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblAddress">
<property name="text">
<string>Request From</string>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>541</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="txtFrom">
<property name="text">
<string>zaddr</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblAmount">
<property name="text">
<string>Amount in </string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="txtAmount">
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>Amount</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="txtAmountUSD">
<property name="text">
<string>Amount USD</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Memo</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="lblMemoLen">
<property name="text">
<string notr="true">0 / 512</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="MemoEdit" name="txtMemo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>My Address</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="lblAddressInfo">
<property name="text">
<string>The recipient will see this address in the &quot;to&quot; field when they pay your request.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MemoEdit</class>
<extends>QPlainTextEdit</extends>
<header>memoedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

803
src/mainwindow.cpp

@ -1,3 +1,6 @@
// Copyright 2019-2020 The Hush developers
// GPLv3
#include "mainwindow.h"
#include "addressbook.h"
#include "viewalladdresses.h"
@ -14,16 +17,48 @@
#include "settings.h"
#include "version.h"
#include "connection.h"
#include "ui_contactrequest.h"
#include "ui_deposithush.h"
#include "ui_requestContactDialog.h"
#include "chatmodel.h"
#include "requestdialog.h"
#include "ui_startupencryption.h"
#include "ui_removeencryption.h"
#include "websockets.h"
#include "sodium.h"
#include "sodium/crypto_generichash_blake2b.h"
#include <QRegularExpression>
#include "FileSystem/FileSystem.h"
#include "Crypto/passwd.h"
#include "Crypto/FileEncryption.h"
#include "DataStore/DataStore.h"
#include "firsttimewizard.h"
using json = nlohmann::json;
#ifdef Q_OS_WIN
auto dirwallet = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.dat");
auto dirwalletenc = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet-enc.dat");
auto dirwalletbackup = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.datBackup");
#endif
#ifdef Q_OS_MACOS
auto dirwallet = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.dat");
auto dirwalletenc = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet-enc.dat");
auto dirwalletbackup = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.datBackup");
#endif
#ifdef Q_OS_LINUX
auto dirwallet = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet.dat");
auto dirwalletenc = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet-enc.dat");
auto dirwalletbackup = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet.datBackup");
#endif
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// Include css
QString theme_name;
try
@ -32,15 +67,28 @@ MainWindow::MainWindow(QWidget *parent) :
}
catch (...)
{
theme_name = "default";
theme_name = "Dark";
}
this->slot_change_theme(theme_name);
ui->setupUi(this);
logger = new Logger(this, QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite-wallet.log"));
// Check for encryption
if(fileExists(dirwalletenc))
{
this->removeWalletEncryptionStartUp();
}
ui->memoTxtChat->setAutoFillBackground(false);
ui->memoTxtChat->setPlaceholderText("Send Message");
ui->memoTxtChat->setTextColor(Qt::white);
// Status Bar
setupStatusBar();
@ -152,6 +200,7 @@ MainWindow::MainWindow(QWidget *parent) :
setupReceiveTab();
setupBalancesTab();
setuphushdTab();
setupchatTab();
rpc = new Controller(this);
@ -167,6 +216,12 @@ MainWindow::MainWindow(QWidget *parent) :
createWebsocket(wormholecode);
}
}
bool MainWindow::fileExists(QString path)
{
QFileInfo check_file(path);
return (check_file.exists() && check_file.isFile());
}
void MainWindow::createWebsocket(QString wormholecode) {
qDebug() << "Listening for app connections on port 8777";
@ -221,6 +276,10 @@ void MainWindow::doClose() {
closeEvent(nullptr);
}
void MainWindow::doClosePw() {
closeEventpw(nullptr);
}
void MainWindow::closeEvent(QCloseEvent* event) {
QSettings s;
@ -230,134 +289,370 @@ void MainWindow::closeEvent(QCloseEvent* event) {
s.sync();
// Let the RPC know to shut down any running service.
rpc->shutdownhushd();
int passphraselenght = DataStore::getChatDataStore()->getPassword().length();
// Check is encryption is ON for SDl
if(passphraselenght > 0)
{
// delete old file before
//auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QFile fileoldencryption(dirwalletenc);
fileoldencryption.remove();
// Encrypt our wallet.dat
QString str = DataStore::getChatDataStore()->getPassword();
// QString str = ed.txtPassword->text(); // data comes from user inputs
int length = str.length();
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, str.toLocal8Bit(), length +1);
#define MESSAGE ((const unsigned char *) sequence)
#define MESSAGE_LEN length
unsigned char hash[crypto_secretstream_xchacha20poly1305_KEYBYTES];
crypto_hash_sha256(hash,MESSAGE, MESSAGE_LEN);
#define PASSWORD sequence
#define KEY_LEN crypto_box_SEEDBYTES
/////////we use the Hash of the Password as Salt, not perfect but still a good solution.
unsigned char key[KEY_LEN];
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
// auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QString source_file = dir.filePath("addresslabels.dat");
QString target_enc_file = dir.filePath("addresslabels.dat.enc");
QString sourceWallet_file = dirwallet;
QString target_encWallet_file = dirwalletenc;
FileEncryption::encrypt(target_enc_file, source_file, key);
FileEncryption::encrypt(target_encWallet_file, sourceWallet_file, key);
///////////////// we rename the plaintext wallet.dat to Backup, for testing.
QFile wallet(dirwallet);
QFile address(dir.filePath("addresslabels.dat"));
wallet.remove();
address.remove();
}
// Bubble up
if (event)
QMainWindow::closeEvent(event);
}
void MainWindow::closeEventpw(QCloseEvent* event) {
// Let the RPC know to shut down any running service.
rpc->shutdownhushd();
}
void MainWindow::encryptWallet() {
// Check if wallet is already encrypted
auto encStatus = rpc->getModel()->getEncryptionStatus();
if (encStatus.first) {
QMessageBox::information(this, tr("Wallet is already encrypted"),
tr("Your wallet is already encrypted with a password.\nPlease use 'Remove Wallet Encryption' if you want to remove the wallet encryption."),
QMessageBox::Ok
);
return;
}
QDialog d(this);
Ui_encryptionDialog ed;
ed.setupUi(&d);
// Handle edits on the password box
auto fnPasswordEdited = [=](const QString&) {
// Enable the OK button if the passwords match.
QString password = ed.txtPassword->text();
if (!ed.txtPassword->text().isEmpty() &&
ed.txtPassword->text() == ed.txtConfirmPassword->text()) {
ed.txtPassword->text() == ed.txtConfirmPassword->text() && password.size() >= 16) {
ed.lblPasswordMatch->setText("");
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
} else {
ed.lblPasswordMatch->setText(tr("Passwords don't match"));
//ed.lblPasswordMatch->setText(tr("Passphrase don't match or You have entered too few letters (16 minimum)"));
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
};
QObject::connect(ed.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited);
QObject::connect(ed.txtPassword, &QLineEdit::textChanged, fnPasswordEdited);
ed.txtPassword->setText("");
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
if (d.exec() == QDialog::Accepted)
{
auto fnShowError = [=](QString title, const json& res) {
QMessageBox::critical(this, title,
tr("Error was:\n") + QString::fromStdString(res.dump()),
QMessageBox::Ok
);
};
QString passphrase = ed.txtPassword->text(); // data comes from user inputs
int length = passphrase.length();
DataStore::getChatDataStore()->setPassword(passphrase);
if (d.exec() == QDialog::Accepted) {
rpc->encryptWallet(ed.txtPassword->text(), [=](json res) {
if (isJsonResultSuccess(res)) {
// Save the wallet
rpc->saveWallet([=] (json reply) {
if (isJsonResultSuccess(reply)) {
QMessageBox::information(this, tr("Wallet Encrypted"),
tr("Your wallet was successfully encrypted! The password will be needed to send funds or export private keys."),
QMessageBox::Ok
);
} else {
fnShowError(tr("Wallet Encryption Failed"), reply);
}
});
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, passphrase.toLocal8Bit(), length +1);
// And then refresh the UI
rpc->refresh(true);
} else {
fnShowError(tr("Wallet Encryption Failed"), res);
}
});
#define MESSAGE ((const unsigned char *) sequence)
#define MESSAGE_LEN length
unsigned char hash[crypto_secretstream_xchacha20poly1305_KEYBYTES];
crypto_hash_sha256(hash,MESSAGE, MESSAGE_LEN);
#define PASSWORD sequence
#define KEY_LEN crypto_box_SEEDBYTES
/////////we use the Hash of the Password as Salt, not perfect but still a good solution.
unsigned char key[KEY_LEN];
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QString source_file = dir.filePath("addresslabels.dat");
QString target_enc_file = dir.filePath("addresslabels.dat.enc");
QString sourceWallet_file = dirwallet;
QString target_encWallet_file = dirwalletenc;
FileEncryption::encrypt(target_enc_file, source_file, key);
FileEncryption::encrypt(target_encWallet_file, sourceWallet_file, key);
QFile wallet(dirwallet);
QFile address(dir.filePath("addresslabels.dat"));
wallet.rename(dirwalletbackup);
address.rename(dir.filePath("addresslabels.datBackup"));
QMessageBox::information(this, tr("Wallet Encryption Success"),
QString("Successfully encrypted your wallet"),
QMessageBox::Ok
);
}
}
void MainWindow::removeWalletEncryption() {
// Check if wallet is already encrypted
auto encStatus = rpc->getModel()->getEncryptionStatus();
if (!encStatus.first) {
QDialog d(this);
Ui_removeencryption ed;
ed.setupUi(&d);
if (fileExists(dirwalletenc) == false) {
QMessageBox::information(this, tr("Wallet is not encrypted"),
tr("Your wallet is not encrypted with a password."),
tr("Your wallet is not encrypted with a passphrase."),
QMessageBox::Ok
);
return;
}
bool ok;
QString password = QInputDialog::getText(this, tr("Wallet Password"),
tr("Please enter your wallet password"), QLineEdit::Password, "", &ok);
auto fnPasswordEdited = [=](const QString&) {
QString password = ed.txtPassword->text();
// Enable the OK button if the passwords match.
if (!ed.txtPassword->text().isEmpty() &&
ed.txtPassword->text() == ed.txtConfirmPassword->text() && password.size() >= 16) {
ed.lblPasswordMatch->setText("");
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
} else {
ed.lblPasswordMatch->setText(tr("Passwords don't match"));
ed.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
// If cancel was pressed, just return
if (!ok) {
return;
}
};
QObject::connect(ed.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited);
QObject::connect(ed.txtPassword, &QLineEdit::textChanged, fnPasswordEdited);
if (d.exec() == QDialog::Accepted)
{
QString str = ed.txtPassword->text(); // data comes from user inputs
int length = str.length();
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, str.toLocal8Bit(), length +1);
#define MESSAGE ((const unsigned char *) sequence)
#define MESSAGE_LEN length
unsigned char hash[crypto_secretstream_xchacha20poly1305_KEYBYTES];
crypto_hash_sha256(hash,MESSAGE, MESSAGE_LEN);
#define PASSWORD sequence
#define KEY_LEN crypto_box_SEEDBYTES
/////////we use the Hash of the Password as Salt, not perfect but still a good solution.
unsigned char key[KEY_LEN];
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QString target_encwallet_file = dirwalletenc;
QString target_decwallet_file = dirwallet;
QString target_encaddr_file = dir.filePath("addresslabels.dat.enc");
QString target_decaddr_file = dir.filePath("addresslabels.dat");
FileEncryption::decrypt(target_decwallet_file, target_encwallet_file, key);
FileEncryption::decrypt(target_decaddr_file, target_encaddr_file, key);
QFile filencrypted(dirwalletenc);
QFile wallet(dirwallet);
if (wallet.size() > 0)
{
QMessageBox::information(this, tr("Wallet decryption Success"),
QString("Successfully delete the encryption"),
QMessageBox::Ok
);
filencrypted.remove();
}else{
QMessageBox::critical(this, tr("Wallet Encryption Failed"),
QString("False password, please try again"),
QMessageBox::Ok
);
this->removeWalletEncryption();
}
if (password.isEmpty()) {
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
tr("Please enter a password to decrypt your wallet!"),
QMessageBox::Ok
);
return;
}
}
rpc->removeWalletEncryption(password, [=] (json res) {
if (isJsonResultSuccess(res)) {
// Save the wallet
rpc->saveWallet([=] (json reply) {
if(isJsonResultSuccess(reply)) {
QMessageBox::information(this, tr("Wallet Encryption Removed"),
tr("Your wallet was successfully decrypted! You will no longer need a password to send funds or export private keys."),
QMessageBox::Ok
);
} else {
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
QString::fromStdString(reply["error"].get<json::string_t>()),
QMessageBox::Ok
);
}
});
void MainWindow::removeWalletEncryptionStartUp() {
QDialog d(this);
Ui_startup ed;
ed.setupUi(&d);
if (d.exec() == QDialog::Accepted)
{
QString password = ed.txtPassword->text(); // data comes from user inputs
int length = password.length();
DataStore::getChatDataStore()->setPassword(password);
char *sequence = NULL;
sequence = new char[length+1];
strncpy(sequence, password.toLocal8Bit(), length +1);
#define MESSAGE ((const unsigned char *) sequence)
#define MESSAGE_LEN length
unsigned char hash[crypto_secretstream_xchacha20poly1305_KEYBYTES];
crypto_hash_sha256(hash,MESSAGE, MESSAGE_LEN);
#define PASSWORD sequence
#define KEY_LEN crypto_box_SEEDBYTES
/////////we use the Hash of the Password as Salt, not perfect but still a good solution.
unsigned char key[KEY_LEN];
// And then refresh the UI
rpc->refresh(true);
} else {
QMessageBox::critical(this, tr("Wallet Decryption Failed"),
QString::fromStdString(res["error"].get<json::string_t>()),
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), hash,
crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
{
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QString target_encwallet_file = dirwalletenc;
QString target_decwallet_file = dirwallet;
QString target_encaddr_file = dir.filePath("addresslabels.dat.enc");
QString target_decaddr_file = dir.filePath("addresslabels.dat");
FileEncryption::decrypt(target_decwallet_file, target_encwallet_file, key);
FileEncryption::decrypt(target_decaddr_file, target_encaddr_file, key);
}
auto dirHome = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
QFile wallet(dirwallet);
//QFile backup(dirHome.filePath(".silentdragonlite/silentdragonlite-wallet.datBACKUP"));*/
if (wallet.size() > 0)
{
if (fileExists(dirwalletbackup))
{
QMessageBox::information(this, tr("You still have plaintext data on your disk!"),
QString("WARNING: Delete it only if you have a backup of your Wallet Seed."),
QMessageBox::Ok
);
// backup.remove();
}
QMessageBox::information(this, tr("Wallet Encryption Success"),
QString("SDL is ready to Rock"),
QMessageBox::Ok
);
}else{
QMessageBox::critical(this, tr("Wallet Encryption Failed"),
QString("false password please try again"),
QMessageBox::Ok
);
}
});
this->removeWalletEncryptionStartUp();
}
}else{
this->doClosePw();
}
}
QString MainWindow::getPassword()
{
return _password;
}
void MainWindow::setPassword(QString password)
{
_password = password;
}
void MainWindow::setupStatusBar() {
@ -368,6 +663,7 @@ void MainWindow::setupStatusBar() {
loadingMovie->start();
loadingLabel->setAttribute(Qt::WA_NoSystemBackground);
loadingLabel->setMovie(loadingMovie);
ui->statusBar->addPermanentWidget(loadingLabel);
loadingLabel->setVisible(false);
@ -429,9 +725,6 @@ void MainWindow::setupSettingsModal() {
this->slot_change_currency(currency_name);
;
// Setup theme combo
int theme_index = settings.comboBoxTheme->findText(Settings::getInstance()->get_theme_name(), Qt::MatchExactly);
settings.comboBoxTheme->setCurrentIndex(theme_index);
@ -454,7 +747,7 @@ void MainWindow::setupSettingsModal() {
// Tell the user to restart
QMessageBox::information(this, tr("Currency Change"), tr("This change can take a few seconds."), QMessageBox::Ok);
});
// Check for updates
settings.chkCheckUpdates->setChecked(Settings::getInstance()->getCheckForUpdates());
@ -767,6 +1060,27 @@ void MainWindow::exportSeed() {
});
}
void MainWindow::addPubkey(QString requestZaddr, QString pubkey)
{
this->pubkeyMap[requestZaddr] = pubkey;
}
QString MainWindow::getPubkeyByAddress(QString requestZaddr)
{
for(auto& pair : this->pubkeyMap)
{
}
if(this->pubkeyMap.count(requestZaddr) > 0)
{
return this->pubkeyMap[requestZaddr];
}
return QString("0xdeadbeef");
}
void MainWindow::exportAllKeys() {
exportKeys("");
}
@ -845,6 +1159,35 @@ void MainWindow::setupBalancesTab() {
ui->unconfirmedWarning->setVisible(false);
ui->lblSyncWarning->setVisible(false);
ui->lblSyncWarningReceive->setVisible(false);
QObject::connect(ui->depositHushButton, &QPushButton::clicked, [=](){
Ui_deposithush deposithush;
QDialog dialog(this);
deposithush.setupUi(&dialog);
Settings::saveRestore(&dialog);
QList<QString> allAddresses;
allAddresses = getRPC()->getModel()->getAllZAddresses();
QString depositzaddr = allAddresses[1];
deposithush.qrcodeDisplayDeposit->setQrcodeString(depositzaddr);
deposithush.zaddr->setText(depositzaddr);
QObject::connect(deposithush.CopyAddress, &QPushButton::clicked, [=](){
QGuiApplication::clipboard()->setText(depositzaddr);
ui->statusBar->showMessage(tr("Copied to clipboard"), 3 * 1000);
});
dialog.exec();
});
// Setup context menu on balances tab
@ -878,6 +1221,7 @@ void MainWindow::setupBalancesTab() {
menu.exec(ui->balancesTable->viewport()->mapToGlobal(pos));
});
}
void MainWindow::setuphushdTab() {
@ -899,8 +1243,22 @@ void MainWindow::setupTransactionsTab() {
});
// Set up context menu on transactions tab
auto theme = Settings::getInstance()->get_theme_name();
if (theme == "Dark" || theme == "Midnight") {
ui->listChat->setStyleSheet("background-image: url(:/icons/res/sdlogo.png) ;background-attachment: fixed ;background-position: center center ;background-repeat: no-repeat;background-size: cover");
}
if (theme == "Default") {ui->listChat->setStyleSheet("background-image: url(:/icons/res/sdlogo2.png) ;background-attachment: fixed ;background-position: center center ;background-repeat: no-repeat;background-size: cover");}
ui->listChat->setResizeMode(QListView::Adjust);
ui->listChat->setWordWrap(true);
ui->listChat->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->listChat->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->listChat->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->listChat->setMinimumSize(200,350);
ui->listChat->setItemDelegate(new ListViewDelegate());
ui->listChat->show();
ui->transactionsTable->setContextMenuPolicy(Qt::CustomContextMenu);
// Table right click
QObject::connect(ui->transactionsTable, &QTableView::customContextMenuRequested, [=] (QPoint pos) {
QModelIndex index = ui->transactionsTable->indexAt(pos);
@ -974,13 +1332,263 @@ void MainWindow::setupTransactionsTab() {
qApp->processEvents();
// Click the memo button
this->memoButtonClicked(1, true);
this->memoButtonClicked(1, true);
});
}
}
menu.exec(ui->transactionsTable->viewport()->mapToGlobal(pos));
});
}
void MainWindow::setupchatTab() {
/////////////Setting Icons for Chattab and different themes
auto theme = Settings::getInstance()->get_theme_name();
if (theme == "Dark" || theme == "Midnight") {
QPixmap send(":/icons/res/send-white.png");
QIcon sendIcon(send);
ui->sendChatButton->setIcon(sendIcon);
QPixmap notification(":/icons/res/requestWhite.png");
QIcon notificationIcon(notification);
ui->pushContact->setIcon(notificationIcon);
QPixmap addContact(":/icons/res/addContactWhite.png");
QIcon addContactIcon(addContact);
ui->safeContactRequest->setIcon(addContactIcon);
QPixmap newAddr(":/icons/res/getAddrWhite.png");
QIcon addnewAddrIcon(newAddr);
ui->givemeZaddr->setIcon(addnewAddrIcon);
ui->memoTxtChat->setTextColor("White");
}else{
QPixmap send(":/icons/res/sendBlack.png");
QIcon sendIcon(send);
ui->sendChatButton->setIcon(sendIcon);
QPixmap notification(":/icons/res/requestBlack.png");
QIcon notificationIcon(notification);
ui->pushContact->setIcon(notificationIcon);
QPixmap addContact(":/icons/res/addContactBlack.png");
QIcon addContactIcon(addContact);
ui->safeContactRequest->setIcon(addContactIcon);
QPixmap newAddr(":/icons/res/getAddrBlack.png");
QIcon addnewAddrIcon(newAddr);
ui->givemeZaddr->setIcon(addnewAddrIcon);
ui->memoTxtChat->setTextColor("Black");
}
QObject::connect(ui->sendChatButton, &QPushButton::clicked, this, &MainWindow::sendChat);
QObject::connect(ui->safeContactRequest, &QPushButton::clicked, this, &MainWindow::addContact);
QObject::connect(ui->pushContact, &QPushButton::clicked, this , &MainWindow::renderContactRequest);
ui->contactNameMemo->setText("");
/////Copy Chatmessages
QMenu* contextMenuChat;
QAction* copymessage;
QAction* viewexplorer;
QAction* copytxid;
contextMenuChat = new QMenu(ui->listChat);
copymessage = new QAction("Copy message to clipboard",contextMenuChat);
viewexplorer = new QAction("View on block explorer",contextMenuChat);
copytxid = new QAction("Copy txid to clipboard ",contextMenuChat);
QObject::connect(ui->listContactWidget, &QTableView::clicked, [=] () {
ui->listChat->setContextMenuPolicy(Qt::ActionsContextMenu);
ui->listChat->addAction(copymessage);
ui->listChat->addAction(viewexplorer);
ui->listChat->addAction(copytxid);
QObject::connect(copymessage, &QAction::triggered, [=] {
QModelIndex index = ui->listChat->currentIndex();
QString memo_chat = index.data(Qt::DisplayRole).toString();
QClipboard *clipboard = QGuiApplication::clipboard();
int startPos = memo_chat.indexOf("<p>") + 3;
int endPos = memo_chat.indexOf("</p>");
int length = endPos - startPos;
QString copymemo = memo_chat.mid(startPos, length);
clipboard->setText(copymemo);
ui->statusBar->showMessage(tr("Copied message to clipboard"), 3 * 1000);
});
QObject::connect(copytxid, &QAction::triggered, [=] {
QModelIndex index = ui->listChat->currentIndex();
QString memo_chat = index.data(Qt::DisplayRole).toString();
QClipboard *clipboard = QGuiApplication::clipboard();
int startPos = memo_chat.indexOf("<p>") + 3;
int endPos = memo_chat.indexOf("</p>");
int length = endPos - startPos;
QString copymemo = memo_chat.mid(startPos, length);
int startPosT = memo_chat.indexOf("<small>") + 7;
int endPosT = memo_chat.indexOf("<b>");
int lengthT = endPosT - startPosT;
QString time = memo_chat.mid(startPosT, lengthT);
for (auto &c : DataStore::getChatDataStore()->getAllRawChatItems()){
if (c.second.getMemo() == copymemo)
{
int timestamp = c.second.getTimestamp();
QDateTime myDateTime;
QString lock;
myDateTime.setTime_t(timestamp);
QString timestamphtml = myDateTime.toString("yyyy-MM-dd hh:mm");
if(timestamphtml == time)
{
clipboard->setText(c.second.getTxid());
ui->statusBar->showMessage(tr("Copied Txid to clipboard"), 3 * 1000);
}else{}
}
}
});
QObject::connect(viewexplorer, &QAction::triggered, [=] {
QModelIndex index = ui->listChat->currentIndex();
QString memo_chat = index.data(Qt::DisplayRole).toString();
int startPos = memo_chat.indexOf("<p>") + 3;
int endPos = memo_chat.indexOf("</p>");
int length = endPos - startPos;
QString copymemo = memo_chat.mid(startPos, length);
int startPosT = memo_chat.indexOf("<small>") + 7;
int endPosT = memo_chat.indexOf("<b>");
int lengthT = endPosT - startPosT;
QString time = memo_chat.mid(startPosT, lengthT);
for (auto &c : DataStore::getChatDataStore()->getAllRawChatItems()){
if (c.second.getMemo() == copymemo)
{
int timestamp = c.second.getTimestamp();
QDateTime myDateTime;
QString lock;
myDateTime.setTime_t(timestamp);
QString timestamphtml = myDateTime.toString("yyyy-MM-dd hh:mm");
if(timestamphtml == time)
{
Settings::openTxInExplorer(c.second.getTxid());
}else{}
}
}
});
});
///////// Add contextmenu
QMenu* contextMenu;
QAction* requestAction;
QAction* editAction;
QAction* HushAction;
QAction* requestHushAction;
QAction* subatomicAction;
contextMenu = new QMenu(ui->listContactWidget);
requestAction = new QAction("Send a contact request - coming soon",contextMenu);
editAction = new QAction("Delete this contact",contextMenu);
HushAction = new QAction("Send a friend some Hush - coming soon",contextMenu);
requestHushAction = new QAction("Request some Hush - coming soon",contextMenu);
subatomicAction = new QAction("Make a subatomic swap with a friend- coming soon",contextMenu);
///////// Set selected Zaddr for Chat with click
QObject::connect(ui->listContactWidget, &QTableView::clicked, [=] () {
ui->listContactWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
ui->listContactWidget->addAction(requestAction);
ui->listContactWidget->addAction(editAction);
ui->listContactWidget->addAction(HushAction);
ui->listContactWidget->addAction(requestHushAction);
ui->listContactWidget->addAction(subatomicAction);
/*QObject::connect(requestHushAction, &QAction::triggered, [=]() {
QModelIndex index = ui->listContactWidget->currentIndex();
QString label_contact = index.data(Qt::DisplayRole).toString();
for(auto &p : AddressBook::getInstance()->getAllAddressLabels())
if (label_contact == p.getName()) {
ui->contactNameMemo->setText(p.getName());
rpc->refresh(true);
}
MainWindow::showRequesthush();
}); */
QObject::connect(editAction, &QAction::triggered, [=]() {
QModelIndex index = ui->listContactWidget->currentIndex();
QString label_contact = index.data(Qt::DisplayRole).toString();
for(auto &p : AddressBook::getInstance()->getAllAddressLabels())
if (label_contact == p.getName()) {
QString label1 = p.getName();
QString addr = p.getPartnerAddress();
QString myzaddr = p.getMyAddress();
QString cid = p.getCid();
QString avatar = p.getAvatar();
AddressBook::getInstance()->removeAddressLabel(label1, addr, myzaddr, cid,avatar);
rpc->refreshContacts(
ui->listContactWidget);
rpc->refresh(true);
}
});
QModelIndex index = ui->listContactWidget->currentIndex();
QString label_contact = index.data(Qt::DisplayRole).toString();
for(auto &p : AddressBook::getInstance()->getAllAddressLabels())
if (label_contact == p.getName()) {
ui->contactNameMemo->setText(p.getName());
rpc->refresh(true);
}
});
ui->memoTxtChat->setLenDisplayLabelChat(ui->memoSizeChat);
}
void MainWindow::updateChat()
{
rpc->refreshChat(ui->listChat,ui->memoSizeChat);
rpc->refresh(true);
}
void MainWindow::updateContacts()
{
}
void MainWindow::addNewZaddr(bool sapling) {
@ -1214,6 +1822,7 @@ void MainWindow::setupReceiveTab() {
// Receive tab add/update label
QObject::connect(ui->rcvUpdateLabel, &QPushButton::clicked, [=]() {
QString addr = ui->listReceiveAddresses->currentText();
if (addr.isEmpty())
return;
@ -1227,7 +1836,7 @@ void MainWindow::setupReceiveTab() {
if (!curLabel.isEmpty() && label.isEmpty()) {
info = "Removed Label '" % curLabel % "'";
AddressBook::getInstance()->removeAddressLabel(curLabel, addr);
AddressBook::getInstance()->removeAddressLabel(curLabel, addr, "", "","" );
}
else if (!curLabel.isEmpty() && !label.isEmpty()) {
info = "Updated Label '" % curLabel % "' to '" % label % "'";
@ -1235,7 +1844,7 @@ void MainWindow::setupReceiveTab() {
}
else if (curLabel.isEmpty() && !label.isEmpty()) {
info = "Added Label '" % label % "'";
AddressBook::getInstance()->addAddressLabel(label, addr);
AddressBook::getInstance()->addAddressLabel(label, addr, "", "", "");
}
// Update labels everywhere on the UI
@ -1285,7 +1894,7 @@ void MainWindow::updateTAddrCombo(bool checked) {
auto allTaddrs = this->rpc->getModel()->getAllTAddresses();
QSet<QString> labels;
for (auto p : AddressBook::getInstance()->getAllAddressLabels()) {
labels.insert(p.second);
labels.insert(p.getPartnerAddress());
}
std::for_each(allTaddrs.begin(), allTaddrs.end(), [=, &addrs] (auto& taddr) {
// If the address is in the address book, add it.
@ -1377,7 +1986,7 @@ void MainWindow::slot_change_theme(const QString& theme_name)
}
catch (...)
{
saved_theme_name = "default";
saved_theme_name = "Dark";
}
QFile qFile(":/css/res/css/" + saved_theme_name +".css");
@ -1406,3 +2015,17 @@ MainWindow::~MainWindow()
delete wsserver;
delete wormhole;
}
void MainWindow::on_givemeZaddr_clicked()
{
bool sapling = true;
rpc->createNewZaddr(sapling, [=] (json reply) {
QString hushchataddr = QString::fromStdString(reply.get<json::array_t>()[0]);
QClipboard *zaddr_Clipboard = QApplication::clipboard();
zaddr_Clipboard ->setText(hushchataddr);
QMessageBox::information(this, "Your new HushChat address was copied to your clipboard!",hushchataddr);
ui->listReceiveAddresses->insertItem(0, hushchataddr);
ui->listReceiveAddresses->setCurrentIndex(0);
});
}

75
src/mainwindow.h

@ -5,12 +5,14 @@
#include "logger.h"
#include "recurring.h"
#include "firsttimewizard.h"
// Forward declare to break circular dependency.
class Controller;
class Settings;
class WSServer;
class WormholeClient;
class ChatModel;
using json = nlohmann::json;
@ -47,18 +49,32 @@ public:
QRegExpValidator* getAmountValidator() { return amtValidator; }
QString doSendTxValidations(Tx tx);
QString doSendChatTxValidations(Tx tx);
QString doSendRequestTxValidations(Tx tx);
QString getCid();
QString getPassword();
std::map<QString, QString> pubkeyMap;
QString getPubkeyByAddress(QString requestZaddr);
void setPassword(QString Password);
void addPubkey(QString requestZaddr, QString pubkey);
void replaceWormholeClient(WormholeClient* newClient);
bool isWebsocketListening();
void createWebsocket(QString wormholecode);
void stopWebsocket();
void saveContact();
void saveandsendContact();
void showRequesthush();
void balancesReady();
void payhushURI(QString uri = "", QString myAddr = "");
void updateLabels();
void updateTAddrCombo(bool checked);
// Disable recurring on mainnet
void disableRecurring();
@ -71,37 +87,68 @@ public:
QLabel* statusIcon;
QLabel* loadingLabel;
QWidget* hushdtab;
//ChatItem* currentChatItem;
Logger* logger;
void doClose();
void doClosePw();
QString createHeaderMemo(QString type, QString cid, QString zaddr,QString headerbytes,QString publickey, int version, int headerNumber);
public slots:
void slot_change_theme(const QString& themeName);
void slot_change_currency(const QString& currencyName);
private:
private slots:
void on_givemeZaddr_clicked();
private:
bool fileExists(QString path);
void closeEvent(QCloseEvent* event);
void closeEventpw(QCloseEvent* event);
QString _password;
void setupSendTab();
void setupTransactionsTab();
void setupReceiveTab();
void setupBalancesTab();
void setuphushdTab();
void setupchatTab();
void renderContactRequest();
void updateContacts();
void updateChat();
void setupSettingsModal();
void setupStatusBar();
void clearSendForm();
Tx createTxFromSendPage();
bool confirmTx(Tx tx, RecurringPaymentInfo* rpi);
Tx createTxFromChatPage();
Tx createTxForSafeContactRequest();
void encryptWallet();
void removeWalletEncryption();
void removeWalletEncryptionStartUp();
void cancelButton();
void sendButton();
void sendChat();
void addContact();
void ContactRequest();
void addAddressSection();
void maxAmountChecked(int checked);
@ -131,13 +178,18 @@ private:
void restoreSavedStates();
bool eventFilter(QObject *object, QEvent *event);
bool uiPaymentsReady = false;
QString pendingURIPayment;
WSServer* wsserver = nullptr;
WormholeClient* wormhole = nullptr;
Controller* rpc = nullptr;
QCompleter* labelCompleter = nullptr;
QRegExpValidator* amtValidator = nullptr;
QRegExpValidator* feesValidator = nullptr;
@ -147,4 +199,21 @@ private:
QMovie* loadingMovie;
};
class ChatMemoEdit : public QTextEdit
{
public:
ChatMemoEdit(QWidget* parent);
void setMaxLenChat(int len);
void setLenDisplayLabelChat(QLabel* label);
void SetSendChatButton(QPushButton* button);
void updateDisplayChat();
private:
int maxlenchat = 235;
QLabel* lenDisplayLabelchat = nullptr;
QPushButton* sendChatButton = nullptr;
};
#endif // MAINWINDOW_H

795
src/mainwindow.ui

@ -10,6 +10,43 @@
<height>779</height>
</rect>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="PlaceholderText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="windowTitle">
<string>SilentDragonLite</string>
</property>
@ -18,11 +55,11 @@
<normaloff>:/icons/res/icon.ico</normaloff>:/icons/res/icon.ico</iconset>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout_18">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>2</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -47,181 +84,184 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Shielded</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balSheilded">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Shielded</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_17">
<item>
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Notarized</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balVerified">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="balSheilded">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_17">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Transparent</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balTransparent">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Notarized</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<widget class="QLabel" name="balVerified">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Total</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balTotal">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Transparent</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblSyncWarning">
<property name="styleSheet">
<string notr="true">color:red;</string>
</property>
<widget class="QLabel" name="balTransparent">
<property name="text">
<string>Your node is still syncing, balances may not be updated.</string>
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="unconfirmedWarning">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Some transactions are not yet confirmed. Balances may change.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<string>Total</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QLabel" name="balTotal">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="text">
<string/>
</property>
</spacer>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblSyncWarning">
<property name="styleSheet">
<string notr="true">color:red;</string>
</property>
<property name="text">
<string>Your node is still syncing, balances may not be updated.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="unconfirmedWarning">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>Some transactions are not yet confirmed. Balances may change.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QPushButton" name="depositHushButton">
<property name="text">
<string>Deposit Hush</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>383</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -389,7 +429,7 @@
<x>0</x>
<y>0</y>
<width>1226</width>
<height>504</height>
<height>493</height>
</rect>
</property>
<layout class="QVBoxLayout" name="sendToLayout">
@ -574,33 +614,6 @@
</item>
<item>
<layout class="QHBoxLayout" name="layoutSendRecurring">
<item>
<widget class="QCheckBox" name="chkRecurring">
<property name="text">
<string>Recurring payment</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblRecurDesc">
<property name="text">
<string>Every month, starting 12-May-2012, for 6 payments</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRecurSchedule">
<property name="text">
<string>Edit Schedule</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
@ -1324,6 +1337,443 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>HushChat</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="1" rowspan="4">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>15</number>
</property>
<item>
<widget class="QPushButton" name="pushContact">
<property name="minimumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Incoming contact request</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../application.qrc">
<normaloff>:/icons/res/requestBlack.png</normaloff>:/icons/res/requestBlack.png</iconset>
</property>
<property name="iconSize">
<size>
<width>50</width>
<height>45</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="safeContactRequest">
<property name="minimumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Add a new contact</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="Dark">
<normalon>:/icons/res/addContactBlack.png</normalon>
</iconset>
</property>
<property name="iconSize">
<size>
<width>50</width>
<height>45</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="givemeZaddr">
<property name="minimumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>51</width>
<height>51</height>
</size>
</property>
<property name="toolTip">
<string>Get a new Address</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../application.qrc">
<normaloff>:/icons/res/getAddrBlack.png</normaloff>:/icons/res/getAddrBlack.png</iconset>
</property>
<property name="iconSize">
<size>
<width>50</width>
<height>45</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>100</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_39">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Contactlist&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="listContactWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="5" rowspan="4">
<layout class="QVBoxLayout" name="verticalLayout_11">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_19">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="contactNameMemo_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Contact Name :&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="contactNameMemo">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListView" name="listChat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>The locks shows you the status of the message. Red lock = unconfirmed, green lock = min. 1 confirmations, orange lock = message is notarized</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragOnly</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::IgnoreAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="movement">
<enum>QListView::Snap</enum>
</property>
<property name="flow">
<enum>QListView::TopToBottom</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="layoutMode">
<enum>QListView::SinglePass</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
<property name="uniformItemSizes">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_23">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="ChatMemoEdit" name="memoTxtChat">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">font: 11pt &quot;Noto Color Emoji&quot;;</string>
</property>
<property name="autoFormatting">
<set>QTextEdit::AutoNone</set>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::WidgetWidth</enum>
</property>
<property name="lineWrapColumnOrWidth">
<number>600</number>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextEditorInteraction</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item alignment="Qt::AlignBottom">
<widget class="QPushButton" name="sendChatButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/sendBlack.png</normalon>
</iconset>
</property>
<property name="iconSize">
<size>
<width>50</width>
<height>49</height>
</size>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="memoSizeChat">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string notr="true">0 / 235</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
@ -1509,6 +1959,11 @@
<extends>QLabel</extends>
<header>fillediconlabel.h</header>
</customwidget>
<customwidget>
<class>ChatMemoEdit</class>
<extends>QTextEdit</extends>
<header>mainwindow.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>Address1</tabstop>

2
src/memodialog.ui

@ -74,7 +74,7 @@
<customwidget>
<class>MemoEdit</class>
<extends>QPlainTextEdit</extends>
<header>memoedit.h</header>
<header location="global">memoedit.h</header>
</customwidget>
</customwidgets>
<resources/>

2
src/mobileappconnector.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Connect Mobile App</string>
<string>Mobile Connector App</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1" colspan="2">

28
src/newseed.ui

@ -6,15 +6,15 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>427</width>
<height>416</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>This is your new wallet's seed phrase. PLEASE BACK IT UP SECURELY.</string>
@ -24,17 +24,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>The seed phrase is the only way to restore the wallet. If you forget the seed phrase, THERE IS NO WAY TO RESTORE YOUR WALLET AND THE FUNDS in it</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -56,6 +46,16 @@
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>The seed phrase is the only way to restore the wallet. If you forget the seed phrase, THERE IS NO WAY TO RESTORE YOUR WALLET AND THE FUNDS in it</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

79
src/newwallet.ui

@ -6,15 +6,29 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>437</width>
<height>381</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Create New SDL Wallet</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Confirm Passphrase:</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="QLineEdit" name="txtConfirmPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -46,7 +60,14 @@
</layout>
</widget>
</item>
<item row="0" column="0">
<item row="5" column="1" colspan="2">
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@ -61,7 +82,7 @@
<item row="0" column="0">
<widget class="QRadioButton" name="radioNewWallet">
<property name="text">
<string>Create a new Wallet</string>
<string>Create a new wallet</string>
</property>
</widget>
</item>
@ -78,6 +99,52 @@
</layout>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Encryption Passphrase:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblPasswordMatch">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Passphrase don't match&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;16 letters minimum&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

2
src/recurringdialog.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Reccuring Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

2
src/recurringmultiple.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Recurring Multiple Payments</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="14" column="0" colspan="2">

2
src/recurringpayments.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Payments</string>
<string>Reocurring Payments</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">

175
src/removeencryption.ui

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>removeencryption</class>
<widget class="QDialog" name="removeencryption">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>Decrypt Your Wallet</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0" colspan="4">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:14pt; color:#ef2929;&quot;&gt;WARNING:&lt;/span&gt; If you remove your wallet.dat encryption, all your transactions and contacts are plaintext on disk!&lt;br/&gt;&lt;br/&gt;Messages sent and received are always encrypted.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QLineEdit" name="txtPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;16 letters minimum&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="2" colspan="2" alignment="Qt::AlignRight">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Encryption Passphrase:</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Confirm Passphrase:</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="2" colspan="2">
<widget class="QLineEdit" name="txtConfirmPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="lblPasswordMatch">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Passphrase don't match&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>removeencryption</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>removeencryption</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

473
src/requestContactDialog.ui

@ -0,0 +1,473 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>requestDialog</class>
<widget class="QDialog" name="requestDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>850</width>
<height>495</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>850</width>
<height>495</height>
</size>
</property>
<property name="windowTitle">
<string>Incoming Contact Request</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Memo of the request&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="6">
<widget class="QListView" name="requestMemo">
<property name="minimumSize">
<size>
<width>500</width>
<height>231</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="modelColumn">
<number>0</number>
</property>
<property name="uniformItemSizes">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Open requests&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="0" rowspan="8">
<widget class="QListView" name="requestContactOld">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>225</width>
<height>190</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
</widget>
</item>
<item row="4" column="4" colspan="3">
<widget class="QLineEdit" name="requestZaddr">
<property name="minimumSize">
<size>
<width>351</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>351</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Request from:</string>
</property>
</widget>
</item>
<item row="6" column="4" colspan="2">
<widget class="QLineEdit" name="requestLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maxLength">
<number>25</number>
</property>
</widget>
</item>
<item row="10" column="3">
<widget class="QLabel" name="zaddrnew">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="6">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Add New Contact</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QLabel" name="requestCID">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="1" colspan="3">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose an avatar for your contact:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>My Zaddr:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="zaddrold">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="10" column="5">
<widget class="QPushButton" name="cancel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QComboBox" name="comboBoxAvatar">
<property name="minimumSize">
<size>
<width>106</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>106</width>
<height>25</height>
</size>
</property>
<item>
<property name="text">
<string>SDLogo</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/SDLogo.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Duke</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Duke.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Denio</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Denio.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Berg</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Berg.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Sharpee</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Sharpee.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Elsa</string>
</property>
<property name="icon">
<iconset>
<normalon>:/icons/res/Elsa.png</normalon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Yoda</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Yoda.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Garfield</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Garfield.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Snoopy</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Snoopy.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Popey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Popey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Pinguin</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Pinguin.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Mickey</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Mickey.png</activeon>
</iconset>
</property>
</item>
<item>
<property name="text">
<string>Stag</string>
</property>
<property name="icon">
<iconset>
<activeon>:/icons/res/Stag.png</activeon>
</iconset>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="requestContact">
<property name="minimumSize">
<size>
<width>225</width>
<height>231</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Recently closed requests&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="3">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Details of the request&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="3">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Give a Nickname:</string>
</property>
</widget>
</item>
<item row="5" column="4" colspan="3">
<widget class="QLineEdit" name="requestMyAddr">
<property name="minimumSize">
<size>
<width>351</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>351</width>
<height>25</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>cancel</sender>
<signal>clicked()</signal>
<receiver>requestDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>339</x>
<y>482</y>
</hint>
<hint type="destinationlabel">
<x>505</x>
<y>251</y>
</hint>
</hints>
</connection>
</connections>
</ui>

252
src/requestdialog.ui

@ -14,37 +14,10 @@
<string>Payment Request</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="18" column="1" colspan="3">
<widget class="AddressCombo" name="cmbMyAddress"/>
</item>
<item row="2" column="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAddressBook">
<property name="text">
<string>AddressBook</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="21" column="0" colspan="4">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="10" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>
@ -55,171 +28,198 @@
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_2">
<item row="15" column="3">
<widget class="QLabel" name="lblAddressInfo">
<property name="text">
<string>My Address</string>
<string>The recipient will see this address in the &quot;to&quot; field when they pay your request.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<widget class="QLabel" name="lblSaplingWarning">
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="text">
<string/>
<item row="12" column="1" colspan="3">
<widget class="MemoEdit" name="txtMemo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="lblAmount">
<item row="0" column="1">
<widget class="QLabel" name="lblPixmap">
<property name="text">
<string>Amount in </string>
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label">
<item row="18" column="1" colspan="3">
<widget class="AddressCombo" name="cmbMyAddress"/>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="24" column="2" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="5" column="1" colspan="3">
<widget class="QLabel" name="lblSaplingWarning">
<property name="styleSheet">
<string notr="true">color: red;</string>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_4">
<item row="11" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string/>
<string>Memo</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLineEdit" name="txtFrom">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="20" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
<property name="placeholderText">
<string>z address</string>
</spacer>
</item>
<item row="11" column="3">
<widget class="QLabel" name="lblMemoLen">
<property name="text">
<string notr="true">0 / 235</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="Line" name="line_3">
<item row="13" column="1" colspan="3">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="12" column="1" colspan="3">
<widget class="MemoEdit" name="txtMemo">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="9" column="1">
<widget class="QLabel" name="txtAmountUSD">
<property name="text">
<string>Amount USD</string>
</property>
</widget>
</item>
<item row="7" column="1" colspan="3">
<widget class="QLineEdit" name="txtAmount">
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>Amount</string>
</property>
</widget>
</item>
<item row="13" column="1" colspan="3">
<widget class="Line" name="line_2">
<item row="21" column="0" colspan="4">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="15" column="3">
<widget class="QLabel" name="lblAddressInfo">
<item row="2" column="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAddressBook">
<property name="text">
<string>AddressBook</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLabel" name="lblHeader">
<property name="text">
<string>The recipient will see this address in the &quot;to&quot; field when they pay your request.</string>
<string>Request payment from a Sapling address. You'll send a hush 0.0001 transaction to the address with a hush payment URI. The memo will be included in the transaction when the address pays you.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="11" column="3">
<widget class="QLabel" name="lblMemoLen">
<property name="text">
<string notr="true">0 / 512</string>
<item row="4" column="1" colspan="3">
<widget class="QLineEdit" name="txtFrom">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>z address</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="txtAmountUSD">
<item row="15" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Amount USD</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
<string>My Address</string>
</property>
</widget>
</item>
<item row="20" column="1">
<spacer name="verticalSpacer">
<item row="24" column="2" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Memo</string>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblPixmap">
<property name="text">
<string>TextLabel</string>
</property>
<item row="7" column="1" colspan="3">
<widget class="QLineEdit" name="txtAmount">
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>Amount</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLabel" name="lblHeader">
<item row="6" column="1">
<widget class="QLabel" name="lblAmount">
<property name="text">
<string>Request payment from a Sapling address. You'll send a hush 0.0001 transaction to the address with a hush payment URI. The memo will be included in the transaction when the address pays you.</string>
<string>Amount in </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>

2
src/restoreseed.ui

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Restore Wallet Seed</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

267
src/sendtab.cpp

@ -13,7 +13,7 @@ using json = nlohmann::json;
void MainWindow::setupSendTab() {
// Create the validator for send to/amount fields
amtValidator = new QRegExpValidator(QRegExp("[0-9]{0,8}\\.?[0-9]{0,8}"));
amtValidator = new QRegExpValidator(QRegExp("[0-9]{0,8}\\.?[0-9]{0,8}"));
ui->Amount1->setValidator(amtValidator);
@ -35,14 +35,14 @@ void MainWindow::setupSendTab() {
});
// The first Memo button
QObject::connect(ui->MemoBtn1, &QPushButton::clicked, [=] () {
QObject::connect(ui->MemoBtn1, &QPushButton::clicked, [=] () {
this->memoButtonClicked(1);
});
setMemoEnabled(1, false);
// This is the damnest thing ever. If we do AddressBook::readFromStorage() directly, the whole file
// doesn't get read. It needs to run in a timer after everything has finished to be able to read
// the file properly.
// the file properly.
QTimer::singleShot(2000, [=]() { updateLabelsAutoComplete(); });
// The first address book button
@ -84,7 +84,7 @@ void MainWindow::setupSendTab() {
ui->lblMinerFeeUSD->setText(fee.toDecimalAUDString());
}
});
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
ui->minerFeeAmt->setText(Settings::getMinerFee().toDecimalString());
// Set up focus enter to set fees
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int pos) {
@ -123,13 +123,13 @@ void MainWindow::setupSendTab() {
} else if (Settings::getInstance()->get_currency_name() == "AUD") {
QString feeUSD = CAmount::fromDecimalString(txt).toDecimalAUDString();
ui->lblMinerFeeUSD->setText(feeUSD);
}
}
}
});
//Fees validator
feesValidator = new QRegExpValidator(QRegExp("[0-9]{0,8}\\.?[0-9]{0,8}"));
feesValidator = new QRegExpValidator(QRegExp("[0-9]{0,8}\\.?[0-9]{0,8}"));
ui->minerFeeAmt->setValidator(feesValidator);
// Font for the first Memo label
@ -138,9 +138,9 @@ void MainWindow::setupSendTab() {
ui->MemoTxt1->setFont(f);
// Recurring button
QObject::connect(ui->chkRecurring, &QCheckBox::stateChanged, [=] (int checked) {
/*QObject::connect(ui->chkRecurring, &QCheckBox::stateChanged, [=] (int checked) {
if (checked) {
ui->btnRecurSchedule->setEnabled(true);
ui->btnRecurSchedule->setEnabled(true);
// If this is the first time the button is checked, open the edit schedule dialog
if (sendTxRecurringInfo == nullptr) {
@ -150,66 +150,66 @@ void MainWindow::setupSendTab() {
ui->btnRecurSchedule->setEnabled(false);
ui->lblRecurDesc->setText("");
}
});
});*/
// Recurring schedule button
QObject::connect(ui->btnRecurSchedule, &QPushButton::clicked, this, &MainWindow::editSchedule);
// QObject::connect(ui->btnRecurSchedule, &QPushButton::clicked, this, &MainWindow::editSchedule);
// Set the default state for the whole page
clearSendForm();
}
void MainWindow::disableRecurring() {
if (!Settings::getInstance()->isTestnet()) {
/* if (!Settings::getInstance()->isTestnet()) {
ui->chkRecurring->setVisible(false);
ui->chkRecurring->setEnabled(false);
ui->btnRecurSchedule->setVisible(false);
ui->btnRecurSchedule->setEnabled(false);
ui->action_Recurring_Payments->setVisible(false);
}
ui->action_Recurring_Payments->setVisible(false);*/
// }
}
void MainWindow::editSchedule() {
// Only on testnet for now
if (!Settings::getInstance()->isTestnet()) {
QMessageBox::critical(this, "Not Supported yet",
QMessageBox::critical(this, "Not Supported yet",
"Recurring payments are only supported on Testnet for now.", QMessageBox::Ok);
return;
}
// Check to see that recurring payments are not selected when there are 2 or more addresses
if (ui->sendToWidgets->children().size()-1 > 2) {
QMessageBox::critical(this, tr("Cannot support multiple addresses"),
QMessageBox::critical(this, tr("Cannot support multiple addresses"),
tr("Recurring payments doesn't currently support multiple addresses"), QMessageBox::Ok);
return;
}
// Open the edit schedule dialog
auto recurringInfo = Recurring::getInstance()->getNewRecurringFromTx(this, this,
createTxFromSendPage(), this->sendTxRecurringInfo);
if (recurringInfo == nullptr) {
// User pressed cancel.
// auto recurringInfo = Recurring::getInstance()->getNewRecurringFromTx(this, this,
// createTxFromSendPage(), this->sendTxRecurringInfo);
// if (recurringInfo == nullptr) {
// User pressed cancel.
// If there is no existing recurring info, uncheck the recurring box
if (sendTxRecurringInfo == nullptr) {
ui->chkRecurring->setCheckState(Qt::Unchecked);
}
}
else {
delete this->sendTxRecurringInfo;
this->sendTxRecurringInfo = recurringInfo;
ui->lblRecurDesc->setText(recurringInfo->getScheduleDescription());
}
// if (sendTxRecurringInfo == nullptr) {
// ui->chkRecurring->setCheckState(Qt::Unchecked);
// }
// }
// else {
// delete this->sendTxRecurringInfo;
// this->sendTxRecurringInfo = recurringInfo;
// ui->lblRecurDesc->setText(recurringInfo->getScheduleDescription());
//}
}
void MainWindow::updateLabelsAutoComplete() {
QList<QString> list;
auto labels = AddressBook::getInstance()->getAllAddressLabels();
std::transform(labels.begin(), labels.end(), std::back_inserter(list), [=] (auto la) -> QString {
return la.first % "/" % la.second;
return la.getName() % "/" % la.getPartnerAddress();
});
delete labelCompleter;
labelCompleter = new QCompleter(list, this);
labelCompleter->setCaseSensitivity(Qt::CaseInsensitive);
@ -221,7 +221,7 @@ void MainWindow::updateLabelsAutoComplete() {
}
}
void MainWindow::addAddressSection() {
int itemNumber = ui->sendToWidgets->children().size() - 1;
@ -239,7 +239,7 @@ void MainWindow::addAddressSection() {
horizontalLayout_12->addWidget(label_4);
auto Address1 = new QLineEdit(verticalGroupBox);
Address1->setObjectName(QString("Address") % QString::number(itemNumber));
Address1->setObjectName(QString("Address") % QString::number(itemNumber));
Address1->setPlaceholderText(tr("Address"));
QObject::connect(Address1, &QLineEdit::textChanged, [=] (auto text) {
this->addressChanged(itemNumber, text);
@ -261,16 +261,16 @@ void MainWindow::addAddressSection() {
auto horizontalLayout_13 = new QHBoxLayout();
horizontalLayout_13->setSpacing(6);
auto label_6 = new QLabel(verticalGroupBox);
label_6->setText(tr("Amount"));
horizontalLayout_13->addWidget(label_6);
auto Amount1 = new QLineEdit(verticalGroupBox);
Amount1->setPlaceholderText(tr("Amount"));
Amount1->setObjectName(QString("Amount") % QString::number(itemNumber));
Amount1->setPlaceholderText(tr("Amount"));
Amount1->setObjectName(QString("Amount") % QString::number(itemNumber));
Amount1->setBaseSize(QSize(200, 0));
Amount1->setAlignment(Qt::AlignRight);
Amount1->setAlignment(Qt::AlignRight);
// Create the validator for send to/amount fields
Amount1->setValidator(amtValidator);
@ -281,7 +281,7 @@ void MainWindow::addAddressSection() {
horizontalLayout_13->addWidget(Amount1);
auto AmtUSD1 = new QLabel(verticalGroupBox);
AmtUSD1->setObjectName(QString("AmtUSD") % QString::number(itemNumber));
AmtUSD1->setObjectName(QString("AmtUSD") % QString::number(itemNumber));
horizontalLayout_13->addWidget(AmtUSD1);
auto horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
@ -289,7 +289,7 @@ void MainWindow::addAddressSection() {
auto MemoBtn1 = new QPushButton(verticalGroupBox);
MemoBtn1->setObjectName(QString("MemoBtn") % QString::number(itemNumber));
MemoBtn1->setText(tr("Memo"));
MemoBtn1->setText(tr("Memo"));
// Connect Memo Clicked button
QObject::connect(MemoBtn1, &QPushButton::clicked, [=] () {
this->memoButtonClicked(itemNumber);
@ -307,24 +307,24 @@ void MainWindow::addAddressSection() {
MemoTxt1->setWordWrap(true);
sendAddressLayout->addWidget(MemoTxt1);
ui->sendToLayout->insertWidget(itemNumber-1, verticalGroupBox);
ui->sendToLayout->insertWidget(itemNumber-1, verticalGroupBox);
// Disable recurring payments if a address section is added, since recurring payments
// aren't supported for more than 1 address
delete sendTxRecurringInfo;
sendTxRecurringInfo = nullptr;
ui->lblRecurDesc->setText("");
ui->chkRecurring->setChecked(false);
ui->chkRecurring->setEnabled(false);
// delete sendTxRecurringInfo;
// sendTxRecurringInfo = nullptr;
// ui->lblRecurDesc->setText("");
// ui->chkRecurring->setChecked(false);
// ui->chkRecurring->setEnabled(false);
// Set focus into the address
Address1->setFocus();
// Delay the call to scroll to allow the scroll window to adjust
QTimer::singleShot(10, [=] () {ui->sendToScrollArea->ensureWidgetVisible(ui->addAddressButton);});
QTimer::singleShot(10, [=] () {ui->sendToScrollArea->ensureWidgetVisible(ui->addAddressButton);});
}
void MainWindow::addressChanged(int itemNumber, const QString& text) {
void MainWindow::addressChanged(int itemNumber, const QString& text) {
auto addr = AddressBook::addressFromAddressLabel(text);
setMemoEnabled(itemNumber, Settings::isZAddress(addr));
}
@ -358,10 +358,10 @@ void MainWindow::amountChanged(int item, const QString& text) {
}
// If there is a recurring payment, update the info there as well
if (sendTxRecurringInfo != nullptr) {
Recurring::getInstance()->updateInfoWithTx(sendTxRecurringInfo, createTxFromSendPage());
ui->lblRecurDesc->setText(sendTxRecurringInfo->getScheduleDescription());
}
//if (sendTxRecurringInfo != nullptr) {
// Recurring::getInstance()->updateInfoWithTx(sendTxRecurringInfo, createTxFromSendPage());
// ui->lblRecurDesc->setText(sendTxRecurringInfo->getScheduleDescription());
// }
}
void MainWindow::setMemoEnabled(int number, bool enabled) {
@ -377,15 +377,15 @@ void MainWindow::setMemoEnabled(int number, bool enabled) {
void MainWindow::memoButtonClicked(int number, bool includeReplyTo) {
// Memos can only be used with zAddrs. So check that first
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") + QString::number(number));
if (! Settings::isZAddress(AddressBook::addressFromAddressLabel(addr->text()))) {
QMessageBox msg(QMessageBox::Critical, tr("Memos can only be used with z-addresses"),
tr("The memo field can only be used with a z-address.\n") + addr->text() + tr("\ndoesn't look like a z-address"),
QMessageBox::Ok, this);
// auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") + QString::number(number));
//if (! Settings::isZAddress(AddressBook::addressFromAddressLabel(addr->text()))) {
// QMessageBox msg(QMessageBox::Critical, tr("Memos can only be used with z-addresses"),
// tr("The memo field can only be used with a z-address.\n") + addr->text() + tr("\ndoesn't look like a z-address"),
// QMessageBox::Ok, this);
msg.exec();
return;
}
// msg.exec();
// return;
// }
// Get the current memo if it exists
auto memoTxt = ui->sendToWidgets->findChild<QLabel *>(QString("MemoTxt") + QString::number(number));
@ -428,7 +428,7 @@ void MainWindow::memoButtonClicked(int number, bool includeReplyTo) {
void MainWindow::clearSendForm() {
// The last one is a spacer, so ignore that
int totalItems = ui->sendToWidgets->children().size() - 2;
int totalItems = ui->sendToWidgets->children().size() - 2;
// Clear the first recipient fields
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address1"));
@ -451,43 +451,43 @@ void MainWindow::clearSendForm() {
// Start the deletion after the first item, since we want to keep 1 send field there all there
for (int i=1; i < totalItems; i++) {
auto addressGroupBox = ui->sendToWidgets->findChild<QGroupBox*>(QString("AddressGroupBox") % QString::number(i+1));
delete addressGroupBox;
}
}
// Reset the recurring button
if (Settings::getInstance()->isTestnet()) {
ui->chkRecurring->setEnabled(true);
}
ui->chkRecurring->setCheckState(Qt::Unchecked);
ui->btnRecurSchedule->setEnabled(false);
ui->lblRecurDesc->setText("");
delete sendTxRecurringInfo;
sendTxRecurringInfo = nullptr;
// ui->chkRecurring->setEnabled(true);
}
// ui->chkRecurring->setCheckState(Qt::Unchecked);
// ui->btnRecurSchedule->setEnabled(false);
// ui->lblRecurDesc->setText("");
// delete sendTxRecurringInfo;
// sendTxRecurringInfo = nullptr;
}
void MainWindow::maxAmountChecked(int checked) {
if (checked == Qt::Checked) {
ui->Amount1->setReadOnly(true);
if (rpc == nullptr) return;
// Calculate maximum amount
CAmount sumAllAmounts;
// Calculate all other amounts
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
// Start counting the sum skipping the first one, because the MAX button is on the first one, and we don't
// want to include it in the sum.
// want to include it in the sum.
for (int i=1; i < totalItems; i++) {
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1));
sumAllAmounts = sumAllAmounts + CAmount::fromDecimalString(amt->text());
}
sumAllAmounts = sumAllAmounts + Settings::getMinerFee();
auto maxamount = rpc->getModel()->getAvailableBalance() - sumAllAmounts;
maxamount = (maxamount < 0) ? CAmount::fromqint64(0): maxamount;
ui->Amount1->setText(maxamount.toDecimalString());
} else if (checked == Qt::Unchecked) {
// Just remove the readonly part, don't change the content
@ -495,61 +495,61 @@ void MainWindow::maxAmountChecked(int checked) {
}
}
// Create a Tx from the current state of the send page.
// Create a Tx from the current state of the send page.
Tx MainWindow::createTxFromSendPage() {
Tx tx;
// For each addr/amt in the sendTo tab
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
CAmount totalAmt;
for (int i=0; i < totalItems; i++) {
QString addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1))->text().trimmed();
// Remove label if it exists
addr = AddressBook::addressFromAddressLabel(addr);
// QString dustamt = "0";
QString amtStr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1))->text().trimmed();
if (amtStr.isEmpty()) {
amtStr = "-1";; // The user didn't specify an amount
}
}
bool ok;
CAmount amt;
// Make sure it parses
amtStr.toDouble(&ok);
if (!ok) {
amt = CAmount::fromqint64(-1);
} else {
amt = CAmount::fromDecimalString(amtStr);
totalAmt = totalAmt + amt;
}
QString memo = ui->sendToWidgets->findChild<QLabel*>(QString("MemoTxt") % QString::number(i+1))->text().trimmed();
tx.toAddrs.push_back( ToFields{addr, amt, memo} );
}
tx.fee = Settings::getMinerFee();
return tx;
}
bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
// Function to split the address to make it easier to read.
// Split it into chunks of 4 chars.
// Function to split the address to make it easier to read.
// Split it into chunks of 4 chars.
auto fnSplitAddressForWrap = [=] (const QString& a) -> QString {
if (Settings::isTAddress(a))
return a;
@ -601,8 +601,8 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
delete confirm.sendToAddrs->findChild<QLabel*>("labelMinerFee");
delete confirm.sendToAddrs->findChild<QLabel*>("minerFee");
delete confirm.sendToAddrs->findChild<QLabel*>("minerFeeUSD");
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
// For each addr/amt/memo, construct the JSON and also build the confirm dialog box
int row = 0;
CAmount totalSpending;
@ -632,7 +632,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalUSDString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (EUR)
} else if (Settings::getInstance()->get_currency_name() == "EUR") {
@ -640,7 +640,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalEURString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (BTC)
} else if (Settings::getInstance()->get_currency_name() == "BTC") {
@ -648,7 +648,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalBTCString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (CNY)
} else if (Settings::getInstance()->get_currency_name() == "CNY") {
@ -656,7 +656,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalCNYString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (RUB)
} else if (Settings::getInstance()->get_currency_name() == "RUB") {
@ -664,7 +664,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalRUBString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (CAD)
} else if (Settings::getInstance()->get_currency_name() == "CAD") {
@ -672,7 +672,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalCADString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (SGD)
} else if (Settings::getInstance()->get_currency_name() == "SGD") {
@ -680,7 +680,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalSGDString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (CHF)
} else if (Settings::getInstance()->get_currency_name() == "CHF") {
@ -688,7 +688,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalCHFString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (INR)
} else if (Settings::getInstance()->get_currency_name() == "INR") {
@ -696,7 +696,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalINRString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (GBP)
} else if (Settings::getInstance()->get_currency_name() == "GBP") {
@ -704,7 +704,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalGBPString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
// Amount (AUD)
} else if (Settings::getInstance()->get_currency_name() == "AUD") {
@ -712,7 +712,7 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
AmtUSD->setObjectName(QString("AmtUSD") % QString::number(i + 1));
AmtUSD->setText(toAddr.amount.toDecimalAUDString());
AmtUSD->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1);
}
// Memo
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.isEmpty()) {
@ -798,10 +798,10 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) {
// Syncing warning
confirm.syncingWarning->setVisible(Settings::getInstance()->isSyncing());
// Show the dialog and submit it if the user confirms
return d.exec() == QDialog::Accepted;
return d.exec() == QDialog::Accepted;
}
// Send button clicked
@ -824,9 +824,9 @@ void MainWindow::sendButton() {
}
// Show a dialog to confirm the Tx
if (confirmTx(tx, sendTxRecurringInfo)) {
// If this is a recurring payment, save the hash so we can
// update the payment if it submits.
if (confirmTx(tx, sendTxRecurringInfo)) {
// If this is a recurring payment, save the hash so we can
// update the payment if it submits.
QString recurringPaymentHash;
// Recurring payments are enabled only if there is exactly 1 destination address.
@ -843,8 +843,18 @@ void MainWindow::sendButton() {
auto d = new QDialog(this);
auto connD = new Ui_ConnectionDialog();
connD->setupUi(d);
QPixmap logo(":/img/res/logobig.gif");
connD->topIcon->setBasePixmap(logo.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation));
QMovie *movie1 = new QMovie(":/img/res/silentdragonlite-animated.gif");;
QMovie *movie2 = new QMovie(":/img/res/silentdragonlite-animated-dark.gif");;
auto theme = Settings::getInstance()->get_theme_name();
if (theme == "Dark" || theme == "Midnight") {
movie2->setScaledSize(QSize(512,512));
connD->topIcon->setMovie(movie2);
movie2->start();
} else {
movie1->setScaledSize(QSize(512,512));
connD->topIcon->setMovie(movie1);
movie1->start();
}
connD->status->setText(tr("Please wait..."));
connD->statusDetail->setText(tr("Computing your transaction"));
@ -852,8 +862,8 @@ void MainWindow::sendButton() {
d->show();
// And send the Tx
rpc->executeTransaction(tx,
[=] (QString txid) {
rpc->executeTransaction(tx,
[=] (QString txid) {
ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid);
connD->status->setText(tr("Done!"));
@ -868,40 +878,40 @@ void MainWindow::sendButton() {
// And switch to the balances tab
ui->tabWidget->setCurrentIndex(0);
});
// Force a UI update so we get the unconfirmed Tx
rpc->refresh(true);
// If this was a recurring payment, update the payment with the info
if (!recurringPaymentHash.isEmpty()) {
// Since this is the send button payment, this is the first payment
Recurring::getInstance()->updatePaymentItem(recurringPaymentHash, 0,
Recurring::getInstance()->updatePaymentItem(recurringPaymentHash, 0,
txid, "", PaymentStatus::COMPLETED);
}
},
// Errored out
[=] (QString opid, QString errStr) {
ui->statusBar->showMessage(QObject::tr(" Tx ") % opid % QObject::tr(" failed"), 15 * 1000);
d->accept();
d->close();
delete connD;
delete d;
if (!opid.isEmpty())
errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr;
errStr = QObject::tr("The transaction with id ") % opid % QObject::tr(" failed. The error was") + ":\n\n" + errStr;
// If this was a recurring payment, update the payment with the failure
if (!recurringPaymentHash.isEmpty()) {
// Since this is the send button payment, this is the first payment
Recurring::getInstance()->updatePaymentItem(recurringPaymentHash, 0,
"", errStr, PaymentStatus::ERROR);
}
Recurring::getInstance()->updatePaymentItem(recurringPaymentHash, 0,
"", errStr, PaymentStatus::ERROR);
}
QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok);
QMessageBox::critical(this, QObject::tr("Transaction Error"), errStr, QMessageBox::Ok);
}
);
}
}
}
QString MainWindow::doSendTxValidations(Tx tx) {
@ -915,7 +925,7 @@ QString MainWindow::doSendTxValidations(Tx tx) {
}
// This technically shouldn't be possible, but issue #62 seems to have discovered a bug
// somewhere, so just add a check to make sure.
// somewhere, so just add a check to make sure.
if (toAddr.amount.toqint64() < 0) {
return QString(tr("Amount for address '%1' is invalid!").arg(toAddr.addr));
}
@ -927,7 +937,7 @@ QString MainWindow::doSendTxValidations(Tx tx) {
auto available = rpc->getModel()->getAvailableBalance();
if (available < total) {
return tr("Not enough available funds to send this transaction\n\nHave: %1\nNeed: %2\n\nNote: Funds need 5 confirmations before they can be spent")
return tr("Not enough available funds to send this transaction\n\nHave: %1\nNeed: %2\n\nNote: Funds need 1 confirmations before they can be spent")
.arg(available.toDecimalhushString(), total.toDecimalhushString());
}
@ -937,4 +947,3 @@ QString MainWindow::doSendTxValidations(Tx tx) {
void MainWindow::cancelButton() {
clearSendForm();
}

13
src/settings.cpp

@ -225,16 +225,12 @@ QString Settings::get_currency_name() {
}
void Settings::set_currency_name(QString currency_name) {
QSettings().setValue("options/currency_name", currency_name);
QSettings().setValue("options/currency_name", currency_name);
}
QString Settings::get_theme_name() {
// Load from the QT Settings.
return QSettings().value("options/theme_name", false).toString();
return QSettings().value("options/theme_name", "Dark").toString();
}
void Settings::set_theme_name(QString theme_name) {
@ -242,6 +238,9 @@ void Settings::set_theme_name(QString theme_name) {
}
//=================================
// Static Stuff
//=================================
@ -303,7 +302,7 @@ QString Settings::getDonationAddr() {
if (Settings::getInstance()->isTestnet())
return "ztestsaplingXXX";
else
return "zs1kwp3h4rwz76zfqzmwqqextq696kndtjskg4fzc80l9ygfal4hchcsst83ua8tjwzzy9nja7v5rr";
return "zs1fq9f7vg797qaeac9lyx0njyjmjg4w7m60hwq6lhyhvdcqltl5hdkm8vwx9cxy60ehuuz2x49jxt";
}

2
src/settings.h

@ -67,6 +67,8 @@ public:
void set_currency_name(QString currency_name);
bool isSaplingActive();
void setZECPrice(double p) { ZECPrice = p; }

39
src/settings.ui

@ -6,10 +6,28 @@
<rect>
<x>0</x>
<y>0</y>
<width>733</width>
<height>539</height>
<width>590</width>
<height>443</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>590</width>
<height>443</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>590</width>
<height>443</height>
</size>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
@ -85,7 +103,7 @@
<rect>
<x>80</x>
<y>110</y>
<width>80</width>
<width>111</width>
<height>25</height>
</rect>
</property>
@ -97,22 +115,27 @@
</property>
<item>
<property name="text">
<string>default</string>
<string>Dark</string>
</property>
</item>
<item>
<property name="text">
<string>Midnight</string>
</property>
</item>
<item>
<property name="text">
<string>blue</string>
<string>Light</string>
</property>
</item>
<item>
<property name="text">
<string>light</string>
<string>Blue</string>
</property>
</item>
<item>
<property name="text">
<string>dark</string>
<string>Default</string>
</property>
</item>
</widget>
@ -236,7 +259,7 @@
<rect>
<x>80</x>
<y>150</y>
<width>80</width>
<width>111</width>
<height>25</height>
</rect>
</property>

129
src/startupencryption.ui

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>startup</class>
<widget class="QDialog" name="startup">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>177</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>177</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>177</height>
</size>
</property>
<property name="windowTitle">
<string>SDL Startup Decryption</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If you have forgotten your passphrase, restore your wallet with your seed!&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Encryption Passphrase:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="txtPassword">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>startup</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>startup</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

2
src/version.h

@ -1 +1 @@
#define APP_VERSION "1.2.2"
#define APP_VERSION "1.3.2-Chat-Beta"

Loading…
Cancel
Save