From b29be565bcf84c15092df7a4ca6e29ece47c41a6 Mon Sep 17 00:00:00 2001 From: Tong Van Linh Date: Mon, 24 Jul 2023 21:40:52 +0700 Subject: [PATCH] 1.9.20 --- CMakeLists.txt | 7 + Images/Device_Icons/Ledger.svg | 4 + Images/calendar-dark.png | Bin 0 -> 289 bytes Images/calendar-dark.svg | 8 + Images/change-password-dark.svg | 3 + Images/close-24px.svg | 3 + Images/coldcard-illustration.svg | 36 + Images/inheritance_backup_password.svg | 254 +++ Images/more-horizontal-dark.svg | 3 + Images/star-dark.png | Bin 0 -> 327 bytes Images/star-dark.svg | 8 + Images/trezor-illustration.svg | 29 + Images/wallet-brand-icon.svg | 28 + Models/AppModel.cpp | 349 ++-- Models/AppModel.h | 7 +- Models/AppSetting.h | 5 +- Models/Chats/ClientController.cpp | 8 +- Models/Chats/ClientController.h | 1 + Models/Chats/QNunchukRoomModel.cpp | 167 +- Models/Chats/QNunchukRoomModel.h | 13 +- Models/Chats/QRoomTransaction.cpp | 14 +- Models/Chats/QUserWallets.cpp | 325 ++- Models/Chats/QUserWallets.h | 43 +- Models/DeviceModel.cpp | 6 +- Models/DeviceModel.h | 4 +- Models/MasterSignerModel.cpp | 6 + Models/MasterSignerModel.h | 2 + Models/ServiceSetting.cpp | 23 + Models/ServiceSetting.h | 46 +- Models/SingleSignerModel.cpp | 39 +- Models/SingleSignerModel.h | 10 +- Models/TransactionModel.cpp | 79 +- Models/TransactionModel.h | 12 +- Models/UTXOModel.cpp | 46 +- Models/UTXOModel.h | 18 +- Models/WalletModel.cpp | 170 +- Models/WalletModel.h | 75 +- Models/Worker.cpp | 109 +- Models/Worker.h | 4 + QAppEngine/QOutlog/QOutlog.h | 9 +- .../QQuickViewer/Common/QCommonDefines.h | 17 + QAppEngine/QQuickViewer/QQuickViewer.cpp | 2 +- .../Buttons/QAssistedWalletDelegate.qml | 124 ++ .../customizes/Buttons/QCheckBoxButton.qml | 54 + .../customizes/Buttons/QLinearGradient.qml | 28 + .../customizes/Buttons/QRadioButtonTypeC.qml | 2 +- .../customizes/Buttons/QRadioButtonTypeD.qml | 10 +- .../customizes/Buttons/QRadioButtonTypeE.qml | 72 + .../customizes/Buttons/QRadioButtonTypeF.qml | 73 + .../customizes/Chats/QConversationInfo.qml | 14 +- .../customizes/QAddAnExistingKey.qml | 139 ++ .../customizes/QAddAssistedWalletSigner.qml | 68 +- .../customizes/QCreateTransaction.qml | 37 +- .../customizes/QOnScreenContent.qml | 1 + .../customizes/QPopupInfoVertical.qml | 8 +- Qml/Components/customizes/QScreen.qml | 17 + .../customizes/QSendTransaction.qml | 6 +- .../customizes/Texts/QTextAreaBoxTypeA.qml | 146 ++ .../customizes/Texts/QTextAreaBoxTypeB.qml | 61 + .../customizes/Texts/QTextAreaBoxTypeC.qml | 118 ++ .../customizes/Texts/QTextInputBoxTypeB.qml | 19 +- .../customizes/Texts/QTextInputBoxTypeE.qml | 62 + Qml/Components/customizes/Texts/QTextLink.qml | 19 + .../services/QInheritanceDetails.qml | 136 ++ .../services/QSelectAnAssistedWallet.qml | 55 + .../services/QViewInheritancePlaning.qml | 348 ++++ Qml/Components/origins/QTextArea.qml | 54 + Qml/Components/origins/QTextField.qml | 10 +- Qml/Global/QGlobal.qml | 17 +- .../LocalMode/SCR_ADD_HARDWARE_SIGNER.qml | 6 +- .../LocalMode/SCR_ADD_NEW_SOFTWARE_SIGNER.qml | 4 +- .../SCR_ADD_REMOTE_SIGNER_RESULT.qml | 42 +- .../LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml | 10 +- .../SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml | 6 +- Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml | 17 +- .../LocalMode/SCR_CREATE_TRANSACTION.qml | 37 +- Qml/Screens/LocalMode/SCR_HOME.qml | 27 +- .../LocalMode/SCR_TRANSACTION_HISTORY.qml | 4 +- .../LocalMode/SCR_TRANSACTION_INFO.qml | 40 +- Qml/Screens/LocalMode/SCR_UTXOS.qml | 5 +- Qml/Screens/LocalMode/SCR_WALLET_INFO.qml | 45 +- Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml | 422 ++++ .../OnlineMode/SCR_ADD_COLDCARD_ASK.qml | 103 + .../OnlineMode/SCR_ADD_COLDCARD_EXIST.qml | 91 + Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml | 49 +- Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml | 14 +- .../OnlineMode/SCR_ADD_LEDGER_EXIST.qml | 92 + Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml | 42 +- Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml | 14 +- .../OnlineMode/SCR_ADD_TREZOR_EXIST.qml | 92 + .../OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml | 8 +- .../SCR_EDIT_YOUR_INHERITANCE_PLAN.qml | 449 ++++ .../SCR_INHERITANCE_TRANSACTION_DETAILS.qml | 4 +- .../SCR_INHERITANCE_WITHDRAW_BALANCE.qml | 4 +- Qml/Screens/OnlineMode/SCR_LOGIN_ONLINE.qml | 8 + .../SCR_LOGIN_WITH_SOFTWARE_KEY.qml | 16 + .../SCR_SELECT_WALLET_CO_SIGN_POLICE.qml | 4 +- .../SCR_SELECT_YOUR_LOCKDOWN_PERIOD.qml | 4 +- .../OnlineMode/SCR_SERVICE_SETTINGS.qml | 99 +- .../OnlineMode/SCR_SHARE_YOUR_SECRETS.qml | 272 +++ Views/Common/ViewStates.h | 7 + Views/Common/ViewsDefines.h | 11 +- Views/Common/ViewsEnums.h | 1120 +++++----- Views/Diagram/NunchuckDiagram.asta | Bin 92392 -> 97125 bytes Views/Diagram/NunchuckDiagram.xml | 1840 ++++++++++++++--- Views/STATE_ID_SCR_ADD_COLDCARD.cpp | 64 + Views/STATE_ID_SCR_ADD_COLDCARD.h | 35 + Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp | 35 + Views/STATE_ID_SCR_ADD_COLDCARD_ASK.h | 34 + Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp | 44 + Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.h | 35 + Views/STATE_ID_SCR_ADD_LEDGER.cpp | 13 +- Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp | 44 + Views/STATE_ID_SCR_ADD_LEDGER_EXIST.h | 35 + Views/STATE_ID_SCR_ADD_TREZOR.cpp | 11 +- Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp | 44 + Views/STATE_ID_SCR_ADD_TREZOR_EXIST.h | 35 + Views/STATE_ID_SCR_ADD_WALLET.cpp | 2 +- .../STATE_ID_SCR_ADD_WALLET_CONFIRMATION.cpp | 72 +- ...ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.cpp | 46 +- Views/STATE_ID_SCR_CONSOLIDATE_OUTPUT.cpp | 3 +- Views/STATE_ID_SCR_CREATE_TRANSACTION.cpp | 6 +- ...TATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp | 51 + .../STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h | 38 + Views/STATE_ID_SCR_HOME.cpp | 19 +- Views/STATE_ID_SCR_HOME.h | 4 + Views/STATE_ID_SCR_REENTER_YOUR_PASSWORD.cpp | 8 + Views/STATE_ID_SCR_SERVICE_SETTINGS.cpp | 33 + Views/STATE_ID_SCR_SERVICE_SETTINGS.h | 4 + Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp | 35 + Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.h | 34 + Views/STATE_ID_SCR_TRANSACTION_INFO.cpp | 7 +- Views/STATE_ID_SCR_WALLET_INFO.cpp | 12 +- Views/Views.h | 92 +- contrib/libnunchuk | 2 +- ifaces/Chats/matrixbrigde.cpp | 16 +- ifaces/Draco.cpp | 301 ++- ifaces/Draco.h | 20 +- ifaces/DracoDefines.h | 21 + ifaces/bridgeifaces.cpp | 335 +-- ifaces/bridgeifaces.h | 22 +- ifaces/nunchuckiface.cpp | 44 +- ifaces/nunchuckiface.h | 17 +- ifaces/nunchucklistener.cpp | 2 + ifaces/qUtils.cpp | 41 + ifaces/qUtils.h | 5 + localization/STR_CPP.h | 2 + localization/STR_QML.js | 154 +- main.cpp | 19 +- qml.qrc | 34 + 150 files changed, 8618 insertions(+), 2010 deletions(-) create mode 100644 Images/Device_Icons/Ledger.svg create mode 100644 Images/calendar-dark.png create mode 100644 Images/calendar-dark.svg create mode 100644 Images/change-password-dark.svg create mode 100644 Images/close-24px.svg create mode 100644 Images/coldcard-illustration.svg create mode 100644 Images/inheritance_backup_password.svg create mode 100644 Images/more-horizontal-dark.svg create mode 100644 Images/star-dark.png create mode 100644 Images/star-dark.svg create mode 100644 Images/trezor-illustration.svg create mode 100644 Images/wallet-brand-icon.svg create mode 100644 Qml/Components/customizes/Buttons/QAssistedWalletDelegate.qml create mode 100644 Qml/Components/customizes/Buttons/QCheckBoxButton.qml create mode 100644 Qml/Components/customizes/Buttons/QLinearGradient.qml create mode 100644 Qml/Components/customizes/Buttons/QRadioButtonTypeE.qml create mode 100644 Qml/Components/customizes/Buttons/QRadioButtonTypeF.qml create mode 100644 Qml/Components/customizes/QAddAnExistingKey.qml create mode 100644 Qml/Components/customizes/Texts/QTextAreaBoxTypeA.qml create mode 100644 Qml/Components/customizes/Texts/QTextAreaBoxTypeB.qml create mode 100644 Qml/Components/customizes/Texts/QTextAreaBoxTypeC.qml create mode 100644 Qml/Components/customizes/Texts/QTextInputBoxTypeE.qml create mode 100644 Qml/Components/customizes/Texts/QTextLink.qml create mode 100644 Qml/Components/customizes/services/QInheritanceDetails.qml create mode 100644 Qml/Components/customizes/services/QSelectAnAssistedWallet.qml create mode 100644 Qml/Components/customizes/services/QViewInheritancePlaning.qml create mode 100644 Qml/Components/origins/QTextArea.qml create mode 100644 Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml create mode 100644 Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml create mode 100644 Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml create mode 100644 Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml create mode 100644 Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml create mode 100644 Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml create mode 100644 Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD.cpp create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD.h create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD_ASK.h create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp create mode 100644 Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.h create mode 100644 Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp create mode 100644 Views/STATE_ID_SCR_ADD_LEDGER_EXIST.h create mode 100644 Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp create mode 100644 Views/STATE_ID_SCR_ADD_TREZOR_EXIST.h create mode 100644 Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp create mode 100644 Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h create mode 100644 Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp create mode 100644 Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.h diff --git a/CMakeLists.txt b/CMakeLists.txt index db484e04..baaaa89a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,13 @@ set(Views_SRCS Views/STATE_ID_SCR_ADD_TREZOR.cpp Views/STATE_ID_SCR_ADD_TREZOR_ASK.cpp Views/STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE.cpp + Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp + Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp + Views/STATE_ID_SCR_ADD_COLDCARD.cpp + Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp + Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp + Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp + Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp ) set(Views_MOCS diff --git a/Images/Device_Icons/Ledger.svg b/Images/Device_Icons/Ledger.svg new file mode 100644 index 00000000..b76d6b15 --- /dev/null +++ b/Images/Device_Icons/Ledger.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Images/calendar-dark.png b/Images/calendar-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..cf33bbf3de4147883bed31ec0eab74f6f32f1b62 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#ZJsWUAr*{Ir}T0*8wj-OFJ;~$Y%;sFweP~& zOT4exb~WZL@b4&+Tkgrj^@_dS<(>Zb9RhQwU7P&6d~xqg5eMb`h_lvN%pChSoj+JC z6}aHY@gTWg!)KP^3KpLw0us*bUeDI9Q*gcRljO1mnH7$_2CUr0bsPU}2=^-Z@b{yq zWu9hS>=xCDTiMv^b?bWB>oaZWrJDtP3$Kd)LVVeZb)9>gTe~DWM4fHA!dl literal 0 HcmV?d00001 diff --git a/Images/calendar-dark.svg b/Images/calendar-dark.svg new file mode 100644 index 00000000..841681d6 --- /dev/null +++ b/Images/calendar-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Images/change-password-dark.svg b/Images/change-password-dark.svg new file mode 100644 index 00000000..ea139659 --- /dev/null +++ b/Images/change-password-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/Images/close-24px.svg b/Images/close-24px.svg new file mode 100644 index 00000000..24d8c035 --- /dev/null +++ b/Images/close-24px.svg @@ -0,0 +1,3 @@ + + + diff --git a/Images/coldcard-illustration.svg b/Images/coldcard-illustration.svg new file mode 100644 index 00000000..d943a3b7 --- /dev/null +++ b/Images/coldcard-illustration.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Images/inheritance_backup_password.svg b/Images/inheritance_backup_password.svg new file mode 100644 index 00000000..b9e349c6 --- /dev/null +++ b/Images/inheritance_backup_password.svg @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Images/more-horizontal-dark.svg b/Images/more-horizontal-dark.svg new file mode 100644 index 00000000..1718d712 --- /dev/null +++ b/Images/more-horizontal-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/Images/star-dark.png b/Images/star-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..489ac5acb0070a66066ec09f1840250fb8bc7dcf GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#JDx6%Ar*{or@rQGau8@?Pi8Drkj-Fs=PX+w z8^EL*(WDyCw2|p;gOEnz9q#lel{)Ny9(!}FzZsdAZ_Xg??PRo>{hHI6`$aYz*^*>F zpAVGY-YgfqdtX9kPG**N#5SL#iiF9R>@FX97wx8Q`IS{|ZT0G%UH>jGb`^2e=c&m& z`18l<=T){-tW7#D6x_;MV|Gv^;_F}M#CgFxA3Aq>^;dRU?g;8ltdUEeTyxmsVer{^ zZp+`4MK%hke26hmG;P^mUZ}m3({sYFT}M<;&Q1Ge-xS)tj4RgdZA0#tkE|QkeYhK2 SJpUxnpA4R^elF{r5}E)4t9`iu literal 0 HcmV?d00001 diff --git a/Images/star-dark.svg b/Images/star-dark.svg new file mode 100644 index 00000000..7c7ac6d4 --- /dev/null +++ b/Images/star-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Images/trezor-illustration.svg b/Images/trezor-illustration.svg new file mode 100644 index 00000000..55022697 --- /dev/null +++ b/Images/trezor-illustration.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Images/wallet-brand-icon.svg b/Images/wallet-brand-icon.svg new file mode 100644 index 00000000..25bcad63 --- /dev/null +++ b/Images/wallet-brand-icon.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Models/AppModel.cpp b/Models/AppModel.cpp index 3b67ecf7..9d602b75 100644 --- a/Models/AppModel.cpp +++ b/Models/AppModel.cpp @@ -27,6 +27,8 @@ #include #include "Chats/matrixbrigde.h" #include "utils/enumconverter.hpp" +#include "Chats/QUserWallets.h" +#include "ServiceSetting.h" AppModel::AppModel(): inititalized_{false}, walletList_(QWalletListModelPtr(new WalletListModel())), @@ -54,16 +56,21 @@ AppModel::AppModel(): inititalized_{false}, newKeySignMessage_("") { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - connect(&timerRefreshHealthCheck_, SIGNAL(timeout()), this, SLOT(timerHealthCheckTimeHandle())); - timerRefreshHealthCheck_.start(60000); // Every 1' - connect(&timerFeeRates_, SIGNAL(timeout()), this, SLOT(timerFeeRatesHandle())); - timerFeeRates_.start(300000); // Every 5' - connect(&timerCheckAuthorized_, SIGNAL(timeout()), this, SLOT(timerCheckAuthorizedHandle())); + connect(&timerRefreshHealthCheck_, &QTimer::timeout, this, &AppModel::timerHealthCheckTimeHandle, Qt::QueuedConnection); + connect(&timerFeeRates_, &QTimer::timeout, this, &AppModel::timerFeeRatesHandle, Qt::QueuedConnection); + connect(&timerCheckAuthorized_, &QTimer::timeout, this, &AppModel::timerCheckAuthorizedHandle, Qt::QueuedConnection); + connect(this, &AppModel::forwardToast, this, &AppModel::recieveToast, Qt::QueuedConnection); + + timerRefreshHealthCheck_.start(60000); // Every 1' + timerFeeRates_.start(300000); // Every 5' qrExported_.clear(); suggestMnemonics_.clear(); - connect(qApp, &QCoreApplication::aboutToQuit, this, [] { - DBG_INFO << "APPLICATION ABOUT TO QUIT"; + connect(qApp, &QCoreApplication::aboutToQuit, this, [this] { + DBG_INFO << "APPLICATION ABOUT TO QUIT" << QThreadPool::globalInstance()->activeThreadCount(); + QThreadPool::globalInstance()->clear(); + QThreadPool::globalInstance()->waitForDone(); + this->disconnect(); bridge::stopNunchuk(); }); } @@ -212,9 +219,11 @@ bool AppModel::makeInstanceForAccount(const QVariant msg, const QString &dbPassp if((int)EWARNING::WarningType::NONE_MSG == nunchukMsg.type()){ ret = true; QString device_id = QString("%1%2").arg(Draco::instance()->deviceId()).arg(Draco::instance()->chatId()); +#if 0 //FIXME Performance Draco::instance()->getMe(); - Draco::instance()->getCurrentUserSubscription(); +#endif AppModel::instance()->timerFeeRatesHandle(); + QUserWallets::instance()->newRequestToAddKey(); timeoutHandler(1000,[account, device_id](){ CLIENT_INSTANCE->requestLogin(); CLIENT_INSTANCE->saveStayLoggedInData(); @@ -462,9 +471,9 @@ void AppModel::setSoftwareSignerDeviceList(const QDeviceListModelPtr &value) QString AppModel::hourFeeCurrency() const { - double exRates = exchangeRates()/100000000; double fee = (double)hourFee_/1000; - double feeCurrency = exRates*fee*140; + double btcRate = btcRates()/100000000; + double feeCurrency = btcRate*fee*140; QLocale locale(QLocale::English); return locale.toString(feeCurrency, 'f', 2); } @@ -486,9 +495,9 @@ void AppModel::setHourFee(qint64 fee) QString AppModel::minFeeCurrency() const { - double exRates = exchangeRates()/100000000; + double btcRate = btcRates()/100000000; double fee = (double)minFee_/1000; - double feeCurrency = exRates*fee*140; + double feeCurrency = btcRate*fee*140; QLocale locale(QLocale::English); return locale.toString(feeCurrency, 'f', 2); } @@ -520,9 +529,9 @@ void AppModel::resetSignersChecked() QString AppModel::halfHourFeeCurrency() const { - double exRates = exchangeRates()/100000000; + double btcRate = btcRates()/100000000; double fee = (double)halfHourFee_/1000; - double feeCurrency = exRates*fee*140; + double feeCurrency = btcRate*fee*140; QLocale locale(QLocale::English); return locale.toString(feeCurrency, 'f', 2); } @@ -544,9 +553,9 @@ void AppModel::setHalfHourFee(qint64 fee) QString AppModel::fastestFeeCurrency() const { - double exRates = exchangeRates()/100000000; + double btcRate = btcRates()/100000000; double fee = (double)fastestFee_/1000; - double feeCurrency = exRates*fee*140; + double feeCurrency = btcRate*fee*140; QLocale locale(QLocale::English); return locale.toString(feeCurrency, 'f', 2); } @@ -646,23 +655,14 @@ int AppModel::walletListCurrentIndex() const return walletListCurrentIndex_; } -void AppModel::setWalletListCurrentIndex(int walletListCurrentIndex) +void AppModel::setWalletListCurrentIndex(int index) { - DBG_INFO << walletListCurrentIndex; - if(walletListCurrentIndex == -1){ - walletListCurrentIndex_ = 0; - } - else{ - walletListCurrentIndex_ = walletListCurrentIndex; - } - setWalletInfoByIndex(walletListCurrentIndex_); - if(walletInfo()){ - QString wallet_id = walletInfo()->id(); - QtConcurrent::run([wallet_id]() { - bridge::nunchukSetSelectedWallet(wallet_id); - }); + if(walletListCurrentIndex_ != index){ + walletListCurrentIndex_ = index; } + DBG_INFO << "FIXME" << index; emit walletListCurrentIndexChanged(); + setWalletInfoByIndex(walletListCurrentIndex_); } AppModel *AppModel::instance() { @@ -674,12 +674,9 @@ void AppModel::requestInitialData() { if(ONLINE_MODE == bridge::nunchukCurrentMode()){ requestCreateUserWallets(); + } else { + startReloadUserDb(); } - QtConcurrent::run([this]() { - startReloadWallets(); - startReloadMasterSigners(); - startReloadRemoteSigners(); - }); } void AppModel::requestSyncWalletDb(const QString &wallet_id) @@ -691,141 +688,98 @@ void AppModel::requestSyncWalletDb(const QString &wallet_id) void AppModel::requestCreateUserWallets() { - if(CLIENT_INSTANCE->getSubCur().isEmpty()) return; - QJsonObject data = Draco::instance()->getAssistedWallets(); - if(!data.isEmpty()){ - QJsonArray wallets = data["wallets"].toArray(); - mUserWallets.clear(); - for(QJsonValue jv_wallet : wallets){ - QJsonObject js_wallet = jv_wallet.toObject(); - QString wallet_id = js_wallet["local_id"].toString(); - QString status = js_wallet["status"].toString(); - if (status == "ACTIVE") { - mUserWallets.append(wallet_id); - } - if(status == "ACTIVE" && !bridge::nunchukHasWallet(wallet_id)){ - QJsonArray signers = js_wallet["signers"].toArray(); - for(QJsonValue jv_signer : signers){ - QJsonObject js_signer = jv_signer.toObject(); - QJsonObject tapsigner = js_signer["tapsigner"].toObject(); - QString name = js_signer["name"].toString(); - QString xfp = js_signer["xfp"].toString(); - if(!tapsigner.isEmpty()){ - QString card_id = tapsigner["card_id"].toString(); - QString version = tapsigner["version"].toString(); - int birth_height = tapsigner["birth_height"].toInt(); - bool is_testnet = tapsigner["is_testnet"].toBool(); - bridge::AddTapsigner(card_id,xfp,name,version,birth_height,is_testnet); - } - else { - QString xpub = js_signer["xpub"].toString(); - QString pubkey = js_signer["pubkey"].toString(); - QString derivation_path = js_signer["derivation_path"].toString(); - QString type = js_signer["type"].toString(); - nunchuk::SingleSigner signer(name.toStdString(), xpub.toStdString(), pubkey.toStdString(), derivation_path.toStdString(), xfp.toStdString(), std::time(0)); - if(!bridge::nunchukHasSinger(signer)){ - bridge::nunchukCreateSigner(name, xpub, pubkey, derivation_path, xfp, type); - } - } - } - QWarningMessage msg; - QString bsms = js_wallet["bsms"].toString(); - nunchuk::Wallet w = qUtils::ParseWalletDescriptor(bsms,msg); - QString name = js_wallet["name"].toString(); - QString description = js_wallet["description"].toString(); - w.set_name(name.toStdString()); - w.set_description(description.toStdString()); - bridge::nunchukCreateWallet(w, true,msg); - } else if (status == "DELETED" && bridge::nunchukHasWallet(wallet_id)){ - QWarningMessage msgwarning; - /*bool ret = */bridge::nunchukDeleteWallet(wallet_id, msgwarning); - } - QWarningMessage msg; - nunchuk::Wallet w = nunchukiface::instance()->GetWallet(wallet_id.toStdString(), msg); - std::vector local_signers = w.get_signers(); - QJsonArray signers = js_wallet["signers"].toArray(); - for(QJsonValue jv_signer : signers){ - QJsonObject js_signer = jv_signer.toObject(); - QString xfp = js_signer["xfp"].toString(); - QJsonArray wtags = js_signer["tags"].toArray(); - std::vector::iterator local_signer = std::find_if(local_signers.begin(), local_signers.end(), [&](const nunchuk::SingleSigner &local){ - return local.get_master_fingerprint() == xfp.toStdString(); - }); - if(wtags.size() != 0){ - QWarningMessage msgIn; - if (local_signer != local_signers.end() && local_signer->has_master_signer()) { - nunchuk::MasterSigner m = nunchukiface::instance()->GetMasterSigner(local_signer->get_master_signer_id(),msgIn); - std::vector tags; // get tags from api signer.tags - for (QJsonValue tag : wtags) { - QString js_tag = tag.toString(); - tags.push_back(SignerTagFromStr(js_tag.toStdString())); - } - // Do update - m.set_tags(tags); - nunchukiface::instance()->UpdateMasterSigner(m,msgIn); - } else { - // update for single signer - // skip for now - } - } - } - - if (!wallet_id.isEmpty()) { - auto syncTransaction = [&]() { - QJsonObject data = Draco::instance()->assistedWalletGetListTx(wallet_id); - QJsonArray transactions = data.value("transactions").toArray(); - for(QJsonValue js_value : transactions){ - QJsonObject transaction = js_value.toObject(); - QString status_ = transaction.value("status").toString(); - QString psbt = transaction.value("psbt").toString(); - QString note = transaction.value("note").toString(); - QString type = transaction.value("type").toString(); - if (status_ == "READY_TO_BROADCAST" || status_ == "PENDING_SIGNATURES" ) { - QWarningMessage _msg; - QTransactionPtr tran = bridge::nunchukImportPsbt(wallet_id, psbt, _msg); - if(tran && (int)EWARNING::WarningType::NONE_MSG == _msg.type()){ - bridge::nunchukUpdateTransactionMemo(wallet_id, - tran->txid(), - note); - long int broadcast_time_milis = static_cast(transaction.value("broadcast_time_milis").toInt()); - // honey badger feature: schedule broadcast - long int current_time_stamp_milis = static_cast(std::time(nullptr)) * 1000; - - if(type == "SCHEDULED" && broadcast_time_milis > current_time_stamp_milis) { - bridge::nunchukUpdateTransactionSchedule(wallet_id, tran->txid(), broadcast_time_milis/1000,msg); + if(CLIENT_INSTANCE->getSubCur().isEmpty()) { + startReloadUserDb(); + return; + } + QtConcurrent::run([this]() { + QJsonObject data = Draco::instance()->getAssistedWallets(); + if(!data.isEmpty()){ + QJsonArray wallets = data["wallets"].toArray(); + mUserWallets.clear(); + for(QJsonValue jv_wallet : wallets){ + QJsonObject js_wallet = jv_wallet.toObject(); + QString wallet_id = js_wallet["local_id"].toString(); + QString status = js_wallet["status"].toString(); + if (status == "ACTIVE") { + mUserWallets.append(wallet_id); + if(!bridge::nunchukHasWallet(wallet_id)){ + QJsonArray signers = js_wallet["signers"].toArray(); + for(QJsonValue jv_signer : signers){ + QJsonObject js_signer = jv_signer.toObject(); + QJsonObject tapsigner = js_signer["tapsigner"].toObject(); + QString name = js_signer["name"].toString(); + QString xfp = js_signer["xfp"].toString(); + if(!tapsigner.isEmpty()){ + QString card_id = tapsigner["card_id"].toString(); + QString version = tapsigner["version"].toString(); + int birth_height = tapsigner["birth_height"].toInt(); + bool is_testnet = tapsigner["is_testnet"].toBool(); + bridge::AddTapsigner(card_id,xfp,name,version,birth_height,is_testnet); + } + else { + QString xpub = js_signer["xpub"].toString(); + QString pubkey = js_signer["pubkey"].toString(); + QString derivation_path = js_signer["derivation_path"].toString(); + QString type = js_signer["type"].toString(); + nunchuk::SingleSigner signer(name.toStdString(), xpub.toStdString(), pubkey.toStdString(), derivation_path.toStdString(), xfp.toStdString(), std::time(0)); + if(!bridge::nunchukHasSinger(signer)){ + bridge::nunchukCreateSigner(name, xpub, pubkey, derivation_path, xfp, type); } } } + QWarningMessage msg; + QString bsms = js_wallet["bsms"].toString(); + nunchuk::Wallet w = qUtils::ParseWalletDescriptor(bsms,msg); + QString name = js_wallet["name"].toString(); + QString description = js_wallet["description"].toString(); + w.set_name(name.toStdString()); + w.set_description(description.toStdString()); + bridge::nunchukCreateWallet(w, true,msg); + } + QWarningMessage msg; + nunchuk::Wallet w = nunchukiface::instance()->GetWallet(wallet_id.toStdString(), msg); + std::vector local_signers = w.get_signers(); + nunchukiface::instance()->UpdateWallet(w, msg); + for (nunchuk::SingleSigner s : local_signers) + { + nunchukiface::instance()->UpdateRemoteSigner(s, msg); } - }; - auto lockDown = [&]() { - int offset = 0; - const int limit = 10; - while (true) { - QJsonObject data = Draco::instance()->assistedWalletDeleteListTx(wallet_id, offset, limit); - QJsonArray transactions = data.value("transactions").toArray(); - for (QJsonValue js_value : transactions) { - QJsonObject transaction = js_value.toObject(); - QString wallet_local_id = transaction.value("wallet_local_id").toString(); - QString transaction_id = transaction.value("transaction_id").toString(); - if (!bridge::nunchukDeleteTransaction(wallet_local_id, transaction_id)) { - DBG_INFO << "not remove "; - return; // exit while loop + QJsonArray signers = js_wallet["signers"].toArray(); + for(QJsonValue jv_signer : signers){ + QJsonObject js_signer = jv_signer.toObject(); + QString xfp = js_signer["xfp"].toString(); + QJsonArray wtags = js_signer["tags"].toArray(); + std::vector::iterator local_signer = std::find_if(local_signers.begin(), local_signers.end(), [&](const nunchuk::SingleSigner &local){ + return local.get_master_fingerprint() == xfp.toStdString(); + }); + if(wtags.size() != 0){ + QWarningMessage msgIn; + if (local_signer != local_signers.end() && local_signer->has_master_signer()) { + nunchuk::MasterSigner m = nunchukiface::instance()->GetMasterSigner(local_signer->get_master_signer_id(),msgIn); + std::vector tags; // get tags from api signer.tags + for (QJsonValue tag : wtags) { + QString js_tag = tag.toString(); + tags.push_back(SignerTagFromStr(js_tag.toStdString())); + } + // Do update + m.set_tags(tags); + nunchukiface::instance()->UpdateMasterSigner(m,msgIn); } } - if (transactions.size() == 0 || transactions.size() < limit) { - return; // exit while loop - } - offset += transactions.size(); } - }; - //===================== - syncTransaction(); - lockDown(); + } + else if (status == "DELETED" && bridge::nunchukHasWallet(wallet_id)){ + QWarningMessage msgwarning; + bridge::nunchukDeleteWallet(wallet_id, msgwarning); + } + else{} } + requestAssistedWalletsSetuped(); + emit walletListChanged(); } - } - DBG_INFO << mUserWallets; + startReloadUserDb(); + }); } void AppModel::requestSyncSharedWallets() @@ -865,6 +819,25 @@ void AppModel::requestSyncSharedWallets() } } +void AppModel::requestAssistedWalletsSetuped() +{ + QStringList setuped {}; + for (QString id : mUserWallets) { + QJsonObject response; + QString errormsg; + bool ret = Draco::instance()->inheritanceGetPlan(id, response, errormsg); + if (ret) { + QJsonObject inheritance = response.value("inheritance").toObject(); + QString status = inheritance.value("status").toString(); + if (status == "ACTIVE") { + setuped.append(id); + } + } + } + ServiceSetting::instance()->setAssistedSetuped(setuped); + DBG_INFO << mUserWallets << setuped; +} + void AppModel::requestClearData() { if(walletList()){ @@ -876,6 +849,7 @@ void AppModel::requestClearData() if(remoteSignerList()){ remoteSignerList()->cleardata(); } + setWalletListCurrentIndex(-1); AppSetting::instance()->setSyncPercent(0); } @@ -900,7 +874,7 @@ QDeviceListModelPtr AppModel::deviceListPtr() const void AppModel::setWalletList(const QWalletListModelPtr &d){ walletList_ = d; if(walletList_){ - walletList_.data()->requestSort(WalletListModel::WalletRoles::wallet_Name_Role, Qt::AscendingOrder); + walletList_.data()->requestSort(WalletListModel::WalletRoles::wallet_createDate_Role, Qt::AscendingOrder); } emit walletListChanged(); } @@ -1073,9 +1047,14 @@ void AppModel::setWalletInfo(const QWalletPtr &d) if(d && 0 != QString::compare(d.data()->id(), walletInfo_->id(), Qt::CaseInsensitive)){ walletInfo_ = d; if(walletInfo_){ - timeoutHandler(2000, [this]() { - requestSyncWalletDb(walletInfo_->id()); - }); + DBG_INFO << "FIXME" << walletInfo_.data()->name(); + QString wallet_id = walletInfo_.data()->id(); + if(wallet_id != ""){ + requestSyncWalletDb(wallet_id); + QtConcurrent::run([wallet_id]() { + bridge::nunchukSetSelectedWallet(wallet_id); + }); + } } emit walletInfoChanged(); } @@ -1083,12 +1062,17 @@ void AppModel::setWalletInfo(const QWalletPtr &d) void AppModel::setWalletInfoByIndex(const int index) { - if(walletList_){ - QWalletPtr newWallet = walletList_.data()->getWalletByIndex(index); - if(!newWallet){ - newWallet = QWalletPtr(new Wallet()); + if(index == -1){ + setWalletInfo(QWalletPtr(new Wallet())); + } + else{ + if(walletList_){ + QWalletPtr newWallet = walletList_.data()->getWalletByIndex(index); + if(!newWallet){ + newWallet = QWalletPtr(new Wallet()); + } + setWalletInfo(newWallet); } - setWalletInfo(newWallet); } } @@ -1189,7 +1173,7 @@ void AppModel::timerFeeRatesHandle() void AppModel::timerCheckAuthorizedHandle() { Draco::instance()->getMe(); - Draco::instance()->getCurrentUserSubscription(); + QUserWallets::instance()->newRequestToAddKey(); } QString AppModel::parseKeystoneSigner(QString qr) @@ -1210,7 +1194,7 @@ bool AppModel::parseKeystoneWallet(const QString name, const QString desc, const walletImported.data()->setCreationMode((int)Wallet::CreationMode::CREATE_BY_IMPORT_QRCODE); walletList()->addWallet(walletImported); resetSignersChecked(); - walletList()->requestSort(WalletListModel::WalletRoles::wallet_Name_Role, Qt::AscendingOrder); + walletList()->requestSort(WalletListModel::WalletRoles::wallet_createDate_Role, Qt::AscendingOrder); int index = walletList()->getWalletIndexById(walletImported.data()->id()); if(-1 != index){ setWalletListCurrentIndex(index); @@ -1410,14 +1394,7 @@ void AppModel::setBtcRates(double btcRates) } void AppModel::showToast(int code, const QString &what, EWARNING::WarningType type, const QString& explain, POPUP::PopupType popup){ - timeoutHandler(500, [this, code, what, type, explain, popup]() { - if(!warningMessage()){ - setWarningMessage(QWarningMessagePtr(new QWarningMessage())); - } - warningMessage()->setWarningMessage(code, what, type, explain); - warningMessage()->setPopupType((int)popup); - QQuickViewer::instance()->sendEvent(E::EVT_SHOW_TOAST_MESSAGE); - }); + emit forwardToast(code, what, type, explain, popup); } void AppModel::setToast(int code, const QString &what, EWARNING::WarningType type, const QString &explain, POPUP::PopupType popup) @@ -1429,3 +1406,15 @@ void AppModel::setToast(int code, const QString &what, EWARNING::WarningType typ warningMessage()->setPopupType((int)popup); emit signalShowToast(); } + +void AppModel::recieveToast(int code, const QString &what, EWARNING::WarningType type, const QString &explain, POPUP::PopupType popup) +{ + timeoutHandler(500, [this, code, what, type, explain, popup]() { + if(!warningMessage()){ + setWarningMessage(QWarningMessagePtr(new QWarningMessage())); + } + warningMessage()->setWarningMessage(code, what, type, explain); + warningMessage()->setPopupType((int)popup); + QQuickViewer::instance()->sendEvent(E::EVT_SHOW_TOAST_MESSAGE); + }); +} diff --git a/Models/AppModel.h b/Models/AppModel.h index 5bcd10a2..567aa1a1 100644 --- a/Models/AppModel.h +++ b/Models/AppModel.h @@ -75,7 +75,7 @@ class AppModel final : public Controller Q_PROPERTY(QString newKeySignMessage READ newKeySignMessage NOTIFY newKeySignMessageChanged) Q_PROPERTY(QString newKeySignMessageSHA256 READ newKeySignMessageSHA256 NOTIFY newKeySignMessageChanged) Q_PROPERTY(int addSignerWizard READ addSignerWizard WRITE setAddSignerWizard NOTIFY addSignerWizardChanged) - + DECLARE_PROPERTY(bool, IsPremiumUser, {}, {}) public: static AppModel *instance(); AppModel(AppModel &other) = delete; @@ -85,6 +85,7 @@ class AppModel final : public Controller void requestSyncWalletDb(const QString& wallet_id); void requestCreateUserWallets(); void requestSyncSharedWallets(); + void requestAssistedWalletsSetuped(); void requestClearData(); WalletListModel *walletList() const; @@ -147,7 +148,7 @@ class AppModel final : public Controller void setDestinationList(const QDestinationListModelPtr &destinationList); int walletListCurrentIndex() const; - void setWalletListCurrentIndex(int walletListCurrentIndex); + void setWalletListCurrentIndex(int index); int chainTip() const; void setChainTip(int chainTip); @@ -342,6 +343,7 @@ class AppModel final : public Controller void newKeySignMessageChanged(); void btcRatesChanged(); void addSignerWizardChanged(); + void forwardToast(int code, const QString &what, EWARNING::WarningType type, const QString &explain, POPUP::PopupType popup); public slots: void timerHealthCheckTimeHandle(); @@ -360,6 +362,7 @@ public slots: bool updateSettingRestartRequired(); QString getFilePath(const QString in); bool enableDatabaseEncryption(const QString in); + void recieveToast(int code, const QString &what, EWARNING::WarningType type, const QString &explain, POPUP::PopupType popup); }; #endif // APPMODEL_H diff --git a/Models/AppSetting.h b/Models/AppSetting.h index 370a5979..ab0f289c 100644 --- a/Models/AppSetting.h +++ b/Models/AppSetting.h @@ -32,8 +32,9 @@ #define TOR_PORT 9050 #define CORERPC_MAINNET_PORT 8332 #define CORERPC_TESTNET_PORT 18332 -#define BLOCKSTREAM_TESTNET "https://blockstream.info/testnet/tx/" -#define BLOCKSTREAM_MAINNET "https://blockstream.info/tx/" +#define EXPLORER_MAINNET "https://mempool.space/tx/" +#define EXPLORER_TESTNET "https://mempool.space/testnet/tx/" +#define EXPLORER_SIGNNET "https://mempool.space/signet/tx/" #define GLOBAL_SIGNET_EXPLORER "https://explorer.bc-2.jp/" diff --git a/Models/Chats/ClientController.cpp b/Models/Chats/ClientController.cpp index e2b93168..c43c3058 100755 --- a/Models/Chats/ClientController.cpp +++ b/Models/Chats/ClientController.cpp @@ -38,6 +38,7 @@ #include #include #include +#include "Chats/QUserWallets.h" using Quotient::NetworkAccessManager; using Quotient::Settings; @@ -359,6 +360,7 @@ void ClientController::requestSignout() if(contacts()){ contacts()->removeAll(); } + QUserWallets::instance()->newRequestToAddKey(); qApp->restoreOverrideCursor(); } @@ -487,7 +489,7 @@ QVariant ClientController::user() const if(plan.isEmpty() == false){ QString slug = plan["slug"].toString(); maps["plan_slug"] = slug; - maps["isPremiumUser"] = slug == "iron_hand" || slug == "honey_badger" ; + maps["isPremiumUser"] = slug == "iron_hand" || slug == "honey_badger" || slug == "honey_badger_testnet"; }else{ maps["plan_slug"] = ""; maps["isPremiumUser"] = false; @@ -590,10 +592,12 @@ void ClientController::setSubCur(const QJsonObject &sub) QJsonObject plan = m_subCur["plan"].toObject(); if (plan.isEmpty() == false) { QString slug = plan["slug"].toString(); - bool isPremiumUser = slug == "iron_hand" || slug == "honey_badger" ; + bool isPremiumUser = slug == "iron_hand" || slug == "honey_badger" || slug == "honey_badger_testnet"; setAttachmentEnable(isPremiumUser); + AppModel::instance()->setIsPremiumUser(isPremiumUser); } else { setAttachmentEnable(false); + AppModel::instance()->setIsPremiumUser(false); } } diff --git a/Models/Chats/ClientController.h b/Models/Chats/ClientController.h index 79158373..6fdd5384 100755 --- a/Models/Chats/ClientController.h +++ b/Models/Chats/ClientController.h @@ -57,6 +57,7 @@ class ClientController final : public QObject Q_PROPERTY(QVariant user READ user NOTIFY userChanged) Q_PROPERTY(bool attachmentEnable READ attachmentEnable NOTIFY attachmentEnableChanged) Q_PROPERTY(bool readySupport READ readySupport NOTIFY readySupportChanged) + private: ClientController(); ~ClientController(); diff --git a/Models/Chats/QNunchukRoomModel.cpp b/Models/Chats/QNunchukRoomModel.cpp index 02a0ddf7..00749b19 100755 --- a/Models/Chats/QNunchukRoomModel.cpp +++ b/Models/Chats/QNunchukRoomModel.cpp @@ -38,6 +38,7 @@ #include "Draco.h" #include "localization/STR_CPP.h" #include +#include "QUserWallets.h" QNunchukRoom::QNunchukRoom(Room *r): m_room(r), @@ -59,6 +60,13 @@ QNunchukRoom::QNunchukRoom(Room *r): if(m_room){ QQmlEngine::setObjectOwnership(m_room, QQmlEngine::CppOwnership); } + + connect(this, SIGNAL(finishConsumeEvent()), this, SLOT(slotFinishConsumeEvent())); +#if 0 //FIXME performance + connect(&m_timeSyncDb, SIGNAL(timeout()), this, SLOT(slotSyncWalletDb())); + m_timeSyncDb.setSingleShot(true); + m_timeSyncDb.start(2000); +#endif qmlRegisterType(); qRegisterMetaType(); } @@ -263,7 +271,7 @@ QString QNunchukRoom::postEvent(const QString& eventType, const QJsonObject& con } else {} if(m_room && evt){ - if(this->isNunchukSyncRoom() && !AppSetting::instance()->enableMultiDeviceSync()){ + if(isNunchukSyncRoom() && !AppSetting::instance()->enableMultiDeviceSync()){ return ""; } txnId = m_room->postEvent(evt); @@ -293,13 +301,13 @@ void QNunchukRoom::slotFinishedDownloadTransaction(nunchuk::RoomTransaction room if(tx.get_txid() != ""){ QTransactionPtr rawtx = bridge::convertTransaction(tx, wallet_id); if(rawtx){ - rawtx.data()->setRoomId(this->id()); + rawtx.data()->setRoomId(id()); rawtx.data()->setInitEventId(QString::fromStdString(room_tx.get_init_event_id())); target.data()->setTransaction(rawtx); } } - if(!this->isDownloaded()){ - this->startGetPendingTxs(); + if(!isDownloaded()){ + startGetPendingTxs(); } if(conversation()){ conversation()->updateTransaction(cons, target); @@ -338,6 +346,17 @@ void QNunchukRoom::slotUpdateInitEventId(const Conversation cons) } } +void QNunchukRoom::slotFinishConsumeEvent() +{ + m_timeSyncDb.stop(); + m_timeSyncDb.start(2000); +} + +void QNunchukRoom::slotSyncWalletDb() +{ + AppModel::instance()->startReloadUserDb(); +} + void QNunchukRoom::sendMessage(const QString &message) { if(m_room && conversation() && message != ""){ @@ -353,8 +372,8 @@ void QNunchukRoom::sendMessage(const QString &message) cons.txnId = txnId; conversation()->addMessage(cons); conversation()->requestSortByTimeAscending(); - this->setLastMessage(cons); - this->setLasttimestamp(cons); + setLastMessage(cons); + setLasttimestamp(cons); } else{ DBG_INFO << "SEND FALSE"; @@ -410,7 +429,7 @@ void QNunchukRoom::sendFile(const QString& description, const QString localFile) }); QObject::connect( m_room, &Room::fileTransferProgress, [=](QString id, qint64 progress, qint64 total) { if (id == txnId) { - qDebug() << "fileTransferProgress:" << progress << total; + DBG_INFO << "fileTransferProgress:" << progress << total; } }); @@ -438,8 +457,8 @@ void QNunchukRoom::sendFile(const QString& description, const QString localFile) } conversation()->addMessage(cons); conversation()->requestSortByTimeAscending(); - this->setLastMessage(cons); - this->setLasttimestamp(cons); + setLastMessage(cons); + setLasttimestamp(cons); } } } @@ -481,11 +500,15 @@ bool QNunchukRoom::joinWalletWithMasterSigner(const QString &id, bool &needXpub) ENUNCHUCK::WalletType walletType = roomWallet()->walletEscrow() ? ENUNCHUCK::WalletType::ESCROW : roomWallet()->walletN() > 1 ? ENUNCHUCK::WalletType::MULTI_SIG : ENUNCHUCK::WalletType::SINGLE_SIG; + ENUNCHUCK::AddressType addressType = (ENUNCHUCK::AddressType)roomWallet()->walletAddressType().toInt(); + QMasterSignerPtr it = AppModel::instance()->masterSignerList()->getMasterSignerById(id); QWarningMessage msgWarning; - QSingleSignerPtr signer = bridge::nunchukGetUnusedSignerFromMasterSigner(id, - walletType, - (ENUNCHUCK::AddressType)roomWallet()->walletAddressType().toInt(), - msgWarning); + QSingleSignerPtr signer {nullptr}; + if (AppModel::instance()->getIsPremiumUser() && (int)ENUNCHUCK::SignerType::NFC == it.data()->signerType()) { + signer = bridge::nunchukGetDefaultSignerFromMasterSigner(id, walletType, addressType, msgWarning); + } else { + signer = bridge::nunchukGetUnusedSignerFromMasterSigner(id, walletType, addressType, msgWarning); + } if(signer && msgWarning.type() == (int)EWARNING::WarningType::NONE_MSG){ msgWarning.resetWarningMessage(); matrixbrigde::JoinWallet(this->id(), signer, msgWarning); @@ -516,7 +539,7 @@ bool QNunchukRoom::joinWalletWithSingleSigner(const QString &xfp) QSingleSignerPtr signer = AppModel::instance()->remoteSignerList()->getSingleSignerByFingerPrint(xfp); if(signer){ QWarningMessage msgWarning; - matrixbrigde::JoinWallet(this->id(), signer, msgWarning); + matrixbrigde::JoinWallet(id(), signer, msgWarning); if((int)EWARNING::WarningType::NONE_MSG == msgWarning.type()){ ret = true; } @@ -530,13 +553,13 @@ bool QNunchukRoom::joinWalletWithSingleSigner(const QString &xfp) return ret; } -bool QNunchukRoom::joinWalletUseSignerFromWalletImport(const QString &id, const QString &xfp) +bool QNunchukRoom::joinWalletUseSignerFromWalletImport(const QString &signer_id, const QString &xfp) { bool ret = false; nunchuk::SingleSigner signer; for(nunchuk::SingleSigner s : m_walletImport.get_signers()){ - if((s.get_master_signer_id() != "" && (s.get_master_signer_id() == id.toStdString() || s.get_master_signer_id() == xfp.toStdString())) - || (s.get_master_fingerprint() != "" && (s.get_master_fingerprint() == id.toStdString() || s.get_master_fingerprint() == xfp.toStdString()))){ + if((s.get_master_signer_id() != "" && (s.get_master_signer_id() == signer_id.toStdString() || s.get_master_signer_id() == xfp.toStdString())) + || (s.get_master_fingerprint() != "" && (s.get_master_fingerprint() == signer_id.toStdString() || s.get_master_fingerprint() == xfp.toStdString()))){ signer = s; break; } @@ -544,7 +567,7 @@ bool QNunchukRoom::joinWalletUseSignerFromWalletImport(const QString &id, const QSingleSignerPtr signerPtr = QSingleSignerPtr(new QSingleSigner(signer)); if(signerPtr && bridge::nunchukHasSinger(signer)){ QWarningMessage msgWarning; - matrixbrigde::JoinWallet(this->id(), signerPtr, msgWarning); + matrixbrigde::JoinWallet(id(), signerPtr, msgWarning); if((int)EWARNING::WarningType::NONE_MSG == msgWarning.type()){ ret = true; } @@ -607,7 +630,7 @@ bool QNunchukRoom::extractNunchukEvent(const QString &matrixType, const QString QString init_event_id = init_event["event_id"].toString(); QString xfp = ""; QWarningMessage joinmsg; - QNunchukMatrixEvent nunJoinEvent = matrixbrigde::GetEvent(this->id(), join_event_id, joinmsg); + QNunchukMatrixEvent nunJoinEvent = matrixbrigde::GetEvent(id(), join_event_id, joinmsg); if((int)EWARNING::WarningType::NONE_MSG == joinmsg.type()){ QJsonObject joinjson = matrixbrigde::stringToJson(nunJoinEvent.get_content()); xfp = joinjson["body"].toObject()["key"].toString().split('/')[0].remove('['); @@ -686,9 +709,9 @@ bool QNunchukRoom::extractNunchukEvent(const QString &matrixType, const QString cons.init_event_json = json; } else if(0 == QString::compare(msgtype, NUNCHUK_MSG_TX_RECEIVE, Qt::CaseInsensitive)){ - if(matrixbrigde::HasRoomWallet(this->id()) == false) return false; + if(matrixbrigde::HasRoomWallet(id()) == false) return false; QWarningMessage roomTxWarning; - QString tx_id = matrixbrigde::GetTransactionId(this->id(), init_event_id, roomTxWarning); + QString tx_id = matrixbrigde::GetTransactionId(id(), init_event_id, roomTxWarning); if((int)EWARNING::WarningType::NONE_MSG == roomTxWarning.type() && tx_id != ""){ cons.init_event_id = tx_id; cons.message = STR_CPP_020; @@ -699,7 +722,7 @@ bool QNunchukRoom::extractNunchukEvent(const QString &matrixType, const QString else { return false; } - downloadTransactionThread(cons, this->id()); + downloadTransactionThread(cons, id()); } else if(0 == QString::compare(matrixType, NUNCHUK_EVENT_EXCEPTION, Qt::CaseInsensitive)){ QJsonObject body = json["body"].toObject(); @@ -756,7 +779,7 @@ void QNunchukRoom::downloadTransactionThread(Conversation cons, const QString &r if(cons.init_event_id != ""){ // FIXME FOR CHECK DUP RECIEVED TX EVT QtConcurrent::run([this, cons, roomid]() { if(cons.messageType == (int)ENUNCHUCK::ROOM_EVT::TX_RECEIVE){ - QString wallet_id = this->roomWallet() ? this->roomWallet()->get_wallet_id() : ""; + QString wallet_id = roomWallet() ? roomWallet()->get_wallet_id() : ""; QString tx_id = cons.init_event_id; QWarningMessage txWarning; nunchuk::Transaction tx = bridge::nunchukGetOriginTransaction(wallet_id, @@ -775,6 +798,14 @@ void QNunchukRoom::downloadTransactionThread(Conversation cons, const QString &r nunchuk::RoomTransaction room_tx = matrixbrigde::GetOriginRoomTransaction(roomid, cons.init_event_id, roomTxWarning); +#if 0 //FIXME + if(cons.messageType == (int)ENUNCHUCK::ROOM_EVT::TX_CANCEL){ + QWarningMessage msggetevt; + QNunchukMatrixEvent evt = matrixbrigde::GetEvent(roomid, cons.init_event_id, msggetevt); + DBG_INFO << "FIXME" + << evt.get_content(); + } +#endif if((int)EWARNING::WarningType::NONE_MSG == roomTxWarning.type() && room_tx.get_wallet_id() != ""){ QWarningMessage txWarning; room_tx.set_room_id(id().toStdString()); @@ -797,7 +828,7 @@ bool QNunchukRoom::leaveWallet(const QString &xfp) QString join_id = roomWallet()->walletSigners()->getJoinEventId(xfp); if("" != join_id){ QWarningMessage msgWarning; - matrixbrigde::LeaveWallet(this->id(), join_id, STR_CPP_008, msgWarning); + matrixbrigde::LeaveWallet(id(), join_id, STR_CPP_008, msgWarning); if((int)EWARNING::WarningType::NONE_MSG == msgWarning.type()){ ret = true; } @@ -1006,7 +1037,10 @@ void QNunchukRoom::downloadHistorical() if(!m_room) return; else{ if(isServerNoticeRoom()){ - // TODO + //FIXME - DEBUG +// for (auto e = m_room->messageEvents().rbegin(); e != m_room->messageEvents().rend(); ++e){ +// nunchukNoticeEvent(**e); // FIXME +// } } else if(isNunchukSyncRoom()){ QtConcurrent::run([this]() { @@ -1036,8 +1070,8 @@ void QNunchukRoom::downloadHistorical() } } conversation()->requestSortByTimeAscending(false); - this->setLastMessage(conversation()->lastMessage()); - this->setLasttimestamp(conversation()->lastTime()); + setLastMessage(conversation()->lastMessage()); + setLasttimestamp(conversation()->lastTime()); if(conversation()->lastIndex() == 0){ if(allHisLoaded() == false){ getMoreContents(10); @@ -1050,7 +1084,7 @@ void QNunchukRoom::downloadHistorical() roomWallet()->setIsCreator(isCreator); } } - this->startGetPendingTxs(); + startGetPendingTxs(); m_downloaded = true; }); } @@ -1083,7 +1117,7 @@ void QNunchukRoom::connectRoomSignals() connect(this, &QNunchukRoom::signalFinishFinalizeWallet, this, &QNunchukRoom::slotFinishFinalizeWallet); connect(this, &QNunchukRoom::signalFinishCancelWallet, this, &QNunchukRoom::slotFinishCancelWallet); connect(this, &QNunchukRoom::signalFinishedGetPendingTxs, this, &QNunchukRoom::slotFinishedGetPendingTxs); - this->downloadHistorical(); + downloadHistorical(); } } @@ -1092,6 +1126,7 @@ void QNunchukRoom::connectRoomServiceSignals() if(m_room){ connect(this, &QNunchukRoom::noticeService, ClientController::instance(), &ClientController::refreshContacts); connect(m_room, &Room::addedMessages, ClientController::instance(), &ClientController::refreshContacts); + connect(m_room, &Room::addedMessages, this, &QNunchukRoom::addedMessages); } } @@ -1203,7 +1238,7 @@ void QNunchukRoom::transactionChanged(const QString &tx_id, const int status, co if(conversation()){ conversation()->transactionChanged(tx_id, status, height); } - this->startGetPendingTxs(); + startGetPendingTxs(); } void QNunchukRoom::updateTransactionMemo(const QString &tx_id, const QString &memo) @@ -1215,10 +1250,10 @@ void QNunchukRoom::updateTransactionMemo(const QString &tx_id, const QString &me void QNunchukRoom::startGetPendingTxs() { - if(matrixbrigde::HasRoomWallet(this->id())){ + if(matrixbrigde::HasRoomWallet(id())){ QtConcurrent::run([this]() { - QRoomTransactionModelPtr ret = matrixbrigde::GetPendingTransactions(this->id()); - emit this->signalFinishedGetPendingTxs(ret); + QRoomTransactionModelPtr ret = matrixbrigde::GetPendingTransactions(id()); + emit signalFinishedGetPendingTxs(ret); }); } } @@ -1378,8 +1413,15 @@ void QNunchukRoom::aboutToAddNewMessages(RoomEventsRange events) void QNunchukRoom::addedMessages(int fromIndex, int toIndex) { + DBG_INFO << fromIndex << toIndex << isServerNoticeRoom(); if(isServerNoticeRoom()){ emit noticeService(); + for (auto e = m_room->messageEvents().rbegin(); e != m_room->messageEvents().rend(); ++e){ + if(fromIndex <= e->index() && toIndex >= e->index()){ + const RoomEvent* lastEvent = e->get(); + nunchukNoticeEvent(*lastEvent); + } + } } else if(isNunchukSyncRoom()){ QtConcurrent::run([=]() { @@ -1389,9 +1431,7 @@ void QNunchukRoom::addedMessages(int fromIndex, int toIndex) nunchukConsumeSyncEvent(*lastEvent); } } - AppModel::instance()->startReloadWallets(); - AppModel::instance()->startReloadMasterSigners(); - AppModel::instance()->startReloadRemoteSigners(); + emit finishConsumeEvent(); }); } else{ @@ -1504,7 +1544,7 @@ void QNunchukRoom::eventToConversation(const RoomEvent& evt, Conversation &resul }, [=](const RoomMemberEvent& e) { // FIXME: Rewind to the name that was at the time of this event - auto subjectName = this->m_room->user(e.userId())->displayname(room()); + auto subjectName = m_room->user(e.userId())->displayname(room()); QString content = ""; // The below code assumes senderName output in AuthorRole switch (e.membership()) { @@ -1675,10 +1715,10 @@ void QNunchukRoom::receiveMessage(int fromIndex, int toIndex) } pos++; if(cons.messageType == (int)ENUNCHUCK::ROOM_EVT::WALLET_CANCEL){ - this->updateCancelWallet(cons.init_event_id); + updateCancelWallet(cons.init_event_id); } if(cons.messageType == (int)ENUNCHUCK::ROOM_EVT::TX_CANCEL){ - this->updateCancelTransaction(cons); + updateCancelTransaction(cons); } } } @@ -1690,8 +1730,8 @@ void QNunchukRoom::receiveMessage(int fromIndex, int toIndex) emit roomNameChanged(); } conversation()->requestSortByTimeAscending(); - this->setLastMessage(conversation()->lastMessage()); - this->setLasttimestamp(conversation()->lastTime()); + setLastMessage(conversation()->lastMessage()); + setLasttimestamp(conversation()->lastTime()); } } @@ -1766,6 +1806,35 @@ void QNunchukRoom::nunchukConsumeSyncEvent(const RoomEvent &evt) } } +void QNunchukRoom::nunchukNoticeEvent(const RoomEvent &evt) +{ + if (CLIENT_INSTANCE->isNunchukLoggedIn() && CLIENT_INSTANCE->isMatrixLoggedIn()) { + QString matrixType = evt.matrixType(); + DBG_INFO << "FIXME" << evt.contentJson(); + if(0 == QString::compare(matrixType, NUNCHUK_ROOM_MESSAGE, Qt::CaseInsensitive)) + { + QString msgtype = evt.contentJson()["msgtype"].toString(); + DBG_INFO << "FIXME" << msgtype; + if (msgtype.toLower().contains("io.nunchuk.custom.draft_wallet")) { + QUserWallets::instance()->newRequestToAddKey(); + } + else if (msgtype.toLower().contains("io.nunchuk.custom.wallet_created")) { + AppModel::instance()->requestCreateUserWallets(); + } + else if(msgtype.toLower().contains("io.nunchuk.custom.transaction")){ + QString wallet_id = evt.fullJson()["content"].toObject()["wallet_local_id"].toString(); + if(AppModel::instance()->walletList()){ + QWalletPtr wallet = AppModel::instance()->walletList()->getWalletById(wallet_id); + if(wallet && wallet.data()->isAssistedWallet()){ + AppModel::instance()->startSyncWalletDb(wallet_id); + } + } + } + else{} + } + } +} + QConversationModel *QNunchukRoom::conversation() const { return m_conversation.data(); @@ -2030,10 +2099,10 @@ void QNunchukRoomListModel::downloadRooms() else{ AppModel::instance()->startMultiDeviceSync(false); } - synchonizesUserData(); emit finishedDownloadRoom(); CLIENT_INSTANCE->setReadySupport(true); downloadRoomWallets(); + synchonizesUserData(); }); }); } @@ -2087,6 +2156,7 @@ void QNunchukRoomListModel::setCurrentRoom(const QNunchukRoomPtr ¤tRoom) m_currentRoom = currentRoom; if(m_currentRoom){ m_currentRoom.data()->setDisplayed(true); + m_currentRoom.data()->startGetPendingTxs(); if(m_currentRoom->conversation()){ if(m_currentRoom->conversation()->unreadLastIndex() + 10 > m_currentRoom->conversation()->count()){ m_currentRoom.data()->conversation()->setCurrentIndex(m_currentRoom.data()->conversation()->rowCount() - 1); @@ -2158,6 +2228,7 @@ void QNunchukRoomListModel::doAddRoom(QNunchukRoomPtr r) m_servive.append(r); if(r.data()->isServerNoticeRoom()){ r.data()->connectRoomServiceSignals(); +// r.data()->downloadHistorical();//FIXME - DEBUG } if(r.data()->isNunchukSyncRoom()){ r.data()->connectRoomSignals(); @@ -2179,9 +2250,10 @@ void QNunchukRoomListModel::doAddRoom(QNunchukRoomPtr r) connect(r.data()->room(), &Room::unreadMessagesChanged, this, [this, r] { refresh(r); }); connect(r.data()->room(), &Room::typingChanged, this, [this, r] { refresh(r); }); connect(r.data()->room(), &Room::unreadMessagesChanged, this, &QNunchukRoomListModel::totalUnreadChanged); + connect(r.data(), &QNunchukRoom::pendingTxsChanged, this, [this, r] { refresh(r); }); } } - emit this->countChanged(); + emit countChanged(); } void QNunchukRoomListModel::removeRoomByIndex(const int index) @@ -2240,9 +2312,7 @@ void QNunchukRoomListModel::leaveCurrentRoom() auto* job = currentRoom()->room()->leaveRoom(); connect(job, &BaseJob::success, this, [this] { removeRoomByIndex(currentIndex()); - AppModel::instance()->startReloadWallets(); - AppModel::instance()->startReloadMasterSigners(); - AppModel::instance()->startReloadRemoteSigners(); + AppModel::instance()->startReloadUserDb(); }); emit countChanged(); } @@ -2560,11 +2630,8 @@ void QNunchukRoomListModel::roomNeedTobeLeaved(const QString &id) void QNunchukRoomListModel::synchonizesUserDataFinished() { - DBG_INFO; AppModel::instance()->closePromtNunchukSync(); - AppModel::instance()->startReloadWallets(); - AppModel::instance()->startReloadMasterSigners(); - AppModel::instance()->startReloadRemoteSigners(); + AppModel::instance()->startReloadUserDb(); } bool sortRoomListTimeAscending(const QNunchukRoomPtr &v1, const QNunchukRoomPtr &v2) diff --git a/Models/Chats/QNunchukRoomModel.h b/Models/Chats/QNunchukRoomModel.h index a6efee0e..af781559 100755 --- a/Models/Chats/QNunchukRoomModel.h +++ b/Models/Chats/QNunchukRoomModel.h @@ -216,17 +216,19 @@ class QNunchukRoom: public QObject QRoomTransaction *m_pinTransaction; nunchuk::Wallet m_walletImport; bool m_IsEncrypted; + QTimer m_timeSyncDb; private: bool validatePendingEvent(const QString& txnId); bool extractNunchukEvent(const RoomEvent& evt, Conversation &cons) ; void eventToConversation(const RoomEvent& evt, Conversation &result, Qt::TextFormat format = Qt::RichText); void receiveMessage(int fromIndex, int toIndex); - Conversation createConversation(const RoomEvent& evt) ; - void nunchukConsumeEvent(const RoomEvent& evt) ; - void nunchukConsumeSyncEvent(const RoomEvent& evt) ; + Conversation createConversation(const RoomEvent& evt); + void nunchukConsumeEvent(const RoomEvent& evt); + void nunchukConsumeSyncEvent(const RoomEvent& evt); + void nunchukNoticeEvent(const RoomEvent& evt); bool joinWalletWithMasterSigner(const QString& id, bool &needXpub); bool joinWalletWithSingleSigner(const QString& xfp); - bool joinWalletUseSignerFromWalletImport(const QString& id,const QString& xfp); + bool joinWalletUseSignerFromWalletImport(const QString& signer_id,const QString& xfp); public slots: void highlightCountChanged(); @@ -247,6 +249,8 @@ public slots: void slotFinishCancelWallet(QString what, int type, int code); void slotFinishedGetPendingTxs(QRoomTransactionModelPtr txs); void slotUpdateInitEventId(const Conversation cons); + void slotFinishConsumeEvent(); + void slotSyncWalletDb(); signals: void userCountChanged(); void userNamesChanged(); @@ -275,6 +279,7 @@ public slots: void signalFinishedGetPendingTxs(QRoomTransactionModelPtr txs); void pinTransactionChanged(); void roomNeedTobeLeaved(const QString& id); + void finishConsumeEvent(); }; Q_DECLARE_METATYPE(Conversation) Q_DECLARE_METATYPE(nunchuk::RoomTransaction) diff --git a/Models/Chats/QRoomTransaction.cpp b/Models/Chats/QRoomTransaction.cpp index 06fe3894..37140e8d 100644 --- a/Models/Chats/QRoomTransaction.cpp +++ b/Models/Chats/QRoomTransaction.cpp @@ -292,8 +292,18 @@ QSharedPointer QRoomTransactionModel::clone() const { QRoomTransactionModelPtr clone = QRoomTransactionModelPtr(new QRoomTransactionModel()); for (QRoomTransactionPtr tx : m_data) { - QRoomTransactionPtr ret = QRoomTransactionPtr(new QRoomTransaction(tx.data()->roomTransaction())); - clone.data()->addTransaction(ret); + if(tx){ + QRoomTransactionPtr ret = QRoomTransactionPtr(new QRoomTransaction(tx.data()->roomTransaction())); + QTransactionPtr nunchukTx = tx.data()->transactionPtr(); + if(nunchukTx){ + QTransactionPtr rawtx = QTransactionPtr(new Transaction()); + rawtx.data()->setNunchukTransaction(nunchukTx.data()->nunchukTransaction()); + rawtx.data()->setInitEventId(nunchukTx.data()->initEventId()); + rawtx.data()->setRoomId(nunchukTx.data()->roomId()); + ret.data()->setTransaction(rawtx); + } + clone.data()->addTransaction(ret); + } } return clone; } diff --git a/Models/Chats/QUserWallets.cpp b/Models/Chats/QUserWallets.cpp index d97b942c..36a023bd 100644 --- a/Models/Chats/QUserWallets.cpp +++ b/Models/Chats/QUserWallets.cpp @@ -75,6 +75,11 @@ bool QUserWallets::requestServerKeyVerifyPassword(const QString &password) return requestVerifyPassword(password,(int)TARGET_ACTION::UPDATE_SERVER_KEY); } +bool QUserWallets::requestInheritancePlanVerifyPassword(const QString &password) +{ + return requestVerifyPassword(password,(int)TARGET_ACTION::UPDATE_INHERITANCE_PLAN); +} + QTransactionPtr QUserWallets::getDummyTx(const QString& wallet_id, const QString& period_id) { QWarningMessage msgWallet; @@ -219,7 +224,7 @@ bool QUserWallets::secQuesAnswer() } } -QVariantList QUserWallets::lockdownPeriods() +QVariantList QUserWallets::periods() { return m_periods; } @@ -274,11 +279,11 @@ bool QUserWallets::lockdownByAnswerSecQues() QString errormsg; QString until_time; bool ret = Draco::instance()->lockdownByAnswerSecQues(m_passwordToken, - m_secQuesToken, - m_period_id, - m_wallet_id, - until_time, - errormsg); + m_secQuesToken, + m_period_id, + m_wallet_id, + until_time, + errormsg); if (!ret) { //show toast AppModel::instance()->showToast(0, @@ -297,11 +302,11 @@ bool QUserWallets::lockdownBySignDummyTx() QString errormsg; QString until_time; bool ret = Draco::instance()->lockdownBySignDummyTx(signatures, - m_passwordToken, - m_period_id, - m_wallet_id, - until_time, - errormsg); + m_passwordToken, + m_period_id, + m_wallet_id, + until_time, + errormsg); if (!ret) { //show toast AppModel::instance()->showToast(0, @@ -442,35 +447,59 @@ int QUserWallets::inheritanceCheck(const QString& magic, const QString& environm } } -bool QUserWallets::inheritanceGetPlan(const QString& magic_inpputed, const QString &wallet_id) +bool QUserWallets::inheritanceGetPlan(const QString &wallet_id) { - // Assisted wallet being used to sign test message or dummy transaction - QJsonObject result; + QStringList ids {}; + if (m_periods.size() == 0) { + inheritancePlanCreatePeriods(); + } + for (QVariant var : m_periods) { + QMap map = var.toMap(); + ids.append(map.value("id").toString()); + } + QJsonObject response; QString errormsg; - bool ret = Draco::instance()->inheritanceGetPlan(wallet_id, result, errormsg); + bool ret = Draco::instance()->inheritanceGetPlan(wallet_id, response, errormsg); if(ret){ //HANDLE RESULT - QJsonObject inheritance = result["inheritance"].toObject(); - QString magic = inheritance["magic"].toString(); - if(0 == QString::compare(magic, magic_inpputed, Qt::CaseInsensitive)){ - // HANDLE RESULT - return true; + QJsonObject inheritance = response["inheritance"].toObject(); + qInfo() << "inheritanceGetPlan" << inheritance; + long int activation_time_milis = static_cast(inheritance.value("activation_time_milis").toDouble()/1000); + if (activation_time_milis > 0) { + ServiceSetting::instance()->setInheritanceActivationDate(QDateTime::fromTime_t(activation_time_milis).date().toString("MM/dd/yyyy")); + } else { + ServiceSetting::instance()->setInheritanceActivationDate(""); } - else{ - AppModel::instance()->showToast(0, - STR_CPP_116, - EWARNING::WarningType::ERROR_MSG, - STR_CPP_116); - return false; + ServiceSetting::instance()->setInheritanceNote(inheritance.value("note").toString()); + QJsonArray emails = inheritance.value("notification_emails").toArray(); + QStringList emailList; + for (QJsonValue js : emails) { + emailList.append(js.toString()); + } + QString email = emailList.join(","); + ServiceSetting::instance()->setInheritanceEmail(email); + ServiceSetting::instance()->setInheritanceMagic(inheritance.value("magic").toString()); + QJsonObject buffer_period = inheritance["buffer_period"].toObject(); + if (!buffer_period.isEmpty()) { + QString id = buffer_period.value("id").toString(); + if (ids.contains(id)) { + ServiceSetting::instance()->setInheritancePeriod(buffer_period.value("display_name").toString()); + ServiceSetting::instance()->setInheritancePeriodId(id); + } + } else { + ServiceSetting::instance()->setInheritancePeriod(""); + ServiceSetting::instance()->setInheritancePeriodId(""); } + ServiceSetting::instance()->inheritanceDataChanged(); + ServiceSetting::instance()->setViewInheritanceIsEdit(false); } else { AppModel::instance()->showToast(0, errormsg, EWARNING::WarningType::ERROR_MSG, STR_CPP_112); - return false; } + return ret; } int QUserWallets::inheritanceDownloadBackup(const QString &magic, const QString &backup_password) @@ -491,6 +520,7 @@ int QUserWallets::inheritanceDownloadBackup(const QString &magic, const QString std::vector base64vec(base64bin.begin(), base64bin.end()); QString backupkey = backup_password; //Inputted from user QString keyname = result["key_name"].toString(); + mInheritance.derivation_path = result["derivation_path"].toString(); QWarningMessage msg; QMasterSignerPtr masterSigner = bridge::ImportTapsignerMasterSigner(base64vec, backupkey, keyname, false, msg); if (masterSigner && NONE_MSG == msg.type()) { @@ -513,7 +543,7 @@ int QUserWallets::inheritanceDownloadBackup(const QString &magic, const QString QJsonDocument doc(data); QString user_data(doc.toJson()); //[SIGN_MESSAGE] flow - nunchuk::SingleSigner signer = nunchukiface::instance()->GetDefaultSignerFromMasterSigner(masterSigner->id().toStdString(),msg); + nunchuk::SingleSigner signer = nunchukiface::instance()->GetSignerFromMasterSigner(masterSigner->id().toStdString(), mInheritance.derivation_path.toStdString(), msg); if (NONE_MSG == msg.type()) { QString messages_to_sign = qUtils::GetHealthCheckMessage(user_data,msg); // user_data in json string if (NONE_MSG == msg.type()) { @@ -581,7 +611,7 @@ bool QUserWallets::inheritanceClaimRequest(const nunchuk::Wallet wallet, const n QString status = transaction.value("status").toString(); QString psbt = transaction.value("psbt").toString(); if (status == "PENDING_CONFIRMATION" || - status == "CONFIRMED"){ + status == "CONFIRMED"){ QWarningMessage _msg; bridge::nunchukImportPsbt(QString::fromStdString(mInheritance.wallet.get_id()), psbt, _msg); QString id = transaction.value("id").toString(); @@ -669,7 +699,7 @@ bool QUserWallets::inheritanceCreateTx(const nunchuk::SingleSigner& signer, cons AppModel::instance()->setTransactionInfo(trans); QList states = QQuickViewer::instance()->getCurrentStates(); if(!states.isEmpty() && states.last() == E::STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE){ - DBG_INFO << "Entry here "; + DBG_INFO << "Entry here "; QQuickViewer::instance()->sendEvent(E::EVT_INHERITANCE_CONFIRM_TRANSACTION_REQUEST); } } @@ -720,7 +750,7 @@ void QUserWallets::inheritanceCreateDraftTransaction(double fee_rate) QString user_data(doc.toJson()); QWarningMessage msg; //[SIGN_MESSAGE] flow - nunchuk::SingleSigner signer = nunchukiface::instance()->GetDefaultSignerFromMasterSigner(mInheritance.masterSignerId.toStdString(),msg); + nunchuk::SingleSigner signer = nunchukiface::instance()->GetSignerFromMasterSigner(mInheritance.masterSignerId.toStdString(), mInheritance.derivation_path.toStdString(), msg); if (NONE_MSG == msg.type()) { QString messages_to_sign = qUtils::GetHealthCheckMessage(user_data,msg); // user_data in json string if (NONE_MSG == msg.type()) { @@ -762,6 +792,108 @@ void QUserWallets::inheritanceSignTransaction() } } +QJsonObject QUserWallets::inheritancePlanBody() +{ + QJsonObject body; + body["wallet"] = ServiceSetting::instance()->getInheritanceWalletId(); + body["note"] = ServiceSetting::instance()->getInheritanceNote(); + body["buffer_period_id"] = ServiceSetting::instance()->getInheritancePeriodId(); + QString email = ServiceSetting::instance()->getInheritanceEmail(); + QStringList emails = email.split(","); + QJsonArray arrays; + for (QString e : emails) { + if (e != "None") { + arrays.append(e); + } + } + body["notification_emails"] = arrays; + body["notify_today"] = ServiceSetting::instance()->getInheritanceIsNotify(); + long int t = qUtils::GetTimeSecond(ServiceSetting::instance()->getInheritanceActivationDate()); + body["activation_time_milis"] = (double)t*1000; + return body; +} + +void QUserWallets::inheritancePlanFinalizeChanges() +{ + long int activeTime = qUtils::GetTimeSecond(ServiceSetting::instance()->getInheritanceActivationDate()); + long int currentTime = qUtils::GetCurrentTimeSecond(); + if (activeTime < currentTime) { + AppModel::instance()->showToast(0, + STR_CPP_120, + EWARNING::WarningType::ERROR_MSG, + STR_CPP_120); + return; + } + QJsonObject body_data = inheritancePlanBody(); + QString errormsg = ""; + bool ret = Draco::instance()->inheritancePlanRequiredSignatures(body_data, required_question, errormsg); + DBG_INFO << errormsg << body_data; + if (ret) { + if (required_question.type == (int)REQUIRED_SIGNATURE_TYPE_INT::SECURITY_QUESTION) { + QUserWallets::instance()->createSecurityQuestions(); + } else if (required_question.type == (int)REQUIRED_SIGNATURE_TYPE_INT::SIGN_DUMMY_TX) { + //Show popup support in moble + emit inheritanceDummyTransactionAlert(); + } else { + } + } else { + emit inheritanceInvalidActivationDateAlert(); + } + return; +} + +void QUserWallets::inheritancePlanUpdate() +{ + QJsonObject data; + data["nonce"] = Draco::instance()->randomNonce(); + data["body"] = inheritancePlanBody(); + QStringList authorizations; + QJsonObject output; + QString errormsg = ""; + DBG_INFO << m_passwordToken << m_secQuesToken << data; + bool ret = Draco::instance()->inheritancePlanUpdate(m_passwordToken, m_secQuesToken, authorizations, data, output, errormsg); + DBG_INFO << errormsg << output; + if (ret) { + emit securityQuestionClosed(); + AppModel::instance()->showToast(0, + errormsg, + EWARNING::WarningType::SUCCESS_MSG, + STR_CPP_119); + } else { + AppModel::instance()->showToast(0, + errormsg, + EWARNING::WarningType::ERROR_MSG, + STR_CPP_112); + } +} + +bool QUserWallets::inheritancePlanCreatePeriods() +{ + m_periods.clear(); + QJsonArray periods; + QString errormsg; + bool ret = Draco::instance()->inheritancePlanBufferPeriod(periods, errormsg); + if (!ret) { + return false; + } else { + for (auto v : periods) { + QJsonObject it = v.toObject(); + DBG_INFO << it.toVariantMap(); + m_periods.append(it.toVariantMap()); + } + QJsonObject notNeed; + notNeed["id"] = ""; + notNeed["display_name"] = "I don’t need a buffer period"; + notNeed["is_recommended"] = false; + m_periods.append(notNeed.toVariantMap()); + if (m_periods.size() == 0) { + errormsg = "There no period"; + return false; + } + } + return true; +} + bool QUserWallets::serverKeyGetCurrentPolicies(const QString& wallet_id) { QWarningMessage msgWallet; @@ -895,3 +1027,134 @@ QUserWallets::inheritance_t QUserWallets::inheritance() const return mInheritance; } +void QUserWallets::newRequestToAddKey() +{ + QtConcurrent::run([this]() { + QJsonObject data = Draco::instance()->assistedWalletGetListKey(); + m_requests = data.value("requests").toArray(); + setLedgerNeed(exist("LEDGER")); + setTrezorNeed(exist("TREZOR")); + setColdCardNeed(exist("COLDCARD")); + }); +} + +void QUserWallets::addKeyRequested() +{ + QMasterSignerPtr signer = AppModel::instance()->masterSignerInfoPtr(); + QString request_id = ""; + QString key = ""; + int key_index = -1; + QJsonObject data; + DBG_INFO << !signer.isNull(); + QWarningMessage warningmsg; + if (!signer.isNull()) { + QJsonArray tags; + if (mLedgerNeed && signer->deviceType() == "ledger") { + key = "LEDGER"; + } + if (mTrezorNeed && signer->deviceType() == "trezor") { + key = "TREZOR"; + } + if (mColdCardNeed && signer->deviceType() == "coldcard") { + key = "COLDCARD"; + } + DBG_INFO << signer->deviceType() << key; + if (!key.isEmpty()) { + tags.append(key); + request_id = getRequestId(key); + key_index = getKeyIndex(key); + } + QSingleSignerPtr ptr = bridge::nunchukGetDefaultSignerFromMasterSigner(signer->id(), + ENUNCHUCK::WalletType::MULTI_SIG, + ENUNCHUCK::AddressType::NATIVE_SEGWIT , + warningmsg); + if (!request_id.isEmpty() && !ptr.isNull()) { + data["name"] = signer->name(); + data["xfp"] = signer->fingerPrint(); + data["derivation_path"] = ptr->derivationPath(); + data["xpub"] = ptr->xpub(); + data["pubkey"] = ptr->publickey(); + data["type"] = qUtils::GetSignerTypeString(ptr->singleSigner().get_type()); + data["tags"] = tags; + data["tapsigner"] = {}; + if (key_index >= 0) { + data["key_index"] = key_index; + } else { + data["key_index"] = {}; + } + bool ret = Draco::instance()->assistedWalletAddKey(request_id, data); + qInfo() << request_id << data << ret; + if (ret) { + AppModel::instance()->setAddSignerWizard(3); + emit addHardwareSuccessAlert(); + return; + } + } else { + QString errormsg = "request id empty or get default error"; + AppModel::instance()->showToast(0, + errormsg, + EWARNING::WarningType::ERROR_MSG, + errormsg); + } + } + AppModel::instance()->setAddSignerWizard(0); + emit addHardwareAlert(); +} + +QJsonObject QUserWallets::getRequest(const QString &key) const +{ + if (m_requests.size() > 0) { + for (QJsonValue request : m_requests) { + QJsonObject requestObj = request.toObject(); + QString status = requestObj.value("status").toString(); + QJsonArray tags = requestObj.value("tags").toArray(); + if (tags.contains(key) && status == "PENDING") { + return requestObj; + } + } + } + return {}; +} + +QString QUserWallets::getRequestId(const QString &key) const +{ + QJsonObject request = getRequest(key); + if (request.empty()) { + return {}; + } else { + return request.value("id").toString(); + } +} + +int QUserWallets::getKeyIndex(const QString &key) const +{ + QJsonObject request = getRequest(key); + if (request.empty()) { + return -1; + } else { + return request.value("key_index").toInt(-1); + } +} + +bool QUserWallets::exist(const QString &key) const +{ + return !getRequest(key).empty(); +} + +void QUserWallets::cancelRequest(const QString& key) +{ + QString request_id = getRequestId(key); + if (!request_id.isEmpty()) { + DBG_INFO << key; + Draco::instance()->assistedWalletRemoveId(request_id); + newRequestToAddKey(); + } +} + +void QUserWallets::additionalGetWalletConfig() +{ + QJsonObject config = Draco::instance()->assistedGetWalletConfig(); + DBG_INFO << config; + int remaining_wallet_count = config.value("remaining_wallet_count").toInt(); + ServiceSetting::instance()->setRemainingAssistedWalletCount(remaining_wallet_count); +} diff --git a/Models/Chats/QUserWallets.h b/Models/Chats/QUserWallets.h index 55eb3213..13019f10 100644 --- a/Models/Chats/QUserWallets.h +++ b/Models/Chats/QUserWallets.h @@ -29,11 +29,14 @@ class QUserWallets : public QObject { Q_OBJECT - Q_PROPERTY(QVariantList securityQuestions READ securityQuestions NOTIFY securityQuestionChanged) - Q_PROPERTY(QVariantList lockdownPeriods READ lockdownPeriods CONSTANT) - Q_PROPERTY(QString untilTime READ untilTime WRITE setUntilTime NOTIFY untilTimeChanged) - Q_PROPERTY(QVariantList tapsigners READ tapsigners NOTIFY tapsignersChanged) - Q_PROPERTY(QMasterSigner* signer READ signer CONSTANT) + Q_PROPERTY(QVariantList securityQuestions READ securityQuestions NOTIFY securityQuestionChanged) + Q_PROPERTY(QVariantList periods READ periods CONSTANT) + Q_PROPERTY(QString untilTime READ untilTime NOTIFY untilTimeChanged) + Q_PROPERTY(QVariantList tapsigners READ tapsigners NOTIFY tapsignersChanged) + Q_PROPERTY(QMasterSigner* signer READ signer CONSTANT) + DECLARE_PROPERTY(bool, LedgerNeed, { if (val == false) { cancelRequest("LEDGER"); } }, {}) + DECLARE_PROPERTY(bool, TrezorNeed, { if (val == false) { cancelRequest("TREZOR"); } }, {}) + DECLARE_PROPERTY(bool, ColdCardNeed, { if (val == false) { cancelRequest("COLDCARD"); } }, {}) public: struct inheritance_t { @@ -44,6 +47,7 @@ class QUserWallets : public QObject nunchuk::Wallet wallet = {}; nunchuk::Transaction tx = {}; double balance = {0.0}; + QString derivation_path = {}; }; QUserWallets(); ~QUserWallets(); @@ -57,6 +61,7 @@ class QUserWallets : public QObject bool requestLockDownVerifyPassword(const QString &password); bool requestRecoverKeyVerifyPassword(const QString &password); bool requestServerKeyVerifyPassword(const QString &password); + bool requestInheritancePlanVerifyPassword(const QString &password); QTransactionPtr getDummyTx(const QString &wallet_id, const QString &period_id); void signDummyTx(const QString& xfp); @@ -68,7 +73,7 @@ class QUserWallets : public QObject Q_INVOKABLE void secQuesAnswer(const QString &id, const QString &answer); bool secQuesAnswer(); - QVariantList lockdownPeriods(); + QVariantList periods(); bool createLockdownPeriods(); bool lockdownRequired(const QString &period_id); int lockdownType(); @@ -89,7 +94,7 @@ class QUserWallets : public QObject QMasterSigner *signer() const; //Inheritance Q_INVOKABLE int inheritanceCheck(const QString& magic = "", const QString& environment = "PRODUCTION"); - bool inheritanceGetPlan(const QString &magic_inpputed, const QString& wallet_id); + bool inheritanceGetPlan(const QString& wallet_id); int inheritanceDownloadBackup(const QString& magic, const QString& backup_password); bool inheritanceClaimRequest(const nunchuk::Wallet wallet, const nunchuk::Transaction txSigned, const QString& magic); int inheritanceClaimStatus(const QJsonObject& data, const QString& autho); @@ -98,6 +103,10 @@ class QUserWallets : public QObject void setInheritanceAddressNewTransaction(const QString& address); void inheritanceCreateDraftTransaction(double fee_rate = 1000.0); void inheritanceSignTransaction(); + QJsonObject inheritancePlanBody(); + void inheritancePlanFinalizeChanges(); + void inheritancePlanUpdate(); + Q_INVOKABLE bool inheritancePlanCreatePeriods(); // For co-signing policies bool serverKeyGetCurrentPolicies(const QString& wallet_id); @@ -106,6 +115,17 @@ class QUserWallets : public QObject bool serverKeyUpdatePoliciesSucceed(); inheritance_t inheritance() const; + // For draft-wallets + void newRequestToAddKey(); + Q_INVOKABLE void addKeyRequested(); + QJsonObject getRequest(const QString& key) const; + QString getRequestId(const QString& key) const; + int getKeyIndex(const QString& key) const; + bool exist(const QString& key) const; + void cancelRequest(const QString& key); + + // Get additional wallet + Q_INVOKABLE void additionalGetWalletConfig(); signals: void verifyPasswordTokenAlert(const QString& errormsg); void lockdownPeriodsAlert(const QString& errormsg); @@ -121,6 +141,12 @@ class QUserWallets : public QObject void serverKeyDummyTransactionAlert(); void securityQuestionClosed(); void thereNoAssistedWalletAlert(); + void addHardwareAlert(); + void addHardwareSuccessAlert(); + + void inheritanceDummyTransactionAlert(); + void inheritanceInvalidActivationDateAlert(); + void inheritanceDiscardChangeAlert(); private: QString m_passwordToken; QString m_secQuesToken; @@ -145,6 +171,9 @@ class QUserWallets : public QObject nunchuk::SingleSigner m_server_key = {}; }; co_signing_t mCoSigning = {}; + bool m_ledgerNeed {false}; + bool m_trezorNeed {false}; + QJsonArray m_requests {}; }; #endif // QUSERWALLETS_H diff --git a/Models/DeviceModel.cpp b/Models/DeviceModel.cpp index 0805a292..f2bb31fe 100644 --- a/Models/DeviceModel.cpp +++ b/Models/DeviceModel.cpp @@ -74,15 +74,17 @@ bool QDevice::needsPinSent() const { return m_device.needs_pin_sent(); } -bool QDevice::usableToAdd() +bool QDevice::usableToAdd() const { bool used = false; if(AppModel::instance()->masterSignerList()){ used = AppModel::instance()->masterSignerList()->containsFingerPrint(masterFingerPrint()); } +#if 0 //Able to upgrade to master signer if(!used && AppModel::instance()->remoteSignerList()){ used = AppModel::instance()->remoteSignerList()->containsFingerPrint(masterFingerPrint()); } +#endif return !used; } @@ -276,7 +278,7 @@ QDevicePtr DeviceListModel::getDeviceNeedPinSent(){ return QDevicePtr(NULL); } -bool DeviceListModel::containsFingerPrint(const QString &xfp) +bool DeviceListModel::containsFingerPrint(const QString &xfp) const { foreach (QDevicePtr it, d_) { if(0 == QString::compare(xfp, it.data()->masterFingerPrint(), Qt::CaseInsensitive)){ diff --git a/Models/DeviceModel.h b/Models/DeviceModel.h index ede10e59..09574baf 100644 --- a/Models/DeviceModel.h +++ b/Models/DeviceModel.h @@ -51,7 +51,7 @@ class QDevice : public QObject bool connected() const; bool needsPassPhraseSent() const; bool needsPinSent() const; - bool usableToAdd(); + bool usableToAdd() const; QString masterSignerId() const; QString cardId() const; void setCardId(const QString &card_id); @@ -110,7 +110,7 @@ class DeviceListModel : public QAbstractListModel device_usableToAdd_role, device_master_signer_id_role, }; - bool containsFingerPrint(const QString& xfp); + bool containsFingerPrint(const QString& xfp) const; // For verify addr QStringList getXFPList(); diff --git a/Models/MasterSignerModel.cpp b/Models/MasterSignerModel.cpp index fc666716..af2d4a7e 100644 --- a/Models/MasterSignerModel.cpp +++ b/Models/MasterSignerModel.cpp @@ -40,6 +40,12 @@ QMasterSigner::~QMasterSigner(){ } +void QMasterSigner::convert(const nunchuk::MasterSigner &src) +{ + isDraft = false; + masterSigner_ = src; +} + QString QMasterSigner::id() const{ if(isDraft){ return id_; diff --git a/Models/MasterSignerModel.h b/Models/MasterSignerModel.h index 90838bbd..3f704cdc 100644 --- a/Models/MasterSignerModel.h +++ b/Models/MasterSignerModel.h @@ -51,6 +51,8 @@ class QMasterSigner : public QObject { QMasterSigner(const nunchuk::MasterSigner &signer); ~QMasterSigner(); + void convert(const nunchuk::MasterSigner& src); + QString id() const; void setId(const QString& d); diff --git a/Models/ServiceSetting.cpp b/Models/ServiceSetting.cpp index ad327e59..3ba03a23 100644 --- a/Models/ServiceSetting.cpp +++ b/Models/ServiceSetting.cpp @@ -128,3 +128,26 @@ QVariantList ServiceSetting::keyCoSigningIntervals() } return m_keyCoSigningIntervals; } + +int ServiceSetting::assistedSize() const +{ + return AppModel::instance()->getUserWallets().size(); +} + +bool ServiceSetting::existKeyType(const QString &type) +{ + for (QMasterSignerPtr ptr : AppModel::instance()->masterSignerList()->fullList()) { + if (ptr && ptr->deviceType() == type) return true; + } + return false; +} + +void ServiceSetting::inheritanceDataChanged() +{ + QJsonObject body = QUserWallets::instance()->inheritancePlanBody(); + if (mInheritancePlanBody != body) + { + mInheritancePlanBody = body; + setViewInheritanceIsEdit(true); + } +} diff --git a/Models/ServiceSetting.h b/Models/ServiceSetting.h index 44e16c0f..87cb82a3 100644 --- a/Models/ServiceSetting.h +++ b/Models/ServiceSetting.h @@ -3,17 +3,36 @@ #include #include +#include "QCommonDefines.h" +#include class ServiceSetting : public QObject { Q_OBJECT - Q_PROPERTY(bool isSubscriber READ isSubscriber WRITE setIsSubscriber NOTIFY isSubscriberChanged) - Q_PROPERTY(int claimInheritanceFlow READ claimInheritanceFlow WRITE setClaimInheritanceFlow NOTIFY claimInheritanceFlowChanged) - Q_PROPERTY(int claimInheritanceStatus READ claimInheritanceStatus WRITE setClaimInheritanceStatus NOTIFY claimInheritanceStatusChanged) - Q_PROPERTY(QString claimInheritancePeriod READ claimInheritancePeriod WRITE setClaimInheritancePeriod NOTIFY claimInheritancePeriodChanged) - Q_PROPERTY(QVariant inheritance READ inheritance NOTIFY inheritanceChanged) - Q_PROPERTY(QVariant keyCoSigning READ keyCoSigning WRITE setKeyCoSigning NOTIFY keyCoSigningChanged) - Q_PROPERTY(QVariantList keyCoSigningIntervals READ keyCoSigningIntervals CONSTANT) + Q_PROPERTY(bool isSubscriber READ isSubscriber WRITE setIsSubscriber NOTIFY isSubscriberChanged) + Q_PROPERTY(int claimInheritanceFlow READ claimInheritanceFlow WRITE setClaimInheritanceFlow NOTIFY claimInheritanceFlowChanged) + Q_PROPERTY(int claimInheritanceStatus READ claimInheritanceStatus WRITE setClaimInheritanceStatus NOTIFY claimInheritanceStatusChanged) + Q_PROPERTY(QString claimInheritancePeriod READ claimInheritancePeriod WRITE setClaimInheritancePeriod NOTIFY claimInheritancePeriodChanged) + Q_PROPERTY(QVariant inheritance READ inheritance NOTIFY inheritanceChanged) + Q_PROPERTY(QVariant keyCoSigning READ keyCoSigning WRITE setKeyCoSigning NOTIFY keyCoSigningChanged) + Q_PROPERTY(QVariantList keyCoSigningIntervals READ keyCoSigningIntervals CONSTANT) + Q_PROPERTY(int assistedSize READ assistedSize CONSTANT) + + DECLARE_PROPERTY(QString, InheritanceWalletName, {}, {}) + DECLARE_PROPERTY(QString, InheritanceWalletId, {}, {}) + DECLARE_PROPERTY(int, InheritancePlan, {}, {}) + DECLARE_PROPERTY(QString, InheritanceActivationDate, {inheritanceDataChanged();}, {}) + DECLARE_PROPERTY(QString, InheritanceNote, {inheritanceDataChanged();}, {}) + DECLARE_PROPERTY(QString, InheritanceMagic, {}, {}) + DECLARE_PROPERTY(QString, InheritancePeriod, {inheritanceDataChanged();}, {}) + DECLARE_PROPERTY(QString, InheritancePeriodId, {}, {}) + DECLARE_PROPERTY(bool, InheritanceIsNotify, {}, {}) + DECLARE_PROPERTY(QString, InheritanceEmail, {inheritanceDataChanged();}, {}) + DECLARE_PROPERTY(QString, InheritanceSecret, {}, {}) + + DECLARE_PROPERTY(int, RemainingAssistedWalletCount, {}, {}) + DECLARE_PROPERTY(QStringList, AssistedSetuped, {}, {}) + DECLARE_PROPERTY(bool, ViewInheritanceIsEdit, {}, {}) public: Q_ENUMS(CIWithDraw) enum class CIWithDraw { @@ -29,6 +48,14 @@ class ServiceSetting : public QObject CI_IS_VALID, CI_IS_ERROR }; + Q_ENUMS(InheritanceEdit) + enum class InheritanceEdit { + IE_NONE, + IE_ACTIVATION_DATE, + IE_LEAVE_MESSAGE, + IE_BUFFER_PERIOD, + IE_NOTIFICATION + }; explicit ServiceSetting(QObject *parent = nullptr); static ServiceSetting *instance(); ServiceSetting(ServiceSetting &other) = delete; @@ -56,6 +83,10 @@ class ServiceSetting : public QObject QVariantList keyCoSigningIntervals(); + int assistedSize() const; + + Q_INVOKABLE bool existKeyType(const QString& type); + void inheritanceDataChanged(); signals: void isSubscriberChanged(); void claimInheritanceFlowChanged(); @@ -71,6 +102,7 @@ class ServiceSetting : public QObject QString m_claimInheritancePeriod {}; QVariant m_keyCoSigning; QVariantList m_keyCoSigningIntervals; + QJsonObject mInheritancePlanBody {}; }; #endif // SERVICESETTING_H diff --git a/Models/SingleSignerModel.cpp b/Models/SingleSignerModel.cpp index 11794a72..902e7b3f 100644 --- a/Models/SingleSignerModel.cpp +++ b/Models/SingleSignerModel.cpp @@ -24,9 +24,9 @@ #include #include "utils/enumconverter.hpp" -QSingleSigner::QSingleSigner() : - isPrimaryKey_(false), - isDraft(true) +QSingleSigner::QSingleSigner() + : isPrimaryKey_(false) + , isDraft(true) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -46,6 +46,12 @@ QSingleSigner::QSingleSigner(const nunchuk::SingleSigner& singleKey): QSingleSigner::~QSingleSigner() {} +void QSingleSigner::convert(const nunchuk::SingleSigner &src) +{ + isDraft = false; + singleSigner_ = src; +} + nunchuk::SingleSigner QSingleSigner::originSingleSigner() const { return singleSigner_; @@ -124,7 +130,7 @@ void QSingleSigner::setDerivationPath(const QString &d) { } } -QString QSingleSigner::masterFingerPrint() { +QString QSingleSigner::masterFingerPrint() const { if(isDraft){ return master_fingerprint_; } @@ -182,9 +188,14 @@ void QSingleSigner::setSignerSigned(const bool d) } } -bool QSingleSigner::needTopUpXpub() const +bool QSingleSigner::needTopUpXpub() { - return needTopUpXpub_; + if((int)ENUNCHUCK::SignerType::HARDWARE == signerType() || (int)ENUNCHUCK::SignerType::SOFTWARE == signerType()){ + return needTopUpXpub_; + } + else{ + return false; + } } void QSingleSigner::setNeedTopUpXpub(bool needTopUpXpub) @@ -247,7 +258,7 @@ void QSingleSigner::setChecked(const bool checked) } } -bool QSingleSigner::readyToSign() +bool QSingleSigner::readyToSign() const { bool signAble = false; if((int)ENUNCHUCK::SignerType::HARDWARE == signerType() || (int)ENUNCHUCK::SignerType::COLDCARD_NFC == signerType()){ @@ -341,6 +352,11 @@ void QSingleSigner::setCardId(const QString &card_id) cardId_ = card_id; } +nunchuk::SingleSigner QSingleSigner::singleSigner() const +{ + return singleSigner_; +} + QString QSingleSigner::timeGapCalculationShort(QDateTime in) { QDateTime today = QDateTime::currentDateTime(); @@ -796,6 +812,15 @@ QList SingleSignerListModel::fullList() const return d_; } +std::vector SingleSignerListModel::signers() const +{ + std::vector signerList; + for (QSingleSignerPtr p : d_) { + signerList.push_back(p->originSingleSigner()); + } + return signerList; +} + QSharedPointer SingleSignerListModel::clone() const { QSharedPointer clone = QSharedPointer(new SingleSignerListModel()); diff --git a/Models/SingleSignerModel.h b/Models/SingleSignerModel.h index 1d38f5b4..3f4d32cd 100644 --- a/Models/SingleSignerModel.h +++ b/Models/SingleSignerModel.h @@ -51,6 +51,8 @@ class QSingleSigner : public QObject { ~QSingleSigner(); + void convert(const nunchuk::SingleSigner& src); + nunchuk::SingleSigner originSingleSigner() const; void setOriginSingleSigner(const nunchuk::SingleSigner signer); @@ -69,7 +71,7 @@ class QSingleSigner : public QObject { QString derivationPath(); void setDerivationPath(const QString& d); - QString masterFingerPrint(); + QString masterFingerPrint() const; void setMasterFingerPrint(const QString& d); QString masterSignerId(); @@ -84,7 +86,7 @@ class QSingleSigner : public QObject { bool signerSigned() const; void setSignerSigned(const bool d); - bool needTopUpXpub() const; + bool needTopUpXpub(); void setNeedTopUpXpub(bool needTopUpXpub); QString message() const; @@ -100,7 +102,7 @@ class QSingleSigner : public QObject { bool checked() const; void setChecked(const bool checked); - bool readyToSign(); + bool readyToSign() const; bool isColdCard(); @@ -114,6 +116,7 @@ class QSingleSigner : public QObject { QString cardId(); void setCardId(const QString &card_id); + nunchuk::SingleSigner singleSigner() const; private: QString xpub_ = ""; QString public_key_ = ""; @@ -230,6 +233,7 @@ class SingleSignerListModel : public QAbstractListModel }; void requestSort(int role, int order); QList fullList() const; + std::vector signers() const; QSharedPointer clone() const; void cleardata(); public slots: diff --git a/Models/TransactionModel.cpp b/Models/TransactionModel.cpp index de2f0780..78f5dfe9 100644 --- a/Models/TransactionModel.cpp +++ b/Models/TransactionModel.cpp @@ -295,6 +295,10 @@ QString Transaction::psbt() const return QString::fromStdString(m_transaction.get_psbt()); } +time_t Transaction::scheduleTime(){ + return m_transaction.get_schedule_time(); +} + bool Transaction::hasChange() const { int index_change = m_transaction.get_change_index(); if(index_change >= 0 && index_change < (int)m_transaction.get_outputs().size()) { @@ -474,8 +478,15 @@ void Transaction::setNunchukTransaction(const nunchuk::Transaction &tx) m_transaction = tx; } -QString Transaction::roomId() const +QString Transaction::roomId() { + if(AppModel::instance()->walletList()){ + QWalletPtr wallet = AppModel::instance()->walletList()->getWalletById(walletId()); + if(wallet){ + m_roomId = wallet.data()->roomId(); + } + } + DBG_INFO << m_roomId; return m_roomId; } @@ -533,6 +544,20 @@ void Transaction::setServerKeyMessage(const QJsonObject &data) } } +QString Transaction::packageFeeRate() +{ + return QString::number((double)m_packageFeeRate/1000, 'f', 2); +} + +void Transaction::setPackageFeeRate(int satvKB) +{ + if (m_packageFeeRate == satvKB) + return; + + m_packageFeeRate = satvKB; + emit packageFeeRateChanged(); +} + QString Transaction::destination() { QString ret = ""; @@ -552,6 +577,19 @@ QString Transaction::destination() return ret; } +bool Transaction::isCpfp() +{ + bool ret = false; + QWarningMessage msg; + nunchuk::Amount packageFeeRate{0}; + if (nunchukiface::instance()->IsCPFP(walletId().toStdString(), nunchukTransaction(), packageFeeRate, msg)) { + ret = true; + } + setPackageFeeRate(packageFeeRate); + DBG_INFO << ret << packageFeeRate; + return ret; +} + TransactionListModel::TransactionListModel() { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -717,6 +755,7 @@ bool TransactionListModel::contains(const QString &tx_id) void TransactionListModel::requestSort(int role, int order) { + DBG_INFO << role << order; beginResetModel(); if(m_data.count() > 1){ switch (role) { @@ -755,9 +794,11 @@ void TransactionListModel::requestSort(int role, int order) break; case transaction_blocktime_role: { - qSort(m_data.begin(), m_data.end(), sortTXsByBlocktimeAscending); if(Qt::DescendingOrder == order){ - qSort(m_data.begin(), m_data.end(), sortTXsByBlocktimeDescendingSkipZero); + qSort(m_data.begin(), m_data.end(), sortTXsByBlocktimeDescending); + } + else{ + qSort(m_data.begin(), m_data.end(), sortTXsByBlocktimeAscending); } linkingReplacedTransactions(); } @@ -826,17 +867,35 @@ int TransactionListModel::count() const bool sortTXsByBlocktimeAscending(const QTransactionPtr &v1, const QTransactionPtr &v2) { - return v1.data()->blocktime() < v2.data()->blocktime(); + if(v1.data()->blocktime() <= 0 && v2.data()->blocktime() <= 0){ + if(v1.data()->status() == v2.data()->status()){ + return (v1.data()->totalSats() > v2.data()->totalSats()); + } + else if(v1.data()->status() < v2.data()->status()){ + return (true); + } + else{ + return v1.data()->blocktime() < v2.data()->blocktime(); + } + } + else if(v1.data()->blocktime() <= 0 && v2.data()->blocktime() > 0){ return true;} + else if(v1.data()->blocktime() > 0 && v2.data()->blocktime() <= 0){ return false;} + else {return v1.data()->blocktime() < v2.data()->blocktime();} } bool sortTXsByBlocktimeDescending(const QTransactionPtr &v1, const QTransactionPtr &v2) { - return v1.data()->blocktime() > v2.data()->blocktime(); -} - -bool sortTXsByBlocktimeDescendingSkipZero(const QTransactionPtr &v1, const QTransactionPtr &v2) -{ - if(v1.data()->blocktime() <= 0 && v2.data()->blocktime() <= 0){ return v1.data()->blocktime() < v2.data()->blocktime();} + if(v1.data()->blocktime() <= 0 && v2.data()->blocktime() <= 0){ + if(v1.data()->status() == v2.data()->status()){ + return (v1.data()->totalSats() > v2.data()->totalSats()); + } + else if(v1.data()->status() < v2.data()->status()){ + return (true); + } + else{ + return v1.data()->blocktime() < v2.data()->blocktime(); + } + } else if(v1.data()->blocktime() <= 0 && v2.data()->blocktime() > 0){ return true;} else if(v1.data()->blocktime() > 0 && v2.data()->blocktime() <= 0){ return false;} else {return v1.data()->blocktime() > v2.data()->blocktime();} diff --git a/Models/TransactionModel.h b/Models/TransactionModel.h index 302d1fcd..843f81be 100644 --- a/Models/TransactionModel.h +++ b/Models/TransactionModel.h @@ -116,7 +116,9 @@ class Transaction : public QObject { Q_PROPERTY(bool createByMe READ createByMe NOTIFY createByMeChanged) Q_PROPERTY(QString psbt READ psbt NOTIFY psbtChanged) Q_PROPERTY(QString serverKeyMessage READ serverKeyMessage NOTIFY serverKeyMessageChanged) + Q_PROPERTY(QString packageFeeRate READ packageFeeRate NOTIFY packageFeeRateChanged) Q_PROPERTY(QString destination READ destination NOTIFY destinationListChanged) + Q_PROPERTY(bool isCpfp READ isCpfp CONSTANT) public: Transaction(); ~Transaction(); @@ -178,7 +180,7 @@ class Transaction : public QObject { nunchuk::Transaction nunchukTransaction() const; void setNunchukTransaction(const nunchuk::Transaction &tx); - QString roomId() const; + QString roomId(); void setRoomId(const QString &roomId); QString initEventId() const; void setInitEventId(const QString &initEventId); @@ -186,8 +188,12 @@ class Transaction : public QObject { void setCreateByMe(bool createByMe); QString serverKeyMessage() const; void setServerKeyMessage(const QJsonObject &data); + QString packageFeeRate() ; + void setPackageFeeRate(int satvKB); QString destination(); + bool isCpfp(); + time_t scheduleTime(); private: QDestinationListModelPtr m_destinations; QSingleSignerListModelPtr m_signers; @@ -199,6 +205,7 @@ class Transaction : public QObject { QString m_initEventId; bool m_createByMe; QString m_serverKeyMessage; + int m_packageFeeRate {0}; signals: void txidChanged(); @@ -226,6 +233,7 @@ class Transaction : public QObject { void walletIdChanged(); void psbtChanged(); void serverKeyMessageChanged(); + void packageFeeRateChanged(); }; typedef OurSharedPointer QTransactionPtr; @@ -253,6 +261,7 @@ class TransactionListModel : public QAbstractListModel void linkingReplacedTransactions(); void cleardata(); int count() const; + bool contains(const QString &tx_id); enum TransactionRoles { transaction_txid_role, @@ -280,7 +289,6 @@ class TransactionListModel : public QAbstractListModel void countChanged(); private: - bool contains(const QString &tx_id); QList m_data; }; typedef OurSharedPointer QTransactionListModelPtr; diff --git a/Models/UTXOModel.cpp b/Models/UTXOModel.cpp index 90c902e0..a787b3d9 100644 --- a/Models/UTXOModel.cpp +++ b/Models/UTXOModel.cpp @@ -19,7 +19,9 @@ **************************************************************************/ #include "UTXOModel.h" #include "AppSetting.h" +#include "AppModel.h" #include "qUtils.h" +#include #include UTXO::UTXO (const QString &txid, @@ -27,14 +29,16 @@ UTXO::UTXO (const QString &txid, const QString &address, const qint64 amount, const int height, - const QString &memo): + const QString &memo, + const int status): txid_(txid), vout_(vout), address_(address), amount_(amount), height_(height), memo_(memo), - selected_(false) + selected_(false), + status_(status) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -45,7 +49,11 @@ UTXO::UTXO() : txid_(""), amount_(0), height_(-1), memo_(""), - selected_(false){} + selected_(false), + status_(0) +{ + +} UTXO::~UTXO() { } @@ -162,6 +170,19 @@ void UTXO::setMemo(const QString &memo) } } +int UTXO::status() const +{ + return status_; +} + +void UTXO::setStatus(int status) +{ + if(status_ != status){ + status_ = status; + emit statusChanged(); + } +} + UTXOListModel::UTXOListModel(){ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -189,6 +210,14 @@ QVariant UTXOListModel::data(const QModelIndex &index, int role) const{ return d_[index.row()]->selected(); case utxo_memo_role: return d_[index.row()]->memo(); + case utxo_confirmed_role: + { + qint64 conf = 0; + if((int)nunchuk::CoinStatus::CONFIRMED == d_[index.row()]->status()){ + conf = std::max(0, (AppModel::instance()->chainTip() - d_[index.row()]->height())+1); + } + return conf; + } default: return QVariant(); } @@ -211,14 +240,21 @@ QHash UTXOListModel::roleNames() const { roles[utxo_amount_role] = "utxo_amount"; roles[utxo_height_role] = "utxo_height"; roles[utxo_selected_role] = "utxo_selected"; + roles[utxo_confirmed_role] = "utxo_confirmed"; roles[utxo_memo_role] = "utxo_memo"; return roles; } -void UTXOListModel::addUTXO(const QString &txid, const int vout, const QString &address, const qint64 amount, const int height, const QString &memo) +void UTXOListModel::addUTXO(const QString &txid, + const int vout, + const QString &address, + const qint64 amount, + const int height, + const QString &memo, + const int status ) { beginResetModel(); - d_.append(QUTXOPtr(new UTXO(txid, vout, address, amount, height, memo))); + d_.append(QUTXOPtr(new UTXO(txid, vout, address, amount, height, memo, status))); endResetModel(); } diff --git a/Models/UTXOModel.h b/Models/UTXOModel.h index 034c3900..3eed354d 100644 --- a/Models/UTXOModel.h +++ b/Models/UTXOModel.h @@ -35,8 +35,15 @@ class UTXO : public QObject{ Q_PROPERTY(QString scriptPublickey READ scriptPublickey NOTIFY scriptPublickeyChanged) Q_PROPERTY(int height READ height NOTIFY heightChanged) Q_PROPERTY(QString memo READ memo NOTIFY memoChanged) + Q_PROPERTY(QString status READ status NOTIFY statusChanged) public: - UTXO(const QString &txid, const int vout, const QString &address, const qint64 amount, const int height, const QString &memo); + UTXO(const QString &txid, + const int vout, + const QString &address, + const qint64 amount, + const int height, + const QString &memo, + const int status); UTXO(); ~UTXO(); @@ -65,6 +72,9 @@ class UTXO : public QObject{ QString memo() const; void setMemo(const QString &memo); + int status() const; + void setStatus(int status); + private: QString txid_; int vout_; @@ -73,6 +83,7 @@ class UTXO : public QObject{ int height_; QString memo_; bool selected_; + int status_; signals: void txidChanged(); void voutChanged(); @@ -82,6 +93,7 @@ class UTXO : public QObject{ void selectedChanged(); void scriptPublickeyChanged(); void memoChanged(); + void statusChanged(); }; typedef QSharedPointer QUTXOPtr; @@ -101,7 +113,8 @@ class UTXOListModel : public QAbstractListModel const QString& address, const qint64 amount, const int height, - const QString &memo); + const QString &memo, + const int status); QUTXOPtr getUTXOByIndex(const int index); void updateSelected(const QString &txid, const int vout); qint64 getAmount(const QString &txid, const int vout); @@ -115,6 +128,7 @@ class UTXOListModel : public QAbstractListModel utxo_amount_role, utxo_height_role, utxo_selected_role, + utxo_confirmed_role, utxo_memo_role }; diff --git a/Models/WalletModel.cpp b/Models/WalletModel.cpp index 42457e69..8de709bc 100644 --- a/Models/WalletModel.cpp +++ b/Models/WalletModel.cpp @@ -23,70 +23,53 @@ #include "AppModel.h" #include #include "bridgeifaces.h" +#include "Draco.h" Wallet::Wallet() : - m_id(""), - m_m(0), - n_n(0), - m_nShared(0), - m_name(""), m_addressType(QString::number((int)ENUNCHUCK::AddressType::NATIVE_SEGWIT)), // Default is NATIVE_SEGWIT - m_balance(0), m_createDate(QDateTime::currentDateTime()), - m_escrow(false), m_signers(QSingleSignerListModelPtr(new SingleSignerListModel())), m_transactionHistory(QTransactionListModelPtr(new TransactionListModel())), - m_capableCreate(true), - m_description(""), - m_descriptior(""), - m_creationMode((int)CreationMode::CREATE_NEW_WALLET), - m_isSharedWallet(false), - m_roomId(""), - m_initEventId("") + m_creationMode((int)CreationMode::CREATE_NEW_WALLET) { QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } -Wallet::Wallet(const QString &pr_id, - const int pr_m, - const int pr_n, - const QString &pr_name, - const QString &pr_addrType, - const qint64 pr_balance, - const QDateTime &pr_createDate, - const bool pr_escrow, - const QSingleSignerListModelPtr& pr_signers, - const QString &pr_description) : - m_id(pr_id), - m_m(pr_m), - n_n(pr_n), - m_nShared(0), - m_name(pr_name), - m_addressType(pr_addrType), - m_balance(pr_balance), - m_createDate(pr_createDate), - m_escrow(pr_escrow), - m_signers(pr_signers), - m_transactionHistory(QTransactionListModelPtr(new TransactionListModel())), - m_address("There is no unused address"), - m_capableCreate(true), - m_description(pr_description), - m_descriptior(""), - m_creationMode((int)CreationMode::CREATE_NEW_WALLET), - m_isSharedWallet(false), - m_roomId(""), - m_initEventId("") +Wallet::Wallet(const nunchuk::Wallet &w) : m_wallet(w) { - m_unUsedAddressList.clear(); - m_usedAddressList.clear(); - m_usedChangeAddressList.clear(); - m_unUsedChangedAddressList.clear(); + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } Wallet::~Wallet(){ } +void Wallet::convert(const Wallet *w) +{ + if (w) { + m_wallet = w->wallet(); + } +} + +void Wallet::convert(const nunchuk::Wallet &w) +{ + setId(QString::fromStdString(w.get_id())); + setM(w.get_m()); + setN(w.get_n()); + setName(QString::fromStdString(w.get_name())); + setAddressType(QString::number((int)w.get_address_type())); + setBalance(w.get_unconfirmed_balance()); + setCreateDate(QDateTime::fromTime_t(w.get_create_date())); + setEscrow(w.is_escrow()); + setGapLimit(w.get_gap_limit()); + setDescription(QString::fromStdString(w.get_description())); + m_signers->cleardata(); + for (nunchuk::SingleSigner signer : w.get_signers()) { + QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); + m_signers->addSingleSigner(ret); + } +} + QString Wallet::id() const {return m_id;} int Wallet::m() const { return m_m;} @@ -432,6 +415,74 @@ void Wallet::setGapLimit(int gap_limit) } } +nunchuk::Wallet Wallet::wallet() const +{ + return m_wallet; +} + +void Wallet::syncAissistedTxs() +{ + if(isAssistedWallet()){ + QString wallet_id = id(); + QJsonObject data = Draco::instance()->assistedWalletGetListTx(wallet_id); + QJsonArray transactions = data.value("transactions").toArray(); + for(QJsonValue js_value : transactions){ + QJsonObject transaction = js_value.toObject(); + QString status = transaction.value("status").toString(); + QString psbt = transaction.value("psbt").toString(); + QString note = transaction.value("note").toString(); + QString memo = (note != "")? note : "--"; + QString type = transaction.value("type").toString(); + QString transaction_id = transaction.value("transaction_id").toString(); + if (status == "READY_TO_BROADCAST" || status == "PENDING_SIGNATURES" ) { + QWarningMessage _msg; + QTransactionPtr tran = bridge::nunchukImportPsbt(wallet_id, psbt, _msg); + if(tran && (int)EWARNING::WarningType::NONE_MSG == _msg.type()){ + if(transactionHistory()){ + QTransactionPtr tx = transactionHistory()->getTransactionByTxid(transaction_id); + if(tx && 0 != QString::compare(memo, tx.data()->memo(), Qt::CaseInsensitive)){ + bridge::nunchukUpdateTransactionMemo(wallet_id, transaction_id, memo); + } + } + long int broadcast_time_milis = static_cast(transaction.value("broadcast_time_milis").toDouble()); + // honey badger feature: schedule broadcast + long int current_time_stamp_milis = static_cast(std::time(nullptr)) * 1000; + if(type == "SCHEDULED" && broadcast_time_milis > current_time_stamp_milis) { + bridge::nunchukUpdateTransactionSchedule(wallet_id, transaction_id, broadcast_time_milis/1000,_msg); + } + } + } + } + //Remove cancelled txs + syncAissistedCancelledTxs(); + } +} + +void Wallet::syncAissistedCancelledTxs() +{ + if(isAssistedWallet()){ + int offset = 0; + const int limit = 10; + QString wallet_id = id(); + while (true) { + QJsonObject data = Draco::instance()->assistedWalletDeleteListTx(wallet_id, offset, limit); + QJsonArray transactions = data.value("transactions").toArray(); + for (QJsonValue js_value : transactions) { + QJsonObject transaction = js_value.toObject(); + QString wallet_local_id = transaction.value("wallet_local_id").toString(); + QString transaction_id = transaction.value("transaction_id").toString(); + if(transactionHistory() && transactionHistory()->contains(transaction_id)){ + bridge::nunchukDeleteTransaction(wallet_local_id, transaction_id); + } + } + if (transactions.size() == 0 || transactions.size() < limit) { + return; // exit while loop + } + offset += transactions.size(); + } + } +} + WalletListModel::WalletListModel(){ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); } @@ -515,24 +566,6 @@ QHash WalletListModel::roleNames() const{ return roles; } -void WalletListModel::addWallet(const QString &pr_id, - const int pr_m, - const int pr_n, - const QString &pr_name, - const QString &pr_addrType, - const qint64 pr_balance, - const QDateTime &pr_createDate, - const bool pr_escrow, - QSingleSignerListModelPtr pr_signers, - const QString &pr_description) -{ - beginResetModel(); - if(!containsId(pr_id)){ - d_.append(QWalletPtr(new Wallet(pr_id, pr_m, pr_n, pr_name, pr_addrType, pr_balance, pr_createDate, pr_escrow, pr_signers, pr_description))); - } - endResetModel(); -} - void WalletListModel::addWallet(const QWalletPtr &wallet) { if(wallet && !containsId(wallet.data()->id())){ @@ -571,6 +604,7 @@ void WalletListModel::addSharedWallet(const QWalletPtr &wallet) void WalletListModel::updateBalance(const QString &walletId, const qint64 balance) { + DBG_INFO << walletId << balance; for (int i = 0; i < d_.count(); i++) { if(d_.at(i).data() && 0 == QString::compare(walletId, d_.at(i)->id(), Qt::CaseInsensitive)){ d_.at(i)->setBalance(balance); @@ -746,7 +780,7 @@ void WalletListModel::requestSort(int role, int order) beginResetModel(); if(d_.count() > 1){ switch (role) { - case wallet_Name_Role: + case wallet_createDate_Role: { if(Qt::DescendingOrder == order){ qSort(d_.begin(), d_.end(), sortWalletByNameDescending); @@ -812,10 +846,10 @@ void WalletListModel::cleardata() bool sortWalletByNameAscending(const QWalletPtr &v1, const QWalletPtr &v2) { - return (QString::compare((v1.data()->name()), (v2.data()->name())) < 0); + return v1.data()->createDateDateTime() < v2.data()->createDateDateTime(); } bool sortWalletByNameDescending(const QWalletPtr &v1, const QWalletPtr &v2) { - return (QString::compare((v1.data()->name()), (v2.data()->name())) > 0); + return v1.data()->createDateDateTime() > v2.data()->createDateDateTime(); } diff --git a/Models/WalletModel.h b/Models/WalletModel.h index 431a03d6..1136c878 100644 --- a/Models/WalletModel.h +++ b/Models/WalletModel.h @@ -58,16 +58,7 @@ class Wallet : public QObject Q_PROPERTY(int gapLimit READ gapLimit NOTIFY gapLimitChanged) public: Wallet(); - Wallet(const QString &pr_id, - const int pr_m, - const int pr_n, - const QString &pr_name, - const QString &pr_addrType, - const qint64 pr_balance, - const QDateTime &pr_createDate, - const bool pr_escrow, - const QSingleSignerListModelPtr &pr_signers, - const QString &pr_description); + Wallet(const nunchuk::Wallet &w); ~Wallet(); enum class CreationMode : int { CREATE_NEW_WALLET, @@ -77,6 +68,9 @@ class Wallet : public QObject CREATE_BY_IMPORT_QRCODE }; + void convert(const Wallet *w); + void convert(const nunchuk::Wallet &w); + QString id() const; int m() const; int n() ; @@ -138,35 +132,40 @@ class Wallet : public QObject bool isAssistedWallet() const; int gapLimit() const; void setGapLimit(int gap_limit); + nunchuk::Wallet wallet() const; + + //Assisted + void syncAissistedTxs(); + void syncAissistedCancelledTxs(); private: - QString m_id; - int m_m; - int n_n; - int m_nShared; - QString m_name; - QString m_addressType; - qint64 m_balance; - QDateTime m_createDate; - bool m_escrow; + QString m_id {}; + int m_m {}; + int n_n {}; + int m_nShared {}; + QString m_name {}; + QString m_addressType {}; + qint64 m_balance {}; + QDateTime m_createDate {}; + bool m_escrow {}; QSingleSignerListModelPtr m_signers; QTransactionListModelPtr m_transactionHistory; // Additional member QString m_address; - QStringList m_usedAddressList; - QStringList m_unUsedAddressList; - QStringList m_usedChangeAddressList; - QStringList m_unUsedChangedAddressList; + QStringList m_usedAddressList {}; + QStringList m_unUsedAddressList {}; + QStringList m_usedChangeAddressList {}; + QStringList m_unUsedChangedAddressList {}; // capable to create wallet - bool m_capableCreate; - QString m_description; - QString m_descriptior; - int m_creationMode; - bool m_isSharedWallet; - QString m_roomId; - QString m_initEventId; + bool m_capableCreate {true}; + QString m_description {}; + QString m_descriptior {}; + int m_creationMode {}; + bool m_isSharedWallet {}; + QString m_roomId {}; + QString m_initEventId {}; int m_gapLimit {0}; - + nunchuk::Wallet m_wallet {false}; signals: void idChanged(); void mChanged(); @@ -195,7 +194,7 @@ class Wallet : public QObject void isAssistedWalletChanged(); void gapLimitChanged(); }; -typedef QSharedPointer QWalletPtr; +typedef OurSharedPointer QWalletPtr; bool sortWalletByNameAscending(const QWalletPtr &v1, const QWalletPtr &v2); bool sortWalletByNameDescending(const QWalletPtr &v1, const QWalletPtr &v2); @@ -210,16 +209,6 @@ class WalletListModel : public QAbstractListModel QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); QHash roleNames() const; - void addWallet(const QString& pr_id, - const int pr_m, - const int pr_n, - const QString& pr_name, - const QString& pr_addrType, - const qint64 pr_balance, - const QDateTime& pr_createDate, - const bool pr_escrow, - QSingleSignerListModelPtr pr_signers, - const QString &pr_description); void addWallet(const QWalletPtr &wallet); void replaceWallet(const QWalletPtr &wallet); void addSharedWallet(const QWalletPtr &wallet); @@ -265,6 +254,6 @@ class WalletListModel : public QAbstractListModel private: QList d_; }; -typedef QSharedPointer QWalletListModelPtr; +typedef OurSharedPointer QWalletListModelPtr; #endif // WALLETLISTMODEL_H diff --git a/Models/Worker.cpp b/Models/Worker.cpp index dec9e419..f66656c7 100644 --- a/Models/Worker.cpp +++ b/Models/Worker.cpp @@ -24,6 +24,7 @@ #include "QQuickViewer.h" #include "Draco.h" #include "localization/STR_CPP.h" +#include "Chats/QUserWallets.h" Worker *Worker::mInstance = NULL; Worker::Worker() @@ -315,7 +316,10 @@ void Worker::slotStartBalanceChanged(const QString &id, if(AppModel::instance()->walletList()){ AppModel::instance()->walletList()->updateBalance(id, balance); } -// emit finishBalanceChanged(id, balance); //FIXME FOR IMPROVEMENT + if(AppModel::instance()->walletInfo() && 0 == QString::compare(id, AppModel::instance()->walletInfo()->id(), Qt::CaseInsensitive)){ + AppModel::instance()->walletInfo()->setBalance(balance); + } + emit finishBalanceChanged(id, balance); } void Worker::slotStartTransactionChanged(const QString &tx_id, @@ -374,12 +378,10 @@ void Worker::slotStartGetUnusedAddresses(const QString wallet_id) void Worker::slotStartGetTransactionHistory(const QString wallet_id) { - qApp->setOverrideCursor(Qt::WaitCursor); if(wallet_id != ""){ std::vector trans_result = bridge::nunchukGetOriginTransactionHistory(wallet_id); emit finishGetTransactionHistory(wallet_id, trans_result); } - qApp->restoreOverrideCursor(); } void Worker::slotStartGetEstimatedFee() @@ -462,6 +464,26 @@ void Worker::slotStartMultiDeviceSync(const bool state) } } +void Worker::slotStartReloadUserDb() +{ + FuncTime f(__PRETTY_FUNCTION__); + QWarningMessage msg; + std::vector wallets = bridge::nunchukGetOriginWallets(msg); + if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ + emit finishReloadWallets(wallets); + } + + std::vector masters = bridge::nunchukGetOriginMasterSigners(msg); + if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ + emit finishReloadMasterSigners(masters); + } + + std::vector remotes = bridge::nunchukGetOriginRemoteSigners(msg); + if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ + emit finishReloadRemoteSigners(remotes); + } +} + void Worker::slotStartReloadWallets() { QWarningMessage msg; @@ -492,6 +514,9 @@ void Worker::slotStartReloadRemoteSigners() void Worker::slotStartSyncWalletDb(const QString &wallet_id) { if(wallet_id != ""){ + std::vector trans_result = bridge::nunchukGetOriginTransactionHistory(wallet_id); + emit finishGetTransactionHistory(wallet_id, trans_result); + QStringList used_addr = bridge::nunchukGetUsedAddresses(wallet_id, false); QStringList used_change_addr = bridge::nunchukGetUsedAddresses(wallet_id, true); @@ -514,9 +539,13 @@ void Worker::slotStartSyncWalletDb(const QString &wallet_id) wallet.data()->setUsedChangeAddressList(used_change_addr); wallet.data()->setunUsedAddressList(unused_addr); wallet.data()->setUnUsedChangeddAddressList(unsued_chabge_addr); + if(wallet && wallet.data()->isAssistedWallet()){ + QtConcurrent::run([wallet]() { + wallet.data()->syncAissistedTxs(); + AppModel::instance()->startGetTransactionHistory(wallet.data()->id()); + }); + } } - std::vector trans_result = bridge::nunchukGetOriginTransactionHistory(wallet_id); - emit finishGetTransactionHistory(wallet_id, trans_result); } emit finishSyncWalletDb(wallet_id); } @@ -627,6 +656,8 @@ Controller::Controller() { connect(this, &Controller::startMultiDeviceSync, worker, &Worker::slotStartMultiDeviceSync, Qt::QueuedConnection); + connect(this, &Controller::startReloadUserDb, worker, &Worker::slotStartReloadUserDb, Qt::QueuedConnection); + connect(this, &Controller::startReloadWallets, worker, &Worker::slotStartReloadWallets, Qt::QueuedConnection); connect(worker, &Worker::finishReloadWallets, this, &Controller::slotFinishReloadWallets, Qt::QueuedConnection); @@ -645,7 +676,7 @@ Controller::Controller() { Controller::~Controller() { if(workerThread.isRunning()){ workerThread.quit(); - workerThread.wait(); + workerThread.wait(5); } this->disconnect(); } @@ -674,13 +705,19 @@ void Controller::slotFinishCreateMasterSigner(const QMasterSignerPtr ret, QMasterSignerPtr newsigner = AppModel::instance()->masterSignerList()->getMasterSignerByXfp(ret.data()->fingerPrint()); AppModel::instance()->setMasterSignerInfo(newsigner); } - if(QQuickViewer::instance()->getCurrentStates().last() == E::STATE_ID_SCR_ADD_HARDWARE_SIGNER){ + int last = QQuickViewer::instance()->getCurrentStates().last(); + if(last == E::STATE_ID_SCR_ADD_HARDWARE_SIGNER){ QQuickViewer::instance()->sendEvent(E::EVT_ADD_MASTER_SIGNER_RESULT); - } - else{ + } else if (last == E::STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET){ QQuickViewer::instance()->sendEvent(E::EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER_RESULT); + } else if (last == E::STATE_ID_SCR_ADD_LEDGER || + last == E::STATE_ID_SCR_ADD_TREZOR || + last == E::STATE_ID_SCR_ADD_COLDCARD){ + QUserWallets::instance()->addKeyRequested(); } - if (AppModel::instance()->addSignerWizard() != 3) { + + if (last == E::STATE_ID_SCR_ADD_HARDWARE_SIGNER || + last == E::STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET) { AppModel::instance()->showToast(0, STR_CPP_057, EWARNING::WarningType::SUCCESS_MSG, @@ -692,6 +729,12 @@ void Controller::slotFinishCreateMasterSigner(const QMasterSignerPtr ret, what, (EWARNING::WarningType)type, STR_CPP_060); + int last = QQuickViewer::instance()->getCurrentStates().last(); + if (last == E::STATE_ID_SCR_ADD_LEDGER || + last == E::STATE_ID_SCR_ADD_TREZOR || + last == E::STATE_ID_SCR_ADD_COLDCARD){ + QQuickViewer::instance()->sendEvent(E::EVT_ONLINE_ONS_CLOSE_REQUEST); + } } AppModel::instance()->setAddSignerStep(-1); } @@ -783,7 +826,10 @@ void Controller::slotFinishSigningTransaction(const QString &walletId, QString tx_id = QString::fromStdString(result.get_txid()); QWalletPtr wallet = AppModel::instance()->walletList()->getWalletById(walletId); if(wallet && wallet->isAssistedWallet()){ - QJsonObject data = Draco::instance()->assistedWalletSignTx(walletId,tx_id,QString::fromStdString(result.get_psbt()),QString::fromStdString(result.get_memo())); + QJsonObject data = Draco::instance()->assistedWalletSignTx(walletId, + tx_id, + QString::fromStdString(result.get_psbt()), + QString::fromStdString(result.get_memo())); QJsonObject transaction = data.value("transaction").toObject(); QString status = transaction.value("status").toString(); QString psbt = transaction.value("psbt").toString(); @@ -1006,26 +1052,12 @@ void Controller::slotFinishCreateWallet(nunchuk::Wallet ret, int type, int code) { + DBG_INFO << "walletListCurrentIndex"; if(type != (int)EWARNING::WarningType::EXCEPTION_MSG){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : ret.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - QWalletPtr wallet_result = QWalletPtr(new Wallet(QString::fromStdString(ret.get_id()), - ret.get_m(), - ret.get_n(), - QString::fromStdString(ret.get_name()), - QString::number((int)ret.get_address_type()), - ret.get_unconfirmed_balance(), - QDateTime::fromTime_t(ret.get_create_date()), - ret.is_escrow(), - signersAssinged, - QString::fromStdString(ret.get_description()))); QString wallet_id = QString::fromStdString(ret.get_id()); - AppModel::instance()->walletList()->addWallet(wallet_result); + AppModel::instance()->walletList()->addWallet(bridge::convertWallet(ret)); AppModel::instance()->resetSignersChecked(); - AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_Name_Role, Qt::AscendingOrder); + AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_createDate_Role, Qt::AscendingOrder); int index = AppModel::instance()->walletList()->getWalletIndexById(wallet_id); if(-1 != index){ AppModel::instance()->setWalletListCurrentIndex(index); @@ -1055,11 +1087,7 @@ void Controller::slotFinishBackupWallet(QString what, void Controller::slotFinishBalanceChanged(const QString &id, const qint64 balance) { - if(AppModel::instance()->walletList()){ - AppModel::instance()->walletList()->updateBalance(id, balance); - AppModel::instance()->startGetUsedAddresses(id); - AppModel::instance()->startGetUnusedAddresses(id); - } + startSyncWalletDb(id); } void Controller::slotFinishTransactionChanged(const QString &tx_id, @@ -1122,7 +1150,6 @@ void Controller::slotFinishGetUnusedAddresses(const QString& wallet_id, void Controller::slotFinishGetTransactionHistory(const QString wallet_id, std::vector ret) { - qApp->setOverrideCursor(Qt::WaitCursor); QWalletPtr wallet = NULL; if(AppModel::instance()->walletInfo()){ if(0 == QString::compare(AppModel::instance()->walletInfo()->id(), wallet_id, Qt::CaseInsensitive)){ @@ -1139,11 +1166,11 @@ void Controller::slotFinishGetTransactionHistory(const QString wallet_id, for (auto it = ret.begin(); it != ret.end(); ++it) { const nunchuk::Transaction &element = *it; QTransactionPtr tx = bridge::convertTransaction(element, wallet_id); - trans_ret.data()->addTransaction(tx); + wallet.data()->transactionHistory()->updateTransaction(tx.data()->txid(), tx); } - wallet.data()->setTransactionHistory(trans_ret); + wallet.data()->transactionHistory()->requestSort(TransactionListModel::TransactionRoles::transaction_blocktime_role, Qt::DescendingOrder); + emit wallet.data()->transactionHistoryChanged(); } - qApp->restoreOverrideCursor(); emit finishedGetTransactionHistory(); } @@ -1263,14 +1290,18 @@ void Controller::slotFinishReloadWallets(std::vector wallets) QWalletListModelPtr ret = bridge::nunchukConvertWallets(wallets); if(ret){ AppModel::instance()->setWalletList(ret); - if(ret->rowCount() > 0){ + if(-1 == AppModel::instance()->walletListCurrentIndex() && ret->rowCount() > 0){ QString lastWalletId = bridge::nunchukGetSelectedWallet(); int lastIndex = -1; if(lastWalletId != ""){ lastIndex = AppModel::instance()->walletList()->getWalletIndexById(lastWalletId); } - AppModel::instance()->setWalletListCurrentIndex(lastIndex); + else{ + lastIndex = 0; + } + AppModel::instance()->setWalletListCurrentIndex(lastIndex == -1 ? 0 : lastIndex); } + AppModel::instance()->walletListCurrentIndexChanged(); } if(ONLINE_MODE == bridge::nunchukCurrentMode()){ if(CLIENT_INSTANCE->isNunchukLoggedIn() && CLIENT_INSTANCE->isMatrixLoggedIn()){ diff --git a/Models/Worker.h b/Models/Worker.h index d3630350..d9d26faf 100644 --- a/Models/Worker.h +++ b/Models/Worker.h @@ -122,6 +122,8 @@ public slots: void slotStartMultiDeviceSync(const bool state); + void slotStartReloadUserDb(); + void slotStartReloadWallets(); void slotStartReloadMasterSigners(); @@ -408,6 +410,8 @@ public slots: void startRemoveAllSigners(); + void startReloadUserDb(); + void startReloadWallets(); void startReloadMasterSigners(); diff --git a/QAppEngine/QOutlog/QOutlog.h b/QAppEngine/QOutlog/QOutlog.h index 0ba7703e..9b001509 100644 --- a/QAppEngine/QOutlog/QOutlog.h +++ b/QAppEngine/QOutlog/QOutlog.h @@ -37,6 +37,7 @@ #include #include #include +#include #include enum class LOG_LEVEL : int @@ -194,7 +195,11 @@ class QOutlog inline QOutlog &operator<<(std::nullptr_t) { mStream << "(nullptr)" << ' ';; return *this; } inline QOutlog &operator<<(const void * t) { mStream << t << ' '; return *this; } - inline QOutlog &operator<<(const QJsonObject & t) { return operator<<(t.toVariantMap()); } + inline QOutlog &operator<<(const QJsonObject & t) { + QJsonDocument doc(t); + QString strJson(doc.toJson(QJsonDocument::Compact)); + return operator<<(strJson); + } inline QOutlog &operator<<(QUrl t) { mStream << t.toString() << ' '; return *this; } template @@ -254,7 +259,9 @@ class FuncTime ~FuncTime() { +#ifndef RELEASE_MODE DBG_INFO << QString("%1 takes %2 ms").arg(mFunc).arg(mTime.elapsed()); +#endif } private: QString mFunc; diff --git a/QAppEngine/QQuickViewer/Common/QCommonDefines.h b/QAppEngine/QQuickViewer/Common/QCommonDefines.h index 923f01c7..308c57c9 100644 --- a/QAppEngine/QQuickViewer/Common/QCommonDefines.h +++ b/QAppEngine/QQuickViewer/Common/QCommonDefines.h @@ -36,5 +36,22 @@ #define JS_POPUPS_TRANSITION_FUNCTION "load_Popup" #define JS_TOASTS_TRANSITION_FUNCTION "load_Toast" +#define DECLARE_PROPERTY(TYPE, NAME, WRITE_NAME, READ_NAME) \ +private: \ + Q_PROPERTY(TYPE q##NAME READ get##NAME WRITE set##NAME NOTIFY NAME##Changed) \ + TYPE m##NAME {}; \ +Q_SIGNALS: void NAME##Changed(); \ +public: \ + TYPE get##NAME() { \ + READ_NAME \ + return m##NAME; \ + } \ + void set##NAME(TYPE val) { \ + if (m##NAME == val) \ + return; \ + m##NAME = val; \ + emit NAME##Changed(); \ + WRITE_NAME \ + } \ #endif // COMMONDEFINES_H diff --git a/QAppEngine/QQuickViewer/QQuickViewer.cpp b/QAppEngine/QQuickViewer/QQuickViewer.cpp index de78769d..c2d8cbfa 100644 --- a/QAppEngine/QQuickViewer/QQuickViewer.cpp +++ b/QAppEngine/QQuickViewer/QQuickViewer.cpp @@ -33,7 +33,7 @@ QQuickViewer::QQuickViewer() : m_viewer(new QQuickView()), m_scrMng(NULL), m_pop m_PopupTriger.clear(); } QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - connect(this, &QQuickViewer::signalNotifySendEvent, this, &QQuickViewer::sendEvent); + connect(this, &QQuickViewer::signalNotifySendEvent, this, &QQuickViewer::sendEvent, Qt::QueuedConnection); } QQuickViewer::~QQuickViewer() diff --git a/Qml/Components/customizes/Buttons/QAssistedWalletDelegate.qml b/Qml/Components/customizes/Buttons/QAssistedWalletDelegate.qml new file mode 100644 index 00000000..ccef2f50 --- /dev/null +++ b/Qml/Components/customizes/Buttons/QAssistedWalletDelegate.qml @@ -0,0 +1,124 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtGraphicalEffects 1.0 +import DataPool 1.0 +import "../../origins" +import "../../customizes/Texts" +import "../../customizes/Buttons" +import "../../../../localization/STR_QML.js" as STR + +QLinearGradient { + id: wldlg + width: 304 + height: 92 + property string walletName : "Name" + property string walletBalance : "0.0000000" + property string walletCurrency : "0.0000000" + property string walletM: "0" + property string walletN: "0" + Column{ + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: 24 + } + QLato{ + font.weight: Font.Bold + text: walletName + color: "#FFFFFF" + } + QLato{ + font.weight: Font.Bold + text: walletBalance + RoomWalletData.unitValue + color: "#FFFFFF" + } + QLato{ + text: qsTr("(%1 %2)").arg(AppSetting.currency).arg(walletCurrency) + color: "#FFFFFF" + } + } + + Item { + width: 80 + height: childrenRect.height + anchors { + right: parent.right + rightMargin: 24 + bottom: parent.bottom + bottomMargin: 24 + } + Column { + width: parent.width + spacing: 4 + Item { + width: parent.width + height: 16 + Rectangle{ + width: 70 + height: parent.height + radius: 20 + color: "#EAEAEA" + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + Row { + anchors.centerIn: parent + spacing: 4 + QImage { + width: 12 + height: 12 + source: "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" + } + QText{ + font.family: "Lato" + font.pixelSize: 10 + color: "#031F2B" + text: STR.STR_QML_679 + font.weight: Font.Bold + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + Rectangle { + width: parent.width + height: 16 + radius: 20 + color: "#EAEAEA" + QText { + anchors.centerIn: parent + text: walletN === "1" ? STR.STR_QML_070 : qsTr("%1/%2 %3").arg(walletM).arg(walletN).arg(STR.STR_QML_069); + color: "#031F2B" + font.weight: Font.Bold + font.pixelSize: 10 + } + } + } + } + + + signal buttonClicked() + MouseArea { + id: walletmouse + hoverEnabled: true + anchors.fill: parent + onClicked: wldlg.buttonClicked() + } +} diff --git a/Qml/Components/customizes/Buttons/QCheckBoxButton.qml b/Qml/Components/customizes/Buttons/QCheckBoxButton.qml new file mode 100644 index 00000000..5cb9e698 --- /dev/null +++ b/Qml/Components/customizes/Buttons/QCheckBoxButton.qml @@ -0,0 +1,54 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtGraphicalEffects 1.0 +import "../../origins" +import "../../customizes/Texts" + +Item { + width: 539 + height: 24 + property string label: "" + property bool checked: false + QLato { + id: text + text: label + font.weight: Font.Bold + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + QImage { + id: _check + width: 24 + height: 24 + anchors.verticalCenter: text.verticalCenter + anchors.right: parent.right + source: checked ? "qrc:/Images/Images/checkbox-checked-dark.svg" : "qrc:/Images/Images/checkbox-dark.svg" + } + MouseArea { + id: mouse + anchors.fill: _check + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { checked = !checked; buttonClicked() } + } + signal buttonClicked() +} diff --git a/Qml/Components/customizes/Buttons/QLinearGradient.qml b/Qml/Components/customizes/Buttons/QLinearGradient.qml new file mode 100644 index 00000000..a819f75d --- /dev/null +++ b/Qml/Components/customizes/Buttons/QLinearGradient.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import QtGraphicalEffects 1.0 + +Item { + LinearGradient { + id: _area + visible: false + height: parent.height + width: parent.width + start: Qt.point(0, 0) + end: Qt.point(parent.width, 0) + gradient: Gradient { + GradientStop { position: 0.0; color: "#2F766D" } + GradientStop { position: 1.0; color: "#1C4A21" } + } + } + Rectangle { + id: mask + anchors.fill: parent + visible: false + radius: 12 + } + OpacityMask { + anchors.fill: parent + source: _area + maskSource: mask + } +} diff --git a/Qml/Components/customizes/Buttons/QRadioButtonTypeC.qml b/Qml/Components/customizes/Buttons/QRadioButtonTypeC.qml index d499adcd..a8cdc55d 100644 --- a/Qml/Components/customizes/Buttons/QRadioButtonTypeC.qml +++ b/Qml/Components/customizes/Buttons/QRadioButtonTypeC.qml @@ -36,7 +36,7 @@ Row { id: icon width: 24 height: 24 - source: selected ? "qrc:/Images/Images/RadioEnabled.png" : "qrc:/Images/Images/RadioDeselected.png" + source: selected ? "qrc:/Images/Images/radio-selected-dark.svg" : "qrc:/Images/Images/radio-dark.svg" anchors.verticalCenter: parent.verticalCenter MouseArea { id: mouse diff --git a/Qml/Components/customizes/Buttons/QRadioButtonTypeD.qml b/Qml/Components/customizes/Buttons/QRadioButtonTypeD.qml index d2737877..9ac077fe 100644 --- a/Qml/Components/customizes/Buttons/QRadioButtonTypeD.qml +++ b/Qml/Components/customizes/Buttons/QRadioButtonTypeD.qml @@ -27,8 +27,8 @@ Row { property string labelTop: "" property string labelCenter: "" property string labelBottom: "" - property string walletType: "" - property string walletIcon: "" + property string type: "" + property string icon: "" signal buttonClicked() spacing: 12 Column { @@ -52,10 +52,10 @@ Row { color: "#EAEAEA" } QBadge { - text: walletType - icon: walletIcon + text: type + icon: icon color: "#EAEAEA" - visible: walletIcon != "" + visible: icon !== "" } } } diff --git a/Qml/Components/customizes/Buttons/QRadioButtonTypeE.qml b/Qml/Components/customizes/Buttons/QRadioButtonTypeE.qml new file mode 100644 index 00000000..1eab770c --- /dev/null +++ b/Qml/Components/customizes/Buttons/QRadioButtonTypeE.qml @@ -0,0 +1,72 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import "../../origins" +import "../../customizes/Texts" + +Rectangle { + id: radioRoot + property bool selected: false + property string label: "" + property string fontFamily: "Lato" + property string textBadge: "" + property int fontPixelSize: 14 + property int fontWeight: Font.Bold + signal buttonClicked() + border.width: 2 + border.color: selected ? "#000000" : "#DEDEDE" + radius: 12 + Row { + anchors.fill: parent + anchors.margins: 20 + spacing: 8 + QImage { + id: icon + width: 24 + height: 24 + source: radioRoot.selected ? "qrc:/Images/Images/radio-selected-dark.svg" : "qrc:/Images/Images/radio-dark.svg" + anchors.verticalCenter: parent.verticalCenter + MouseArea { + id: mouse + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { buttonClicked() } + } + } + QText { + id: text + text: label + font.family: fontFamily + font.pixelSize: fontPixelSize + font.weight: fontWeight + color: "#031F2B" + anchors.verticalCenter: parent.verticalCenter + width: paintedWidth + } + QBadge { + text: textBadge + color: "#EAEAEA" + visible: textBadge !== "" + } + } +} + + diff --git a/Qml/Components/customizes/Buttons/QRadioButtonTypeF.qml b/Qml/Components/customizes/Buttons/QRadioButtonTypeF.qml new file mode 100644 index 00000000..9a0c2c93 --- /dev/null +++ b/Qml/Components/customizes/Buttons/QRadioButtonTypeF.qml @@ -0,0 +1,73 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import "../../origins" +import "../../customizes/Texts" + +Rectangle { + id: radioRoot + property bool selected: false + property string labelTop: "" + property string labelBottom: "" + property int labelMaxWidth: 467 + signal buttonClicked() + border.width: 2 + border.color: selected ? "#000000" : "#DEDEDE" + radius: 12 + + Row { + anchors.fill: parent + anchors.margins: 18 + spacing: 12 + QImage { + id: icon + width: 24 + height: 24 + source: selected ? "qrc:/Images/Images/radio-selected-dark.svg" : "qrc:/Images/Images/radio-dark.svg" + anchors.verticalCenter: _top.verticalCenter + MouseArea { + id: mouse + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { buttonClicked() } + } + } + Column { + id: info + spacing: 4 + QLato { + id: _top + text: labelTop + font.weight: Font.DemiBold + width: Math.min(labelMaxWidth, implicitWidth) + wrapMode: Text.WordWrap + } + QLato { + text: labelBottom + width: Math.min(labelMaxWidth, implicitWidth) + visible: labelBottom != "" + wrapMode: Text.WordWrap + lineHeight: 28 + lineHeightMode: Text.FixedHeight + } + } + } +} diff --git a/Qml/Components/customizes/Chats/QConversationInfo.qml b/Qml/Components/customizes/Chats/QConversationInfo.qml index 51e98a53..403367f2 100644 --- a/Qml/Components/customizes/Chats/QConversationInfo.qml +++ b/Qml/Components/customizes/Chats/QConversationInfo.qml @@ -361,13 +361,13 @@ Rectangle { height: 80 anchors.horizontalCenter: parent.horizontalCenter readonly property QtObject txObject: model.room_tx_transaction - property int tx_status: txObject ? txObject.status : -1 - property string tx_id: txObject ? txObject.txid : "" - property string to_addr: txObject ? txObject.destinationList.reciever : "" - property string tx_amount: txObject ? txObject.total + RoomWalletData.unitValue : "" - property int tx_m: txObject ? txObject.m : 0 - property int tx_signeds:txObject ? txObject.numberSigned : 0 - property int tx_pending_signatures: Math.max(0, iteminit.tx_m - iteminit.tx_signeds) + property int tx_status : txObject ? txObject.status : -1 + property string tx_id : txObject ? txObject.txid : "" + property string to_addr : txObject ? txObject.destinationList.reciever : "" + property string tx_amount : txObject ? txObject.total + RoomWalletData.unitValue : "" + property int tx_m : txObject ? txObject.m : 0 + property int tx_signeds : txObject ? txObject.numberSigned : 0 + property int tx_pending_signatures: Math.max(0, iteminit.tx_m - iteminit.tx_signeds) Rectangle { anchors.fill: parent diff --git a/Qml/Components/customizes/QAddAnExistingKey.qml b/Qml/Components/customizes/QAddAnExistingKey.qml new file mode 100644 index 00000000..a1a58f9a --- /dev/null +++ b/Qml/Components/customizes/QAddAnExistingKey.qml @@ -0,0 +1,139 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +Item { + property string keyType: "" + property string fingerPrint: "" + property string notice: "" + Column { + spacing: 24 + QLato { + text: notice + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Rectangle { + width: 539 + height: 464 + border.width: 1 + border.color: "#EAEAEA" + radius: 8 + Column + { + anchors.fill: parent + Repeater { + model: AppModel.masterSignerList + Item { + width: 539 - 12 + visible: keyType === model.master_signer_deviceType + height: visible ? 92 : 0 + anchors{ + left: parent.left + leftMargin: 12 + } + Row{ + anchors.fill: parent + spacing: 8 + Rectangle { + width: 48 + height: 48 + radius: width + color: "#F5F5F5" + anchors.verticalCenter: parent.verticalCenter + QImage { + width: 24 + height: 24 + anchors.centerIn: parent + source: GlobalData.iconTypes(keyType, model.master_signer_type) + sourceSize.width: 100 + sourceSize.height: 100 + } + } + Item{ + width: 146 + height: 60 + anchors.verticalCenter: parent.verticalCenter + Column{ + spacing: 4 + QText { + width: 146 + height: 20 + text: model.master_signer_name + color: "#031F2B" + font.weight: Font.Normal + font.family: "Lato" + font.pixelSize: 16 + } + QBadge { + text: STR.STR_QML_898 + color: "#EAEAEA" + } + QText { + width: 146 + height: 20 + text: "XFP: " + model.master_signer_fingerPrint + color: "#595959" + font.weight: Font.Normal + font.capitalization: Font.AllUppercase + font.family: "Lato" + font.pixelSize: 12 + } + } + } + } + QImage { + width: 24 + height: 24 + source: fingerPrint === model.master_signer_fingerPrint ? "qrc:/Images/Images/radio-selected-dark.svg" : "qrc:/Images/Images/radio-dark.svg" + scale: primaryKeyMouse.containsMouse ? 1.1 : 1.0 + anchors{ + right: parent.right + rightMargin: 12 + verticalCenter: parent.verticalCenter + } + } + MouseArea { + id: primaryKeyMouse + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + onClicked: { + fingerPrint = model.master_signer_fingerPrint + } + } + } + } + } + } + } +} diff --git a/Qml/Components/customizes/QAddAssistedWalletSigner.qml b/Qml/Components/customizes/QAddAssistedWalletSigner.qml index 99e316c1..7bb8161d 100644 --- a/Qml/Components/customizes/QAddAssistedWalletSigner.qml +++ b/Qml/Components/customizes/QAddAssistedWalletSigner.qml @@ -15,38 +15,50 @@ Rectangle { Item { anchors.fill: parent anchors.margins: 16 - Column { - spacing: 16 - QLato { - width: 257 - height: 28 - text: addTitle - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter + QLato { + anchors { + top: parent.top + topMargin: 0 } - Row { - spacing: 16 - QTextButton { - width: 120 - height: 48 - label.text: STR.STR_QML_245 - label.font.pixelSize: 16 - type: eTypeM - onButtonClicked: { - cancel() - } + width: 257 + height: paintedHeight + text: addTitle + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + lineHeight: 28 + lineHeightMode: Text.FixedHeight + } + Item { + anchors { + bottom: parent.bottom + bottomMargin: 0 + } + width: 257 + height: 48 + QTextButton { + width: label.paintedWidth + 12*2 + height: 48 + anchors.left: parent.left + label.text: STR.STR_QML_245 + label.font.pixelSize: 16 + type: eTypeM + onButtonClicked: { + cancel() } - QTextButton { - width: 120 - height: 48 - label.text: addText - label.font.pixelSize: 16 - type: eTypeN - onButtonClicked: { - add() - } + } + QTextButton { + width: label.paintedWidth + 12*2 + height: 48 + anchors.right: parent.right + label.text: addText + label.font.pixelSize: 16 + type: eTypeN + onButtonClicked: { + add() } } } + } } diff --git a/Qml/Components/customizes/QCreateTransaction.qml b/Qml/Components/customizes/QCreateTransaction.qml index 73b06334..7bc27e15 100644 --- a/Qml/Components/customizes/QCreateTransaction.qml +++ b/Qml/Components/customizes/QCreateTransaction.qml @@ -411,7 +411,7 @@ Item { anchors.verticalCenter: parent.verticalCenter } QText { - text: STR.STR_QML_220.arg(transactionInfo.m) + text: STR.str_QML_220(transactionInfo.m) font.pixelSize: 12 font.family: "Lato" color: indicatorStatus.color @@ -587,7 +587,7 @@ Item { font.pixelSize: 14 color: "#031F2B" horizontalAlignment: Text.AlignRight - text: Math.max(0, (AppModel.chainTip - utxo_height)+1) + text: utxo_confirmed//Math.max(0, (AppModel.chainTip - utxo_height)+1) } } Item { @@ -614,14 +614,27 @@ Item { Item { width: parent.width height: 36 - QText { - text: STR.STR_QML_225 - color: "#031F2B" - font.weight: Font.Bold - font.pixelSize: 16 - font.family: "Lato" + Column { + spacing: 4 anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter + QText { + text: STR.STR_QML_225 + color: "#031F2B" + font.weight: Font.Bold + font.pixelSize: 16 + font.family: "Lato" + } + QText { + text: STR.STR_QML_895 + width: 250 + wrapMode: Text.WordWrap + color: "#595959" + font.pixelSize: 12 + font.family: "Lato" + verticalAlignment: Text.AlignVCenter + visible: manualfeesetting.switchOn && transactionInfo.isCpfp + } } QSwitchTypeB { id: manualfeesetting @@ -757,14 +770,12 @@ Item { } } Item {width: parent.width; height: 12; visible: !feeinput.validInput} - QText { + QLato { id: cpfptext color: "#595959" height: 28 - visible: false //FIXME - text: "Child fee rate: ? sat/vB" - font.pixelSize: 16 - font.family: "Lato" + text: STR.STR_QML_836.arg(transactionInfo.packageFeeRate) + visible: transactionInfo.isCpfp } } Column { diff --git a/Qml/Components/customizes/QOnScreenContent.qml b/Qml/Components/customizes/QOnScreenContent.qml index 9804f92e..ac73289f 100644 --- a/Qml/Components/customizes/QOnScreenContent.qml +++ b/Qml/Components/customizes/QOnScreenContent.qml @@ -36,6 +36,7 @@ Item { property alias bottomLeft: botLeft.sourceComponent property alias bottomRight: botRight.sourceComponent readonly property Item contentItem: contentInfo.item + readonly property Item rightItem: botRight.item property bool enableHeader: true property int offset: 36 signal closeClicked() diff --git a/Qml/Components/customizes/QPopupInfoVertical.qml b/Qml/Components/customizes/QPopupInfoVertical.qml index 3a6d98c3..1e8a7175 100644 --- a/Qml/Components/customizes/QPopupInfoVertical.qml +++ b/Qml/Components/customizes/QPopupInfoVertical.qml @@ -92,18 +92,18 @@ Popup { QTextButton { anchors.horizontalCenter: parent.horizontalCenter width: Math.max(lwidths[0],label.paintedWidth + 20*2) - height: 36 + height: 48 label.text: labels[0] - label.font.pixelSize: 12 + label.font.pixelSize: 16 type: eTypeE onButtonClicked: {confirmYes()} } QTextButton { anchors.horizontalCenter: parent.horizontalCenter width: Math.max(lwidths[1],label.paintedWidth + 10*2) - height: 36 + height: 48 label.text: labels[1] - label.font.pixelSize: 12 + label.font.pixelSize: 16 type: eTypeB onButtonClicked: {confirmNo()} } diff --git a/Qml/Components/customizes/QScreen.qml b/Qml/Components/customizes/QScreen.qml index 18b25b27..fd4c1470 100644 --- a/Qml/Components/customizes/QScreen.qml +++ b/Qml/Components/customizes/QScreen.qml @@ -17,6 +17,8 @@ * along with this program. If not, see . * * * **************************************************************************/ +import NUNCHUCKTYPE 1.0 +import HMIEVENTS 1.0 import QtQuick 2.4 import "../origins" @@ -43,4 +45,19 @@ Item { anchors.fill: parent onClicked: {root.focus = true} } + function closeTo(tab) { + switch(tab) { + case NUNCHUCKTYPE.WALLET_TAB: + QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST) + break; + case NUNCHUCKTYPE.SERVICE_TAB: + QMLHandle.sendEvent(EVT.EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST) + break; + case NUNCHUCKTYPE.CHAT_TAB: + QMLHandle.sendEvent(EVT.EVT_ONLINE_ONS_CLOSE_REQUEST) + break; + case NUNCHUCKTYPE.SETTING_TAB: + break; + } + } } diff --git a/Qml/Components/customizes/QSendTransaction.qml b/Qml/Components/customizes/QSendTransaction.qml index ae64dd47..5a7164aa 100644 --- a/Qml/Components/customizes/QSendTransaction.qml +++ b/Qml/Components/customizes/QSendTransaction.qml @@ -99,7 +99,7 @@ Item { id: lstDestination model: transactionInfo.destinationList width: parent.width - height: count > 10 ? 400 : 40*count + height: count > 10 ? 400 : 60*count delegate: destDelegate clip: true cacheBuffer: 600 @@ -435,7 +435,7 @@ Item { anchors.verticalCenter: parent.verticalCenter } QText { - text: STR.STR_QML_220.arg(Math.max(0, (transactionInfo.m - transactionInfo.numberSigned))) + text: STR.str_QML_220(Math.max(0, (transactionInfo.m - transactionInfo.numberSigned))) font.pixelSize: 12 font.family: "Lato" color: indicatorStatus.color @@ -478,7 +478,7 @@ Item { color: "#595959" font.family: "Lato" font.pixelSize: 12 - text: STR.STR_QML_220.arg(Math.max(0, (transactionInfo.m - transactionInfo.numberSigned))) + text: STR.str_QML_220(Math.max(0, (transactionInfo.m - transactionInfo.numberSigned))) anchors.verticalCenter: parent.verticalCenter } } diff --git a/Qml/Components/customizes/Texts/QTextAreaBoxTypeA.qml b/Qml/Components/customizes/Texts/QTextAreaBoxTypeA.qml new file mode 100644 index 00000000..1822b5cd --- /dev/null +++ b/Qml/Components/customizes/Texts/QTextAreaBoxTypeA.qml @@ -0,0 +1,146 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtGraphicalEffects 1.0 +import "../../origins" + +Column { + id: textipboxType + property string label: "This is label" + property string optional: "" + property alias errorText: textErrorItem.text + property alias errorTextColor: textErrorItem.color + property alias textInputted: _input.text + property var textweight: Font.Bold + property alias length: _input.length + property bool enableLengthLimit: false + property int boxWidth: 338 + property int boxHeight: 48 + property bool isValid: true + property bool showError: false + signal typingFinished(var currentText) + property alias textBoxFocus: _input.focus + property alias input: _input + spacing: 4 + + signal downKeyRequest() + signal upKeyRequest() + signal enterKeyRequest() + signal pasteKeyRequest() + signal tabKeyRequest() + + Row { + width: parent.width + QText { + id:txt1 + width: paintedWidth + font.family: "Lato" + font.pixelSize: 16 + font.weight: textweight + color: "#031F2B" + text: label + visible: label != "" + anchors.bottom: parent.bottom + } + QText { + id:txt2 + width: paintedWidth + font.family: "Lato" + font.pixelSize: 12 + font.weight: textweight + color: "#595959" + text: optional + visible: optional != "" + anchors.verticalCenter: txt1.verticalCenter + } + QText { + width: textipboxType.width - txt1.width - txt2.width + font.family: "Lato" + font.pixelSize: 12 + color: "#031F2B" + text: textipboxType.length + "/" + textipboxType.maxLength + visible: textipboxType.enableLengthLimit + horizontalAlignment: Text.AlignRight + anchors.bottom: parent.bottom + } + } + Item { + width: myRectangle.width+2 + height: myRectangle.height+2 + Item { + id: _background + width: myRectangle.width+2 + height: myRectangle.height+2 + Rectangle { + id: myRectangle + anchors.centerIn: parent + width: boxWidth + height: boxHeight + radius: 8 + color: textipboxType.enabled ? (isValid ? "#FFFFFF" : "#FFD7D9") : "#EAEAEA" + border.color: isValid ? "#DEDEDE" : "#CF4018" + } + } + QTextArea { + id: _input + anchors.fill: parent + background: _background + color: "#031F2B" + font.pixelSize: 16 + clip: true + onTypingFinished: textipboxType.typingFinished(currentText) + Keys.onDownPressed: { downKeyRequest() } + Keys.onUpPressed: { upKeyRequest() } + Keys.onPressed: function (keyEvent) { + if (keyEvent.matches(StandardKey.Paste)) { pasteKeyRequest() } + if (keyEvent.key === Qt.Key_Tab) { keyEvent.accepted = false; tabKeyRequest() } + } + } + } + Item{ + width: myRectangle.width+2 + height: 28 + QImage { + id: alert + width: 20 + height: 20 + source: "qrc:/Images/Images/error_outline_24px.png" + anchors { + left: parent.left + leftMargin: 0 + verticalCenter: parent.verticalCenter + } + visible: !isValid && showError + } + QText { + id: textErrorItem + width: myRectangle.width+2 + font.family: "Lato" + font.pixelSize: 16 + color: "#CF4018" + anchors { + left: alert.right + leftMargin: 6 + verticalCenter: parent.verticalCenter + } + } + visible: !isValid && showError + } +} diff --git a/Qml/Components/customizes/Texts/QTextAreaBoxTypeB.qml b/Qml/Components/customizes/Texts/QTextAreaBoxTypeB.qml new file mode 100644 index 00000000..80b376e4 --- /dev/null +++ b/Qml/Components/customizes/Texts/QTextAreaBoxTypeB.qml @@ -0,0 +1,61 @@ +import QtQuick 2.0 +import "../../origins" +import "../../../../localization/STR_QML.js" as STR +Item { + property string icon: "" + property alias label: _label + property alias edit: _edit + property alias input: _input + property string textColor: "#FFFFFF" + signal textEditClicked() + height: 84 + Column { + anchors.fill: parent + spacing: 12 + Item { + width: parent.width + height: 24 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: sourceSize.width + height: sourceSize.height + anchors.verticalCenter: parent.verticalCenter + source: icon + visible: icon !== "" + } + QLato { + id: _label + font.weight: Font.Bold + font.pixelSize: 16 + color: textColor + text: STR.STR_QML_848 + anchors.verticalCenter: parent.verticalCenter + } + } + Row { + anchors.fill: parent + layoutDirection: Qt.RightToLeft + spacing: 12 + QTextLink { + id: _edit + width: 29 + height: 20 + text: STR.STR_QML_849 + color: textColor + anchors.verticalCenter: parent.verticalCenter + onTextClicked: { + textEditClicked() + } + } + } + } + QTextArea { + id: _input + width: parent.width + height: 48 + leftPadding: 12 + } + } +} diff --git a/Qml/Components/customizes/Texts/QTextAreaBoxTypeC.qml b/Qml/Components/customizes/Texts/QTextAreaBoxTypeC.qml new file mode 100644 index 00000000..464faa0c --- /dev/null +++ b/Qml/Components/customizes/Texts/QTextAreaBoxTypeC.qml @@ -0,0 +1,118 @@ +import QtQuick 2.0 +import "../../origins" +import "../../../../localization/STR_QML.js" as STR +Item { + property string icon: "" + property alias label: _label + property alias edit: _edit + property string textColor: "#FFFFFF" + property string leftText1: "" + property string rightText1: "" + property string leftText2: "" + property string rightText2: "" + property var rightList: rightText1.split(",") + + signal textEditClicked() + height: 64 + Math.max(1, rightList.length) * 20 + Column { + anchors.fill: parent + spacing: 12 + Item { + width: parent.width + height: 24 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: sourceSize.width + height: sourceSize.height + anchors.verticalCenter: parent.verticalCenter + source: icon + visible: icon !== "" + } + QLato { + id: _label + font.weight: Font.Bold + font.pixelSize: 16 + color: textColor + text: STR.STR_QML_852 + anchors.verticalCenter: parent.verticalCenter + } + } + Row { + anchors.fill: parent + layoutDirection: Qt.RightToLeft + spacing: 12 + QTextLink { + id: _edit + width: 29 + height: 20 + text: STR.STR_QML_849 + color: textColor + anchors.verticalCenter: parent.verticalCenter + onTextClicked: { + textEditClicked() + } + } + } + } + Rectangle { + width: 651 + height: 85 + Math.max(1, rightList.length) * 20 + radius: 12 + color: "#F5F5F5" + Column { + anchors.centerIn: parent + spacing: 16 + Item { + width: 619 + height: Math.max(1, rightList.length) * 20 + QLato { + width: 302 + height: 20 + anchors.left: parent.left + text: leftText1 + } + Column { + anchors.right: parent.right + spacing: 1 + Repeater { + model: rightList + QLato { + width: 302 + height: 20 + font.weight: Font.Bold + text: rightList[index] + color: rightList[index] === "None" ? "#CF4018" : "#031F2B" + horizontalAlignment: Text.AlignRight + } + } + } + } + Rectangle { + width: 311 + height: 1 + color: "#EAEAEA" + } + Item { + width: 619 + height: 20 + QLato { + width: 302 + height: 20 + anchors.left: parent.left + text: STR.STR_QML_868 + } + QLato { + width: 302 + height: 20 + font.weight: Font.Bold + anchors.right: parent.right + text: rightText2 + horizontalAlignment: Text.AlignRight + } + } + } + } + } +} diff --git a/Qml/Components/customizes/Texts/QTextInputBoxTypeB.qml b/Qml/Components/customizes/Texts/QTextInputBoxTypeB.qml index e5506abd..a4079385 100644 --- a/Qml/Components/customizes/Texts/QTextInputBoxTypeB.qml +++ b/Qml/Components/customizes/Texts/QTextInputBoxTypeB.qml @@ -27,20 +27,21 @@ Column { property string optional: "" property alias errorText: textErrorItem.text property alias errorTextColor: textErrorItem.color - property alias textInputted: input.text - property alias validator: input.validator - property alias acceptableInput : input.acceptableInput + property alias textInputted: _input.text + property alias validator: _input.validator + property alias acceptableInput : _input.acceptableInput property var textweight: Font.Bold - property alias echoMode: input.echoMode - property alias maxLength: input.maximumLength - property alias length: input.length + property alias echoMode: _input.echoMode + property alias maxLength: _input.maximumLength + property alias length: _input.length property bool enableLengthLimit: false property int boxWidth: 338 property int boxHeight: 48 property bool isValid: true property bool showError: false signal typingFinished(var currentText) - property alias textBoxFocus: input.focus + property alias textBoxFocus: _input.focus + property alias input: _input property bool isPassword: false spacing: 4 @@ -103,7 +104,7 @@ Column { } } QTextField { - id: input + id: _input anchors.fill: parent background: _background color: "#031F2B" @@ -129,7 +130,7 @@ Column { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: 12 - visible: (input.text !== "") && isPassword + visible: (_input.text !== "") && isPassword MouseArea { anchors.fill: parent onClicked: showpass.visiblity =! showpass.visiblity diff --git a/Qml/Components/customizes/Texts/QTextInputBoxTypeE.qml b/Qml/Components/customizes/Texts/QTextInputBoxTypeE.qml new file mode 100644 index 00000000..05f0d9e2 --- /dev/null +++ b/Qml/Components/customizes/Texts/QTextInputBoxTypeE.qml @@ -0,0 +1,62 @@ +import QtQuick 2.0 +import "../../origins" +import "../../../../localization/STR_QML.js" as STR +Item { + property string icon: "" + property alias label: _label + property alias edit: _edit + property alias input: _input + property string textColor: "#FFFFFF" + signal textEditClicked() + height: 84 + Column { + anchors.fill: parent + spacing: 12 + Item { + width: parent.width + height: 24 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: sourceSize.width + height: sourceSize.height + anchors.verticalCenter: parent.verticalCenter + source: icon + visible: icon !== "" + } + QLato { + id: _label + font.weight: Font.Bold + font.pixelSize: 16 + color: textColor + text: STR.STR_QML_848 + anchors.verticalCenter: parent.verticalCenter + } + } + Row { + anchors.fill: parent + layoutDirection: Qt.RightToLeft + spacing: 12 + QTextLink { + id: _edit + width: 29 + height: 20 + text: STR.STR_QML_849 + color: textColor + anchors.verticalCenter: parent.verticalCenter + onTextClicked: { + textEditClicked() + } + } + } + } + QTextField { + id: _input + width: parent.width + height: 48 + leftPadding: 12 + wrapMode: Text.WordWrap + } + } +} diff --git a/Qml/Components/customizes/Texts/QTextLink.qml b/Qml/Components/customizes/Texts/QTextLink.qml new file mode 100644 index 00000000..81b153be --- /dev/null +++ b/Qml/Components/customizes/Texts/QTextLink.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 +import "../../origins" + +QLato { + font.weight: Font.Bold + font.pixelSize: 16 + signal textClicked() + scale: btnMouse.containsMouse ? 1.1 : 1 + font.underline: true + MouseArea { + id: btnMouse + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + textClicked() + } + } +} diff --git a/Qml/Components/customizes/services/QInheritanceDetails.qml b/Qml/Components/customizes/services/QInheritanceDetails.qml new file mode 100644 index 00000000..d7a45992 --- /dev/null +++ b/Qml/Components/customizes/services/QInheritanceDetails.qml @@ -0,0 +1,136 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../origins" +import "../../customizes" +import "../../customizes/Texts" +import "../../../../localization/STR_QML.js" as STR + +Item { + property string title: STR.STR_QML_887 + property string magicPhrase: ServiceSetting.qInheritanceMagic + property string warning: STR.STR_QML_890 + width: 346 + height: 512 + Column { + width: parent.width + spacing: 16 + QLato { + width: parent.width + text: title + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Rectangle { + width: 346 + height: 88 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: 24 + height: 24 + source: "qrc:/Images/Images/1.Active.svg" + } + Column { + width: 310 + height: 88 + spacing: 12 + QLato { + width: 310 + text: STR.STR_QML_888 + horizontalAlignment: Text.AlignLeft + } + Rectangle { + width: 310 + height: 48 + color: "#F5F5F5" + radius: 12 + QLato { + width: 310 + text: magicPhrase + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + } + } + } + } + } + Rectangle { + width: 346 + height: 112 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: 24 + height: 24 + source: "qrc:/Images/Images/2.Active.svg" + } + QLato { + width: 310 + height: 112 + text: STR.STR_QML_889 + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + anchors.verticalCenter: parent.verticalCenter + } + } + } + Rectangle { + width: 346 + height: 164 + color: "#FDEBD2" + radius: 8 + Row { + anchors.fill: parent + anchors.margins: 12 + spacing: 12 + QImage { + width: 24 + height: 24 + source: "qrc:/Images/Images/warning-dark.svg" + anchors.verticalCenter: parent.verticalCenter + } + QLato { + width: 310 + height: 164 + text: warning + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + anchors.verticalCenter: parent.verticalCenter + } + } + } + } +} diff --git a/Qml/Components/customizes/services/QSelectAnAssistedWallet.qml b/Qml/Components/customizes/services/QSelectAnAssistedWallet.qml new file mode 100644 index 00000000..51c48749 --- /dev/null +++ b/Qml/Components/customizes/services/QSelectAnAssistedWallet.qml @@ -0,0 +1,55 @@ +import QtQuick 2.0 +import QtGraphicalEffects 1.0 +import DataPool 1.0 +import HMIEVENTS 1.0 +import "../../customizes/Texts" +import "../../customizes/Buttons" +import "../../customizes" +import "../../../../localization/STR_QML.js" as STR + +Item { + id: _id + function contains(id) { + for (var i = 0; i < ServiceSetting.qAssistedSetuped.length; i++) { + if (ServiceSetting.qAssistedSetuped[i] === id) + { + return true + } + } + return false + } + Column { + anchors.fill: parent + anchors.margins: 24 + spacing: 24 + QLato { + text: STR.STR_QML_837 + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + font.pixelSize: 28 + font.weight: Font.Bold + } + + + Repeater { + model: AppModel.walletList + QLinearGradient { + width: 651 + height: dele.visible ? 92 : 0 + QAssistedWalletDelegate { + id: dele + anchors.fill: parent + walletName: model.wallet_name + walletBalance: model.wallet_Balance + walletCurrency: model.wallet_Balance_Currency + walletM: model.wallet_M + walletN: model.wallet_N + visible: model.wallet_isAssistedWallet && _id.contains(model.wallet_id) + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_SERVICE_SELECT_WALLET_REQUEST, model.wallet_id) + } + } + } + } + } +} diff --git a/Qml/Components/customizes/services/QViewInheritancePlaning.qml b/Qml/Components/customizes/services/QViewInheritancePlaning.qml new file mode 100644 index 00000000..59a80c50 --- /dev/null +++ b/Qml/Components/customizes/services/QViewInheritancePlaning.qml @@ -0,0 +1,348 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.12 +import QtQuick.Controls 2.1 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 +import QtQuick.Controls.Styles 1.4 +import Qt.labs.platform 1.1 +import HMIEVENTS 1.0 +import NUNCHUCKTYPE 1.0 +import QRCodeItem 1.0 +import DataPool 1.0 +import DRACO_CODE 1.0 +import EWARNING 1.0 +import "../../origins" +import "../../customizes" +import "../../customizes/Chats" +import "../../customizes/Texts" +import "../../customizes/Buttons" +import "../../customizes/services" +import "../../../../localization/STR_QML.js" as STR + +Item { + property string dateString: { + if (ServiceSetting.qInheritanceActivationDate === "") { + ServiceSetting.qInheritanceActivationDate = Qt.formatDateTime(new Date(), "MM/dd/yyyy") + } + return ServiceSetting.qInheritanceActivationDate + } + Connections { + target: UserWallet + } + + QContextMenu { + id: optionMenu + menuWidth: 300 + icons: [ + "qrc:/Images/Images/close-24px.svg" + ] + labels: [ + STR.STR_QML_844 + ] + colors: [ + "#CF4018" + ] + onItemClicked: { + switch(index){ + case 0: + ServiceSetting.qInheritanceWalletName = "" + break; + default: + break; + } + } + } + Rectangle { + id: _img_bg + width: parent.width + height: parent.height * 0.5 + color: "#D0E2FF" + QIconButton{ + id:_more + anchors{ + top: parent.top + topMargin: 24 + right: parent.right + rightMargin: 24 + } + width: 48 + height: 48 + bgColor: parent.color + icon: "qrc:/Images/Images/more-horizontal-dark.svg" + onClicked: { + optionMenu.popup() + } + } + } + Column { + anchors.fill: parent + anchors.margins: 24 + spacing: 28 + Row { + height: 28 + spacing: 16 + QIconButton { + iconSize: 24 + icon: "qrc:/Images/Images/left-arrow-dark.svg" + visible: ServiceSetting.qAssistedSetuped.length > 1 + anchors.verticalCenter: parent.verticalCenter + onButtonClicked: { + ServiceSetting.qInheritanceWalletName = "" + } + bgColor: "transparent" + } + QText { + font.family: "Lato" + font.pixelSize: 28 + color: "#031F2B" + font.weight: Font.Bold + text: STR.STR_QML_843 + } + } + Rectangle { + width: parent.width + height: _img_bg.height * 0.75 + radius: 24 + color: "#2F466C" + Column { + anchors.fill: parent + anchors.margins: 24 + spacing: 24 + Item { + width: parent.width + height: 60 + Row { + anchors.fill: parent + spacing: 12 + QImage { + width: 60 + height: 60 + anchors.verticalCenter: parent.verticalCenter + source: "qrc:/Images/Images/wallet-brand-icon.svg" + } + Column { + width: 304 + height: 44 + anchors.verticalCenter: parent.verticalCenter + spacing: 4 + QLato { + font.weight: Font.Bold + font.pixelSize: 16 + color: "#FFFFFF" + text: STR.STR_QML_845 + } + QLato { + color: "#FFFFFF" + text: ServiceSetting.qInheritanceWalletName + } + } + } + Row { + anchors.fill: parent + layoutDirection: Qt.RightToLeft + spacing: 12 + QTextButton { + width: 162 + height: 48 + label.text: STR.STR_QML_847 + label.font.pixelSize: 16 + anchors.verticalCenter: parent.verticalCenter + type: eTypeC + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_SHARE_YOUR_SECRET_REQUEST) + } + } + QTextLink { + width: 220 + height: 48 + font.weight: Font.Bold + font.pixelSize: 16 + color: "#FFFFFF" + text: STR.STR_QML_846 + anchors.verticalCenter: parent.verticalCenter + font.underline: false + onTextClicked: { + Qt.openUrlExternally("https://nunchuk.io/howtoclaim") + } + } + } + } + QTextInputBoxTypeE { + width: parent.width + icon: "qrc:/Images/Images/calendar-dark.png" + input.text: dateString + input.verticalAlignment: Text.AlignVCenter + onTextEditClicked: { + QMLHandle.sendEvent(EVT.EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST, ServiceType.IE_ACTIVATION_DATE) + } + } + Item { + width: parent.width + height: 104 + Row { + spacing: 24 + QTextInputBoxTypeE { + width: 387 + height: 104 + icon: "qrc:/Images/Images/star-dark.png" + edit.visible: false + label.text: STR.STR_QML_749 + input.text: ServiceSetting.qInheritanceMagic + input.verticalAlignment: Text.AlignTop + input.height: 68 + } + QTextInputBoxTypeE { + width: 387 + height: 104 + icon: "qrc:/Images/Images/change-password-dark.svg" + edit.visible: false + label.text: STR.STR_QML_727 + input.text: STR.STR_QML_917 + input.verticalAlignment: Text.AlignTop + input.height: 68 + } + } + } + } + } + Item { + width: parent.width - 24 + height: parent.height * 0.58 - 24 + Flickable { + anchors.top: parent.top + anchors.topMargin: 12 + clip: true + width: 661 + height: 372 + contentWidth: width + contentHeight: _colum.childrenRect.height + 100 + ScrollBar.vertical: ScrollBar { active: true } + Column { + id: _colum + anchors.top: parent.top + anchors.topMargin: 24 + width: parent.width + spacing: 24 + QTextAreaBoxTypeB { + width: 651 + height: 128 + label.text: STR.STR_QML_850 + input.text: ServiceSetting.qInheritanceNote + input.backgroundColor: "#F5F5F5" + input.verticalAlignment: Text.AlignTop + input.height: 96 + input.readOnly: true + textColor: "#031F2B" + onTextEditClicked: { + QMLHandle.sendEvent(EVT.EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST, ServiceType.IE_LEAVE_MESSAGE) + } + } + Rectangle { + height: 1 + width: 651 + color: "#EAEAEA" + } + QTextInputBoxTypeE { + width: 651 + height: 84 + label.text: STR.STR_QML_851 + input.text: ServiceSetting.qInheritancePeriodId === "" ? STR.STR_QML_921 : ServiceSetting.qInheritancePeriod + input.backgroundColor: "#F5F5F5" + input.height: 52 + input.readOnly: true + textColor: "#031F2B" + onTextEditClicked: { + if (UserWallet.inheritancePlanCreatePeriods()) { + QMLHandle.sendEvent(EVT.EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST, ServiceType.IE_BUFFER_PERIOD) + } + } + } + Rectangle { + height: 1 + width: 651 + color: "#EAEAEA" + } + QTextAreaBoxTypeC { + width: 651 +// height: 137 + textColor: "#031F2B" + leftText1: STR.STR_QML_867 + rightText1: ServiceSetting.qInheritanceEmail === "" ? "None" : ServiceSetting.qInheritanceEmail + leftText2: STR.STR_QML_868 + rightText2: ServiceSetting.qInheritanceIsNotify ? STR.STR_QML_433 : STR.STR_QML_432 + onTextEditClicked: { + QMLHandle.sendEvent(EVT.EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST, ServiceType.IE_NOTIFICATION) + } + } + } + } + } + } + Rectangle { + id: normalRect + height: 80 + anchors{ + left: parent.left + right: parent.right + bottom: parent.bottom + } + layer.enabled: true + layer.effect: DropShadow { + radius: 4 + samples: radius * 2 + source: normalRect + color: Qt.rgba(0, 0, 0, 0.5) + } + Row { + anchors{ + right: parent.right + rightMargin: 24 + bottom: parent.bottom + bottomMargin: 16 + } + spacing: 12 + layoutDirection: Qt.RightToLeft + QTextButton { + id: _save + width: 214 + height: 48 + label.text: STR.STR_QML_804 + label.font.pixelSize: 16 + type: eTypeE + enabled: ServiceSetting.qViewInheritanceIsEdit + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_INHERITANCE_PLAN_FINALIZE_REQUEST, 1) + } + } + QTextButton { + width: 148 + height: 48 + label.text: STR.STR_QML_805 + label.font.pixelSize: 16 + type: eTypeF + enabled: ServiceSetting.qViewInheritanceIsEdit + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_INHERITANCE_PLAN_FINALIZE_REQUEST, 2) + } + } + } + } +} diff --git a/Qml/Components/origins/QTextArea.qml b/Qml/Components/origins/QTextArea.qml new file mode 100644 index 00000000..111ae282 --- /dev/null +++ b/Qml/Components/origins/QTextArea.qml @@ -0,0 +1,54 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.12 +import QtQuick.Controls 2.1 + +TextArea { + id: textEdit + property var borderColor: "#DEDEDE" + property var backgroundColor: "#FFFFFF" + color: "#031F2B" + font.family: "Lato" + font.pixelSize: 16 + font.weight: Font.Medium + background: Rectangle { + anchors.fill: parent + radius: 8 + border.color: borderColor + color: backgroundColor + } + activeFocusOnTab : true + activeFocusOnPress: true + verticalAlignment: Text.AlignVCenter + cursorVisible: !readOnly && textEdit.activeFocus + selectByMouse: true + renderType: Text.QtRendering + wrapMode: Text.WrapAnywhere + signal typingFinished(var currentText) + onTextChanged: if(initialized === true) inputIdentify.restart() + + property bool initialized: false + Timer { + id: inputIdentify + interval: 250 + onTriggered: { if(textEdit.text !== "") typingFinished(textEdit.text) } + } + Component.onCompleted: initialized = true +} diff --git a/Qml/Components/origins/QTextField.qml b/Qml/Components/origins/QTextField.qml index 0fc86b5a..2825b4f8 100644 --- a/Qml/Components/origins/QTextField.qml +++ b/Qml/Components/origins/QTextField.qml @@ -22,12 +22,17 @@ import QtQuick.Controls 2.1 TextField { id: textEdit + property var borderColor: "#DEDEDE" + property var backgroundColor: "#FFFFFF" color: "#031F2B" + font.family: "Lato" + font.pixelSize: 16 + font.weight: Font.Medium background: Rectangle { anchors.fill: parent radius: 8 - border.color: "#DEDEDE" - color: "#FFFFFF" + border.color: borderColor + color: backgroundColor } activeFocusOnTab : true activeFocusOnPress: true @@ -35,6 +40,7 @@ TextField { cursorVisible: !readOnly && textEdit.activeFocus selectByMouse: true renderType: Text.QtRendering + wrapMode: Text.WrapAnywhere signal typingFinished(var currentText) onTextChanged: if(initialized === true) inputIdentify.restart() diff --git a/Qml/Global/QGlobal.qml b/Qml/Global/QGlobal.qml index 6f2680ac..91f38012 100644 --- a/Qml/Global/QGlobal.qml +++ b/Qml/Global/QGlobal.qml @@ -123,7 +123,7 @@ QtObject { case "trezor": img = "qrc:/Images/Images/Device_Icons/Trezor.svg"; break case "coldcard": img = "qrc:/Images/Images/Device_Icons/ColdCard.svg"; break case "bitbox02": img = "qrc:/Images/Images/Device_Icons/bitbox.png"; break - case "ledger": img = "qrc:/Images/Images/Device_Icons/ledger.png"; break + case "ledger": img = "qrc:/Images/Images/Device_Icons/Ledger.svg"; break case "software": img = "qrc:/Images/Images/Device_Icons/software_drak.svg"; break case "nfc" : img = "qrc:/Images/Images/Device_Icons/nfc-key-dark.svg"; break default: switch(intType){ @@ -146,6 +146,7 @@ QtObject { case NUNCHUCKTYPE.NFC: n = "NFC"; break case NUNCHUCKTYPE.COLDCARD_NFC: n = "COLDCARD-NFC"; break case NUNCHUCKTYPE.SERVER: n = "PLATFORM"; break + case NUNCHUCKTYPE.UNKNOWN: n = "UNKNOWN"; break default: n = "" } return n @@ -161,8 +162,22 @@ QtObject { case NUNCHUCKTYPE.NFC: name = STR.STR_QML_678; break case NUNCHUCKTYPE.COLDCARD_NFC: name = "COLDCARD-NFC"; break case NUNCHUCKTYPE.SERVER: name = "Platform"; break + case NUNCHUCKTYPE.UNKNOWN: name = "UNKNOWN"; break default: name = "" } return name } + + property int countRandom : 0 + property var generatedValues: [0, 1, 2] + function swapPositions() { + let temp = generatedValues[countRandom % 3]; + generatedValues[countRandom % 3] = generatedValues[(countRandom + 1) % 3]; + generatedValues[(countRandom + 1) % 3] = temp; + countRandom++; + if (countRandom > 5) { + countRandom = 0; + } + return generatedValues; + } } diff --git a/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER.qml b/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER.qml index 8def1b7c..6a5d2121 100644 --- a/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER.qml +++ b/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER.qml @@ -326,8 +326,10 @@ QScreen { onTagFound: { var jsonstring = ""; jsonstring = AppModel.parseQRSigners(qrscaner.tags) - signerinforInput.jsonProcess(jsonstring) - qrscaner.close() + if(jsonstring !== ""){ + signerinforInput.jsonProcess(jsonstring) + qrscaner.close() + } } } function jsonProcess(jsonstring){ diff --git a/Qml/Screens/LocalMode/SCR_ADD_NEW_SOFTWARE_SIGNER.qml b/Qml/Screens/LocalMode/SCR_ADD_NEW_SOFTWARE_SIGNER.qml index d786893b..74fbc8bf 100644 --- a/Qml/Screens/LocalMode/SCR_ADD_NEW_SOFTWARE_SIGNER.qml +++ b/Qml/Screens/LocalMode/SCR_ADD_NEW_SOFTWARE_SIGNER.qml @@ -49,7 +49,7 @@ QScreen { left: parent.left leftMargin: 36 top: parent.top - topMargin: 65 + topMargin: 65 + 24 } verticalAlignment: Text.AlignVCenter color: "#031F2B" @@ -65,7 +65,7 @@ QScreen { height: 500 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - anchors.topMargin: 150 + anchors.topMargin: 150 + 24 columns: 6 spacing: 12 Repeater { diff --git a/Qml/Screens/LocalMode/SCR_ADD_REMOTE_SIGNER_RESULT.qml b/Qml/Screens/LocalMode/SCR_ADD_REMOTE_SIGNER_RESULT.qml index 2a570233..fe238d4f 100644 --- a/Qml/Screens/LocalMode/SCR_ADD_REMOTE_SIGNER_RESULT.qml +++ b/Qml/Screens/LocalMode/SCR_ADD_REMOTE_SIGNER_RESULT.qml @@ -62,42 +62,18 @@ QScreen { } } } - - Row{ - anchors { - left: _content.label.right - leftMargin: 12 - verticalCenter: _content.label.verticalCenter - } - Rectangle{ - width: 89 - height: 24 - radius: 20 - color: "#FDD95C" + extraHeader: Row { + spacing: 8 + QBadge { + text: STR.STR_QML_641 visible: isPrimaryKey - QText { - text: STR.STR_QML_641 - font.family: "Lato" - font.weight: Font.Medium - font.pixelSize: 12 - anchors.centerIn: parent - color: "#031F2B" - } + color: "#FDD95C" + anchors.verticalCenter: parent.verticalCenter } - Rectangle{ - width: signerTypeText.implicitWidth+10 - height: 24 - radius: 20 + QBadge { + text: GlobalData.signerNames(signerType) color: "#EAEAEA" - QText { - id: signerTypeText - text: GlobalData.signerNames(signerType) - font.family: "Lato" - font.weight: Font.Medium - font.pixelSize: 12 - anchors.centerIn: parent - color: "#031F2B" - } + anchors.verticalCenter: parent.verticalCenter } } diff --git a/Qml/Screens/LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml b/Qml/Screens/LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml index 2a0fea8e..5d009017 100644 --- a/Qml/Screens/LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml +++ b/Qml/Screens/LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml @@ -204,9 +204,9 @@ QScreen { model: AppModel.newWalletInfo.walletSingleSignerAssigned delegate: Item { id: signerAssigneddlg - property int signerType: model.single_signer_type - property bool isRemoteSigner: model.single_signer_type === NUNCHUCKTYPE.AIRGAP || model.single_signer_type === NUNCHUCKTYPE.FOREIGN_SOFTWARE - property bool isNeedGetXpubs: model.single_signer_need_Topup_Xpub + property int signerType: model.single_signer_type + property bool isRemoteSigner: (model.single_signer_type !== NUNCHUCKTYPE.HARDWARE) && (model.single_signer_type !== NUNCHUCKTYPE.SOFTWARE) + property bool isNeedGetXpubs: model.single_signer_need_Topup_Xpub width: 343 height: signerAssigneddlg.isRemoteSigner ? 73 : 53 Rectangle { @@ -286,7 +286,7 @@ QScreen { Rectangle { id:_type - width: 70 + width: 100 height: 21 anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right @@ -294,7 +294,7 @@ QScreen { radius: 4 visible: !signerAssigneddlg.isNeedGetXpubs QText { - text: GlobalData.signerNames(signerAssigneddlg.signerType) + text: GlobalData.signers(signerAssigneddlg.signerType) font.family: "Lato" font.weight: Font.Bold font.pixelSize: 10 diff --git a/Qml/Screens/LocalMode/SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml b/Qml/Screens/LocalMode/SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml index d87bf217..35616503 100644 --- a/Qml/Screens/LocalMode/SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml +++ b/Qml/Screens/LocalMode/SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml @@ -198,7 +198,7 @@ QScreen { visible: master_signer_type !== NUNCHUCKTYPE.HARDWARE QText { id: signerTypeText - text: GlobalData.signerNames(master_signer_type) + text: GlobalData.signers(master_signer_type) font.family: "Lato" font.weight: Font.Bold font.pixelSize: 10 @@ -289,7 +289,7 @@ QScreen { color: "#C9DEF1" radius: 4 QText { - text: GlobalData.signerNames(single_signer_type) + text: GlobalData.signers(single_signer_type) font.family: "Lato" font.weight: Font.Bold font.pixelSize: 10 @@ -535,7 +535,7 @@ QScreen { radius: 4 visible: model.single_signer_type !== NUNCHUCKTYPE.HARDWARE QText { - text: GlobalData.signerNames(model.single_signer_type) + text: GlobalData.signers(model.single_signer_type) font.family: "Lato" font.weight: Font.Bold font.pixelSize: 10 diff --git a/Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml b/Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml index 7a0a50e2..9657a8b7 100644 --- a/Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml +++ b/Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml @@ -25,6 +25,7 @@ import QtGraphicalEffects 1.12 import HMIEVENTS 1.0 import EWARNING 1.0 import NUNCHUCKTYPE 1.0 +import DataPool 1.0 import "../../Components/origins" import "../../Components/customizes" import "../../Components/customizes/Texts" @@ -34,7 +35,6 @@ import "../../../localization/STR_QML.js" as STR QScreen { id: rootAddsignerToWallet property string textMnemonic: AppModel.mnemonic - property var numsIndexSelection: [0, 1, 2] QOnScreenContent { width: popupWidth height: popupHeight @@ -142,8 +142,8 @@ QScreen { var r = Math.floor(Math.random() * (numWords - 1)) + 1; if(arr.indexOf(r) === -1) arr.push(r); } - numsIndexSelection = numsIndexSelection.sort(() => Math.random() - 0.5) - numsIndexSelection = numsIndexSelection.sort(() => Math.random() - 0.5) + var numsIndexSelection = GlobalData.swapPositions() + console.log(numsIndexSelection) // #1 random1.indexArray = [arr[0], arr[1], arr[2]]; random1.indexNeeded = random1.indexArray[numsIndexSelection[0]]; @@ -160,4 +160,15 @@ QScreen { random3.phraseNeeded = mnemomics[random3.indexNeeded]; random3.phraseArray = [mnemomics[random3.indexArray[0]], mnemomics[random3.indexArray[1]], mnemomics[random3.indexArray[2]]]; } + + function getTimeBasedNumbers() { + const currentTime = new Date().getTime(); + + const randomValues = [ (currentTime % 3), + ((currentTime + 1) % 3), + ((currentTime + 2) % 3)]; + + console.log(randomValues) + return randomValues; + } } diff --git a/Qml/Screens/LocalMode/SCR_CREATE_TRANSACTION.qml b/Qml/Screens/LocalMode/SCR_CREATE_TRANSACTION.qml index 47722210..423a0298 100644 --- a/Qml/Screens/LocalMode/SCR_CREATE_TRANSACTION.qml +++ b/Qml/Screens/LocalMode/SCR_CREATE_TRANSACTION.qml @@ -463,7 +463,7 @@ QScreen { anchors.verticalCenter: parent.verticalCenter } QText { - text: STR.STR_QML_220.arg(AppModel.transactionInfo.m) + text: STR.str_QML_220(AppModel.transactionInfo.m) font.pixelSize: 12 font.family: "Lato" color: indicatorStatus.color @@ -638,7 +638,7 @@ QScreen { font.pixelSize: 14 color: "#031F2B" horizontalAlignment: Text.AlignRight - text: Math.max(0, (AppModel.chainTip - utxo_height)+1) + text: utxo_confirmed//Math.max(0, (AppModel.chainTip - utxo_height)+1) } } Item { @@ -665,14 +665,27 @@ QScreen { Item { width: parent.width height: 36 - QText { - text: STR.STR_QML_225 - color: "#031F2B" - font.weight: Font.Bold - font.pixelSize: 16 - font.family: "Lato" + Column { + spacing: 4 anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter + QText { + text: STR.STR_QML_225 + color: "#031F2B" + font.weight: Font.Bold + font.pixelSize: 16 + font.family: "Lato" + } + QText { + text: STR.STR_QML_895 + width: 250 + wrapMode: Text.WordWrap + color: "#595959" + font.pixelSize: 12 + font.family: "Lato" + verticalAlignment: Text.AlignVCenter + visible: manualfeesetting.switchOn && AppModel.transactionInfo.isCpfp + } } QSwitchTypeB { id: manualfeesetting @@ -820,14 +833,12 @@ QScreen { } } Item {width: parent.width; height: 12; visible: !feeinput.validInput} - QText { + QLato { id: cpfptext color: "#595959" height: 28 - visible: false //FIXME - text: "Child fee rate: ? sat/vB" - font.pixelSize: 16 - font.family: "Lato" + text: STR.STR_QML_836.arg(AppModel.transactionInfo.packageFeeRate) + visible: AppModel.transactionInfo.isCpfp } } Column { diff --git a/Qml/Screens/LocalMode/SCR_HOME.qml b/Qml/Screens/LocalMode/SCR_HOME.qml index 299a6ce2..4d06376a 100644 --- a/Qml/Screens/LocalMode/SCR_HOME.qml +++ b/Qml/Screens/LocalMode/SCR_HOME.qml @@ -373,7 +373,7 @@ QScreen { anchors.margins: 5 horizontalAlignment: Text.AlignHCenter wrapMode: Text.WrapAnywhere - font.weight: Font.Medium + font.weight: Font.Normal font.pixelSize: 16 color: "#031F2B"; text: qrCode.textInput @@ -523,7 +523,7 @@ QScreen { memoWidth: transaction_lst.width*0.20 amountWidth: transaction_lst.width*0.25 onButtonClicked: { - QMLHandle.sendEvent(EVT.EVT_HOME_TRANSACTION_INFO_REQUEST, transaction_txid) + QMLHandle.signalNotifySendEvent(EVT.EVT_HOME_TRANSACTION_INFO_REQUEST, transactiontxid) } } } @@ -755,7 +755,7 @@ QScreen { Flickable { id: flickerSignerList anchors.fill: parent - property bool signerReady: (mastersignerlist.count > 0) || (remoteSignerlist.count > 0) + property bool signerReady: (mastersignerlist.count > 0) || (remoteSignerlist.count > 0) || UserWallet.qLedgerNeed || UserWallet.qTrezorNeed || UserWallet.qColdCardNeed visible: signerReady clip: true flickableDirection: Flickable.VerticalFlick @@ -766,29 +766,42 @@ QScreen { Column { id: contentDisplay QAddAssistedWalletSigner{ - visible: false + visible: UserWallet.qLedgerNeed && ClientController.isNunchukLoggedIn addTitle: STR.STR_QML_810 addText: STR.STR_QML_811 anchors.horizontalCenter: parent.horizontalCenter onCancel: { - + UserWallet.qLedgerNeed = false; } onAdd: { QMLHandle.sendEvent(EVT.EVT_ASK_LEDGER_REQ) } } QAddAssistedWalletSigner{ - visible: false + visible: UserWallet.qTrezorNeed && ClientController.isNunchukLoggedIn addTitle: STR.STR_QML_813 addText: STR.STR_QML_814 anchors.horizontalCenter: parent.horizontalCenter onCancel: { - + UserWallet.qTrezorNeed = false; } onAdd: { QMLHandle.sendEvent(EVT.EVT_ASK_TREZOR_REQ) } } + QAddAssistedWalletSigner{ + visible: UserWallet.qColdCardNeed && ClientController.isNunchukLoggedIn + addTitle: STR.STR_QML_903 + addText: STR.STR_QML_904 + height: 152 + anchors.horizontalCenter: parent.horizontalCenter + onCancel: { + UserWallet.qColdCardNeed = false; + } + onAdd: { + QMLHandle.sendEvent(EVT.EVT_ASK_COLDCARD_REQ) + } + } QListView { id: mastersignerlist diff --git a/Qml/Screens/LocalMode/SCR_TRANSACTION_HISTORY.qml b/Qml/Screens/LocalMode/SCR_TRANSACTION_HISTORY.qml index beb37ce6..d50fd928 100644 --- a/Qml/Screens/LocalMode/SCR_TRANSACTION_HISTORY.qml +++ b/Qml/Screens/LocalMode/SCR_TRANSACTION_HISTORY.qml @@ -78,8 +78,8 @@ QScreen { readonly property int transaction_status_role : 2 readonly property int transaction_subtotal_role : 9 readonly property int transaction_total_role : 10 - readonly property int transaction_blocktime_role : 12 - readonly property int transaction_height_role : 13 + readonly property int transaction_blocktime_role : 13 + readonly property int transaction_height_role : 14 QTableElement { width: transaction_lst.width*0.15 height: 32 diff --git a/Qml/Screens/LocalMode/SCR_TRANSACTION_INFO.qml b/Qml/Screens/LocalMode/SCR_TRANSACTION_INFO.qml index 6e33e8f7..a5abf7bf 100644 --- a/Qml/Screens/LocalMode/SCR_TRANSACTION_INFO.qml +++ b/Qml/Screens/LocalMode/SCR_TRANSACTION_INFO.qml @@ -283,8 +283,7 @@ QScreen { menuWidth: 320 labels: [ STR.STR_QML_300, - STR.STR_QML_115, - STR.STR_QML_116, + STR.STR_QML_114, STR.STR_QML_301, STR.STR_QML_302, STR.STR_QML_303 @@ -292,7 +291,6 @@ QScreen { icons: [ "qrc:/Images/Images/ExportFile.svg", "qrc:/Images/Images/OnlineMode/QRCodeScan.png", - "qrc:/Images/Images/OnlineMode/QRCodeScan.png", "qrc:/Images/Images/importFile.svg", "qrc:/Images/Images/OnlineMode/QRCodeScan.png", "qrc:/Images/Images/OnlineMode/QRCodeScan.png" @@ -308,16 +306,13 @@ QScreen { case 1: // Export via QR Keystone requestExportQRKeyStone() break; - case 2: "Export via QR Passport" - requestExportQRPassport() - break; - case 3: // Import via file [.psbt] + case 2: // Import via file [.psbt] openfileDialog.open() break; - case 4: // Import via QR Keystone + case 3: // Import via QR Keystone requestImportQRKeyStone() break; - case 5: // Import via QR Passport + case 4: // Import via QR Passport requestImportQRPassport() break; default: @@ -363,13 +358,11 @@ QScreen { menuWidth: 320 labels: [ STR.STR_QML_300, - STR.STR_QML_115, - STR.STR_QML_116, + STR.STR_QML_114, ] icons: [ "qrc:/Images/Images/ExportFile.svg", "qrc:/Images/Images/OnlineMode/QRCodeScan.png", - "qrc:/Images/Images/OnlineMode/QRCodeScan.png" ] onItemClicked: { switch(index){ @@ -382,9 +375,6 @@ QScreen { case 1: // Export via QR Keystone requestExportQRKeyStone() break; - case 2: // Export via QR Passport - requestExportQRPassport() - break; default: break; } @@ -449,12 +439,10 @@ QScreen { menuWidth: 320 labels: [ STR.STR_QML_300, - STR.STR_QML_115, - STR.STR_QML_116, + STR.STR_QML_114, ] icons: [ "qrc:/Images/Images/ExportFile.svg", - "qrc:/Images/Images/OnlineMode/QRCodeScan.png", "qrc:/Images/Images/OnlineMode/QRCodeScan.png" ] onItemClicked: { @@ -468,9 +456,6 @@ QScreen { case 1: // Export via QR Keystone requestExportQRKeyStone() break; - case 1: // Export via QR Passport - requestExportQRPassport() - break; default: break; } @@ -532,14 +517,12 @@ QScreen { menuWidth: 320 labels: [ STR.STR_QML_300, - STR.STR_QML_115, - STR.STR_QML_116, + STR.STR_QML_114, STR.STR_QML_691, ] icons: [ "qrc:/Images/Images/ExportFile.svg", "qrc:/Images/Images/OnlineMode/QRCodeScan.png", - "qrc:/Images/Images/OnlineMode/QRCodeScan.png", "qrc:/Images/Images/copy-dark.svg" ] onItemClicked: { @@ -553,10 +536,7 @@ QScreen { case 1: // Export via QR Keystone requestExportQRKeyStone() break; - case 2: // Export via QR Passport - requestExportQRPassport() - break; - case 3: // Copy transaction ID + case 2: // Copy transaction ID requestCopyTransactionID() break; default: @@ -813,10 +793,10 @@ QScreen { var activeLink = "" switch(AppSetting.primaryServer){ case NUNCHUCKTYPE.MAIN: - activeLink = BLOCKSTREAM_MAINNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_MAINNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.TESTNET: - activeLink = BLOCKSTREAM_TESTNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_TESTNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.SIGNET: activeLink = AppSetting.signetStream + AppModel.transactionInfo.txid diff --git a/Qml/Screens/LocalMode/SCR_UTXOS.qml b/Qml/Screens/LocalMode/SCR_UTXOS.qml index c223ac56..cc8e84b0 100644 --- a/Qml/Screens/LocalMode/SCR_UTXOS.qml +++ b/Qml/Screens/LocalMode/SCR_UTXOS.qml @@ -218,7 +218,8 @@ QScreen { QListView { id: utxo_lst width: 720 - height: (pagecontrol.currentPage === pagecontrol.totalPage) ? (utxo_lst.count % utxo_lst.rowsOnPage)*utxo_lst.rowHeight : utxo_lst.pageHeight + height: (pagecontrol.currentPage !== pagecontrol.totalPage) ? utxo_lst.pageHeight : + utxo_lst.count % utxo_lst.rowsOnPage == 0 ? utxo_lst.pageHeight :((utxo_lst.count % utxo_lst.rowsOnPage) * utxo_lst.rowHeight) model: AppModel.utxoList anchors { top: parent.top @@ -238,7 +239,7 @@ QScreen { amountWidth: amounttab.width unspentoutput_address: utxo_address unspentoutput_memo: utxo_memo - unspentoutput_confirmation: Math.max(0, (AppModel.chainTip - utxo_height)+1) + unspentoutput_confirmation: utxo_confirmed//Math.max(0, (AppModel.chainTip - utxo_height)+1) unspentoutput_amount: utxo_amount utxoSelected: utxo_selected onButtonClicked: {QMLHandle.sendEvent(EVT.EVT_UTXOS_ITEM_SELECTED, index) } diff --git a/Qml/Screens/LocalMode/SCR_WALLET_INFO.qml b/Qml/Screens/LocalMode/SCR_WALLET_INFO.qml index c91cad0e..2b049628 100644 --- a/Qml/Screens/LocalMode/SCR_WALLET_INFO.qml +++ b/Qml/Screens/LocalMode/SCR_WALLET_INFO.qml @@ -374,7 +374,6 @@ QScreen { STR.STR_QML_327, STR.STR_QML_328, STR.STR_QML_329, - STR.STR_QML_330, STR.STR_QML_674 ] icons: [ @@ -384,7 +383,6 @@ QScreen { "qrc:/Images/Images/backup.png", "qrc:/Images/Images/fileDownload.png", "qrc:/Images/Images/exportqr.png", - "qrc:/Images/Images/exportqr.png", "qrc:/Images/Images/fileDownload.png" ] onItemClicked: { @@ -428,11 +426,7 @@ QScreen { qrcodeExportResult.open() QMLHandle.sendEvent(EVT.EVT_WALLET_INFO_EXPORT_QRCODE, "keystone") break; - case 6: //"Export as QR Passport" - qrcodeExportResult.open() - QMLHandle.sendEvent(EVT.EVT_WALLET_INFO_EXPORT_QRCODE, "passport") - break; - case 7: //"Export wallet to Bitbox" + case 6: //"Export wallet to Bitbox" var addrs = AppModel.walletInfo.walletunUsedAddressList; if(addrs.length > 0){ displayAddressBusybox.addrToVerify = addrs[0] @@ -476,7 +470,7 @@ QScreen { ls.push(STR.STR_QML_532) if(ClientController.user.isPremiumUser){ ls.push(STR.STR_QML_686) -// ls.push(STR.STR_QML_825) + ls.push(STR.STR_QML_825) } return ls } @@ -748,6 +742,8 @@ QScreen { onTriggered: { stop() forceRefreshBusybox.close() + _warning.warningType = EWARNING.SUCCESS_MSG + _warning.warningExplain = STR.STR_QML_690 _warning.open() } } @@ -756,8 +752,6 @@ QScreen { id:_warning x:contenCenter.x + 36 y:contenCenter.y + 520 - warningType:EWARNING.SUCCESS_MSG - warningExplain:STR.STR_QML_690 } Popup { @@ -811,9 +805,14 @@ QScreen { label: "" boxWidth: 252 boxHeight: 48 - isValid: textInputted != "" - errorText: "Dummy" - showError: true + validator: IntValidator {bottom: 0;} + textInputted: AppModel.walletInfo.gapLimit + onTextInputtedChanged: { + if(!inputGapLimit.isValid){ + inputGapLimit.isValid = true + } + inputGapLimit.showError = false; + } } } Row { @@ -822,8 +821,8 @@ QScreen { QTextButton { width: 120 height: 36 - label.text: "Cancel" - label.font.pixelSize: 12 + label.text: STR.STR_QML_035 + label.font.pixelSize: 16 type: eTypeB onButtonClicked: { gaplimit.close() @@ -832,11 +831,21 @@ QScreen { QTextButton { width: 120 height: 36 - label.text: "Save" - label.font.pixelSize: 12 + label.text: STR.STR_QML_835 + label.font.pixelSize: 16 type: eTypeE onButtonClicked: { - + if (parseInt(inputGapLimit.textInputted) > 100) { + inputGapLimit.errorText = STR.STR_QML_834 + inputGapLimit.isValid = false + inputGapLimit.showError = true; + } else { + gaplimit.close() + _warning.warningType = EWARNING.SUCCESS_MSG + _warning.warningExplain = STR.STR_QML_833 + _warning.open() + QMLHandle.sendEvent(EVT.EVT_WALLET_INFO_GAP_LIMIT_REQUEST,inputGapLimit.textInputted) + } } } } diff --git a/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml new file mode 100644 index 00000000..4fd73fd6 --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml @@ -0,0 +1,422 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + readonly property int _INFORMATION: 0 + readonly property int _REFRESH_DEVICE: 1 + readonly property int _LOADING: 2 + readonly property int _SUCCESSFULLY: 3 + QOnScreenContentTypeA { + visible: AppModel.addSignerWizard === _INFORMATION + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_904 + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: Item { + Row { + spacing: 36 + Rectangle { + width: 346 + height: 512 + radius: 24 + color: "#D0E2FF" + QImage { + width: 346 + height: 300 + anchors.verticalCenter: parent.verticalCenter + source: "qrc:/Images/Images/coldcard-illustration.svg" + } + } + Item { + width: 346 + height: 512 + Column { + width: parent.width + spacing: 24 + QLato { + width: parent.width + text: STR.STR_QML_817 + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Repeater { + id: _guide + width: parent.width + readonly property var content_map: [ + {height: 48, headline:STR.STR_QML_907, content: STR.STR_QML_908 , icon: "qrc:/Images/Images/1.Active.svg" }, + {height: 84, headline:STR.STR_QML_909, content: STR.STR_QML_910 , icon: "qrc:/Images/Images/2.Active.svg" }, + ] + model: content_map.length + Rectangle { + property var _item: _guide.content_map[index] + width: 346 + height: _item.height + Row { + spacing: 12 + QImage { + id: _ico + width: 24 + height: 24 + source: _item.icon + } + Column { + width: 310 + height: _item.height + spacing: 4 + QText { + width: 310 + text: _item.headline + color: "#031F2B" + font.family: "Lato" + font.pixelSize: 16 + font.weight: Font.DemiBold + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + QText { + id: _term + width: 310 + text: _item.content + color: "#031F2B" + font.family: "Lato" + font.pixelSize: 16 + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + onLinkActivated: Qt.openUrlExternally("https://coldcard.com/docs/quick") + MouseArea { + anchors.fill: parent + cursorShape: _term.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.NoButton + } + } + } + } + } + } + } + } + } + + } + + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + onNextClicked: { + AppModel.addSignerWizard = _REFRESH_DEVICE + } + } + readonly property string _COLDCARD: "Coldcard" + readonly property string _COLDCARD_TYPE: "coldcard" + QOnScreenContentTypeA { + visible: AppModel.addSignerWizard === _REFRESH_DEVICE + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_904 + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: Item { + Item { + width: 529 + QLato { + id: text + width: parent.width + text: STR.STR_QML_911 + font.pixelSize: 16 + font.weight: Font.Bold + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + QImage { + id: nodevice + width: parent.width + visible: AppModel.deviceList.count === 0 + anchors { + left: text.left + top: text.bottom + topMargin: 8 + } + source: "qrc:/Images/Images/Signer_Level2.png" + QRefreshButton { + width: 160 + height: 48 + label: STR.STR_QML_105 + fontPixelSize: 16 + borderColor: ["transparent", "transparent", "transparent"] + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + onButtonClicked: scanDevice() + } + } + Rectangle { + visible: AppModel.deviceList.count !== 0 + anchors { + left: text.left + top: text.bottom + topMargin: 8 + } + border.width: 1 + border.color: "#EAEAEA" + width: 539 + height: 464 + radius: 8 + QRefreshButton { + width: 160 + height: 48 + label: STR.STR_QML_105 + fontPixelSize: 16 + borderColor: ["transparent", "transparent", "transparent"] + anchors { + right: parent.right + top: parent.top + topMargin: 6 + } + onButtonClicked: scanDevice() + } + QListView { + id: devicelist + property bool needPin: false + visible: devicelist.count + width: parent.width + height: Math.min(230, (devicelist.count*44) + ((devicelist.count-1)*8)) + model: AppModel.deviceList + anchors { + left: parent.left + leftMargin: 12 + top: parent.top + topMargin: 12 + } + spacing: 8 + currentIndex: -1 + clip: true + interactive: devicelist.count > 3 + ScrollBar.vertical: ScrollBar { active: true } + delegate: Item { + width: 342 + height: 44 + visible: device_type === _COLDCARD_TYPE + Rectangle { + id: rect + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width - 2 + height: 40 + color: "transparent" + QImage { + anchors { + left: parent.left + leftMargin: 16 + verticalCenter: parent.verticalCenter + } + source: index == devicelist.currentIndex ? "qrc:/Images/Images/radio-selected-dark.svg" : "qrc:/Images/Images/radio-dark.svg" + } + Column { + width: 290 + height: 37 + anchors { + left: parent.left + leftMargin: 48 + verticalCenter: parent.verticalCenter + } + QText { + width: parent.width + height: 21 + font.family: "Montserrat" + font.pixelSize: 14 + color: "#031F2B" + font.weight: Font.DemiBold + text: _COLDCARD + } + QText { + width: parent.width + height: 16 + font.family: "Lato" + font.pixelSize: 12 + color: "#031F2B" + text: "XFP: " + device_master_fingerprint + font.capitalization: Font.AllUppercase + } + } + } + Rectangle { + anchors.fill: parent + visible: !device_usable_to_add + color: Qt.rgba(255, 255, 255, 0.5) + } + MouseArea { + anchors.fill: parent + enabled: device_usable_to_add + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + devicelist.currentIndex = index + signerName = _COLDCARD + } + } + } + } + } + } + property string signerName: "" + function scanDevice() { + QMLHandle.sendEvent(EVT.EVT_SCAN_COLDCARD_DEVICE_REQUEST) + } + function addDevice() { + if(devicelist.currentIndex !== -1){ + var masterSignerObj = { "signerNameInputted" : signerName, + "deviceIndexSelected" : devicelist.currentIndex}; + QMLHandle.sendEvent(EVT.EVT_ADD_COLDCARD_DEVICE_REQUEST, masterSignerObj) + } + } + } + onPrevClicked: { + AppModel.addSignerWizard = _INFORMATION + } + onNextClicked: { + contentItem.addDevice() + } + } + + QOnScreenContent { + visible: AppModel.addSignerWizard === _LOADING + width: popupWidth + height: popupHeight + anchors.centerIn: parent + enableHeader: false + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: Item { + Column { + width: 400 + height: 56 + anchors.centerIn: parent + spacing: 16 + QProgressbarTypeA { + id: progresBar + percentage: AppModel.addSignerPercentage + } + QLato{ + font.weight: Font.Bold + font.pixelSize: 20 + text: STR.STR_QML_912 + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + } + } + } + } + + QOnScreenContent { + visible: AppModel.addSignerWizard === _SUCCESSFULLY + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: "" + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: Item { + Item { + anchors.centerIn: parent + width: 400 + height: 228 + Column { + width: parent.width + spacing: 24 + Rectangle { + width: 96;height: 96; + radius: 48 + color: "#A7F0BA" + anchors.horizontalCenter: parent.horizontalCenter + QImage { + anchors.centerIn: parent + width: 60; height: 60; + source: "qrc:/Images/Images/check-dark.svg" + } + } + QLato { + width: parent.width + height: 40 + text: STR.STR_QML_913 + font.pixelSize: 32 + font.weight: Font.DemiBold + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + QLato { + width: parent.width + height: 28 + text: STR.STR_QML_828 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + lineHeightMode: Text.FixedHeight + lineHeight: 28 + wrapMode: Text.WordWrap + } + } + } + } + bottomRight: Row { + spacing: 12 + QTextButton { + width: 120 + height: 48 + label.text: STR.STR_QML_777 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + } + } + } + + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_914 + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml new file mode 100644 index 00000000..232daf01 --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml @@ -0,0 +1,103 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + popupWidth: 300 + popupHeight: 236 + QOnScreenContent { + id:_content + width: popupWidth + height: popupHeight + anchors.centerIn: parent + enableHeader:false + offset: 24 + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + QLato { + anchors{ + top: parent.top + topMargin: 24 + horizontalCenter: parent.horizontalCenter + } + width: popupWidth - _content.offset*2 + height: 20 + text: STR.STR_QML_904 + font.weight: Font.Bold + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + QLato { + anchors{ + top: parent.top + topMargin: 20 + 12 + 24 + horizontalCenter: parent.horizontalCenter + } + width: 252 + height: 84 + text: STR.STR_QML_905 + lineHeightMode: Text.FixedHeight + lineHeight: 20 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + bottomLeft: Row { + spacing: 8 + QTextButton { + width: 120 + height: 48 + label.text: STR.STR_QML_432 + label.font.pixelSize: 16 + type: eTypeF + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + } + } + bottomRight: Row { + spacing: 12 + QTextButton { + width: 120 + height: 48 + label.text: STR.STR_QML_433 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + if (ServiceSetting.existKeyType("coldcard")) { + QMLHandle.sendEvent(EVT.EVT_EXIST_COLDCARD_REQ) + } else { + QMLHandle.sendEvent(EVT.EVT_ADD_COLDCARD_REQUEST) + } + } + } + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml new file mode 100644 index 00000000..9641485c --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml @@ -0,0 +1,91 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + signal addExistKey() + QOnScreenContentTypeB { + id:_content + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_901 + extraHeader: Item {} + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: QAddAnExistingKey { + notice: STR.STR_QML_916 + keyType: "coldcard" + } + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + bottomRight: Row { + spacing: 12 + QTextButton { + width: 215 + height: 48 + label.text: STR.STR_QML_900 + label.font.pixelSize: 16 + type: eTypeB + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_ADD_NEW_COLDCARD_REQUEST) + } + } + QTextButton { + width: 150 + height: 48 + label.text: STR.STR_QML_899 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + var coldcardXfp = _content.contentItem.fingerPrint + QMLHandle.sendEvent(EVT.EVT_ADD_EXIST_COLDCARD_REQUEST, coldcardXfp) + } + } + } + } + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_914 + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + onAddHardwareSuccessAlert:{ + closeTo(NUNCHUCKTYPE.WALLET_TAB) + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml index fa2eff5d..06d04ecd 100644 --- a/Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml +++ b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml @@ -36,17 +36,13 @@ QScreen { readonly property int _REFRESH_DEVICE: 1 readonly property int _LOADING: 2 readonly property int _SUCCESSFULLY: 3 - function closeScreen() { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_LEDGER) - } - QOnScreenContentTypeA { visible: AppModel.addSignerWizard === _INFORMATION width: popupWidth height: popupHeight anchors.centerIn: parent label.text: STR.STR_QML_811 - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Row { spacing: 36 @@ -134,19 +130,20 @@ QScreen { } - onPrevClicked: closeScreen() + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) onNextClicked: { AppModel.addSignerWizard = _REFRESH_DEVICE } } - + readonly property string _LEDGER: "Ledger" + readonly property string _LEDGER_TYPE: "ledger" QOnScreenContentTypeA { visible: AppModel.addSignerWizard === _REFRESH_DEVICE width: popupWidth height: popupHeight anchors.centerIn: parent label.text: STR.STR_QML_811 - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Item { width: 529 @@ -226,11 +223,12 @@ QScreen { spacing: 8 currentIndex: -1 clip: true - interactive : devicelist.count > 3 + interactive: devicelist.count > 3 ScrollBar.vertical: ScrollBar { active: true } delegate: Item { width: 342 height: 44 + visible: device_type === _LEDGER_TYPE Rectangle { id: rect anchors.horizontalCenter: parent.horizontalCenter @@ -260,7 +258,7 @@ QScreen { font.pixelSize: 14 color: "#031F2B" font.weight: Font.DemiBold - text: device_type + text: _LEDGER } QText { width: parent.width @@ -285,7 +283,7 @@ QScreen { cursorShape: Qt.PointingHandCursor onClicked: { devicelist.currentIndex = index - signerName = device_type + signerName = _LEDGER } } } @@ -309,7 +307,6 @@ QScreen { } onNextClicked: { contentItem.addDevice() - AppModel.addSignerWizard = _LOADING } } @@ -319,7 +316,7 @@ QScreen { height: popupHeight anchors.centerIn: parent enableHeader: false - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Column { width: 400 @@ -339,14 +336,6 @@ QScreen { } } } - Connections { - target: AppModel - onAddSignerPercentageChanged:{ - if (AppModel.addSignerPercentage === 100) { - AppModel.addSignerWizard = _SUCCESSFULLY - } - } - } } QOnScreenContent { @@ -355,7 +344,7 @@ QScreen { height: popupHeight anchors.centerIn: parent label.text: "" - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Item { anchors.centerIn: parent @@ -405,9 +394,23 @@ QScreen { label.text: STR.STR_QML_777 label.font.pixelSize: 16 type: eTypeE - onButtonClicked: closeScreen() + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) } } } + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_840_LEDGER + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + } } diff --git a/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml index 29596fca..396e5e05 100644 --- a/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml +++ b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml @@ -41,9 +41,7 @@ QScreen { anchors.centerIn: parent enableHeader:false offset: 24 - onCloseClicked: { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_TREZOR_ASK) - } + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) QLato { anchors{ top: parent.top @@ -81,9 +79,7 @@ QScreen { label.text: STR.STR_QML_432 label.font.pixelSize: 16 type: eTypeF - onButtonClicked: { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_LEDGER_ASK) - } + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) } } bottomRight: Row { @@ -95,7 +91,11 @@ QScreen { label.font.pixelSize: 16 type: eTypeE onButtonClicked: { - QMLHandle.sendEvent(EVT.EVT_ADD_LEDGER_REQUEST) + if (ServiceSetting.existKeyType("ledger")) { + QMLHandle.sendEvent(EVT.EVT_EXIST_LEDGER_REQ) + } else { + QMLHandle.sendEvent(EVT.EVT_ADD_LEDGER_REQUEST) + } } } } diff --git a/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml new file mode 100644 index 00000000..20162b8c --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml @@ -0,0 +1,92 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + property string ledgerXfp: "" + signal addExistKey() + QOnScreenContentTypeB { + id:_content + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_901 + extraHeader: Item {} + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: QAddAnExistingKey { + notice: STR.STR_QML_902 + keyType: "ledger" + } + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + bottomRight: Row { + spacing: 12 + QTextButton { + width: 215 + height: 48 + label.text: STR.STR_QML_900 + label.font.pixelSize: 16 + type: eTypeB + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_ADD_NEW_LEDGER_REQUEST) + } + } + QTextButton { + width: 150 + height: 48 + label.text: STR.STR_QML_899 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + var ledgerXfp = _content.contentItem.fingerPrint + QMLHandle.sendEvent(EVT.EVT_ADD_EXIST_LEDGER_REQUEST, ledgerXfp) + } + } + } + } + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_840_LEDGER + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + onAddHardwareSuccessAlert:{ + closeTo(NUNCHUCKTYPE.WALLET_TAB) + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml index b4886568..e7717ca2 100644 --- a/Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml +++ b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml @@ -36,17 +36,13 @@ QScreen { readonly property int _REFRESH_DEVICE: 1 readonly property int _LOADING: 2 readonly property int _SUCCESSFULLY: 3 - function closeScreen() { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_LEDGER) - } - QOnScreenContentTypeA { visible: AppModel.addSignerWizard === _INFORMATION width: popupWidth height: popupHeight anchors.centerIn: parent label.text: STR.STR_QML_814 - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Row { spacing: 36 @@ -59,7 +55,7 @@ QScreen { width: 346 height: 300 anchors.verticalCenter: parent.verticalCenter - source: "qrc:/Images/Images/ledger-illustration.svg" + source: "qrc:/Images/Images/trezor-illustration.svg" } } Item { @@ -133,19 +129,21 @@ QScreen { } - onPrevClicked: closeScreen() + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) onNextClicked: { AppModel.addSignerWizard = _REFRESH_DEVICE } } + readonly property string _TREZOR: "Trezor" + readonly property string _TREZOR_TYPE: "trezor" QOnScreenContentTypeA { visible: AppModel.addSignerWizard === _REFRESH_DEVICE width: popupWidth height: popupHeight anchors.centerIn: parent label.text: STR.STR_QML_814 - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Item { width: 529 @@ -225,11 +223,12 @@ QScreen { spacing: 8 currentIndex: -1 clip: true - interactive : devicelist.count > 3 + interactive: devicelist.count > 3 ScrollBar.vertical: ScrollBar { active: true } delegate: Item { width: 342 height: 44 + visible: device_type === _TREZOR_TYPE Rectangle { id: rect anchors.horizontalCenter: parent.horizontalCenter @@ -259,7 +258,7 @@ QScreen { font.pixelSize: 14 color: "#031F2B" font.weight: Font.DemiBold - text: device_type + text: _TREZOR } QText { width: parent.width @@ -284,7 +283,7 @@ QScreen { cursorShape: Qt.PointingHandCursor onClicked: { devicelist.currentIndex = index - signerName = device_type + signerName = _TREZOR } } } @@ -308,7 +307,6 @@ QScreen { } onNextClicked: { contentItem.addDevice() - AppModel.addSignerWizard = _LOADING } } @@ -318,7 +316,7 @@ QScreen { height: popupHeight anchors.centerIn: parent enableHeader: false - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Column { width: 400 @@ -354,7 +352,7 @@ QScreen { height: popupHeight anchors.centerIn: parent label.text: "" - onCloseClicked: closeScreen() + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) content: Item { Item { anchors.centerIn: parent @@ -404,9 +402,23 @@ QScreen { label.text: STR.STR_QML_777 label.font.pixelSize: 16 type: eTypeE - onButtonClicked: closeScreen() + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) } } } + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_840 + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + } } diff --git a/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml index 68f4d82a..e30acf72 100644 --- a/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml +++ b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml @@ -41,9 +41,7 @@ QScreen { anchors.centerIn: parent enableHeader:false offset: 24 - onCloseClicked: { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_TREZOR_ASK) - } + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) QLato { anchors{ top: parent.top @@ -81,9 +79,7 @@ QScreen { label.text: STR.STR_QML_432 label.font.pixelSize: 16 type: eTypeF - onButtonClicked: { - QMLHandle.sendEvent(EVT.EVT_ONS_CLOSE_REQUEST, EVT.STATE_ID_SCR_ADD_TREZOR_ASK) - } + onButtonClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) } } bottomRight: Row { @@ -95,7 +91,11 @@ QScreen { label.font.pixelSize: 16 type: eTypeE onButtonClicked: { - QMLHandle.sendEvent(EVT.EVT_ADD_TREZOR_REQUEST) + if (ServiceSetting.existKeyType("trezor")) { + QMLHandle.sendEvent(EVT.EVT_EXIST_TREZOR_REQ) + } else { + QMLHandle.sendEvent(EVT.EVT_ADD_TREZOR_REQUEST) + } } } } diff --git a/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml new file mode 100644 index 00000000..72c538ae --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml @@ -0,0 +1,92 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + property string ledgerXfp: "" + signal addExistKey() + QOnScreenContentTypeB { + id:_content + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_901 + extraHeader: Item {} + onCloseClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + content: QAddAnExistingKey { + notice: STR.STR_QML_915 + keyType: "trezor" + } + onPrevClicked: closeTo(NUNCHUCKTYPE.WALLET_TAB) + bottomRight: Row { + spacing: 12 + QTextButton { + width: 215 + height: 48 + label.text: STR.STR_QML_900 + label.font.pixelSize: 16 + type: eTypeB + onButtonClicked: { + QMLHandle.sendEvent(EVT.EVT_ADD_NEW_TREZOR_REQUEST) + } + } + QTextButton { + width: 150 + height: 48 + label.text: STR.STR_QML_899 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + var trezorXfp = _content.contentItem.fingerPrint + QMLHandle.sendEvent(EVT.EVT_ADD_EXIST_TREZOR_REQUEST, trezorXfp) + } + } + } + } + QPopupInfo{ + id:_info1 + contentText: STR.STR_QML_840 + onGotItClicked: { + close() + } + } + + Connections { + target: UserWallet + onAddHardwareAlert:{ + _info1.open() + } + onAddHardwareSuccessAlert:{ + closeTo(NUNCHUCKTYPE.WALLET_TAB) + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml b/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml index 432fe7bd..2ba9754b 100644 --- a/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml +++ b/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml @@ -461,7 +461,7 @@ QScreen { anchors.verticalCenter: parent.verticalCenter } QText { - text: STR.STR_QML_220.arg(Math.max(0, (AppModel.transactionInfo.m - AppModel.transactionInfo.numberSigned))) + text: STR.str_QML_220(Math.max(0, (AppModel.transactionInfo.m - AppModel.transactionInfo.numberSigned))) font.pixelSize: 12 font.family: "Lato" color: indicatorStatus.color @@ -501,7 +501,7 @@ QScreen { color: "#595959" font.family: "Lato" font.pixelSize: 12 - text: STR.STR_QML_220.arg(Math.max(0, (AppModel.transactionInfo.m - AppModel.transactionInfo.numberSigned))) + text: STR.str_QML_220(Math.max(0, (AppModel.transactionInfo.m - AppModel.transactionInfo.numberSigned))) anchors.verticalCenter: parent.verticalCenter } } @@ -991,10 +991,10 @@ QScreen { var activeLink = "" switch(AppSetting.primaryServer){ case NUNCHUCKTYPE.MAIN: - activeLink = BLOCKSTREAM_MAINNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_MAINNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.TESTNET: - activeLink = BLOCKSTREAM_TESTNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_TESTNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.SIGNET: activeLink = AppSetting.signetStream + AppModel.transactionInfo.txid diff --git a/Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml b/Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml new file mode 100644 index 00000000..c88740c3 --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml @@ -0,0 +1,449 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.12 +import QtQuick.Controls.Styles 1.4 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../../localization/STR_QML.js" as STR + +QScreen { + function fclose() { + QMLHandle.sendEvent(EVT.EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST, EVT.STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN) + } + property string dateString: ServiceSetting.qInheritanceActivationDate !== "" ? ServiceSetting.qInheritanceActivationDate : Qt.formatDateTime(new Date(), "MM/dd/yyyy") + property string message: ServiceSetting.qInheritanceNote + property string period: "" + property string period_id: ServiceSetting.qInheritancePeriodId + property string email: ServiceSetting.qInheritanceEmail + property bool isNotify: ServiceSetting.qInheritanceIsNotify + + QOnScreenContentTypeB { + id: _Activation + visible: ServiceSetting.qInheritancePlan === ServiceType.IE_ACTIVATION_DATE + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_854 + onCloseClicked: fclose() + content: Item { + Column { + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: -16 + spacing: 24 + QLato { + width: 539 + height: 56 + text: STR.STR_QML_855 + anchors.left: parent.left + font.weight: Font.Normal + wrapMode: Text.WrapAnywhere + lineHeight: 28 + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Item { + width: 539 + height: 72 + QTextInputBoxTypeB { + label: STR.STR_QML_848 + width: 539 + height: 72 + boxWidth: 539 + boxHeight: 48 + isValid: true + textInputted: dateString + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + propagateComposedEvents: true + onClicked: { + _calendar.open() + } + } + } + } + Popup { + id: _calendar + width: cal.width + height: cal.height + modal: true + focus: true + closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape + background: Item{} + anchors.centerIn: parent + Calendar { + id: cal + anchors.centerIn: parent + onClicked: { + dateString = Qt.formatDateTime(date, "MM/dd/yyyy") + _calendar.close() + } + style: CalendarStyle { + gridVisible: false + dayDelegate: Rectangle { + gradient: Gradient { + GradientStop { + position: 0.00 + color: styleData.selected ? "#111" : (styleData.visibleMonth && styleData.valid ? "#444" : "#666"); + } + GradientStop { + position: 1.00 + color: styleData.selected ? "#444" : (styleData.visibleMonth && styleData.valid ? "#111" : "#666"); + } + GradientStop { + position: 1.00 + color: styleData.selected ? "#777" : (styleData.visibleMonth && styleData.valid ? "#111" : "#666"); + } + } + + Label { + text: styleData.date.getDate() + anchors.centerIn: parent + color: styleData.valid ? "white" : "grey" + } + + Rectangle { + width: parent.width + height: 1 + color: "#555" + anchors.bottom: parent.bottom + } + + Rectangle { + width: 1 + height: parent.height + color: "#555" + anchors.right: parent.right + } + } + } + } + } + Rectangle { + width: parent.width + height: 80 + anchors { + bottom: parent.bottom + bottomMargin: 36 + } + color:"#EAEAEA" + radius: 8 + Row { + anchors.fill: parent + anchors.margins: 12 + spacing: 8 + QImage { + anchors.verticalCenter: parent.verticalCenter + width: 36; height: 36; + source: "qrc:/Images/Images/info-60px.png" + } + QLato { + anchors.verticalCenter: parent.verticalCenter + text: STR.STR_QML_856 + width: 660 + height: 56 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + } + } + } + bottomRight: QTextButton { + width: 195 + height: 48 + label.text: STR.STR_QML_857 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + _Activation.nextClicked() + } + } + onPrevClicked: fclose() + onNextClicked: { + ServiceSetting.qInheritanceActivationDate = dateString + fclose() + } + } + + QOnScreenContentTypeB { + id: _Message + visible: ServiceSetting.qInheritancePlan === ServiceType.IE_LEAVE_MESSAGE + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_920 + onCloseClicked: fclose() + content: Item { + Column { + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: -16 + spacing: 24 + QLato { + width: 539 + height: 56 + text: STR.STR_QML_859 + anchors.left: parent.left + font.weight: Font.Normal + wrapMode: Text.WrapAnywhere + lineHeight: 28 + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + QTextAreaBoxTypeA { + label: STR.STR_QML_860 + optional: " (optional)" + boxWidth: 539 + boxHeight: 276 + isValid: true + textInputted: message + onTextInputtedChanged: { + message = textInputted + } + + input.verticalAlignment: Text.AlignTop + input.wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + } + } + bottomRight: QTextButton { + width: 195 + height: 48 + label.text: STR.STR_QML_861 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + _Message.nextClicked() + } + } + onPrevClicked: fclose() + onNextClicked: { + ServiceSetting.qInheritanceNote = message + fclose() + } + } + + QOnScreenContentTypeB { + id: _Period + visible: ServiceSetting.qInheritancePlan === ServiceType.IE_BUFFER_PERIOD + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_862 + onCloseClicked: fclose() + content: Item { + Column { + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: -16 + spacing: 24 + QLato { + width: 539 + height: 140 + text: STR.STR_QML_863 + anchors.left: parent.left + font.weight: Font.Normal + lineHeight: 28 + lineHeightMode: Text.FixedHeight + wrapMode: Text.WrapAnywhere + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Item { + width: 539 + height: 212 + Column { + anchors.fill: parent + spacing: 16 + QListView { + id: questions + width: 539 + height: childrenRect.height + spacing: 8 + clip: true + model: UserWallet.periods + interactive: false + delegate: QRadioButtonTypeE { + id: btn + width: 539 + height: 60 + label: modelData.display_name + fontFamily: "Lato" + fontPixelSize: 16 + fontWeight: btn.selected ? Font.ExtraBold : Font.DemiBold + selected: period_id === modelData.id + textBadge: modelData.is_recommended ? STR.STR_QML_879 : "" + onButtonClicked: { + period = modelData.display_name + period_id = modelData.id + } + } + } + } + } + } + } + bottomRight: QTextButton { + width: 195 + height: 48 + label.text: STR.STR_QML_864 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + _Period.nextClicked() + } + } + onPrevClicked: fclose() + onNextClicked: { + ServiceSetting.qInheritancePeriod = period + ServiceSetting.qInheritancePeriodId = period_id + fclose() + } + } + + QOnScreenContentTypeB { + id: _Notification + visible: ServiceSetting.qInheritancePlan === ServiceType.IE_NOTIFICATION + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_865 + onCloseClicked: fclose() + content: Item { + Column { + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: -16 + spacing: 24 + QLato { + width: 539 + height: 56 + text: STR.STR_QML_866 + anchors.left: parent.left + font.weight: Font.Normal + wrapMode: Text.WrapAnywhere + lineHeight: 28 + lineHeightMode: Text.FixedHeight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + QTextInputBoxTypeB { + label: STR.STR_QML_867 + boxWidth: 539 + boxHeight: 116 + isValid: true + textInputted: email + onTextInputtedChanged: { + email = textInputted + } + input.verticalAlignment: Text.AlignTop + input.wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + QCheckBoxButton{ + id: notify + width: 539 + height: 24 + label: STR.STR_QML_868 + checked: ServiceSetting.qInheritanceIsNotify + onButtonClicked: { + isNotify = checked + } + } + } + Rectangle { + width: parent.width + height: 80 + anchors { + bottom: parent.bottom + bottomMargin: 36 + } + color:"#FDEBD2" + radius: 8 + Row { + anchors.fill: parent + anchors.margins: 12 + spacing: 8 + QImage { + anchors.verticalCenter: parent.verticalCenter + width: 36; height: 36; + source: "qrc:/Images/Images/warning-dark.svg" + } + QLato { + anchors.verticalCenter: parent.verticalCenter + text: STR.STR_QML_869 + width: 660 + height: 56 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + } + } + } + + bottomRight: Row { + spacing: 12 + QTextButton { + width: 239 + height: 48 + label.text: STR.STR_QML_871 + label.font.pixelSize: 16 + type: eTypeB + onButtonClicked: { + ServiceSetting.qInheritanceIsNotify = false + ServiceSetting.qInheritanceEmail = "" + fclose() + } + } + QTextButton { + width: 259 + height: 48 + label.text: STR.STR_QML_870 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + _Notification.nextClicked() + } + } + } + onPrevClicked: fclose() + onNextClicked: { + ServiceSetting.qInheritanceIsNotify = isNotify + ServiceSetting.qInheritanceEmail = email + fclose() + } + } +} diff --git a/Qml/Screens/OnlineMode/SCR_INHERITANCE_TRANSACTION_DETAILS.qml b/Qml/Screens/OnlineMode/SCR_INHERITANCE_TRANSACTION_DETAILS.qml index 874b9ad8..60c6ebcd 100644 --- a/Qml/Screens/OnlineMode/SCR_INHERITANCE_TRANSACTION_DETAILS.qml +++ b/Qml/Screens/OnlineMode/SCR_INHERITANCE_TRANSACTION_DETAILS.qml @@ -88,10 +88,10 @@ QScreen { var activeLink = "" switch(AppSetting.primaryServer){ case NUNCHUCKTYPE.MAIN: - activeLink = BLOCKSTREAM_MAINNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_MAINNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.TESTNET: - activeLink = BLOCKSTREAM_TESTNET + AppModel.transactionInfo.txid + activeLink = EXPLORER_TESTNET + AppModel.transactionInfo.txid break; case NUNCHUCKTYPE.SIGNET: activeLink = AppSetting.signetStream + AppModel.transactionInfo.txid diff --git a/Qml/Screens/OnlineMode/SCR_INHERITANCE_WITHDRAW_BALANCE.qml b/Qml/Screens/OnlineMode/SCR_INHERITANCE_WITHDRAW_BALANCE.qml index bb26e62e..e9a1d8b6 100644 --- a/Qml/Screens/OnlineMode/SCR_INHERITANCE_WITHDRAW_BALANCE.qml +++ b/Qml/Screens/OnlineMode/SCR_INHERITANCE_WITHDRAW_BALANCE.qml @@ -68,10 +68,10 @@ QScreen { labelTop: model.wallet_name labelCenter: qsTr("%1/%2 %3").arg(model.wallet_M).arg(model.wallet_N).arg(STR.STR_QML_069) labelBottom: model.wallet_Balance + RoomWalletData.unitValue - walletIcon: model.wallet_isSharedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : + icon: model.wallet_isSharedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : model.wallet_isAssistedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : model.wallet_Escrow ? "qrc:/Images/Images/OnlineMode/Escrow Wallet.png" : "" - walletType: model.wallet_isSharedWallet ? STR.STR_QML_438 : + type: model.wallet_isSharedWallet ? STR.STR_QML_438 : model.wallet_isAssistedWallet ? STR.STR_QML_679 : "" selected: currentSelect === index onButtonClicked: { diff --git a/Qml/Screens/OnlineMode/SCR_LOGIN_ONLINE.qml b/Qml/Screens/OnlineMode/SCR_LOGIN_ONLINE.qml index 091e0469..579670d4 100644 --- a/Qml/Screens/OnlineMode/SCR_LOGIN_ONLINE.qml +++ b/Qml/Screens/OnlineMode/SCR_LOGIN_ONLINE.qml @@ -789,6 +789,8 @@ QScreen { source: Draco.stayLoggedIn ? "qrc:/Images/Images/Checked_n.png" : "qrc:/Images/Images/UnChecked_n.png" MouseArea { anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor onClicked: {Draco.stayLoggedIn = !Draco.stayLoggedIn} } } @@ -800,6 +802,12 @@ QScreen { font.family: "Lato" font.pixelSize: 16 font.weight: Font.DemiBold + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: {Draco.stayLoggedIn = !Draco.stayLoggedIn} + } } } QText { diff --git a/Qml/Screens/OnlineMode/SCR_LOGIN_WITH_SOFTWARE_KEY.qml b/Qml/Screens/OnlineMode/SCR_LOGIN_WITH_SOFTWARE_KEY.qml index 7a171850..d0dfdda7 100644 --- a/Qml/Screens/OnlineMode/SCR_LOGIN_WITH_SOFTWARE_KEY.qml +++ b/Qml/Screens/OnlineMode/SCR_LOGIN_WITH_SOFTWARE_KEY.qml @@ -79,6 +79,14 @@ QScreen { } primary_key_name.showError = false; } + onEnterKeyRequest: { + commonError.visible = false + commonError.text = "" + var signIn = {"primary_key":primary_key, + "passphrase":_passphrase.textInputted + } + QMLHandle.sendEvent(EVT.EVT_PRIMARY_KEY_SIGNIN_ACCOUNT_REQUEST, signIn) + } } QText { id: commonError @@ -107,6 +115,8 @@ QScreen { source: Draco.stayLoggedIn ? "qrc:/Images/Images/Checked_n.png" : "qrc:/Images/Images/UnChecked_n.png" MouseArea { anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor onClicked: {Draco.stayLoggedIn = !Draco.stayLoggedIn} } } @@ -118,6 +128,12 @@ QScreen { font.family: "Lato" font.pixelSize: 16 font.weight: Font.Normal + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: {Draco.stayLoggedIn = !Draco.stayLoggedIn} + } } } } diff --git a/Qml/Screens/OnlineMode/SCR_SELECT_WALLET_CO_SIGN_POLICE.qml b/Qml/Screens/OnlineMode/SCR_SELECT_WALLET_CO_SIGN_POLICE.qml index 2201ef96..25c09c46 100644 --- a/Qml/Screens/OnlineMode/SCR_SELECT_WALLET_CO_SIGN_POLICE.qml +++ b/Qml/Screens/OnlineMode/SCR_SELECT_WALLET_CO_SIGN_POLICE.qml @@ -61,10 +61,10 @@ QScreen { labelTop: model.wallet_name labelCenter: qsTr("%1/%2 %3").arg(model.wallet_M).arg(model.wallet_N).arg(STR.STR_QML_069) labelBottom: model.wallet_Balance + RoomWalletData.unitValue - walletIcon: model.wallet_isSharedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : + icon: model.wallet_isSharedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : model.wallet_isAssistedWallet ? "qrc:/Images/Images/OnlineMode/Joint wallet_031F2B.png" : model.wallet_Escrow ? "qrc:/Images/Images/OnlineMode/Escrow Wallet.png" : "" - walletType: model.wallet_isSharedWallet ? STR.STR_QML_438 : + type: model.wallet_isSharedWallet ? STR.STR_QML_438 : model.wallet_isAssistedWallet ? STR.STR_QML_679 : "" selected: currentSelect === index onButtonClicked: { diff --git a/Qml/Screens/OnlineMode/SCR_SELECT_YOUR_LOCKDOWN_PERIOD.qml b/Qml/Screens/OnlineMode/SCR_SELECT_YOUR_LOCKDOWN_PERIOD.qml index 230e8a3b..acc1b6f0 100644 --- a/Qml/Screens/OnlineMode/SCR_SELECT_YOUR_LOCKDOWN_PERIOD.qml +++ b/Qml/Screens/OnlineMode/SCR_SELECT_YOUR_LOCKDOWN_PERIOD.qml @@ -34,7 +34,7 @@ import "../../../localization/STR_QML.js" as STR QScreen { id: _period property int questionSelected: 0 - property var qSelected : UserWallet.lockdownPeriods[questionSelected] + property var qSelected : UserWallet.periods[questionSelected] QOnScreenContentTypeB { width: popupWidth height: popupHeight @@ -66,7 +66,7 @@ QScreen { height: childrenRect.height spacing: 8 clip: true - model: UserWallet.lockdownPeriods + model: UserWallet.periods interactive: false delegate: Item { id: questionsdlg diff --git a/Qml/Screens/OnlineMode/SCR_SERVICE_SETTINGS.qml b/Qml/Screens/OnlineMode/SCR_SERVICE_SETTINGS.qml index fc3ddfa7..821d908e 100644 --- a/Qml/Screens/OnlineMode/SCR_SERVICE_SETTINGS.qml +++ b/Qml/Screens/OnlineMode/SCR_SERVICE_SETTINGS.qml @@ -151,21 +151,30 @@ QScreen { readonly property int _EMERGENCY_LOCKDOWN: 1 readonly property int _KEY_RECOVERY: 2 readonly property int _INHERITANCE_PLANING: 3 - readonly property int _CLAIM_AN_INHERITANCE: 4 - readonly property int _YOUR_SUBSCRIPTION: 5 - readonly property int _PLATFORM_KEY_CO_SIGNING_POLICIES: 6 - readonly property int _GET_ADDITIONAL_WALLETS: 7 - readonly property int _ORDER_NEW_HARDWARE: 8 - readonly property int _MANAGE_SUBSCRIPTION: 9 function isHoneyBadger(){ return ClientController.user.plan_slug === "honey_badger" } - + readonly property int _VIEW_INHERITANCE_PLANING: 4 + readonly property int _CLAIM_AN_INHERITANCE: 5 + readonly property int _YOUR_SUBSCRIPTION: 6 + readonly property int _PLATFORM_KEY_CO_SIGNING_POLICIES: 7 + readonly property int _GET_ADDITIONAL_WALLETS: 8 + readonly property int _ORDER_NEW_HARDWARE: 9 + readonly property int _MANAGE_SUBSCRIPTION: 10 readonly property var setting_map: [ {screen:_EMERGENCY, visible: true, enable:false, title:STR.STR_QML_702, icon: "qrc:/Images/Images/emergency-light.svg" ,action: function(){} }, {screen:_EMERGENCY_LOCKDOWN, visible: true, enable:true, title:STR.STR_QML_697, icon: "" ,action: function(){} }, {screen:_KEY_RECOVERY, visible: true, enable:true, title:STR.STR_QML_698, icon: "" ,action: function(){} }, {screen:_INHERITANCE_PLANING, visible: isHoneyBadger(), enable:false, title:STR.STR_QML_736, icon: "qrc:/Images/Images/inheritance-light.svg" ,action: function(){} }, + {screen:_VIEW_INHERITANCE_PLANING, visible: isHoneyBadger() && ServiceSetting.qAssistedSetuped.length > 0, enable:true, title:STR.STR_QML_875, icon: "" ,action: function(){ + ServiceSetting.qInheritanceWalletName = "" + if (ServiceSetting.qAssistedSetuped.length > 1) { + GlobalData.serviceIndex = _VIEW_INHERITANCE_PLANING + } else if (ServiceSetting.qAssistedSetuped.length === 1) { + QMLHandle.sendEvent(EVT.EVT_SERVICE_SELECT_WALLET_REQUEST, ServiceSetting.qAssistedSetuped[0]) + GlobalData.serviceIndex = _VIEW_INHERITANCE_PLANING + } + } }, {screen:_CLAIM_AN_INHERITANCE, visible: isHoneyBadger(), enable:true, title:STR.STR_QML_737, icon: "" ,action: function(){ GlobalData.serviceIndex = _CLAIM_AN_INHERITANCE ServiceSetting.claimInheritanceStatus = ServiceType.CI_NONE @@ -176,7 +185,14 @@ QScreen { var screenObj = { "state_id" : EVT.STATE_ID_SCR_SERVICE_SETTINGS } QMLHandle.sendEvent(EVT.EVT_REENTER_YOUR_PASSWORD_REQUEST,screenObj) } }, - {screen:_GET_ADDITIONAL_WALLETS,visible: false, enable:false, title:STR.STR_QML_707, icon: "" ,action: function(){} }, + {screen:_GET_ADDITIONAL_WALLETS,visible: true, enable:true, title:STR.STR_QML_707, icon: "" ,action: function(){ + UserWallet.additionalGetWalletConfig() + _InfoVer.link = "https://nunchuk.io/claim"; + var remainCount = ServiceSetting.qRemainingAssistedWalletCount; + _InfoVer.contentText = (remainCount > 1 ? STR.STR_QML_841 : STR.STR_QML_842).arg(remainCount); + _InfoVer.labels = [STR.STR_QML_341,STR.STR_QML_683]; + _InfoVer.open(); + } }, {screen:_ORDER_NEW_HARDWARE, visible: true, enable:true, title:STR.STR_QML_700, icon: "" ,action: function(){_InfoVer.link = "https://nunchuk.io/hardware-replacement";_InfoVer.contentText = STR.STR_QML_735;_InfoVer.labels = [STR.STR_QML_341,STR.STR_QML_683];_InfoVer.open();} }, {screen:_MANAGE_SUBSCRIPTION, visible: true, enable:true, title:STR.STR_QML_682, icon: "" ,action: function(){_InfoVer.link = "https://nunchuk.io/my-plan";_InfoVer.contentText = STR.STR_QML_684;_InfoVer.labels = [STR.STR_QML_341,STR.STR_QML_683];_InfoVer.open();}} ] @@ -590,6 +606,57 @@ QScreen { } } } + Item { + anchors.fill: parent + visible: GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING + enabled: visible + QViewInheritancePlaning { + anchors.fill: parent + visible: ServiceSetting.qInheritanceWalletName !== "" + } + QSelectAnAssistedWallet { + visible: ServiceSetting.qAssistedSetuped.length > 1 && ServiceSetting.qInheritanceWalletName === "" + } + Connections { + target: UserWallet + onSecurityQuestionChanged: { + if (GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING) { + _Security.action = function() { + QMLHandle.sendEvent(EVT.EVT_INHERITANCE_PLAN_FINALIZE_REQUEST, 3) + } + _Security.open(); + } + } + onSecurityQuestionClosed: { + if (GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING) { + _Security.close() + } + } + onInheritanceDummyTransactionAlert: { + if (GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING) { + _info1.contentText = STR.STR_QML_897 + _info1.open(); + } + } + onInheritanceInvalidActivationDateAlert: { + if (GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING) { + _info1.contentText = STR.STR_QML_896 + _info1.open(); + } + } + onInheritanceDiscardChangeAlert: { + if (GlobalData.serviceIndex === itemsSetting._VIEW_INHERITANCE_PLANING) { + _confirm.title = STR.STR_QML_024 + _confirm.contentText = STR.STR_QML_919 + _confirm.open(); + _confirm.fClose = function() { + ServiceSetting.qInheritanceWalletName = "" + GlobalData.serviceIndex = itemsSetting._CLAIM_AN_INHERITANCE + } + } + } + } + } Item { anchors.fill: parent visible: GlobalData.serviceIndex === itemsSetting._CLAIM_AN_INHERITANCE @@ -1088,6 +1155,9 @@ QScreen { } onSecurityQuestionChanged: { if (GlobalData.serviceIndex === itemsSetting._PLATFORM_KEY_CO_SIGNING_POLICIES) { + _Security.action = function() { + QMLHandle.sendEvent(EVT.EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED) + } _Security.open(); } } @@ -1498,8 +1568,19 @@ QScreen { close() } } + QConfirmYesNoPopup{ + id:_confirm + property var fClose + contentText: STR.STR_QML_919 + onConfirmNo: close() + onConfirmYes: { + close() + fClose() + } + } QPopupEmpty { id: _Security + property var action content: QAnswerSecurityQuestion { id:_popup width: 600 @@ -1527,7 +1608,7 @@ QScreen { } onNextClicked: { - QMLHandle.sendEvent(EVT.EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED) + _Security.action() _popup.clearText() } } diff --git a/Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml b/Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml new file mode 100644 index 00000000..7b86293e --- /dev/null +++ b/Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml @@ -0,0 +1,272 @@ +/************************************************************************** + * This file is part of the Nunchuk software (https://nunchuk.io/) * + * Copyright (C) 2020-2022 Enigmo * + * Copyright (C) 2022 Nunchuk * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 3 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + **************************************************************************/ +import QtQuick 2.4 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.12 +import HMIEVENTS 1.0 +import EWARNING 1.0 +import NUNCHUCKTYPE 1.0 +import DataPool 1.0 +import "../../Components/origins" +import "../../Components/customizes" +import "../../Components/customizes/Chats" +import "../../Components/customizes/Texts" +import "../../Components/customizes/Buttons" +import "../../Components/customizes/services" +import "../../../localization/STR_QML.js" as STR + +QScreen { + function fclose() { + QMLHandle.sendEvent(EVT.EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST, EVT.STATE_ID_SCR_SHARE_YOUR_SECRETS) + } + property string option: STR.STR_QML_881 + property string selectedOption: "" + + function findObj(obj, _property) { + if (obj.hasOwnProperty(_property)) return obj + else return findObj(obj.parent, _property) + } + + QOnScreenContentTypeB { + id: _Option + visible: selectedOption === "" + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_847 + onCloseClicked: fclose() + content: Item { + Column { + anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: -16 + spacing: 24 + QLato { + width: 539 + height: 56 + text: STR.STR_QML_880 + anchors.left: parent.left + font.weight: Font.Normal + lineHeight: 28 + lineHeightMode: Text.FixedHeight + wrapMode: Text.WrapAnywhere + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + } + Flickable { + width: 549 + height: 440 + contentWidth: width + contentHeight: _colum.childrenRect.height + ScrollBar.vertical: ScrollBar { active: true } + clip: true + Column { + id: _colum + anchors.fill: parent + spacing: 16 + QRadioButtonTypeF { + width: 539 + height: 116 + selected: option === labelTop + labelTop: STR.STR_QML_881 + labelBottom: STR.STR_QML_882 + onButtonClicked: { option = labelTop; } + } + QRadioButtonTypeF { + width: 539 + height: 144 + selected: option === labelTop + labelTop: STR.STR_QML_883 + labelBottom: STR.STR_QML_884 + onButtonClicked: { option = labelTop; } + } + QRadioButtonTypeF { + width: 539 + height: 172 + selected: option === labelTop + labelTop: STR.STR_QML_885 + labelBottom: STR.STR_QML_886 + onButtonClicked: { option = labelTop; } + } + } + } + } + } + bottomRight: QTextButton { + width: 98 + height: 48 + label.text: STR.STR_QML_097 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + _Option.nextClicked() + } + } + onPrevClicked: fclose() + onNextClicked: { + selectedOption = option + } + } + + QOnScreenContentTypeB { + visible: selectedOption === label.text + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_881 + onCloseClicked: fclose() + content: Item { + Row { + spacing: 36 + Rectangle { + width: 346 + height: 512 + radius: 24 + color: "#D0E2FF" + QImage { + width: 153 + height: 214 + anchors.centerIn: parent + source: "qrc:/Images/Images/inheritance_backup_password.svg" + } + } + QInheritanceDetails { + width: 346 + height: 512 + title: STR.STR_QML_887 + warning: STR.STR_QML_890 + } + } + } + bottomRight: QTextButton { + width: 71 + height: 48 + label.text: STR.STR_QML_777 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + findObj(parent, "nextClicked").nextClicked() + fclose() + } + } + bottomLeft: Item {} + onPrevClicked: fclose() + onNextClicked: { + AppModel.qInheritanceSecret = selectedOption + } + } + + QOnScreenContentTypeB { + visible: selectedOption === label.text + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_883 + onCloseClicked: fclose() + content: Item { + Row { + spacing: 36 + Rectangle { + width: 346 + height: 512 + radius: 24 + color: "#D0E2FF" + QImage { + width: 153 + height: 214 + anchors.centerIn: parent + source: "qrc:/Images/Images/inheritance_backup_password.svg" + } + } + QInheritanceDetails { + width: 346 + height: 512 + title: STR.STR_QML_891 + warning: STR.STR_QML_893 + } + } + } + bottomRight: QTextButton { + width: 71 + height: 48 + label.text: STR.STR_QML_777 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + findObj(parent, "nextClicked").nextClicked() + fclose() + } + } + bottomLeft: Item {} + onPrevClicked: fclose() + onNextClicked: { + AppModel.qInheritanceSecret = selectedOption + } + } + + QOnScreenContentTypeB { + visible: selectedOption === label.text + width: popupWidth + height: popupHeight + anchors.centerIn: parent + label.text: STR.STR_QML_885 + onCloseClicked: fclose() + content: Item { + Row { + spacing: 36 + Rectangle { + width: 346 + height: 512 + radius: 24 + color: "#D0E2FF" + QImage { + width: 153 + height: 214 + anchors.centerIn: parent + source: "qrc:/Images/Images/inheritance_backup_password.svg" + } + } + QInheritanceDetails { + width: 346 + height: 512 + title: STR.STR_QML_892 + warning: STR.STR_QML_894 + } + } + } + bottomRight: QTextButton { + width: 71 + height: 48 + label.text: STR.STR_QML_777 + label.font.pixelSize: 16 + type: eTypeE + onButtonClicked: { + findObj(parent, "nextClicked").nextClicked() + fclose() + } + } + bottomLeft: Item {} + onPrevClicked: fclose() + onNextClicked: { + AppModel.qInheritanceSecret = selectedOption + } + } + +} diff --git a/Views/Common/ViewStates.h b/Views/Common/ViewStates.h index 720c49de..36618711 100644 --- a/Views/Common/ViewStates.h +++ b/Views/Common/ViewStates.h @@ -25,10 +25,14 @@ #include "ViewsDefines.h" #include "ViewsEnums.h" #include "STATE_ID_ROOT.h" +#include "STATE_ID_SCR_ADD_COLDCARD.h" +#include "STATE_ID_SCR_ADD_COLDCARD_ASK.h" +#include "STATE_ID_SCR_ADD_COLDCARD_EXIST.h" #include "STATE_ID_SCR_ADD_HARDWARE_SIGNER.h" #include "STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET.h" #include "STATE_ID_SCR_ADD_LEDGER.h" #include "STATE_ID_SCR_ADD_LEDGER_ASK.h" +#include "STATE_ID_SCR_ADD_LEDGER_EXIST.h" #include "STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT.h" #include "STATE_ID_SCR_ADD_NEW_SIGNER.h" #include "STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET.h" @@ -36,6 +40,7 @@ #include "STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT.h" #include "STATE_ID_SCR_ADD_TREZOR.h" #include "STATE_ID_SCR_ADD_TREZOR_ASK.h" +#include "STATE_ID_SCR_ADD_TREZOR_EXIST.h" #include "STATE_ID_SCR_ADD_WALLET.h" #include "STATE_ID_SCR_ADD_WALLET_CONFIRMATION.h" #include "STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.h" @@ -50,6 +55,7 @@ #include "STATE_ID_SCR_CREATE_SHARED_WALLET.h" #include "STATE_ID_SCR_CREATE_TRANSACTION.h" #include "STATE_ID_SCR_DUMMY_TRANSACTION_INFO.h" +#include "STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h" #include "STATE_ID_SCR_ENTER_BACKUP_PASSWORD.h" #include "STATE_ID_SCR_HOME.h" #include "STATE_ID_SCR_HOME_ONLINE.h" @@ -82,6 +88,7 @@ #include "STATE_ID_SCR_SERVICE_SETTINGS.h" #include "STATE_ID_SCR_SHARED_WALLET_CONFIGURE.h" #include "STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION.h" +#include "STATE_ID_SCR_SHARE_YOUR_SECRETS.h" #include "STATE_ID_SCR_SIGN_IN.h" #include "STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY.h" #include "STATE_ID_SCR_SIGN_IN_MANUALLY.h" diff --git a/Views/Common/ViewsDefines.h b/Views/Common/ViewsDefines.h index 56a8eb64..9942630a 100644 --- a/Views/Common/ViewsDefines.h +++ b/Views/Common/ViewsDefines.h @@ -23,10 +23,14 @@ #define VIEWSDEFINES_H #define ROOT "" +#define SCR_ADD_COLDCARD "qrc:/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml" +#define SCR_ADD_COLDCARD_ASK "qrc:/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml" +#define SCR_ADD_COLDCARD_EXIST "qrc:/Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml" #define SCR_ADD_HARDWARE_SIGNER "qrc:/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER.qml" #define SCR_ADD_HARDWARE_SIGNER_TO_WALLET "qrc:/Qml/Screens/LocalMode/SCR_ADD_HARDWARE_SIGNER_TO_WALLET.qml" #define SCR_ADD_LEDGER "qrc:/Qml/Screens/OnlineMode/SCR_ADD_LEDGER.qml" #define SCR_ADD_LEDGER_ASK "qrc:/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_ASK.qml" +#define SCR_ADD_LEDGER_EXIST "qrc:/Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml" #define SCR_ADD_MASTER_SIGNER_RESULT "qrc:/Qml/Screens/LocalMode/SCR_ADD_MASTER_SIGNER_RESULT.qml" #define SCR_ADD_NEW_SIGNER "qrc:/Qml/Screens/LocalMode/SCR_ADD_NEW_SIGNER.qml" #define SCR_ADD_NEW_SIGNER_TO_WALLET "qrc:/Qml/Screens/LocalMode/SCR_ADD_NEW_SIGNER_TO_WALLET.qml" @@ -34,6 +38,7 @@ #define SCR_ADD_REMOTE_SIGNER_RESULT "qrc:/Qml/Screens/LocalMode/SCR_ADD_REMOTE_SIGNER_RESULT.qml" #define SCR_ADD_TREZOR "qrc:/Qml/Screens/OnlineMode/SCR_ADD_TREZOR.qml" #define SCR_ADD_TREZOR_ASK "qrc:/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_ASK.qml" +#define SCR_ADD_TREZOR_EXIST "qrc:/Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml" #define SCR_ADD_WALLET "qrc:/Qml/Screens/LocalMode/SCR_ADD_WALLET.qml" #define SCR_ADD_WALLET_CONFIRMATION "qrc:/Qml/Screens/LocalMode/SCR_ADD_WALLET_CONFIRMATION.qml" #define SCR_ADD_WALLET_SIGNER_CONFIGURATION "qrc:/Qml/Screens/LocalMode/SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml" @@ -47,8 +52,9 @@ #define SCR_CREATE_NEW_SEED "qrc:/Qml/Screens/LocalMode/SCR_CREATE_NEW_SEED.qml" #define SCR_CREATE_SHARED_WALLET "qrc:/Qml/Screens/OnlineMode/SCR_CREATE_SHARED_WALLET.qml" #define SCR_CREATE_TRANSACTION "qrc:/Qml/Screens/LocalMode/SCR_CREATE_TRANSACTION.qml" -#define SCR_DUMMY_TRANSACTION_INFO "qrc:/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml" -#define SCR_ENTER_BACKUP_PASSWORD "qrc:/Qml/Screens/OnlineMode/SCR_ENTER_BACKUP_PASSWORD.qml" +#define SCR_DUMMY_TRANSACTION_INFO "qrc:/Qml/Screens/OnlineMode/SCR_DUMMY_TRANSACTION_INFO.qml" +#define SCR_EDIT_YOUR_INHERITANCE_PLAN "qrc:/Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml" +#define SCR_ENTER_BACKUP_PASSWORD "qrc:/Qml/Screens/OnlineMode/SCR_ENTER_BACKUP_PASSWORD.qml" #define SCR_HOME "qrc:/Qml/Screens/LocalMode/SCR_HOME.qml" #define SCR_HOME_ONLINE "qrc:/Qml/Screens/OnlineMode/SCR_HOME_ONLINE.qml" #define SCR_INPUT_PASSPHRASE "qrc:/Qml/Screens/LocalMode/SCR_INPUT_PASSPHRASE.qml" @@ -77,6 +83,7 @@ #define SCR_SERVICE_SETTINGS "qrc:/Qml/Screens/OnlineMode/SCR_SERVICE_SETTINGS.qml" #define SCR_SHARED_WALLET_CONFIGURE "qrc:/Qml/Screens/OnlineMode/SCR_SHARED_WALLET_CONFIGURE.qml" #define SCR_SHARED_WL_DEVICE_REGISTRATION "qrc:/Qml/Screens/OnlineMode/SCR_SHARED_WL_DEVICE_REGISTRATION.qml" +#define SCR_SHARE_YOUR_SECRETS "qrc:/Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml" #define SCR_SIGN_IN "qrc:/Qml/Screens/OnlineMode/SCR_SIGN_IN.qml" #define SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY "qrc:/Qml/Screens/OnlineMode/SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY.qml" #define SCR_SIGN_IN_MANUALLY "qrc:/Qml/Screens/OnlineMode/SCR_SIGN_IN_MANUALLY.qml" diff --git a/Views/Common/ViewsEnums.h b/Views/Common/ViewsEnums.h index 5a74b98a..b3b7b711 100644 --- a/Views/Common/ViewsEnums.h +++ b/Views/Common/ViewsEnums.h @@ -100,6 +100,13 @@ class E: public QObject Q_ENUMS(EVT_STATE_ID_SCR_ADD_LEDGER) Q_ENUMS(EVT_STATE_ID_SCR_ADD_TREZOR) Q_ENUMS(EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE) + Q_ENUMS(EVT_STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN) + Q_ENUMS(EVT_STATE_ID_SCR_SHARE_YOUR_SECRETS) + Q_ENUMS(EVT_STATE_ID_SCR_ADD_COLDCARD_ASK) + Q_ENUMS(EVT_STATE_ID_SCR_ADD_COLDCARD) + Q_ENUMS(EVT_STATE_ID_SCR_ADD_LEDGER_EXIST) + Q_ENUMS(EVT_STATE_ID_SCR_ADD_TREZOR_EXIST) + Q_ENUMS(EVT_STATE_ID_SCR_ADD_COLDCARD_EXIST) public: enum EVT_STATE_ID_REGISTED { @@ -177,749 +184,814 @@ class E: public QObject STATE_ID_SCR_ADD_LEDGER , // 71 STATE_ID_SCR_ADD_TREZOR , // 72 STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE , // 73 - EVT_STATE_ID_REGISTED_MAX , // 74 + STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN , // 74 + STATE_ID_SCR_SHARE_YOUR_SECRETS , // 75 + STATE_ID_SCR_ADD_COLDCARD_ASK , // 76 + STATE_ID_SCR_ADD_COLDCARD , // 77 + STATE_ID_SCR_ADD_LEDGER_EXIST , // 78 + STATE_ID_SCR_ADD_TREZOR_EXIST , // 79 + STATE_ID_SCR_ADD_COLDCARD_EXIST , // 80 + EVT_STATE_ID_REGISTED_MAX , // 81 }; enum EVT_STATE_ID_ROOT { - EVT_STATE_ID_ROOT_MIN=EVT_STATE_ID_REGISTED_MAX+1, // 75 - EVT_STARTING_APPLICATION_LOCALMODE , // 76 - EVT_STARTING_APPLICATION_ONLINEMODE , // 77 - EVT_STARTING_APPLICATION_ONLINE_HWL , // 78 - EVT_SETTING_ACCOUNT_CHANGE_PASSWORD , // 79 - EVT_ONS_CLOSE_ALL_REQUEST , // 80 - EVT_ROOT_SIGN_IN_PRIMARY_KEY_REQUEST , // 81 - EVT_ROOT_CREATE_PRIMARY_KEY_REQUEST , // 82 - EVT_GOTO_HOME_WALLET_TAB , // 83 - EVT_ONS_CLOSE_REQUEST , // 84 - EVT_LOGIN_DB_REQUEST , // 85 - EVT_ROOT_PROMT_PIN , // 86 - EVT_ROOT_PROMT_PASSPHRASE , // 87 - EVT_LOGIN_MATRIX_REQUEST , // 88 - EVT_GOTO_HOME_CHAT_TAB , // 89 - EVT_ONLINE_ONS_CLOSE_REQUEST , // 90 - EVT_SHOW_TOAST_MESSAGE , // 91 - EVT_ROOT_UPDATE_PROFILE , // 92 - EVT_SHOW_CREATE_ACCOUNT_REQUEST , // 93 - EVT_GOTO_APP_SETTINGS_TAB , // 94 - EVT_SIGN_IN_REQUEST , // 95 - EVT_ROOT_ENTRY_PRIMARY_KEY_REQUEST , // 96 - EVT_LOGIN_WITH_SOFTWARE_KEY_REQUEST , // 97 - EVT_GOTO_SERVICE_SETTING_TAB , // 98 - EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST , // 99 - EVT_NUNCHUK_LOGIN_SUCCEEDED , // 100 - EVT_STATE_ID_ROOT_MAX , // 101 + EVT_STATE_ID_ROOT_MIN=EVT_STATE_ID_REGISTED_MAX+1, // 82 + EVT_STARTING_APPLICATION_LOCALMODE , // 83 + EVT_STARTING_APPLICATION_ONLINEMODE , // 84 + EVT_STARTING_APPLICATION_ONLINE_HWL , // 85 + EVT_SETTING_ACCOUNT_CHANGE_PASSWORD , // 86 + EVT_ONS_CLOSE_ALL_REQUEST , // 87 + EVT_ROOT_SIGN_IN_PRIMARY_KEY_REQUEST , // 88 + EVT_ROOT_CREATE_PRIMARY_KEY_REQUEST , // 89 + EVT_GOTO_HOME_WALLET_TAB , // 90 + EVT_ONS_CLOSE_REQUEST , // 91 + EVT_LOGIN_DB_REQUEST , // 92 + EVT_ROOT_PROMT_PIN , // 93 + EVT_ROOT_PROMT_PASSPHRASE , // 94 + EVT_LOGIN_MATRIX_REQUEST , // 95 + EVT_GOTO_HOME_CHAT_TAB , // 96 + EVT_ONLINE_ONS_CLOSE_REQUEST , // 97 + EVT_SHOW_TOAST_MESSAGE , // 98 + EVT_ROOT_UPDATE_PROFILE , // 99 + EVT_SHOW_CREATE_ACCOUNT_REQUEST , // 100 + EVT_GOTO_APP_SETTINGS_TAB , // 101 + EVT_SIGN_IN_REQUEST , // 102 + EVT_ROOT_ENTRY_PRIMARY_KEY_REQUEST , // 103 + EVT_LOGIN_WITH_SOFTWARE_KEY_REQUEST , // 104 + EVT_GOTO_SERVICE_SETTING_TAB , // 105 + EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST , // 106 + EVT_NUNCHUK_LOGIN_SUCCEEDED , // 107 + EVT_STATE_ID_ROOT_MAX , // 108 }; enum EVT_STATE_ID_SCR_HOME { - EVT_STATE_ID_SCR_HOME_MIN=EVT_STATE_ID_ROOT_MAX+1, // 102 - EVT_HOME_WALLET_SELECTED , // 103 - EVT_HOME_WALLET_COPY_ADDRESS , // 104 - EVT_HOME_SETTING_REQUEST , // 105 - EVT_HOME_DISPLAY_ADDRESS , // 106 - EVT_HOME_IMPORT_PSBT , // 107 - EVT_HOME_EXPORT_BSMS , // 108 - EVT_HOME_ADD_WALLET_REQUEST , // 109 - EVT_HOME_MASTER_SIGNER_INFO_REQUEST , // 110 - EVT_HOME_SEND_REQUEST , // 111 - EVT_HOME_RECEIVE_REQUEST , // 112 - EVT_HOME_TRANSACTION_HISTORY_REQUEST , // 113 - EVT_HOME_WALLET_INFO_REQUEST , // 114 - EVT_HOME_TRANSACTION_INFO_REQUEST , // 115 - EVT_HOME_REMOTE_SIGNER_INFO_REQUEST , // 116 - EVT_HOME_ADD_NEW_SIGNER_REQUEST , // 117 - EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST , // 118 - EVT_ASK_LEDGER_REQ , // 119 - EVT_ASK_TREZOR_REQ , // 120 - EVT_STATE_ID_SCR_HOME_MAX , // 121 + EVT_STATE_ID_SCR_HOME_MIN=EVT_STATE_ID_ROOT_MAX+1, // 109 + EVT_HOME_WALLET_SELECTED , // 110 + EVT_HOME_WALLET_COPY_ADDRESS , // 111 + EVT_HOME_SETTING_REQUEST , // 112 + EVT_HOME_DISPLAY_ADDRESS , // 113 + EVT_HOME_IMPORT_PSBT , // 114 + EVT_HOME_EXPORT_BSMS , // 115 + EVT_HOME_ADD_WALLET_REQUEST , // 116 + EVT_HOME_MASTER_SIGNER_INFO_REQUEST , // 117 + EVT_HOME_SEND_REQUEST , // 118 + EVT_HOME_RECEIVE_REQUEST , // 119 + EVT_HOME_TRANSACTION_HISTORY_REQUEST , // 120 + EVT_HOME_WALLET_INFO_REQUEST , // 121 + EVT_HOME_TRANSACTION_INFO_REQUEST , // 122 + EVT_HOME_REMOTE_SIGNER_INFO_REQUEST , // 123 + EVT_HOME_ADD_NEW_SIGNER_REQUEST , // 124 + EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST , // 125 + EVT_ASK_LEDGER_REQ , // 126 + EVT_ASK_TREZOR_REQ , // 127 + EVT_EXIST_LEDGER_REQ , // 128 + EVT_EXIST_TREZOR_REQ , // 129 + EVT_EXIST_COLDCARD_REQ , // 130 + EVT_ASK_COLDCARD_REQ , // 131 + EVT_STATE_ID_SCR_HOME_MAX , // 132 }; enum EVT_STATE_ID_SCR_ADD_WALLET { - EVT_STATE_ID_SCR_ADD_WALLET_MIN=EVT_STATE_ID_SCR_HOME_MAX+1, // 122 - EVT_ADD_WALLET_IMPORT , // 123 - EVT_ADD_WALLET_BACK_REQUEST , // 124 - EVT_ADD_WALLET_SIGNER_CONFIGURATION_REQUEST , // 125 - EVT_ADD_WALLET_IMPORT_SUCCEED , // 126 - EVT_STATE_ID_SCR_ADD_WALLET_MAX , // 127 + EVT_STATE_ID_SCR_ADD_WALLET_MIN=EVT_STATE_ID_SCR_HOME_MAX+1, // 133 + EVT_ADD_WALLET_IMPORT , // 134 + EVT_ADD_WALLET_BACK_REQUEST , // 135 + EVT_ADD_WALLET_SIGNER_CONFIGURATION_REQUEST , // 136 + EVT_ADD_WALLET_IMPORT_SUCCEED , // 137 + EVT_STATE_ID_SCR_ADD_WALLET_MAX , // 138 }; enum EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER { - EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_WALLET_MAX+1, // 128 - EVT_ADD_HARDWARE_SIGNER_ADD_MASTER_SIGNER_REQUEST , // 129 - EVT_ADD_HARDWARE_SIGNER_REFRESH_REQUEST , // 130 - EVT_ADD_HARDWARE_SIGNER_ADD_REMOTE_SIGNER_REQUEST , // 131 - EVT_ADD_HARDWARE_SIGNER_PROMT_PIN_REQUEST , // 132 - EVT_ADD_HARDWARE_SIGNER_SEND_PIN_REQUEST , // 133 - EVT_ADD_MASTER_SIGNER_RESULT , // 134 - EVT_ADD_REMOTE_SIGNER_RESULT , // 135 - EVT_ADD_HARDWARE_SIGNER_BACK_REQUEST , // 136 - EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MAX , // 137 + EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_WALLET_MAX+1, // 139 + EVT_ADD_HARDWARE_SIGNER_ADD_MASTER_SIGNER_REQUEST , // 140 + EVT_ADD_HARDWARE_SIGNER_REFRESH_REQUEST , // 141 + EVT_ADD_HARDWARE_SIGNER_ADD_REMOTE_SIGNER_REQUEST , // 142 + EVT_ADD_HARDWARE_SIGNER_PROMT_PIN_REQUEST , // 143 + EVT_ADD_HARDWARE_SIGNER_SEND_PIN_REQUEST , // 144 + EVT_ADD_MASTER_SIGNER_RESULT , // 145 + EVT_ADD_REMOTE_SIGNER_RESULT , // 146 + EVT_ADD_HARDWARE_SIGNER_BACK_REQUEST , // 147 + EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MAX , // 148 }; enum EVT_STATE_ID_SCR_MASTER_SIGNER_INFO { - EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MIN=EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MAX+1, // 138 - EVT_MASTER_SIGNER_INFO_EDIT_NAME , // 139 - EVT_MASTER_SIGNER_INFO_HEALTH_CHECK , // 140 - EVT_MASTER_SIGNER_INFO_REMOVE_REQUEST , // 141 - EVT_MASTER_SIGNER_INFO_PROMT_PIN , // 142 - EVT_MASTER_SIGNER_INFO_SEND_PIN , // 143 - EVT_MASTER_SIGNER_INFO_SEND_PASSPHRASE , // 144 - EVT_MASTER_SIGNER_INFO_GET_XPUBS , // 145 - EVT_MASTER_SIGNER_INFO_BACK_REQUEST , // 146 - EVT_MASTER_SIGNER_INFO_BACK_WALLET_INFO , // 147 - EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MAX , // 148 + EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MIN=EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_MAX+1, // 149 + EVT_MASTER_SIGNER_INFO_EDIT_NAME , // 150 + EVT_MASTER_SIGNER_INFO_HEALTH_CHECK , // 151 + EVT_MASTER_SIGNER_INFO_REMOVE_REQUEST , // 152 + EVT_MASTER_SIGNER_INFO_PROMT_PIN , // 153 + EVT_MASTER_SIGNER_INFO_SEND_PIN , // 154 + EVT_MASTER_SIGNER_INFO_SEND_PASSPHRASE , // 155 + EVT_MASTER_SIGNER_INFO_GET_XPUBS , // 156 + EVT_MASTER_SIGNER_INFO_BACK_REQUEST , // 157 + EVT_MASTER_SIGNER_INFO_BACK_WALLET_INFO , // 158 + EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MAX , // 159 }; enum EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION { - EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MIN=EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MAX+1, // 149 - EVT_SIGNER_CONFIGURATION_SELECT_MASTER_SIGNER , // 150 - EVT_SIGNER_CONFIGURATION_REMOVE_SIGNER , // 151 - EVT_SIGNER_CONFIGURATION_SELECT_REMOTE_SIGNER , // 152 - EVT_SIGNER_CONFIGURATION_MASTER_SIGNER_SEND_PASSPHRASE , // 153 - EVT_SIGNER_CONFIGURATION_TRY_REVIEW , // 154 - EVT_ADD_WALLET_SIGNER_CONFIGURATION_BACK , // 155 - EVT_ADD_WALLET_SIGNER_CONFIGURATION_REVIEW , // 156 - EVT_ADD_SIGNER_TO_WALLET_REQUEST , // 157 - EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MAX , // 158 + EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MIN=EVT_STATE_ID_SCR_MASTER_SIGNER_INFO_MAX+1, // 160 + EVT_SIGNER_CONFIGURATION_SELECT_MASTER_SIGNER , // 161 + EVT_SIGNER_CONFIGURATION_REMOVE_SIGNER , // 162 + EVT_SIGNER_CONFIGURATION_SELECT_REMOTE_SIGNER , // 163 + EVT_SIGNER_CONFIGURATION_MASTER_SIGNER_SEND_PASSPHRASE , // 164 + EVT_SIGNER_CONFIGURATION_TRY_REVIEW , // 165 + EVT_ADD_WALLET_SIGNER_CONFIGURATION_BACK , // 166 + EVT_ADD_WALLET_SIGNER_CONFIGURATION_REVIEW , // 167 + EVT_ADD_SIGNER_TO_WALLET_REQUEST , // 168 + EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MAX , // 169 }; enum EVT_STATE_ID_SCR_RECEIVE { - EVT_STATE_ID_SCR_RECEIVE_MIN=EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MAX+1, // 159 - EVT_BTN_GEN_NEW_ADDRESS , // 160 - EVT_RECEIVE_COPY_ADDRESS , // 161 - EVT_RECEIVE_SET_QUICK_RECEIVE_ADDRESS , // 162 - EVT_RECEIVE_DISPLAY_ADDRESS , // 163 - EVT_RECEIVE_ADDRESS_BALANCE , // 164 - EVT_RECEIVE_BACK_REQUEST , // 165 - EVT_STATE_ID_SCR_RECEIVE_MAX , // 166 + EVT_STATE_ID_SCR_RECEIVE_MIN=EVT_STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION_MAX+1, // 170 + EVT_BTN_GEN_NEW_ADDRESS , // 171 + EVT_RECEIVE_COPY_ADDRESS , // 172 + EVT_RECEIVE_SET_QUICK_RECEIVE_ADDRESS , // 173 + EVT_RECEIVE_DISPLAY_ADDRESS , // 174 + EVT_RECEIVE_ADDRESS_BALANCE , // 175 + EVT_RECEIVE_BACK_REQUEST , // 176 + EVT_STATE_ID_SCR_RECEIVE_MAX , // 177 }; enum EVT_STATE_ID_SCR_SEND { - EVT_STATE_ID_SCR_SEND_MIN=EVT_STATE_ID_SCR_RECEIVE_MAX+1, // 167 - EVT_SEND_ADD_DESTINATION_REQUEST , // 168 - EVT_SEND_CREATE_TRANSACTION_REQUEST , // 169 - EVT_SEND_BACK_REQUEST , // 170 - EVT_SEND_CREATE_TRANSACTION_SUCCEED , // 171 - EVT_SEND_BACK_HOME_SHARED_WL , // 172 - EVT_STATE_ID_SCR_SEND_MAX , // 173 + EVT_STATE_ID_SCR_SEND_MIN=EVT_STATE_ID_SCR_RECEIVE_MAX+1, // 178 + EVT_SEND_ADD_DESTINATION_REQUEST , // 179 + EVT_SEND_CREATE_TRANSACTION_REQUEST , // 180 + EVT_SEND_BACK_REQUEST , // 181 + EVT_SEND_CREATE_TRANSACTION_SUCCEED , // 182 + EVT_SEND_BACK_HOME_SHARED_WL , // 183 + EVT_STATE_ID_SCR_SEND_MAX , // 184 }; enum EVT_STATE_ID_SCR_CREATE_TRANSACTION { - EVT_STATE_ID_SCR_CREATE_TRANSACTION_MIN=EVT_STATE_ID_SCR_SEND_MAX+1, // 174 - EVT_CREATE_TRANSACTION_MAKE_DRAFT_TX , // 175 - EVT_CREATE_TRANSACTION_SAVE_REQUEST , // 176 - EVT_CREATE_TRANSACTION_UTXO_SORT_REQUEST , // 177 - EVT_CREATE_TRANSACTION_SIGN_REQUEST , // 178 - EVT_CREATE_TRANSACTION_BACK_REQUEST , // 179 - EVT_CREATE_TRANSACTION_SIGN_SUCCEED , // 180 - EVR_CREATE_TRANSACTION_BACK_UTXO_CONSILIDATE , // 181 - EVT_STATE_ID_SCR_CREATE_TRANSACTION_MAX , // 182 + EVT_STATE_ID_SCR_CREATE_TRANSACTION_MIN=EVT_STATE_ID_SCR_SEND_MAX+1, // 185 + EVT_CREATE_TRANSACTION_MAKE_DRAFT_TX , // 186 + EVT_CREATE_TRANSACTION_SAVE_REQUEST , // 187 + EVT_CREATE_TRANSACTION_UTXO_SORT_REQUEST , // 188 + EVT_CREATE_TRANSACTION_SIGN_REQUEST , // 189 + EVT_CREATE_TRANSACTION_BACK_REQUEST , // 190 + EVT_CREATE_TRANSACTION_SIGN_SUCCEED , // 191 + EVR_CREATE_TRANSACTION_BACK_UTXO_CONSILIDATE , // 192 + EVT_STATE_ID_SCR_CREATE_TRANSACTION_MAX , // 193 }; enum EVT_STATE_ID_SCR_TRANSACTION_INFO { - EVT_STATE_ID_SCR_TRANSACTION_INFO_MIN=EVT_STATE_ID_SCR_CREATE_TRANSACTION_MAX+1, // 183 - EVT_TRANSACTION_SIGN_REQUEST , // 184 - EVT_TRANSACTION_EXPORT_REQUEST , // 185 - EVT_TRANSACTION_EXPORT_QRCODE , // 186 - EVT_TRANSACTION_IMPORT_REQUEST , // 187 - EVT_TRANSACTION_IMPORT_QRCODE , // 188 - EVT_TRANSACTION_BROADCAST_REQUEST , // 189 - EVT_TRANSACTION_SET_MEMO_REQUEST , // 190 - EVT_TRANSACTION_SCAN_DEVICE_REQUEST , // 191 - EVT_TRANSACTION_REMOVE_REQUEST , // 192 - EVT_TRANSACTION_SEND_PIN_REQUEST , // 193 - EVT_TRANSACTION_PROMT_PIN_REQUEST , // 194 - EVT_TRANSACTION_VERIFY_ADDRESS , // 195 - EVT_TRANSACTION_SEND_PASSPHRASE , // 196 - EVT_TRANSACTION_CANCEL_REQUEST , // 197 - EVT_TRANSACTION_INFO_BACK_REQUEST , // 198 - EVT_TRANSACTION_INFO_BACK_TO_CREATE_TRANSACTION_REQUEST , // 199 - EVT_TRANSACTION_REPLACE_BY_FEE_REQUEST , // 200 - EVT_TRANSACTION_INFO_BACK_UTXO_INFO , // 201 - EVT_STATE_ID_SCR_TRANSACTION_INFO_MAX , // 202 + EVT_STATE_ID_SCR_TRANSACTION_INFO_MIN=EVT_STATE_ID_SCR_CREATE_TRANSACTION_MAX+1, // 194 + EVT_TRANSACTION_SIGN_REQUEST , // 195 + EVT_TRANSACTION_EXPORT_REQUEST , // 196 + EVT_TRANSACTION_EXPORT_QRCODE , // 197 + EVT_TRANSACTION_IMPORT_REQUEST , // 198 + EVT_TRANSACTION_IMPORT_QRCODE , // 199 + EVT_TRANSACTION_BROADCAST_REQUEST , // 200 + EVT_TRANSACTION_SET_MEMO_REQUEST , // 201 + EVT_TRANSACTION_SCAN_DEVICE_REQUEST , // 202 + EVT_TRANSACTION_REMOVE_REQUEST , // 203 + EVT_TRANSACTION_SEND_PIN_REQUEST , // 204 + EVT_TRANSACTION_PROMT_PIN_REQUEST , // 205 + EVT_TRANSACTION_VERIFY_ADDRESS , // 206 + EVT_TRANSACTION_SEND_PASSPHRASE , // 207 + EVT_TRANSACTION_CANCEL_REQUEST , // 208 + EVT_TRANSACTION_INFO_BACK_REQUEST , // 209 + EVT_TRANSACTION_INFO_BACK_TO_CREATE_TRANSACTION_REQUEST , // 210 + EVT_TRANSACTION_REPLACE_BY_FEE_REQUEST , // 211 + EVT_TRANSACTION_INFO_BACK_UTXO_INFO , // 212 + EVT_STATE_ID_SCR_TRANSACTION_INFO_MAX , // 213 }; enum EVT_STATE_ID_SCR_TRANSACTION_HISTORY { - EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MIN=EVT_STATE_ID_SCR_TRANSACTION_INFO_MAX+1, // 203 - EVT_TRANSACTION_HISTORY_SORT_REQUEST , // 204 - EVT_TRANSACTION_HISTORY_BACK_REQUEST , // 205 - EVT_TRANSACTION_INFO_ITEM_SELECTED , // 206 - EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MAX , // 207 + EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MIN=EVT_STATE_ID_SCR_TRANSACTION_INFO_MAX+1, // 214 + EVT_TRANSACTION_HISTORY_SORT_REQUEST , // 215 + EVT_TRANSACTION_HISTORY_BACK_REQUEST , // 216 + EVT_TRANSACTION_INFO_ITEM_SELECTED , // 217 + EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MAX , // 218 }; enum EVT_STATE_ID_SCR_APP_SETTINGS { - EVT_STATE_ID_SCR_APP_SETTINGS_MIN=EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MAX+1, // 208 - EVT_APP_SETTING_DELETE_ACCOUNT_REQUEST , // 209 - EVT_APP_SETTING_CHANGE_PASSPHRASE , // 210 - EVT_APP_SETTING_REQUEST_RESTART , // 211 - EVT_APP_SETTING_REQUEST_RESCAN , // 212 - EVT_APP_SETTING_DELETE_PRIMARY_KEY_ACCOUNT_REQUEST , // 213 - EVT_APP_SETTING_BACK_REQUEST , // 214 - EVT_APP_SETTING_BACK_TO_ONLINE_MODE , // 215 - EVT_SHOW_REPLACE_PRIMARY_KEY_REQUEST , // 216 - EVT_STATE_ID_SCR_APP_SETTINGS_MAX , // 217 + EVT_STATE_ID_SCR_APP_SETTINGS_MIN=EVT_STATE_ID_SCR_TRANSACTION_HISTORY_MAX+1, // 219 + EVT_APP_SETTING_DELETE_ACCOUNT_REQUEST , // 220 + EVT_APP_SETTING_CHANGE_PASSPHRASE , // 221 + EVT_APP_SETTING_REQUEST_RESTART , // 222 + EVT_APP_SETTING_REQUEST_RESCAN , // 223 + EVT_APP_SETTING_DELETE_PRIMARY_KEY_ACCOUNT_REQUEST , // 224 + EVT_APP_SETTING_BACK_REQUEST , // 225 + EVT_APP_SETTING_BACK_TO_ONLINE_MODE , // 226 + EVT_SHOW_REPLACE_PRIMARY_KEY_REQUEST , // 227 + EVT_STATE_ID_SCR_APP_SETTINGS_MAX , // 228 }; enum EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT { - EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MIN=EVT_STATE_ID_SCR_APP_SETTINGS_MAX+1, // 218 - EVT_REMOTE_SIGNER_RESULT_HEALTH_CHECK , // 219 - EVT_REMOTE_SIGNER_RESULT_EDIT_NAME , // 220 - EVT_REMOTE_SIGNER_RESULT_IMPORT_SIGNATURE , // 221 - EVT_REMOTE_SIGNER_RESULT_EXPORT_MESSAGE , // 222 - EVT_REMOTE_SIGNER_RESULT_GET_XPUBS , // 223 - EVT_REMOTE_SIGNER_RESULT_DELETE_REQUEST , // 224 - EVT_REMOTE_SIGNER_RESULT_CONFIRM_ADD_TO_WALLET_SIGNER_CONFIG , // 225 - EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MAX , // 226 + EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MIN=EVT_STATE_ID_SCR_APP_SETTINGS_MAX+1, // 229 + EVT_REMOTE_SIGNER_RESULT_HEALTH_CHECK , // 230 + EVT_REMOTE_SIGNER_RESULT_EDIT_NAME , // 231 + EVT_REMOTE_SIGNER_RESULT_IMPORT_SIGNATURE , // 232 + EVT_REMOTE_SIGNER_RESULT_EXPORT_MESSAGE , // 233 + EVT_REMOTE_SIGNER_RESULT_GET_XPUBS , // 234 + EVT_REMOTE_SIGNER_RESULT_DELETE_REQUEST , // 235 + EVT_REMOTE_SIGNER_RESULT_CONFIRM_ADD_TO_WALLET_SIGNER_CONFIG , // 236 + EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MAX , // 237 }; enum EVT_STATE_ID_SCR_UTXOS { - EVT_STATE_ID_SCR_UTXOS_MIN=EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MAX+1, // 227 - EVT_UTXOS_SORT_REQUEST , // 228 - EVT_UTXOS_BACK_REQUEST , // 229 - EVT_UTXOS_CONSOLIDATE_REQUEST , // 230 - EVT_UTXOS_ITEM_SELECTED , // 231 - EVT_UTXO_OUTPUT_BACK_SHARED_WALLET , // 232 - EVT_STATE_ID_SCR_UTXOS_MAX , // 233 + EVT_STATE_ID_SCR_UTXOS_MIN=EVT_STATE_ID_SCR_ADD_REMOTE_SIGNER_RESULT_MAX+1, // 238 + EVT_UTXOS_SORT_REQUEST , // 239 + EVT_UTXOS_BACK_REQUEST , // 240 + EVT_UTXOS_CONSOLIDATE_REQUEST , // 241 + EVT_UTXOS_ITEM_SELECTED , // 242 + EVT_UTXO_OUTPUT_BACK_SHARED_WALLET , // 243 + EVT_STATE_ID_SCR_UTXOS_MAX , // 244 }; enum EVT_STATE_ID_SCR_WALLET_INFO { - EVT_STATE_ID_SCR_WALLET_INFO_MIN=EVT_STATE_ID_SCR_UTXOS_MAX+1, // 234 - EVT_WALLET_INFO_EDIT_NAME , // 235 - EVT_WALLET_INFO_REMOVE , // 236 - EVT_WALLET_INFO_EXPORT_DB , // 237 - EVT_WALLET_INFO_EXPORT_CSV , // 238 - EVT_WALLET_INFO_EXPORT_DESCRIPTOR , // 239 - EVT_WALLET_INFO_EXPORT_COLDCARD , // 240 - EVT_WALLET_INFO_EXPORT_QRCODE , // 241 - EVT_WALLET_INFO_SIGNER_INFO_REQUEST , // 242 - EVT_WALLET_INFO_EDIT_DESCRIPTION , // 243 - EVT_WALLET_INFO_IMPORT_PSBT , // 244 - EVT_WALLET_INFO_REFRESH_WALLET_REQUEST , // 245 - EVT_WALLET_INFO_GAP_LIMIT_REQUEST , // 246 - EVT_WALLET_INFO_BACK_REQUEST , // 247 - EVT_WALLET_INFO_UTXOS_REQUEST , // 248 - EVT_WALLET_INFO_CHANGE_ADDRESS_REQUEST , // 249 - EVT_WALLET_INFO_MASTER_SIGNER_INFO_REQUEST , // 250 - EVT_WALLET_INFO_REMOTE_SIGNER_INFO_REQUEST , // 251 - EVT_STATE_ID_SCR_WALLET_INFO_MAX , // 252 + EVT_STATE_ID_SCR_WALLET_INFO_MIN=EVT_STATE_ID_SCR_UTXOS_MAX+1, // 245 + EVT_WALLET_INFO_EDIT_NAME , // 246 + EVT_WALLET_INFO_REMOVE , // 247 + EVT_WALLET_INFO_EXPORT_DB , // 248 + EVT_WALLET_INFO_EXPORT_CSV , // 249 + EVT_WALLET_INFO_EXPORT_DESCRIPTOR , // 250 + EVT_WALLET_INFO_EXPORT_COLDCARD , // 251 + EVT_WALLET_INFO_EXPORT_QRCODE , // 252 + EVT_WALLET_INFO_SIGNER_INFO_REQUEST , // 253 + EVT_WALLET_INFO_EDIT_DESCRIPTION , // 254 + EVT_WALLET_INFO_IMPORT_PSBT , // 255 + EVT_WALLET_INFO_REFRESH_WALLET_REQUEST , // 256 + EVT_WALLET_INFO_GAP_LIMIT_REQUEST , // 257 + EVT_WALLET_INFO_BACK_REQUEST , // 258 + EVT_WALLET_INFO_UTXOS_REQUEST , // 259 + EVT_WALLET_INFO_CHANGE_ADDRESS_REQUEST , // 260 + EVT_WALLET_INFO_MASTER_SIGNER_INFO_REQUEST , // 261 + EVT_WALLET_INFO_REMOTE_SIGNER_INFO_REQUEST , // 262 + EVT_STATE_ID_SCR_WALLET_INFO_MAX , // 263 }; enum EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION { - EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MIN=EVT_STATE_ID_SCR_WALLET_INFO_MAX+1, // 253 - EVT_ADD_WALLET_CONFIRM_CREATE , // 254 - EVT_ADD_WALLET_TOP_UP_XPUBS_REQUEST , // 255 - EVT_ADD_WALLET_DOWNLOAD_DESCRIPTOR , // 256 - EVT_ADD_WALLET_GENERATE_SIGNER , // 257 - EVT_ADD_WALLET_GET_WALLET_DESCRIPTOR , // 258 - EVT_ADD_WALLET_COPY_WALLET_DESCRIPTOR , // 259 - EVT_ADD_WALLET_CONFIRMATION_BACK_REQUEST , // 260 - EVT_ADD_WALLET_SUCCESSFULLY , // 261 - EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MAX , // 262 + EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MIN=EVT_STATE_ID_SCR_WALLET_INFO_MAX+1, // 264 + EVT_ADD_WALLET_CONFIRM_CREATE , // 265 + EVT_ADD_WALLET_TOP_UP_XPUBS_REQUEST , // 266 + EVT_ADD_WALLET_DOWNLOAD_DESCRIPTOR , // 267 + EVT_ADD_WALLET_GENERATE_SIGNER , // 268 + EVT_ADD_WALLET_GET_WALLET_DESCRIPTOR , // 269 + EVT_ADD_WALLET_COPY_WALLET_DESCRIPTOR , // 270 + EVT_ADD_WALLET_CONFIRMATION_BACK_REQUEST , // 271 + EVT_ADD_WALLET_SUCCESSFULLY , // 272 + EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MAX , // 273 }; enum EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET { - EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MIN=EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MAX+1, // 263 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER , // 264 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_REMOTE_SIGNER , // 265 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER_REFRESH , // 266 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_SEND_PIN , // 267 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_PROMT_PIN , // 268 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_REMOTE_SIGNER_RESULT , // 269 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER_RESULT , // 270 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET_BACK , // 271 - EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MAX , // 272 + EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MIN=EVT_STATE_ID_SCR_ADD_WALLET_CONFIRMATION_MAX+1, // 274 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER , // 275 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_REMOTE_SIGNER , // 276 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER_REFRESH , // 277 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_SEND_PIN , // 278 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_PROMT_PIN , // 279 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_REMOTE_SIGNER_RESULT , // 280 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_MASTER_SIGNER_RESULT , // 281 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET_BACK , // 282 + EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MAX , // 283 }; enum EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES { - EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MIN=EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MAX+1, // 273 - EVT_WALLET_CHANGE_ADDRESSES_GEN_NEW_ADDRESS , // 274 - EVT_WALLET_CHANGE_ADDRESSES_COPY , // 275 - EVT_WALLET_CHANGE_ADDRESS_BACK_REQUEST , // 276 - EVT_CHANGE_ADDRESS_BACK_SHARED_WALLET , // 277 - EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MAX , // 278 + EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MIN=EVT_STATE_ID_SCR_ADD_HARDWARE_SIGNER_TO_WALLET_MAX+1, // 284 + EVT_WALLET_CHANGE_ADDRESSES_GEN_NEW_ADDRESS , // 285 + EVT_WALLET_CHANGE_ADDRESSES_COPY , // 286 + EVT_WALLET_CHANGE_ADDRESS_BACK_REQUEST , // 287 + EVT_CHANGE_ADDRESS_BACK_SHARED_WALLET , // 288 + EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MAX , // 289 }; enum EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT { - EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MIN=EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MAX+1, // 279 - EVT_ADD_MASTER_SIGNER_RESULT_RUN_HEALTHCHECK , // 280 - EVT_ADD_MASTER_SIGNER_RESULT_PROMT_PIN , // 281 - EVT_ADD_MASTER_SIGNER_RESULT_GET_XPUBS , // 282 - EVT_ADD_MASTER_SIGNER_INFO_REMOVE_REQUEST , // 283 - EVT_ADD_MASTER_SIGNER_FINISHED , // 284 - EVT_ADD_MASTER_SIGNER_RESULT_CONFIRM_ADD_TO_WALLET_CONFIGURATION , // 285 - EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MAX , // 286 + EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MIN=EVT_STATE_ID_SCR_WALLET_CHANGE_ADDRESSES_MAX+1, // 290 + EVT_ADD_MASTER_SIGNER_RESULT_RUN_HEALTHCHECK , // 291 + EVT_ADD_MASTER_SIGNER_RESULT_PROMT_PIN , // 292 + EVT_ADD_MASTER_SIGNER_RESULT_GET_XPUBS , // 293 + EVT_ADD_MASTER_SIGNER_INFO_REMOVE_REQUEST , // 294 + EVT_ADD_MASTER_SIGNER_FINISHED , // 295 + EVT_ADD_MASTER_SIGNER_RESULT_CONFIRM_ADD_TO_WALLET_CONFIGURATION , // 296 + EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MAX , // 297 }; enum EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO { - EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MIN=EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MAX+1, // 287 - EVT_REMOTE_SIGNER_INFO_HEALTH_CHECK , // 288 - EVT_REMOTE_SIGNER_INFO_EDIT_NAME , // 289 - EVT_REMOTE_SIGNER_INFO_IMPORT_SIGNATURE , // 290 - EVT_REMOTE_SIGNER_INFO_EXPORT_MESSAGE , // 291 - EVT_REMOTE_SIGNER_INFO_DELETE_REQUEST , // 292 - EVT_REMOTE_SIGNER_INFO_GET_XPUBS , // 293 - EVT_REMOTE_SIGNER_INFO_BACK_WALLET_INFO , // 294 - EVT_REMOTE_SIGNER_INFO_BACK_HOME , // 295 - EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MAX , // 296 + EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MIN=EVT_STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_MAX+1, // 298 + EVT_REMOTE_SIGNER_INFO_HEALTH_CHECK , // 299 + EVT_REMOTE_SIGNER_INFO_EDIT_NAME , // 300 + EVT_REMOTE_SIGNER_INFO_IMPORT_SIGNATURE , // 301 + EVT_REMOTE_SIGNER_INFO_EXPORT_MESSAGE , // 302 + EVT_REMOTE_SIGNER_INFO_DELETE_REQUEST , // 303 + EVT_REMOTE_SIGNER_INFO_GET_XPUBS , // 304 + EVT_REMOTE_SIGNER_INFO_BACK_WALLET_INFO , // 305 + EVT_REMOTE_SIGNER_INFO_BACK_HOME , // 306 + EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MAX , // 307 }; enum EVT_STATE_ID_SCR_UNLOCK_DB { - EVT_STATE_ID_SCR_UNLOCK_DB_MIN=EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MAX+1, // 297 - EVT_LOGIN_PERFORM_PASSWORD_REQUEST , // 298 - EVT_STATE_ID_SCR_UNLOCK_DB_MAX , // 299 + EVT_STATE_ID_SCR_UNLOCK_DB_MIN=EVT_STATE_ID_SCR_REMOTE_SIGNER_INFO_MAX+1, // 308 + EVT_LOGIN_PERFORM_PASSWORD_REQUEST , // 309 + EVT_STATE_ID_SCR_UNLOCK_DB_MAX , // 310 }; enum EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT { - EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MIN=EVT_STATE_ID_SCR_UNLOCK_DB_MAX+1, // 300 - EVT_CONSOLIDATE_MAKE_TRANSACTION , // 301 - EVT_CONSOLIDATE_BACK_REQUEST , // 302 - EVT_CONSOLIDATE_MAKE_TRANSACTION_SUCCEED , // 303 - EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MAX , // 304 + EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MIN=EVT_STATE_ID_SCR_UNLOCK_DB_MAX+1, // 311 + EVT_CONSOLIDATE_MAKE_TRANSACTION , // 312 + EVT_CONSOLIDATE_BACK_REQUEST , // 313 + EVT_CONSOLIDATE_MAKE_TRANSACTION_SUCCEED , // 314 + EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MAX , // 315 }; enum EVT_STATE_ID_SCR_UTXO_OUTPUT { - EVT_STATE_ID_SCR_UTXO_OUTPUT_MIN=EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MAX+1, // 305 - EVT_UTXO_INFO_CHECKOUT_TX_RELATED , // 306 - EVT_UTXO_INFO_BACK_REQUEST , // 307 - EVT_UTXO_INFO_VIEW_TX_RELATED , // 308 - EVT_STATE_ID_SCR_UTXO_OUTPUT_MAX , // 309 + EVT_STATE_ID_SCR_UTXO_OUTPUT_MIN=EVT_STATE_ID_SCR_CONSOLIDATE_OUTPUT_MAX+1, // 316 + EVT_UTXO_INFO_CHECKOUT_TX_RELATED , // 317 + EVT_UTXO_INFO_BACK_REQUEST , // 318 + EVT_UTXO_INFO_VIEW_TX_RELATED , // 319 + EVT_STATE_ID_SCR_UTXO_OUTPUT_MAX , // 320 }; enum EVT_STATE_ID_SCR_INPUT_PIN { - EVT_STATE_ID_SCR_INPUT_PIN_MIN=EVT_STATE_ID_SCR_UTXO_OUTPUT_MAX+1, // 310 - EVT_INPUT_PIN_SEND_PIN , // 311 - EVT_INPUT_PIN_CLOSE , // 312 - EVT_STATE_ID_SCR_INPUT_PIN_MAX , // 313 + EVT_STATE_ID_SCR_INPUT_PIN_MIN=EVT_STATE_ID_SCR_UTXO_OUTPUT_MAX+1, // 321 + EVT_INPUT_PIN_SEND_PIN , // 322 + EVT_INPUT_PIN_CLOSE , // 323 + EVT_STATE_ID_SCR_INPUT_PIN_MAX , // 324 }; enum EVT_STATE_ID_SCR_ADD_NEW_SIGNER { - EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MIN=EVT_STATE_ID_SCR_INPUT_PIN_MAX+1, // 314 - EVT_ADD_HARDWARE_SIGNER_REQUEST , // 315 - EVT_ADD_NEW_SIGNER_BACK_REQUEST , // 316 - EVT_ADD_NEW_SIGNER_SOFTWARE_SIGNER_NEW_SEED , // 317 - EVT_ADD_NEW_SIGNER_SOFTWARE_SIGNER_EXIST_SEED , // 318 - EVT_ADD_NEW_SIGNER_BACK_TO_HOME_ONLINE , // 319 - EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MAX , // 320 + EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MIN=EVT_STATE_ID_SCR_INPUT_PIN_MAX+1, // 325 + EVT_ADD_HARDWARE_SIGNER_REQUEST , // 326 + EVT_ADD_NEW_SIGNER_BACK_REQUEST , // 327 + EVT_ADD_NEW_SIGNER_SOFTWARE_SIGNER_NEW_SEED , // 328 + EVT_ADD_NEW_SIGNER_SOFTWARE_SIGNER_EXIST_SEED , // 329 + EVT_ADD_NEW_SIGNER_BACK_TO_HOME_ONLINE , // 330 + EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MAX , // 331 }; enum EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER { - EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MAX+1, // 321 - EVT_ADD_NEW_SOFTWARE_SIGNER_BACK , // 322 - EVT_CREATE_NEW_SEED , // 323 - EVT_ADD_NEW_SOFTWARE_SIGNER_TO_WALLET_BACK , // 324 - EVT_NEW_SOFTWARE_SIGNER_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 325 - EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MAX , // 326 + EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_NEW_SIGNER_MAX+1, // 332 + EVT_ADD_NEW_SOFTWARE_SIGNER_BACK , // 333 + EVT_CREATE_NEW_SEED , // 334 + EVT_ADD_NEW_SOFTWARE_SIGNER_TO_WALLET_BACK , // 335 + EVT_NEW_SOFTWARE_SIGNER_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 336 + EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MAX , // 337 }; enum EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER { - EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MAX+1, // 327 - EVT_RECOVER_SOFTWARE_SIGNER_REQUEST , // 328 - EVT_RECOVER_SOFTWARE_SIGNER_BACK , // 329 - EVT_RECOVER_SOFTWARE_SIGNER_SUCCEED , // 330 - EVT_RECOVER_SOFTWARE_SIGNER_TO_WALLET_BACK , // 331 - EVT_RECOVER_SOFTWARE_SIGNER_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 332 - EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MAX , // 333 + EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MIN=EVT_STATE_ID_SCR_ADD_NEW_SOFTWARE_SIGNER_MAX+1, // 338 + EVT_RECOVER_SOFTWARE_SIGNER_REQUEST , // 339 + EVT_RECOVER_SOFTWARE_SIGNER_BACK , // 340 + EVT_RECOVER_SOFTWARE_SIGNER_SUCCEED , // 341 + EVT_RECOVER_SOFTWARE_SIGNER_TO_WALLET_BACK , // 342 + EVT_RECOVER_SOFTWARE_SIGNER_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 343 + EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MAX , // 344 }; enum EVT_STATE_ID_SCR_CREATE_NEW_SEED { - EVT_STATE_ID_SCR_CREATE_NEW_SEED_MIN=EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MAX+1, // 334 - EVT_CREATE_NEW_SEED_BACK , // 335 - EVT_CREATE_NEW_SEED_SUCCEED , // 336 - EVT_NEW_SEED_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 337 - EVT_STATE_ID_SCR_CREATE_NEW_SEED_MAX , // 338 + EVT_STATE_ID_SCR_CREATE_NEW_SEED_MIN=EVT_STATE_ID_SCR_RECOVER_SOFTWARE_SIGNER_MAX+1, // 345 + EVT_CREATE_NEW_SEED_BACK , // 346 + EVT_CREATE_NEW_SEED_SUCCEED , // 347 + EVT_NEW_SEED_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 348 + EVT_STATE_ID_SCR_CREATE_NEW_SEED_MAX , // 349 }; enum EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION { - EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MIN=EVT_STATE_ID_SCR_CREATE_NEW_SEED_MAX+1, // 339 - EVT_SOFTWARE_SIGNER_REQUEST_CREATE , // 340 - EVT_ADD_SOFTWARE_SIGNER_RESULT , // 341 - EVT_SOFTWARE_SIGNER_CONFIGURATION_BACK , // 342 - EVT_SOFTWARE_SIGNER_CONFIGURATION_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 343 - EVT_PRIMARY_KEY_CONFIGURATION_REQUEST , // 344 - EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MAX , // 345 + EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MIN=EVT_STATE_ID_SCR_CREATE_NEW_SEED_MAX+1, // 350 + EVT_SOFTWARE_SIGNER_REQUEST_CREATE , // 351 + EVT_ADD_SOFTWARE_SIGNER_RESULT , // 352 + EVT_SOFTWARE_SIGNER_CONFIGURATION_BACK , // 353 + EVT_SOFTWARE_SIGNER_CONFIGURATION_BACK_TO_WALLET_SIGNER_CONFIGURATION , // 354 + EVT_PRIMARY_KEY_CONFIGURATION_REQUEST , // 355 + EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MAX , // 356 }; enum EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET { - EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MIN=EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MAX+1, // 346 - EVT_ADD_SIGNER_TO_WALLET_BACK_REQUEST , // 347 - EVT_ADD_HARDWARE_SIGNER_TO_WALLET , // 348 - EVT_ADD_NEW_SOFTWARE_SIGNER_TO_WALLET , // 349 - EVT_RECOVER_SOFTWARE_SIGNER_TO_WALLET , // 350 - EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MAX , // 351 + EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MIN=EVT_STATE_ID_SCR_SOFTWARE_SIGNER_CONFIGURATION_MAX+1, // 357 + EVT_ADD_SIGNER_TO_WALLET_BACK_REQUEST , // 358 + EVT_ADD_HARDWARE_SIGNER_TO_WALLET , // 359 + EVT_ADD_NEW_SOFTWARE_SIGNER_TO_WALLET , // 360 + EVT_RECOVER_SOFTWARE_SIGNER_TO_WALLET , // 361 + EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MAX , // 362 }; enum EVT_STATE_ID_SCR_INPUT_PASSPHRASE { - EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MIN=EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MAX+1, // 352 - EVT_INPUT_PASSPHRASE_SEND_PASSPHRASE , // 353 - EVT_INPUT_PASSPHRASE_CLOSE , // 354 - EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MAX , // 355 + EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MIN=EVT_STATE_ID_SCR_ADD_NEW_SIGNER_TO_WALLET_MAX+1, // 363 + EVT_INPUT_PASSPHRASE_SEND_PASSPHRASE , // 364 + EVT_INPUT_PASSPHRASE_CLOSE , // 365 + EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MAX , // 366 }; enum EVT_STATE_ID_SCR_LOGIN_ONLINE { - EVT_STATE_ID_SCR_LOGIN_ONLINE_MIN=EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MAX+1, // 356 - EVT_LOGIN_ONLINE_CREATE_ACCOUNT , // 357 - EVT_LOGIN_ONLINE_SIGN_IN , // 358 - EVT_LOGIN_ONLINE_SWITCH_LOCAL_MODE , // 359 - EVT_LOGIN_ONLINE_CHANGE_PASSWORD , // 360 - EVT_LOGIN_ONLINE_FORGOT_PASSWORD , // 361 - EVT_LOGIN_ONLINE_RECOVER_PASSWORD , // 362 - EVT_LOGIN_ONLINE_STAY_SIGNED_IN , // 363 - EVT_LOGIN_ONLINE_VERIFY_NEW_DEVICE , // 364 - EVT_LOGIN_ONLINE_RESEND_CONFIRM_CODE , // 365 - EVT_STATE_ID_SCR_LOGIN_ONLINE_MAX , // 366 + EVT_STATE_ID_SCR_LOGIN_ONLINE_MIN=EVT_STATE_ID_SCR_INPUT_PASSPHRASE_MAX+1, // 367 + EVT_LOGIN_ONLINE_CREATE_ACCOUNT , // 368 + EVT_LOGIN_ONLINE_SIGN_IN , // 369 + EVT_LOGIN_ONLINE_SWITCH_LOCAL_MODE , // 370 + EVT_LOGIN_ONLINE_CHANGE_PASSWORD , // 371 + EVT_LOGIN_ONLINE_FORGOT_PASSWORD , // 372 + EVT_LOGIN_ONLINE_RECOVER_PASSWORD , // 373 + EVT_LOGIN_ONLINE_STAY_SIGNED_IN , // 374 + EVT_LOGIN_ONLINE_VERIFY_NEW_DEVICE , // 375 + EVT_LOGIN_ONLINE_RESEND_CONFIRM_CODE , // 376 + EVT_STATE_ID_SCR_LOGIN_ONLINE_MAX , // 377 }; enum EVT_STATE_ID_SCR_HOME_ONLINE { - EVT_STATE_ID_SCR_HOME_ONLINE_MIN=EVT_STATE_ID_SCR_LOGIN_ONLINE_MAX+1, // 367 - EVT_HOME_ONLINE_ADD_SIGNER , // 368 - EVT_HOME_ONLINE_CREATE_CHAT_ROOM , // 369 - EVT_HOME_ONLINE_CREATE_DIRECT_CHAT , // 370 - EVT_HOME_ONLINE_DELETE_DIRECT_ROOM , // 371 - EVT_HOME_ONLINE_DELETE_ROOM , // 372 - EVT_HOME_ONLINE_SEND_CHAT_CONTENT , // 373 - EVT_HOME_ONLINE_CANCEL_SHARED_WL , // 374 - EVT_HOME_ONLINE_CREATE_SHARED_WALLET , // 375 - EVT_HOME_ONLINE_CANCEL_TRANSACTION , // 376 - EVT_HOME_ONLINE_SERVICE_SUPPORT_REQ , // 377 - EVT_HOME_ONLINE_ADD_CONTACT , // 378 - EVT_HOME_SHOW_ALL_PENDING_CONTACT , // 379 - EVT_HOME_ONLINE_SIGNER_AVAILABLE_FOR_SWL , // 380 - EVT_HOME_SHARED_WALLET_CONFIGURE , // 381 - EVT_HOME_BACKUP_SHARED_WALLET , // 382 - EVT_HOME_ONLINE_SIGNER_UNAVAILABLE_FOR_SWL , // 383 - EVT_HOME_SHARED_WL_SEND_REQUEST , // 384 - EVT_HOME_ONLINE_TRANSACTION_INFO_REQUEST , // 385 - EVT_STATE_ID_SCR_HOME_ONLINE_MAX , // 386 + EVT_STATE_ID_SCR_HOME_ONLINE_MIN=EVT_STATE_ID_SCR_LOGIN_ONLINE_MAX+1, // 378 + EVT_HOME_ONLINE_ADD_SIGNER , // 379 + EVT_HOME_ONLINE_CREATE_CHAT_ROOM , // 380 + EVT_HOME_ONLINE_CREATE_DIRECT_CHAT , // 381 + EVT_HOME_ONLINE_DELETE_DIRECT_ROOM , // 382 + EVT_HOME_ONLINE_DELETE_ROOM , // 383 + EVT_HOME_ONLINE_SEND_CHAT_CONTENT , // 384 + EVT_HOME_ONLINE_CANCEL_SHARED_WL , // 385 + EVT_HOME_ONLINE_CREATE_SHARED_WALLET , // 386 + EVT_HOME_ONLINE_CANCEL_TRANSACTION , // 387 + EVT_HOME_ONLINE_SERVICE_SUPPORT_REQ , // 388 + EVT_HOME_ONLINE_ADD_CONTACT , // 389 + EVT_HOME_SHOW_ALL_PENDING_CONTACT , // 390 + EVT_HOME_ONLINE_SIGNER_AVAILABLE_FOR_SWL , // 391 + EVT_HOME_SHARED_WALLET_CONFIGURE , // 392 + EVT_HOME_BACKUP_SHARED_WALLET , // 393 + EVT_HOME_ONLINE_SIGNER_UNAVAILABLE_FOR_SWL , // 394 + EVT_HOME_SHARED_WL_SEND_REQUEST , // 395 + EVT_HOME_ONLINE_TRANSACTION_INFO_REQUEST , // 396 + EVT_STATE_ID_SCR_HOME_ONLINE_MAX , // 397 }; enum EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS { - EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MIN=EVT_STATE_ID_SCR_HOME_ONLINE_MAX+1, // 387 - EVT_ONLINE_ADD_CONTACTS_SEARCH_ID , // 388 - EVT_ONLINE_ADD_CONTACTS_SEND_INVITATION , // 389 - EVT_ONLINE_ADD_CONTACTS_BACK , // 390 - EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MAX , // 391 + EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MIN=EVT_STATE_ID_SCR_HOME_ONLINE_MAX+1, // 398 + EVT_ONLINE_ADD_CONTACTS_SEARCH_ID , // 399 + EVT_ONLINE_ADD_CONTACTS_SEND_INVITATION , // 400 + EVT_ONLINE_ADD_CONTACTS_BACK , // 401 + EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MAX , // 402 }; enum EVT_STATE_ID_SCR_PENDING_REQUEST { - EVT_STATE_ID_SCR_PENDING_REQUEST_MIN=EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MAX+1, // 392 - EVT_PENDING_REQUEST_ACCEPT , // 393 - EVT_PENDING_REQUEST_IGNORE , // 394 - EVT_PENDING_REQUEST_BACK , // 395 - EVT_STATE_ID_SCR_PENDING_REQUEST_MAX , // 396 + EVT_STATE_ID_SCR_PENDING_REQUEST_MIN=EVT_STATE_ID_SCR_ONLINE_ADD_CONTACTS_MAX+1, // 403 + EVT_PENDING_REQUEST_ACCEPT , // 404 + EVT_PENDING_REQUEST_IGNORE , // 405 + EVT_PENDING_REQUEST_BACK , // 406 + EVT_STATE_ID_SCR_PENDING_REQUEST_MAX , // 407 }; enum EVT_STATE_ID_SCR_CREATE_SHARED_WALLET { - EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_PENDING_REQUEST_MAX+1, // 397 - EVT_CREATE_SHARED_WALLET_REQUEST , // 398 - EVT_CANCEL_SHARED_WALLET_REQUEST , // 399 - EVT_CREATE_SHARED_WALLET_BACK , // 400 - EVT_CREATE_SHARED_WALLET_REQUEST_CONFIGURATION , // 401 - EVT_RECOVER_SHARED_WALLET_REQUEST , // 402 - EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MAX , // 403 + EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_PENDING_REQUEST_MAX+1, // 408 + EVT_CREATE_SHARED_WALLET_REQUEST , // 409 + EVT_CANCEL_SHARED_WALLET_REQUEST , // 410 + EVT_CREATE_SHARED_WALLET_BACK , // 411 + EVT_CREATE_SHARED_WALLET_REQUEST_CONFIGURATION , // 412 + EVT_RECOVER_SHARED_WALLET_REQUEST , // 413 + EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MAX , // 414 }; enum EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET { - EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MAX+1, // 404 - EVT_CONFIGURE_SHARED_WALLET_REQUEST , // 405 - EVT_CONFIGURE_SHARED_WALLET_BACK , // 406 - EVT_CONFIGURE_SHARED_WALLET_REVIEW_REQUEST , // 407 - EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MAX , // 408 + EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_CREATE_SHARED_WALLET_MAX+1, // 415 + EVT_CONFIGURE_SHARED_WALLET_REQUEST , // 416 + EVT_CONFIGURE_SHARED_WALLET_BACK , // 417 + EVT_CONFIGURE_SHARED_WALLET_REVIEW_REQUEST , // 418 + EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MAX , // 419 }; enum EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET { - EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MAX+1, // 409 - EVT_REVIEW_SHARED_WALLET_BACK , // 410 - EVT_REVIEW_SHARED_WALLET_INVITE_SIGNER , // 411 - EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MAX , // 412 + EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_CONFIGURE_SHARED_WALLET_MAX+1, // 420 + EVT_REVIEW_SHARED_WALLET_BACK , // 421 + EVT_REVIEW_SHARED_WALLET_INVITE_SIGNER , // 422 + EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MAX , // 423 }; enum EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET { - EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MAX+1, // 413 - EVT_ASSIGN_SIGNER_TO_SHARED_REQUEST , // 414 - EVT_ASSIGN_SIGNER_TO_SHARED_WALLET_BACK_REVIEW_WALLET , // 415 - EVT_ASSIGN_SIGNER_TO_SHARED_BACK_WALLET_CONFIG , // 416 - EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MAX , // 417 + EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_REVIEW_SHARED_WALLET_MAX+1, // 424 + EVT_ASSIGN_SIGNER_TO_SHARED_REQUEST , // 425 + EVT_ASSIGN_SIGNER_TO_SHARED_WALLET_BACK_REVIEW_WALLET , // 426 + EVT_ASSIGN_SIGNER_TO_SHARED_BACK_WALLET_CONFIG , // 427 + EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MAX , // 428 }; enum EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE { - EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MIN=EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MAX+1, // 418 - EVT_SHARED_WALLET_FINALIZE_WALLET , // 419 - EVT_SHARED_WALLET_CONFIGURE_CANCEL , // 420 - EVT_SHARED_WALLET_CONFIGURE_EXPORT_COLDCARD , // 421 - EVT_SHARED_WALLET_CONFIGURE_EXPORT_QRCODE , // 422 - EVT_SHARED_WALLET_CONFIGURE_DELETE_SWL , // 423 - EVT_SHARED_WALLET_CONFIGURE_EXPORT_BSMS , // 424 - EVT_SHARED_WALLET_CONFIGURE_BACK , // 425 - EVT_SHARED_WALLET_ADD_SIGNER_REQUEST , // 426 - EVT_SHARED_WALLET_UTXO_OUTPUT , // 427 - EVT_SHARED_WALLET_CHANGE_ADDRESS , // 428 - EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MAX , // 429 + EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MIN=EVT_STATE_ID_SCR_ASSIGN_SIGNER_TO_SHARED_WALLET_MAX+1, // 429 + EVT_SHARED_WALLET_FINALIZE_WALLET , // 430 + EVT_SHARED_WALLET_CONFIGURE_CANCEL , // 431 + EVT_SHARED_WALLET_CONFIGURE_EXPORT_COLDCARD , // 432 + EVT_SHARED_WALLET_CONFIGURE_EXPORT_QRCODE , // 433 + EVT_SHARED_WALLET_CONFIGURE_DELETE_SWL , // 434 + EVT_SHARED_WALLET_CONFIGURE_EXPORT_BSMS , // 435 + EVT_SHARED_WALLET_CONFIGURE_BACK , // 436 + EVT_SHARED_WALLET_ADD_SIGNER_REQUEST , // 437 + EVT_SHARED_WALLET_UTXO_OUTPUT , // 438 + EVT_SHARED_WALLET_CHANGE_ADDRESS , // 439 + EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MAX , // 440 }; enum EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET { - EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MAX+1, // 430 - EVT_BACKUP_SHARED_WALLET_REQUEST , // 431 - EVT_BACKUP_SHARED_WALLET_SKIP , // 432 - EVT_BACKUP_SHARED_WALLET_EXPORT_BSMS , // 433 - EVT_BACKUP_SHARED_WALLET_BACK , // 434 - EVT_BACKUP_WALLET_DEVICE_REGISTRATION , // 435 - EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MAX , // 436 + EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MIN=EVT_STATE_ID_SCR_SHARED_WALLET_CONFIGURE_MAX+1, // 441 + EVT_BACKUP_SHARED_WALLET_REQUEST , // 442 + EVT_BACKUP_SHARED_WALLET_SKIP , // 443 + EVT_BACKUP_SHARED_WALLET_EXPORT_BSMS , // 444 + EVT_BACKUP_SHARED_WALLET_BACK , // 445 + EVT_BACKUP_WALLET_DEVICE_REGISTRATION , // 446 + EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MAX , // 447 }; enum EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION { - EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MIN=EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MAX+1, // 437 - EVT_SHARED_WALLET_EXPORT_COLDCARD , // 438 - EVT_SHARED_WALLET_EXPORT_QRCODE , // 439 - EVT_SHARED_WALLET_SKIP_REGISTRATION , // 440 - EVT_SHARED_WL_DEVICE_REGISTRAION_BACK , // 441 - EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MAX , // 442 + EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MIN=EVT_STATE_ID_SCR_BACKUP_SHARED_WALLET_MAX+1, // 448 + EVT_SHARED_WALLET_EXPORT_COLDCARD , // 449 + EVT_SHARED_WALLET_EXPORT_QRCODE , // 450 + EVT_SHARED_WALLET_SKIP_REGISTRATION , // 451 + EVT_SHARED_WL_DEVICE_REGISTRAION_BACK , // 452 + EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MAX , // 453 }; enum EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER { - EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MIN=EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MAX+1, // 443 - EVT_STARTING_CREATE_SIGNER_DUMMY , // 444 - EVT_STARTING_CREATE_SIGNER_BACK , // 445 - EVT_ONLINE_MODE_ADD_NEW_SIGNER , // 446 - EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MAX , // 447 + EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MIN=EVT_STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_MAX+1, // 454 + EVT_STARTING_CREATE_SIGNER_DUMMY , // 455 + EVT_STARTING_CREATE_SIGNER_BACK , // 456 + EVT_ONLINE_MODE_ADD_NEW_SIGNER , // 457 + EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MAX , // 458 }; enum EVT_STATE_ID_TOAST_MESSAGE_DISPLAY { - EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MIN=EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MAX+1, // 448 - EVT_CLOSE_TOAST_MESSAGE , // 449 - EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MAX , // 450 + EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MIN=EVT_STATE_ID_SCR_STARTING_CREATE_SIGNER_MAX+1, // 459 + EVT_CLOSE_TOAST_MESSAGE , // 460 + EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MAX , // 461 }; enum EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET { - EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MIN=EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MAX+1, // 451 - EVT_IMPORT_BSMS_SHARED_WALLET , // 452 - EVT_IMPORT_QR_SHARED_WALLET , // 453 - EVT_IMPORT_SHARED_WALLET_SUCCEED , // 454 - EVT_RECOVER_SHARED_WALLET_BACK , // 455 - EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MAX , // 456 + EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MIN=EVT_STATE_ID_TOAST_MESSAGE_DISPLAY_MAX+1, // 462 + EVT_IMPORT_BSMS_SHARED_WALLET , // 463 + EVT_IMPORT_QR_SHARED_WALLET , // 464 + EVT_IMPORT_SHARED_WALLET_SUCCEED , // 465 + EVT_RECOVER_SHARED_WALLET_BACK , // 466 + EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MAX , // 467 }; enum EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT { - EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MIN=EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MAX+1, // 457 - EVT_SELECT_PRIMARY_KEY_ACCOUNT_REQUEST , // 458 - EVT_PRIMARY_KEY_BACK_TO_CREATE_ACCOUNT , // 459 - EVT_PRIMARY_KEY_ACCOUNT_BACK , // 460 - EVT_ADD_PRIMARY_KEY_REQUEST , // 461 - EVT_SHOW_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_REQUEST , // 462 - EVT_SCR_SIGN_IN_MANUALLY_REQUEST , // 463 - EVT_PRIMARY_KEY_BACK_TO_SIGN_IN , // 464 - EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MAX , // 465 + EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MIN=EVT_STATE_ID_SCR_RECOVER_SHARED_WALLET_MAX+1, // 468 + EVT_SELECT_PRIMARY_KEY_ACCOUNT_REQUEST , // 469 + EVT_PRIMARY_KEY_BACK_TO_CREATE_ACCOUNT , // 470 + EVT_PRIMARY_KEY_ACCOUNT_BACK , // 471 + EVT_ADD_PRIMARY_KEY_REQUEST , // 472 + EVT_SHOW_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_REQUEST , // 473 + EVT_SCR_SIGN_IN_MANUALLY_REQUEST , // 474 + EVT_PRIMARY_KEY_BACK_TO_SIGN_IN , // 475 + EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MAX , // 476 }; enum EVT_STATE_ID_SCR_CREATE_ACCOUNT { - EVT_STATE_ID_SCR_CREATE_ACCOUNT_MIN=EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MAX+1, // 466 - EVT_CREATE_ACCOUNT_REQUEST , // 467 - EVT_CREATE_PRIMARY_KEY_REQUEST , // 468 - EVT_CREATE_ACCOUNT_PRIMARY_KEY_REQUEST , // 469 - EVT_CHANGE_PASSWORD_SHOW_REQUEST , // 470 - EVT_STATE_ID_SCR_CREATE_ACCOUNT_MAX , // 471 + EVT_STATE_ID_SCR_CREATE_ACCOUNT_MIN=EVT_STATE_ID_SCR_PRIMARY_KEY_ACCOUNT_MAX+1, // 477 + EVT_CREATE_ACCOUNT_REQUEST , // 478 + EVT_CREATE_PRIMARY_KEY_REQUEST , // 479 + EVT_CREATE_ACCOUNT_PRIMARY_KEY_REQUEST , // 480 + EVT_CHANGE_PASSWORD_SHOW_REQUEST , // 481 + EVT_STATE_ID_SCR_CREATE_ACCOUNT_MAX , // 482 }; enum EVT_STATE_ID_SCR_CHANGE_PASSWORD { - EVT_STATE_ID_SCR_CHANGE_PASSWORD_MIN=EVT_STATE_ID_SCR_CREATE_ACCOUNT_MAX+1, // 472 - EVT_CHANGE_PASSWORD_REQUEST , // 473 - EVT_CHANGE_PASSWORD_BACK , // 474 - EVT_CHANGE_PASSWORD_SUCCESS , // 475 - EVT_STATE_ID_SCR_CHANGE_PASSWORD_MAX , // 476 + EVT_STATE_ID_SCR_CHANGE_PASSWORD_MIN=EVT_STATE_ID_SCR_CREATE_ACCOUNT_MAX+1, // 483 + EVT_CHANGE_PASSWORD_REQUEST , // 484 + EVT_CHANGE_PASSWORD_BACK , // 485 + EVT_CHANGE_PASSWORD_SUCCESS , // 486 + EVT_STATE_ID_SCR_CHANGE_PASSWORD_MAX , // 487 }; enum EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY { - EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MIN=EVT_STATE_ID_SCR_CHANGE_PASSWORD_MAX+1, // 477 - EVT_PRIMARY_KEY_ENTER_PASSPHRASE_REQUEST , // 478 - EVT_PRIMARY_KEY_ENTER_PASSPHRASE_SIGN_IN_REQUEST , // 479 - EVT_IMPORT_PRIMARY_KEY_WITH_SEED_REQUEST , // 480 - EVT_PRIMARY_KEY_ENTER_PASSPHRASE_SUCCEED , // 481 - EVT_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_BACK , // 482 - EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MAX , // 483 + EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MIN=EVT_STATE_ID_SCR_CHANGE_PASSWORD_MAX+1, // 488 + EVT_PRIMARY_KEY_ENTER_PASSPHRASE_REQUEST , // 489 + EVT_PRIMARY_KEY_ENTER_PASSPHRASE_SIGN_IN_REQUEST , // 490 + EVT_IMPORT_PRIMARY_KEY_WITH_SEED_REQUEST , // 491 + EVT_PRIMARY_KEY_ENTER_PASSPHRASE_SUCCEED , // 492 + EVT_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_BACK , // 493 + EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MAX , // 494 }; enum EVT_STATE_ID_SCR_SIGN_IN_MANUALLY { - EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MIN=EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MAX+1, // 484 - EVT_ADD_PRIMARY_KEY_ACCOUNT_REQUEST , // 485 - EVT_PRIMARY_KEY_CHECK_USERNAME_REQUEST , // 486 - EVT_CHALLENGE_MESSAGE_REFRESH_REQUEST , // 487 - EVT_ADD_PRIMARY_KEY_ACCOUNT_SUCCEED , // 488 - EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MAX , // 489 + EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MIN=EVT_STATE_ID_SCR_SIGN_IN_BY_IMPORTING_THE_PRIMARY_KEY_MAX+1, // 495 + EVT_ADD_PRIMARY_KEY_ACCOUNT_REQUEST , // 496 + EVT_PRIMARY_KEY_CHECK_USERNAME_REQUEST , // 497 + EVT_CHALLENGE_MESSAGE_REFRESH_REQUEST , // 498 + EVT_ADD_PRIMARY_KEY_ACCOUNT_SUCCEED , // 499 + EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MAX , // 500 }; enum EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY { - EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MIN=EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MAX+1, // 490 - EVT_PRIMARY_KEY_SIGNIN_ACCOUNT_REQUEST , // 491 - EVT_LOGIN_WITH_SOFTWARE_KEY_BACK , // 492 - EVT_LOGIN_WITH_SOFTWARE_KEY_SUCCEED , // 493 - EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MAX , // 494 + EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MIN=EVT_STATE_ID_SCR_SIGN_IN_MANUALLY_MAX+1, // 501 + EVT_PRIMARY_KEY_SIGNIN_ACCOUNT_REQUEST , // 502 + EVT_LOGIN_WITH_SOFTWARE_KEY_BACK , // 503 + EVT_LOGIN_WITH_SOFTWARE_KEY_SUCCEED , // 504 + EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MAX , // 505 }; enum EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY { - EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MIN=EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MAX+1, // 495 - EVT_REPLACE_PRIMARY_KEY_REQUEST , // 496 - EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MAX , // 497 + EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MIN=EVT_STATE_ID_SCR_LOGIN_WITH_SOFTWARE_KEY_MAX+1, // 506 + EVT_REPLACE_PRIMARY_KEY_REQUEST , // 507 + EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MAX , // 508 }; enum EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION { - EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MIN=EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MAX+1, // 498 - EVT_PRIMARY_KEY_SIGN_IN_REQUEST , // 499 - EVT_PRIMARY_KEY_SIGN_IN_SUCCEED , // 500 - EVT_PRIMARY_KEY_CONFIGURATION_BACK , // 501 - EVT_PRIMARY_KEY_CONFIGURATION_FINISHED , // 502 - EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MAX , // 503 + EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MIN=EVT_STATE_ID_SCR_REPLACE_PRIMARY_KEY_MAX+1, // 509 + EVT_PRIMARY_KEY_SIGN_IN_REQUEST , // 510 + EVT_PRIMARY_KEY_SIGN_IN_SUCCEED , // 511 + EVT_PRIMARY_KEY_CONFIGURATION_BACK , // 512 + EVT_PRIMARY_KEY_CONFIGURATION_FINISHED , // 513 + EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MAX , // 514 }; enum EVT_STATE_ID_SCR_SIGN_IN { - EVT_STATE_ID_SCR_SIGN_IN_MIN=EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MAX+1, // 504 - EVT_SIGN_IN_PASSWORD_REQUEST , // 505 - EVT_SIGN_IN_PRIMARY_KEY_REQUEST , // 506 - EVT_SHOW_SIGN_IN_PRIMARY_KEY_REQUEST , // 507 - EVT_STATE_ID_SCR_SIGN_IN_MAX , // 508 + EVT_STATE_ID_SCR_SIGN_IN_MIN=EVT_STATE_ID_SCR_PRIMARY_KEY_CONFIGURATION_MAX+1, // 515 + EVT_SIGN_IN_PASSWORD_REQUEST , // 516 + EVT_SIGN_IN_PRIMARY_KEY_REQUEST , // 517 + EVT_SHOW_SIGN_IN_PRIMARY_KEY_REQUEST , // 518 + EVT_STATE_ID_SCR_SIGN_IN_MAX , // 519 }; enum EVT_STATE_ID_SCR_UPDATE_PROFILE { - EVT_STATE_ID_SCR_UPDATE_PROFILE_MIN=EVT_STATE_ID_SCR_SIGN_IN_MAX+1, // 509 - EVT_UPDATE_PROFILE_REQUEST , // 510 - EVT_UPDATE_PROFILE_BACK , // 511 - EVT_STATE_ID_SCR_UPDATE_PROFILE_MAX , // 512 + EVT_STATE_ID_SCR_UPDATE_PROFILE_MIN=EVT_STATE_ID_SCR_SIGN_IN_MAX+1, // 520 + EVT_UPDATE_PROFILE_REQUEST , // 521 + EVT_UPDATE_PROFILE_BACK , // 522 + EVT_STATE_ID_SCR_UPDATE_PROFILE_MAX , // 523 }; enum EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS { - EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MIN=EVT_STATE_ID_SCR_UPDATE_PROFILE_MAX+1, // 513 - EVT_TAPSIGNER_RECOVERED_KEY_INFO_REQUEST , // 514 - EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MAX , // 515 + EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MIN=EVT_STATE_ID_SCR_UPDATE_PROFILE_MAX+1, // 524 + EVT_TAPSIGNER_RECOVERED_KEY_INFO_REQUEST , // 525 + EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MAX , // 526 }; enum EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD { - EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MIN=EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MAX+1, // 516 - EVT_INPUT_BACKUP_PASSWORD_REQUEST , // 517 - EVT_ENTER_BACKUP_PASSWORD_BACK , // 518 - EVT_TAPSIGNER_RECOVERED_SUCCESS_REQUEST , // 519 - EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MAX , // 520 + EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MIN=EVT_STATE_ID_SCR_TAPSIGNER_RECOVERED_SUCCESS_MAX+1, // 527 + EVT_INPUT_BACKUP_PASSWORD_REQUEST , // 528 + EVT_ENTER_BACKUP_PASSWORD_BACK , // 529 + EVT_TAPSIGNER_RECOVERED_SUCCESS_REQUEST , // 530 + EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MAX , // 531 }; enum EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION { - EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MIN=EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MAX+1, // 521 - EVT_INPUT_KEY_RECOVERY_ANSER_REQUEST , // 522 - EVT_ANSER_SECURITY_QUESTION_BACK , // 523 - EVT_ENTER_BACKUP_PASSWORD_RERQUEST , // 524 - EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MAX , // 525 + EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MIN=EVT_STATE_ID_SCR_ENTER_BACKUP_PASSWORD_MAX+1, // 532 + EVT_INPUT_KEY_RECOVERY_ANSER_REQUEST , // 533 + EVT_ANSER_SECURITY_QUESTION_BACK , // 534 + EVT_ENTER_BACKUP_PASSWORD_RERQUEST , // 535 + EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MAX , // 536 }; enum EVT_STATE_ID_SCR_KEY_RECOVERY { - EVT_STATE_ID_SCR_KEY_RECOVERY_MIN=EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MAX+1, // 526 - EVT_INPUT_TAPSIGNER_SELECT_REQUEST , // 527 - EVT_ANSER_SECURITY_QUESTION_REQUEST , // 528 - EVT_STATE_ID_SCR_KEY_RECOVERY_MAX , // 529 + EVT_STATE_ID_SCR_KEY_RECOVERY_MIN=EVT_STATE_ID_SCR_KEY_RECOVERY_ANSER_SECURITY_QUESTION_MAX+1, // 537 + EVT_INPUT_TAPSIGNER_SELECT_REQUEST , // 538 + EVT_ANSER_SECURITY_QUESTION_REQUEST , // 539 + EVT_STATE_ID_SCR_KEY_RECOVERY_MAX , // 540 }; enum EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD { - EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MIN=EVT_STATE_ID_SCR_KEY_RECOVERY_MAX+1, // 530 - EVT_INPUT_PASSWORD_REQUEST , // 531 - EVT_REENTER_YOUR_PASSWORD_BACK , // 532 - EVT_KEY_RECOVERY_REQUEST , // 533 - EVT_SELECT_YOUR_LOCKDOWN_PERIOD_REQUEST , // 534 - EVT_WALLET_CO_SIGN_POLICE_REQUEST , // 535 - EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MAX , // 536 + EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MIN=EVT_STATE_ID_SCR_KEY_RECOVERY_MAX+1, // 541 + EVT_INPUT_PASSWORD_REQUEST , // 542 + EVT_REENTER_YOUR_PASSWORD_BACK , // 543 + EVT_KEY_RECOVERY_REQUEST , // 544 + EVT_SELECT_YOUR_LOCKDOWN_PERIOD_REQUEST , // 545 + EVT_WALLET_CO_SIGN_POLICE_REQUEST , // 546 + EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MAX , // 547 }; enum EVT_STATE_ID_SCR_SERVICE_SETTINGS { - EVT_STATE_ID_SCR_SERVICE_SETTINGS_MIN=EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MAX+1, // 537 - EVT_CLAIM_INHERITANCE_CHECK_REQUEST , // 538 - EVT_CO_SIGNING_SERVER_KEY_UPDATE_REQUEST , // 539 - EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED , // 540 - EVT_REENTER_YOUR_PASSWORD_REQUEST , // 541 - EVT_SERVICE_SUPPORT_REQUEST , // 542 - EVT_INHERITANCE_WITHDRAW_BALANCE_REQUEST , // 543 - EVT_STATE_ID_SCR_SERVICE_SETTINGS_MAX , // 544 + EVT_STATE_ID_SCR_SERVICE_SETTINGS_MIN=EVT_STATE_ID_SCR_REENTER_YOUR_PASSWORD_MAX+1, // 548 + EVT_CLAIM_INHERITANCE_CHECK_REQUEST , // 549 + EVT_CO_SIGNING_SERVER_KEY_UPDATE_REQUEST , // 550 + EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED , // 551 + EVT_SERVICE_SELECT_WALLET_REQUEST , // 552 + EVT_INHERITANCE_PLAN_FINALIZE_REQUEST , // 553 + EVT_REENTER_YOUR_PASSWORD_REQUEST , // 554 + EVT_SERVICE_SUPPORT_REQUEST , // 555 + EVT_INHERITANCE_WITHDRAW_BALANCE_REQUEST , // 556 + EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST , // 557 + EVT_SHARE_YOUR_SECRET_REQUEST , // 558 + EVT_STATE_ID_SCR_SERVICE_SETTINGS_MAX , // 559 }; enum EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD { - EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MIN=EVT_STATE_ID_SCR_SERVICE_SETTINGS_MAX+1, // 545 - EVT_INPUT_DAYS_VALUE_REQUEST , // 546 - EVT_LOCKDOWN_ANSER_SECURITY_QUESTION_REQUEST , // 547 - EVT_DUMMY_TRANSACTION_INFO_REQUEST , // 548 - EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MAX , // 549 + EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MIN=EVT_STATE_ID_SCR_SERVICE_SETTINGS_MAX+1, // 560 + EVT_INPUT_DAYS_VALUE_REQUEST , // 561 + EVT_LOCKDOWN_ANSER_SECURITY_QUESTION_REQUEST , // 562 + EVT_DUMMY_TRANSACTION_INFO_REQUEST , // 563 + EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MAX , // 564 }; enum EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION { - EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MIN=EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MAX+1, // 550 - EVT_INPUT_LOCKDOWN_ANSER_REQUEST , // 551 - EVT_LOCKDOWN_ANSER_SECURITY_QUESTION_BACK , // 552 - SCR_LOCKDOWN_SUCCESS_REQUEST , // 553 - EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MAX , // 554 + EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MIN=EVT_STATE_ID_SCR_SELECT_YOUR_LOCKDOWN_PERIOD_MAX+1, // 565 + EVT_INPUT_LOCKDOWN_ANSER_REQUEST , // 566 + EVT_LOCKDOWN_ANSER_SECURITY_QUESTION_BACK , // 567 + SCR_LOCKDOWN_SUCCESS_REQUEST , // 568 + EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MAX , // 569 }; enum EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS { - EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MIN=EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MAX+1, // 555 - EVT_LOCKDOWN_SUCCESS_CLOSE_REQUEST , // 556 - EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MAX , // 557 + EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MIN=EVT_STATE_ID_SCR_LOCKDOWN_ANSER_SECURITY_QUESTION_MAX+1, // 570 + EVT_LOCKDOWN_SUCCESS_CLOSE_REQUEST , // 571 + EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MAX , // 572 }; enum EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO { - EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MIN=EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MAX+1, // 558 - EVT_DUMMY_TRANSACTION_SIGN_REQUEST , // 559 - EVT_DUMMY_TRANSACTION_SIGN_CONFIRM_REQUEST , // 560 - EVT_DUMMY_TRANSACTION_VERIFY_ADDRESS , // 561 - EVT_DUMMY_TRANSACTION_SET_MEMO_REQUEST , // 562 - EVT_DUMMY_TRANSACTION_SCAN_DEVICE_REQUEST , // 563 - EVT_DUMMY_TRANSACTION_INFO_BACK , // 564 - EVT_DUMMY_TRANSACTION_LOCKDOWN_SUCCEEDED_REQUEST , // 565 - EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MAX , // 566 + EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MIN=EVT_STATE_ID_SCR_LOCKDOWN_SUCCESS_MAX+1, // 573 + EVT_DUMMY_TRANSACTION_SIGN_REQUEST , // 574 + EVT_DUMMY_TRANSACTION_SIGN_CONFIRM_REQUEST , // 575 + EVT_DUMMY_TRANSACTION_VERIFY_ADDRESS , // 576 + EVT_DUMMY_TRANSACTION_SET_MEMO_REQUEST , // 577 + EVT_DUMMY_TRANSACTION_SCAN_DEVICE_REQUEST , // 578 + EVT_DUMMY_TRANSACTION_INFO_BACK , // 579 + EVT_DUMMY_TRANSACTION_LOCKDOWN_SUCCEEDED_REQUEST , // 580 + EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MAX , // 581 }; enum EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION { - EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MIN=EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MAX+1, // 567 - EVT_INHERITANCE_CREATE_DRAFT_TX_FEE_REQ , // 568 - EVT_INHERITANCE_TRANSACTION_DETAILS_REQUEST , // 569 - EVT_INHERITANCE_CONFIRM_TRANSACTION_BACK , // 570 - EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MAX , // 571 + EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MIN=EVT_STATE_ID_SCR_DUMMY_TRANSACTION_INFO_MAX+1, // 582 + EVT_INHERITANCE_CREATE_DRAFT_TX_FEE_REQ , // 583 + EVT_INHERITANCE_TRANSACTION_DETAILS_REQUEST , // 584 + EVT_INHERITANCE_CONFIRM_TRANSACTION_BACK , // 585 + EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MAX , // 586 }; enum EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS { - EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MIN=EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MAX+1, // 572 - EVT_INHERITANCE_TRANSACTION_DETAILS_BACK , // 573 - EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MAX , // 574 + EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MIN=EVT_STATE_ID_SCR_INHERITANCE_CONFIRM_TRANSACTION_MAX+1, // 587 + EVT_INHERITANCE_TRANSACTION_DETAILS_BACK , // 588 + EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MAX , // 589 }; enum EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE { - EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MIN=EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MAX+1, // 575 - EVT_INHERITANCE_CREATE_DRAFT_TX_REQUEST , // 576 - EVT_INHERITANCE_NEW_TRANSACTION_REQ , // 577 - EVT_INHERITANCE_WITHDRAW_BALANCE_BACK , // 578 - EVT_INHERITANCE_CONFIRM_TRANSACTION_REQUEST , // 579 - EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MAX , // 580 + EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MIN=EVT_STATE_ID_SCR_INHERITANCE_TRANSACTION_DETAILS_MAX+1, // 590 + EVT_INHERITANCE_CREATE_DRAFT_TX_REQUEST , // 591 + EVT_INHERITANCE_NEW_TRANSACTION_REQ , // 592 + EVT_INHERITANCE_WITHDRAW_BALANCE_BACK , // 593 + EVT_INHERITANCE_CONFIRM_TRANSACTION_REQUEST , // 594 + EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MAX , // 595 }; enum EVT_STATE_ID_SCR_ADD_LEDGER_ASK { - EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MIN=EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MAX+1, // 581 - EVT_ADD_LEDGER_REQUEST , // 582 - EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MAX , // 583 + EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MIN=EVT_STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE_MAX+1, // 596 + EVT_ADD_LEDGER_REQUEST , // 597 + EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MAX , // 598 }; enum EVT_STATE_ID_SCR_ADD_TREZOR_ASK { - EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MIN=EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MAX+1, // 584 - EVT_ADD_TREZOR_REQUEST , // 585 - EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MAX , // 586 + EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MIN=EVT_STATE_ID_SCR_ADD_LEDGER_ASK_MAX+1, // 599 + EVT_ADD_TREZOR_REQUEST , // 600 + EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MAX , // 601 }; enum EVT_STATE_ID_SCR_ADD_LEDGER { - EVT_STATE_ID_SCR_ADD_LEDGER_MIN=EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MAX+1, // 587 - EVT_SCAN_LEDGER_DEVICE_REQUEST , // 588 - EVT_ADD_LEDGER_DEVICE_REQUEST , // 589 - EVT_STATE_ID_SCR_ADD_LEDGER_MAX , // 590 + EVT_STATE_ID_SCR_ADD_LEDGER_MIN=EVT_STATE_ID_SCR_ADD_TREZOR_ASK_MAX+1, // 602 + EVT_SCAN_LEDGER_DEVICE_REQUEST , // 603 + EVT_ADD_LEDGER_DEVICE_REQUEST , // 604 + EVT_STATE_ID_SCR_ADD_LEDGER_MAX , // 605 }; enum EVT_STATE_ID_SCR_ADD_TREZOR { - EVT_STATE_ID_SCR_ADD_TREZOR_MIN=EVT_STATE_ID_SCR_ADD_LEDGER_MAX+1, // 591 - EVT_SCAN_TREZOR_DEVICE_REQUEST , // 592 - EVT_ADD_TREZOR_DEVICE_REQUEST , // 593 - EVT_STATE_ID_SCR_ADD_TREZOR_MAX , // 594 + EVT_STATE_ID_SCR_ADD_TREZOR_MIN=EVT_STATE_ID_SCR_ADD_LEDGER_MAX+1, // 606 + EVT_SCAN_TREZOR_DEVICE_REQUEST , // 607 + EVT_ADD_TREZOR_DEVICE_REQUEST , // 608 + EVT_STATE_ID_SCR_ADD_TREZOR_MAX , // 609 }; enum EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE { - EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_MIN=EVT_STATE_ID_SCR_ADD_TREZOR_MAX+1, // 595 - EVT_SELECT_WALLET_REQUEST , // 596 - EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_MAX , // 597 + EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_MIN=EVT_STATE_ID_SCR_ADD_TREZOR_MAX+1, // 610 + EVT_SELECT_WALLET_REQUEST , // 611 + EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_MAX , // 612 + }; + enum EVT_STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN + { + EVT_STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_MIN=EVT_STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_MAX+1, // 613 + EVT_UPDATE_ACTIVATION_DATE_REQUEST , // 614 + EVT_UPDATE_MESSAGE_REQUEST , // 615 + EVT_UPDATE_BUFFER_PERIOD_REQUEST , // 616 + EVT_UPDATE_NOTIFICATION_PREFERENCE_REQ , // 617 + EVT_NOT_UPDATE_ANY_NOTI_REQ , // 618 + EVT_STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_MAX , // 619 + }; + enum EVT_STATE_ID_SCR_SHARE_YOUR_SECRETS + { + EVT_STATE_ID_SCR_SHARE_YOUR_SECRETS_MIN=EVT_STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_MAX+1, // 620 + EVT_UPDATE_YOUR_SECRET_REQUEST , // 621 + EVT_STATE_ID_SCR_SHARE_YOUR_SECRETS_MAX , // 622 + }; + enum EVT_STATE_ID_SCR_ADD_COLDCARD_ASK + { + EVT_STATE_ID_SCR_ADD_COLDCARD_ASK_MIN=EVT_STATE_ID_SCR_SHARE_YOUR_SECRETS_MAX+1, // 623 + EVT_ADD_COLDCARD_REQUEST , // 624 + EVT_STATE_ID_SCR_ADD_COLDCARD_ASK_MAX , // 625 + }; + enum EVT_STATE_ID_SCR_ADD_COLDCARD + { + EVT_STATE_ID_SCR_ADD_COLDCARD_MIN=EVT_STATE_ID_SCR_ADD_COLDCARD_ASK_MAX+1, // 626 + EVT_SCAN_COLDCARD_DEVICE_REQUEST , // 627 + EVT_ADD_COLDCARD_DEVICE_REQUEST , // 628 + EVT_STATE_ID_SCR_ADD_COLDCARD_MAX , // 629 + }; + enum EVT_STATE_ID_SCR_ADD_LEDGER_EXIST + { + EVT_STATE_ID_SCR_ADD_LEDGER_EXIST_MIN=EVT_STATE_ID_SCR_ADD_COLDCARD_MAX+1, // 630 + EVT_ADD_EXIST_LEDGER_REQUEST , // 631 + EVT_ADD_NEW_LEDGER_REQUEST , // 632 + EVT_STATE_ID_SCR_ADD_LEDGER_EXIST_MAX , // 633 + }; + enum EVT_STATE_ID_SCR_ADD_TREZOR_EXIST + { + EVT_STATE_ID_SCR_ADD_TREZOR_EXIST_MIN=EVT_STATE_ID_SCR_ADD_LEDGER_EXIST_MAX+1, // 634 + EVT_ADD_EXIST_TREZOR_REQUEST , // 635 + EVT_ADD_NEW_TREZOR_REQUEST , // 636 + EVT_STATE_ID_SCR_ADD_TREZOR_EXIST_MAX , // 637 + }; + enum EVT_STATE_ID_SCR_ADD_COLDCARD_EXIST + { + EVT_STATE_ID_SCR_ADD_COLDCARD_EXIST_MIN=EVT_STATE_ID_SCR_ADD_TREZOR_EXIST_MAX+1, // 638 + EVT_ADD_EXIST_COLDCARD_REQUEST , // 639 + EVT_ADD_NEW_COLDCARD_REQUEST , // 640 + EVT_STATE_ID_SCR_ADD_COLDCARD_EXIST_MAX , // 641 }; }; diff --git a/Views/Diagram/NunchuckDiagram.asta b/Views/Diagram/NunchuckDiagram.asta index d0dc48f3f9d1374ec62c52d1eefe4c59efe4b21a..5dd54d0d9593bcf28dad7b1c518b0119387cbe9a 100644 GIT binary patch literal 97125 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 btKsS5ZUt2YApdt69<~a?_5}X$u=f7|&B4fA literal 92392 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

l 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 WmH~%I{9Vhv$!Gpo2F^5Y$(Fi{u_RhQI;- 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

qzxgIZB;3*}7hhelD3Q#JILa;CP@ z(hDKn3rs1$tQtmP4b1v+oI!~zYjA%nAVUs3!}h?2QI;A}!wq;oryQ~6(3E1>oa0cn zrC9ALTZ7VMa^O5|hcJ{w64zlwPK=TgCQid1l%Vb~wz7#qUj-M!gducdyiFt^cn)0* zvFHIflq!;oU-__@ln!?u=4%MP$_9FD2KJQgv=*kt0nYtg{8birsDfGOpHTtaaS!}r46bkY_Bb{7h9FEyCKa?G0@3f6@^nLKE1 z9kkJbUfSTloW**+6h`4RtkfP@LP}~X!t+rJRzwZNyB)L2!7%2*{`mlQ9Tvz=xJQ(V zaU5dN2(>Q-IE@%NrGnMa;}UM|0ED3fdfts0q(r-uXlI8E^~2X&1|Q@AhDxa-XK@6?Jxr&%C4Y< z##%fCAHrfyX_1t(w-T;ZG3MhE76MAASPS{1l)wQjXq54F5JrC$bb1?p4Pu9dGJgkf z8|UG*RAG&xq`KvpC=X3i^m6Fj;z+Gs>pj$8jZcHs@in>UyARCll+l+fzK9_<^iHbX*TORn& zl(@GJOA)1VQVQ1)R+1L@iAS&nvJ2LNvb;($z&1F-rLfPGs925t-Es&Qr7=>zt_Nov zgeytun58fe=dek{!Ln{boq!3ghYStSt{PVCWw^BiXhOMotFd`;3Id!5{~(l82oZHc zO^?AqUBFGQ$53@Jk(AL@1fgjG2FrjhWua9=KgzMhG~#iX^4kia-G}kidlCInHsvl@ zfm&Qcz|%V=@;XsR>B^LWMVVEVSatVdRjY!sJFpx#;cB}vqB`8J2L~tt)`s0d%4DT% zRLVD{kE`1-Zzh1ri zFP0M{R?|y}((b~Oa1*S2AtvB7{HBxGD`P4vx1fYS`!;%QSBc1;Ugya$UC zW#^p-Bp0B+7qE*%Il(R1IxxU5p_H}NxM#{gZ^vW35xWqSDo5GIi*YYauzDtl<00CI z!!>x!Dy5X4f_F#>-KU_i>u|0aN_PSah6b0^V(ngxrJRGGXn{M!|6pol`u_k>O9u$Q zIp}d@s0bZ>HHP)h{{000000RRC2IRF3vnP>q3000 - + + + + + @@ -4442,19 +4446,25 @@ - + + + + + - + + + @@ -4508,6 +4518,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4796,16 +4834,16 @@ - + - + @@ -4893,6 +4931,7 @@ + @@ -4943,6 +4982,7 @@ + @@ -5018,6 +5058,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8179,32 +8530,202 @@ - - - - - - - - - - - - - - - - - -8201.806766957703 - -1973.8221633573712 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -8201.806766957703 + -1973.8221633573712 + + + + + + + + @@ -8234,8 +8755,12 @@ - + + + + + @@ -9532,8 +10057,10 @@ - + + + @@ -9766,10 +10293,10 @@ - - + + @@ -9817,7 +10344,7 @@ -3646.8758764194818 - 2059.46239167257 + 2219.839750163136 @@ -9837,7 +10364,7 @@ -2731.1615907051964 - 2052.319534529713 + 2220.2440628316 @@ -9849,6 +10376,7 @@ + @@ -9856,7 +10384,7 @@ -3646.547469194523 - 2269.298188060091 + 2429.675546550657 @@ -9868,6 +10396,7 @@ + @@ -9875,7 +10404,7 @@ -2731.161590705196 - 2269.4623916725704 + 2437.386919974457 @@ -9897,116 +10426,254 @@ -962.4290370851568 - + - + - - - - + + + - + + - -3334.2902932741144 - -701.6562500151983 + 4063.4741650019196 + -900.2512342192765 - - - - -3465.4366360765816 - -613.8537542150955 - - - 106.49867374005294 - -31.653404067197187 - - - - - - - - -3521.195481659506 - -615.3068792150955 - - - 0.7007847597562482 - 0.23755083629371543 - - - 0.4999999999999999 - 0.1514222546285936 - - - -3521.195481659506 - -615.3068792150955 - - - + + - + - - - - + + + - + + - -3334.2902932741144 - -701.6562500151983 + 4063.170140845742 + -665.9117155961767 - - - - -3416.6932082294265 - -574.9310010848872 - - - 11.936339522546405 - -29.88505747126436 - - - - - - - - -3468.6313790954036 - -576.3841260848872 - - - 0.05632437549992315 - 0.4247036321628312 - - - 0.774557769456627 - 0.5 - - - -3468.6313790954036 - -576.3841260848872 - - - + + - + - - - + + + + + + + + + + -1801.170795701778 + 2437.466541366987 + + + + + + + + + + + + + + + + + + + -1801.1707957017784 + 2220.3236842241295 + + + + + + + + + + + + + + + + + + + -3646.453814569703 + 2039.7826521713905 + + + + + + + + + + + + + + + + + + + -2731.3594749470617 + 2040.2032022964195 + + + + + + + + + + + + + + + + + + + -1801.1707957017782 + 2039.78265217139 + + + + + + + + + + + + + + + + + + -3334.2902932741144 + -701.6562500151983 + + + + + -3465.4366360765816 + -613.8537542150955 + + + 106.49867374005294 + -31.653404067197187 + + + + + + + + -3521.195481659506 + -615.3068792150955 + + + 0.7007847597562482 + 0.23755083629371543 + + + 0.4999999999999999 + 0.1514222546285936 + + + -3521.195481659506 + -615.3068792150955 + + + + + + + + + + + + + + + + + + -3334.2902932741144 + -701.6562500151983 + + + + + -3416.6932082294265 + -574.9310010848872 + + + 11.936339522546405 + -29.88505747126436 + + + + + + + + -3468.6313790954036 + -576.3841260848872 + + + 0.05632437549992315 + 0.4247036321628312 + + + 0.774557769456627 + 0.5 + + + -3468.6313790954036 + -576.3841260848872 + + + + + + + + + + + + @@ -10016,7 +10683,7 @@ -701.6562500151983 - + -3263.720099783978 151.24276517468422 @@ -10074,7 +10741,7 @@ -701.6562500151983 - + -3300.3752721977708 201.30950309789685 @@ -10132,7 +10799,7 @@ -701.6562500151983 - + -4025.858169082271 -45.62217743994472 @@ -10175,7 +10842,7 @@ -701.6562500151983 - + -4135.358169082271 -45.62217743994472 @@ -10218,7 +10885,7 @@ -701.6562500151983 - + -4001.5976339008776 -590.6012374151242 @@ -10261,7 +10928,7 @@ -701.6562500151983 - + -4588.967982269121 -543.1036283238357 @@ -10311,7 +10978,7 @@ -701.6562500151983 - + -4550.765506583886 -584.1292693494768 @@ -10361,7 +11028,7 @@ -701.6562500151983 - + -3781.6313790954027 281.7354294057032 @@ -10404,7 +11071,7 @@ -701.6562500151983 - + -4058.896569990833 281.7354294057032 @@ -10447,7 +11114,7 @@ -697.1107954697438 - + -1984.4200166608694 -606.1922695046433 @@ -10490,7 +11157,7 @@ -697.1107954697438 - + -1958.4200166608694 -568.6571484166282 @@ -10533,7 +11200,7 @@ -697.1107954697438 - + -920.2899035516436 -725.550841097089 @@ -10576,7 +11243,7 @@ -697.1107954697438 - + -1500.1558264929793 -725.550841097089 @@ -10619,7 +11286,7 @@ -697.1107954697438 - + -3315.847955490415 -677.3342736809511 @@ -10677,7 +11344,7 @@ -697.1107954697438 - + -879.351963353248 -371.21915424301585 @@ -10720,7 +11387,7 @@ -697.1107954697438 - + -1429.4740034672288 960.2456015034014 @@ -10770,7 +11437,7 @@ -697.1107954697438 - + -752.4577489822182 1060.2456015034013 @@ -10828,7 +11495,7 @@ -697.1107954697438 - + -4653.890837923096 -236.30685241647302 @@ -10867,7 +11534,7 @@ -697.1107954697438 - + -4656.890837923096 -284.1641345101294 @@ -10906,7 +11573,7 @@ -697.1107954697438 - + -3439.088367287303 -780.1689771295894 @@ -10960,7 +11627,7 @@ -697.1107954697438 - + -5255.802841817371 -56.38024610783256 @@ -11003,7 +11670,7 @@ -697.1107954697438 - + -5604.078703886336 -56.38024610783256 @@ -11046,7 +11713,7 @@ -697.1107954697438 - + -4991.015329810498 458.4836088756332 @@ -11104,7 +11771,7 @@ -697.1107954697438 - + -5061.681996477164 248.07292199643342 @@ -11158,7 +11825,7 @@ -697.1107954697438 - + -4066.678678624242 -590.6012374151242 @@ -11201,7 +11868,7 @@ -697.1107954697438 - + -5183.002908335401 -661.5062753953052 @@ -11244,7 +11911,7 @@ -697.1107954697438 - + -5639.175322128504 -661.5062753953052 @@ -11287,7 +11954,7 @@ -697.1107954697438 - + -4670.441156136609 -304.8065514706275 @@ -11341,7 +12008,7 @@ -697.1107954697438 - + -4880.441156136609 -165.90251657422627 @@ -11395,7 +12062,7 @@ -697.1107954697438 - + -4022.7490550219 -1439.8727559557838 @@ -11453,7 +12120,7 @@ -697.1107954697438 - + -2739.9841864450864 352.7882200288675 @@ -11496,7 +12163,7 @@ -697.1107954697438 - + -3185.6856170253577 32.91579937266545 @@ -11554,7 +12221,7 @@ -697.1107954697438 - + -2073.403245404529 -45.51654719046505 @@ -11608,7 +12275,7 @@ -697.1107954697438 - + -1752.0211115196848 504.2718242731226 @@ -11658,7 +12325,7 @@ -697.1107954697438 - + -1506.1724761737607 -371.21915424301585 @@ -11701,7 +12368,7 @@ -697.1107954697438 - + -4282.055711405376 -1348.4009403407922 @@ -11759,7 +12426,7 @@ -697.1107954697438 - + -6308.295283512095 1012.1499364604692 @@ -11821,7 +12488,7 @@ -697.1107954697438 - + -4454.075208127684 624.1001437629707 @@ -11875,7 +12542,7 @@ -697.1107954697438 - + -4474.842972606101 740.3192959189714 @@ -11929,7 +12596,7 @@ -697.1107954697438 - + -5886.247958636628 1069.7005049108807 @@ -11987,7 +12654,7 @@ -697.1107954697438 - + -5943.273006957754 1119.7005049108807 @@ -12045,7 +12712,7 @@ -697.1107954697438 - + -4560.719833599496 -962.8294344195647 @@ -12103,7 +12770,7 @@ -697.1107954697438 - + -3079.9028171392406 -1457.8916969890574 @@ -12157,7 +12824,7 @@ -697.1107954697438 - + -5132.85798739706 169.43523766029574 @@ -12200,7 +12867,7 @@ -697.1107954697438 - + -5577.843062023925 169.43523766029574 @@ -12243,7 +12910,7 @@ -697.1107954697438 - + -4702.8047604943995 360.47656701048686 @@ -12289,7 +12956,7 @@ -697.1107954697438 - + -4666.5884336158015 299.51207266539507 @@ -12335,7 +13002,7 @@ -697.1107954697438 - + -5745.891419549895 468.6543410400628 @@ -12389,7 +13056,7 @@ -697.1107954697438 - + -5840.891419549895 462.10619674191867 @@ -12443,7 +13110,7 @@ -697.1107954697438 - + -6082.513041171516 30.646382803747372 @@ -12497,7 +13164,7 @@ -697.1107954697438 - + -6134.567095225569 38.717014554805246 @@ -12551,7 +13218,7 @@ -697.1107954697438 - + -4172.487432044621 -473.6097165263192 @@ -12609,7 +13276,7 @@ -697.1107954697438 - + -1929.900103661164 556.9271752366052 @@ -12663,7 +13330,7 @@ -697.1107954697438 - + -3402.358169082272 151.04923552755167 @@ -12721,7 +13388,7 @@ -697.1107954697438 - + -3322.478720473633 206.48217202544276 @@ -12779,7 +13446,7 @@ -697.1107954697438 - + -253.58393141203692 -1414.0137126630211 @@ -12833,7 +13500,7 @@ -697.1107954697438 - + -256.5996510851721 -1278.0323744257933 @@ -12887,7 +13554,7 @@ -697.1107954697438 - + -2097.9622528579835 23.236635594918766 @@ -12930,7 +13597,7 @@ -697.1107954697438 - + -2485.860889521144 23.236635594918766 @@ -12973,7 +13640,7 @@ -697.1107954697438 - + -3242.356730883347 -232.66985136607218 @@ -13027,7 +13694,7 @@ -697.1107954697438 - + -3239.356730883347 -173.15455797735405 @@ -13081,7 +13748,7 @@ -697.1107954697438 - + -3048.4231188109125 480.60966615364754 @@ -13139,7 +13806,7 @@ -697.1107954697438 - + -3085.4744008621938 652.7078750098394 @@ -13197,7 +13864,7 @@ -697.1107954697438 - + -1926.4385651996251 501.7285568993941 @@ -13251,7 +13918,7 @@ -697.1107954697438 - + -1868.9550487161089 665.9876123661734 @@ -13305,7 +13972,7 @@ -697.1107954697438 - + -1512.4481751037233 1296.681105023576 @@ -13348,7 +14015,7 @@ -697.1107954697438 - + -1551.4481751037233 1343.399175135743 @@ -13391,7 +14058,7 @@ -697.1107954697438 - + -1642.2169126975837 1660.9235803859483 @@ -13434,7 +14101,7 @@ -697.1107954697438 - + -1011.6627627625651 1433.737730963425 @@ -13473,7 +14140,7 @@ -697.1107954697438 - + -2773.988747497373 1763.9876145555859 @@ -13531,7 +14198,7 @@ -697.1107954697438 - + -806.041938240259 21.737629164096518 @@ -13574,7 +14241,7 @@ -697.1107954697438 - + -1142.249319614799 21.737629164096518 @@ -13617,7 +14284,7 @@ -697.1107954697438 - + -1834.5771584480074 525.1658878667756 @@ -13671,7 +14338,7 @@ -697.1107954697438 - + -1831.4964345090943 603.4755051010169 @@ -13725,7 +14392,7 @@ -697.1107954697438 - + -1763.2355649438766 804.4631891798043 @@ -13779,7 +14446,7 @@ -697.1107954697438 - + -1756.4275682373125 874.1818397172829 @@ -13833,7 +14500,7 @@ -697.1107954697438 - + -499.7653268651295 1433.737730963425 @@ -13876,7 +14543,7 @@ -697.1107954697438 - + -345.35860923001815 163.78380386749075 @@ -13930,7 +14597,7 @@ -697.1107954697438 - + -452.9172566805271 311.9876993086604 @@ -13984,7 +14651,7 @@ -697.1107954697438 - + -337.39864010951464 1286.8591832127308 @@ -14042,7 +14709,7 @@ -697.1107954697438 - + -330.56707512277876 1514.0428183626534 @@ -14100,7 +14767,7 @@ -697.1107954697438 - + 257.13795957375004 -1457.8916969890574 @@ -14154,7 +14821,7 @@ -697.1107954697438 - + 258.2493184903812 -1487.6235292075517 @@ -14208,7 +14875,7 @@ -230.80644764365695 - + -6459.860056649477 2281.5494614086574 @@ -14262,7 +14929,7 @@ -230.80644764365695 - + -6703.964278115455 3085.3172385884677 @@ -14316,7 +14983,7 @@ -230.80644764365695 - + -5263.873653276649 2885.700492070512 @@ -14370,7 +15037,7 @@ -230.80644764365695 - + -5175.901199428103 3018.126942853542 @@ -14424,7 +15091,7 @@ -230.80644764365695 - + -5226.9932801638915 3127.123723366318 @@ -14478,7 +15145,7 @@ -230.80644764365695 - + -5156.881345860535 3173.327337343403 @@ -14532,7 +15199,7 @@ -230.80644764365695 - + -5509.37683853562 3434.1281216501175 @@ -14582,7 +15249,7 @@ -230.80644764365695 - + -5503.7164611771295 3517.1469895746463 @@ -14632,7 +15299,7 @@ -230.80644764365695 - + -4230.307071417519 3560.695527606189 @@ -14675,7 +15342,7 @@ -230.80644764365695 - + -4122.307071417519 3464.2687430588385 @@ -14718,7 +15385,7 @@ -230.80644764365695 - + -3062.0778501203467 3447.583246095677 @@ -14761,7 +15428,7 @@ -230.80644764365695 - + -2957.0778501203467 3506.15216432241 @@ -14800,7 +15467,7 @@ -230.80644764365695 - + -1800.0667195724104 3447.583246095677 @@ -14843,7 +15510,7 @@ -230.80644764365695 - + -1923.0667195724104 3505.708187392518 @@ -14886,7 +15553,7 @@ -230.80644764365695 - + -6781.703738249707 3245.393768196993 @@ -14940,7 +15607,7 @@ -230.80644764365695 - + -5837.844119851388 4088.1368066114255 @@ -14990,7 +15657,7 @@ -230.80644764365695 - + -5881.658933727741 4126.633216758953 @@ -15040,7 +15707,7 @@ -230.80644764365695 - + -5965.482339875752 4447.461374452067 @@ -15090,7 +15757,7 @@ -230.80644764365695 - + -5920.206477806786 4381.313394382259 @@ -15140,7 +15807,7 @@ 269.19355235634305 - + -4149.405628017125 4663.04291019314 @@ -15183,7 +15850,7 @@ 269.19355235634305 - + -4145.405628017125 4556.439136608235 @@ -15226,7 +15893,7 @@ -230.80644764365695 - + -5406.7537562565085 3211.5549685803385 @@ -15280,7 +15947,7 @@ -230.80644764365695 - + -5321.7537562565085 3256.6605917749175 @@ -15330,7 +15997,7 @@ -230.80644764365695 - + -3145.9148011327825 1952.6609553925746 @@ -15384,7 +16051,7 @@ -230.80644764365695 - + -3143.084952132618 2065.2083815227265 @@ -15438,7 +16105,7 @@ -230.80644764365695 - + -7043.549830511265 -1269.6444507754513 @@ -15496,7 +16163,7 @@ -215.4731143103237 - + -2272.998604210608 4219.512962385836 @@ -15546,7 +16213,7 @@ -215.4731143103237 - + -2473.225238382363 4157.295745097037 @@ -15596,7 +16263,7 @@ -215.4731143103237 - + -7300.243013950485 2729.03277051553 @@ -15654,7 +16321,7 @@ -215.4731143103237 - + -7404.760255329797 2642.388850564707 @@ -15712,7 +16379,7 @@ -215.4731143103237 - + -7290.66966545596 2784.628427190492 @@ -15766,7 +16433,7 @@ -215.4731143103237 - + -6942.645772682066 2788.0327653344266 @@ -15820,7 +16487,7 @@ -215.4731143103237 - + -6456.794201297476 1795.9786742819442 @@ -15874,7 +16541,7 @@ -215.4731143103237 - + -6460.794201297476 1709.7919167262721 @@ -15928,7 +16595,7 @@ -215.4731143103237 - + -4429.535277573868 2184.099947725079 @@ -15994,7 +16661,7 @@ -215.4731143103237 - + -4517.918530579889 2088.483224995943 @@ -16060,7 +16727,7 @@ -215.4731143103237 - + -6685.046712819636 932.6164080173463 @@ -16118,7 +16785,7 @@ -213.62126245847196 - + -2416.6737484329474 4823.492554588166 @@ -16172,7 +16839,7 @@ -213.62126245847196 - + -2487.9026978647216 4854.600199280906 @@ -16226,7 +16893,7 @@ -213.62126245847196 - + -2681.960465821991 3846.5164410677285 @@ -16276,7 +16943,7 @@ -213.62126245847196 - + -4237.829818440684 3682.4903994010606 @@ -16326,7 +16993,7 @@ -213.62126245847196 - + -6560.812909679041 1167.7752106723938 @@ -16376,7 +17043,7 @@ -213.62126245847196 - + -6007.7359321759295 1318.703320754818 @@ -16419,7 +17086,7 @@ -213.62126245847196 - + -6457.379070948662 1328.6568313190594 @@ -16469,7 +17136,7 @@ -213.62126245847196 - + -5536.988109512843 1219.5490988973236 @@ -16508,7 +17175,7 @@ -213.62126245847196 - + -5484.125177517524 1131.0649012154113 @@ -16558,7 +17225,7 @@ -213.62126245847196 - + -4794.95435488778 1367.8370093456629 @@ -16604,7 +17271,7 @@ -213.62126245847196 - + -5516.673968473389 1327.6254267835866 @@ -16654,7 +17321,7 @@ -213.62126245847196 - + -3263.7324593698077 1417.3089673257386 @@ -16708,7 +17375,7 @@ -213.62126245847196 - + -5647.619914419336 1513.2046413196654 @@ -16762,7 +17429,7 @@ -213.62126245847196 - + -4632.361832030409 583.2397431546501 @@ -16812,7 +17479,7 @@ -213.62126245847196 - + -5387.924660475141 1436.60464296955 @@ -16858,7 +17525,7 @@ -213.62126245847196 - + -5606.265866987975 1586.5197190629665 @@ -16912,7 +17579,7 @@ -213.62126245847196 - + -4558.427699319827 753.9231999441894 @@ -16966,7 +17633,7 @@ -213.62126245847196 - + -6374.078827771604 1714.198518546094 @@ -17016,7 +17683,7 @@ -213.62126245847196 - + -4512.318918608709 1371.587817876014 @@ -17066,7 +17733,7 @@ -213.62126245847196 - + -3129.383556528758 783.1344758081772 @@ -17116,7 +17783,7 @@ -213.62126245847196 - + -3423.2334063786075 165.00655256608093 @@ -17166,7 +17833,7 @@ -213.62126245847196 - + -1039.7638805580716 1779.1146585707766 @@ -17209,7 +17876,7 @@ -213.62126245847196 - + -523.3915040328209 1779.1146585707766 @@ -17248,7 +17915,7 @@ -213.62126245847196 - + -4039.7162301622766 1959.6067177570753 @@ -17298,7 +17965,7 @@ -213.62126245847196 - + -3235.822129371775 1318.0296144242288 @@ -17348,7 +18015,7 @@ -213.62126245847196 - + -1343.9718586787073 -1364.2228558068791 @@ -17402,7 +18069,7 @@ -213.62126245847196 - + -6396.438530896242 -1204.0747388879583 @@ -17452,7 +18119,7 @@ -213.62126245847196 - + -4321.673537095424 3765.4541742766833 @@ -17498,7 +18165,7 @@ -213.62126245847196 - + -2075.8320865528135 -1408.5820071041821 @@ -17548,7 +18215,7 @@ -213.62126245847196 - + -6526.8869621242775 1446.475820753974 @@ -17598,7 +18265,7 @@ -213.62126245847196 - + -6512.333269423029 1991.8860241708394 @@ -17648,7 +18315,7 @@ -213.62126245847196 - + -3250.2744822175355 21.71846323604845 @@ -17702,7 +18369,7 @@ 22.09302325581382 - + 1026.273416459941 -1348.1173173684087 @@ -17752,7 +18419,7 @@ 22.09302325581382 - + 870.1264400096215 -1008.3064719154979 @@ -17795,7 +18462,7 @@ 22.09302325581382 - + 1145.9280323193702 -1008.3064719154979 @@ -17838,7 +18505,7 @@ 22.09302325581382 - + 938.1553685391564 -719.5831471470816 @@ -17881,7 +18548,7 @@ 22.09302325581382 - + 813.7070926770875 -437.7855165076786 @@ -17924,7 +18591,7 @@ 22.09302325581382 - + 1111.7760581943287 -437.7855165076786 @@ -17963,7 +18630,7 @@ 22.09302325581382 - + 813.5168580232298 -177.6889569490936 @@ -18002,7 +18669,7 @@ 22.09302325581382 - + 1144.7668580232298 -177.6889569490936 @@ -18045,7 +18712,7 @@ 22.09302325581382 - + 776.3918580232298 85.65707847346994 @@ -18084,7 +18751,7 @@ 22.09302325581382 - + -375.55158934690064 657.6785960582204 @@ -18130,7 +18797,7 @@ 22.09302325581382 - + 1643.125696738587 -875.0515015774615 @@ -18176,7 +18843,7 @@ 22.09302325581382 - + 1512.2021872567798 -441.14091646826904 @@ -18219,7 +18886,7 @@ 22.09302325581382 - + 1912.8020405207017 -441.14091646826904 @@ -18258,7 +18925,7 @@ 22.09302325581382 - + 1801.6373102061239 -177.62535150316262 @@ -18297,7 +18964,7 @@ 0.0 - + 1204.4745789449794 -1391.6112459205128 @@ -18347,7 +19014,7 @@ 0.0 - + 2333.890846477955 -547.9047874785633 @@ -18393,7 +19060,7 @@ 0.0 - + 2556.265356721765 -612.1922695046433 @@ -18439,7 +19106,7 @@ 0.0 - + 2281.003358471995 -44.00153749861454 @@ -18485,7 +19152,7 @@ 0.0 - + -3623.349045874398 -948.1614090354324 @@ -18539,7 +19206,7 @@ 0.0 - + -350.72536076022334 3085.317238588468 @@ -18589,10 +19256,10 @@ 0.0 - + - 2293.860013979096 - -1077.726708552884 + 2285.8957143122925 + -1061.7981092192765 @@ -18601,11 +19268,11 @@ 3431.0722774944293 - -1079.179833552884 + -1063.2512342192765 0.5 - 0.8712670807744111 + 0.963908879879362 0.24440368966322618 @@ -18613,7 +19280,7 @@ 3431.0722774944293 - -1079.179833552884 + -1063.2512342192765 @@ -18635,10 +19302,10 @@ 0.0 - + - 2477.2982141627544 - -1141.5614422535343 + 2439.0966580660374 + -1081.7981092192765 @@ -18646,20 +19313,20 @@ - 3682.113944161096 - -1143.0145672535343 + 3665.4741650019196 + -1083.2512342192765 - 0.5875998921948712 + 0.5648518396734657 0.5 0.5 - 0.5 + 0.8475875421839786 - 3682.113944161096 - -1143.0145672535343 + 3665.4741650019196 + -1083.2512342192765 @@ -18681,7 +19348,7 @@ 0.0 - + 3066.0722774944293 -695.563694834209 @@ -18724,7 +19391,7 @@ 0.0 - + 3072.0722774944293 -445.08535935587327 @@ -18767,7 +19434,7 @@ 0.0 - + 3467.9927312632703 -695.563694834209 @@ -18810,7 +19477,7 @@ 0.0 - + 3473.9927312632703 -445.08535935587327 @@ -18846,13 +19513,13 @@ 0.0 - 0.0 + 160.37735849056617 - + -3503.456026076672 - 2229.0840442603835 + 2389.4614027509497 @@ -18885,13 +19552,13 @@ 0.0 - 0.0 + 167.92452830188677 - + -2586.905943974866 - 2225.594717495195 + 2393.5192457970816 @@ -18927,10 +19594,10 @@ 0.0 - + - -3325.825806486113 - 565.8801979894706 + -3082.8221293717747 + 571.4635801681345 @@ -18940,8 +19607,10 @@ -3684.2568905406188 -353.177161639123 - -3146.825806486113 + -2903.8221293717747 -353.177161639123 + -2903.8221293717747 + 2283.090379557189 0.47193026947985595 @@ -18954,8 +19623,10 @@ -3684.2568905406188 -353.177161639123 - -3146.825806486113 + -2903.8221293717747 -353.177161639123 + -2903.8221293717747 + 2283.090379557189 @@ -18977,10 +19648,10 @@ 0.0 - + - -2834.441191101497 - 317.1164617257342 + -2927.192349580143 + 488.09499925050017 @@ -18990,8 +19661,10 @@ -3684.2568905406188 -353.177161639123 - -2656.441191101497 + -2749.192349580143 -353.177161639123 + -2749.192349580143 + 2283.4946922256527 0.47193026947985595 @@ -19004,8 +19677,10 @@ -3684.2568905406188 -353.177161639123 - -2656.441191101497 + -2749.192349580143 -353.177161639123 + -2749.192349580143 + 2283.4946922256527 @@ -19027,7 +19702,7 @@ 0.0 - + 1725.0896016325148 -926.0021073686953 @@ -19047,6 +19722,503 @@ + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + 2833.2396160560106 + -1114.2981092192767 + + + + + + + + 4429.21490574266 + -1115.7512342192767 + + + 0.5 + 0.6585653684289791 + + + 0.5 + 0.5 + + + 4429.21490574266 + -1115.7512342192767 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + 2883.726346031542 + -1149.0080654441579 + + + + + + + + 4030.223761630707 + -1150.4611904441579 + 4030.223761630707 + -579.9429655961767 + + + 0.5 + 0.45668994145766023 + + + 0.5 + 0.5 + + + 4030.223761630707 + -1150.4611904441579 + 4030.223761630707 + -579.9429655961767 + + + + + + + + + + + + + + + + + + 929.990795003418 + 168.00414969441636 + + + + + -1675.9151489714482 + 2393.598867189611 + + + + + + + + 0.5 + 0.5 + + + 0.5 + 0.5 + + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -4401.319377949687 + 1126.394921313783 + + + + + + + + -4212.319377949687 + -227.20841163912303 + -4212.319377949687 + 2103.0332815654433 + + + 0.5 + 0.5 + + + 0.7248830755901606 + 0.4999999999999991 + + + -4212.319377949687 + -227.20841163912303 + -4212.319377949687 + 2103.0332815654433 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -4290.090574126027 + 1730.6548748557566 + + + + + + + + -4102.090574126027 + -227.20841163912303 + -4102.090574126027 + 2011.5968768453554 + -2375.103828216732 + 2011.5968768453554 + + + 0.5 + 0.5 + + + 0.5 + 0.5 + + + -4102.090574126027 + -227.20841163912303 + -4102.090574126027 + 2011.5968768453554 + -2375.103828216732 + 2011.5968768453554 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -4157.40714316109 + 2027.7443516861108 + + + + + + + + -4118.2017308908635 + -227.20841163912303 + -4118.2017308908635 + 2026.2912266861108 + -1444.9151489714482 + 2026.2912266861108 + + + 0.5 + 0.5 + + + 0.5 + 0.5 + + + -4118.2017308908635 + -227.20841163912303 + -4118.2017308908635 + 2026.2912266861108 + -1444.9151489714482 + 2026.2912266861108 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -3950.4236644760795 + 2309.554766115036 + + + + + + + + -3702.423664476079 + 2123.370760910181 + -3702.423664476079 + 2492.92617594471 + + + 0.49999999999999967 + 0.6607689879102607 + + + 0.5 + 0.5 + + + -3702.423664476079 + 2123.370760910181 + -3702.423664476079 + 2492.92617594471 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -3013.6027689536913 + 2313.5562222602784 + + + + + + + + -2766.6027689536913 + 2123.370760910181 + -2766.6027689536913 + 2500.63754936851 + + + 0.4719302694798556 + 0.6574445140745228 + + + 0.528069730520144 + 0.5 + + + -2766.6027689536913 + 2123.370760910181 + -2766.6027689536913 + 2500.63754936851 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -2122.0917264798663 + 2303.3283511632417 + + + + + + + + -1856.0917264798663 + 2103.033281565443 + -1856.0917264798663 + 2500.7171707610396 + + + 0.5 + 0.5 + + + 0.5 + 0.5 + + + -1856.0917264798663 + 2103.033281565443 + -1856.0917264798663 + 2500.7171707610396 + + + + + + + + + + + + + + + + + + 0.0 + 0.0 + + + + + -2963.6027689536913 + 1405.2651450114752 + + + + + + + + -2766.6027689536913 + -227.20841163912303 + -2766.6027689536913 + 1979.8344235739798 + -1410.6955266591508 + 1979.8344235739798 + + + 0.5 + 0.5 + + + 0.5480267788403651 + 0.4999999999999991 + + + -2766.6027689536913 + -227.20841163912303 + -2766.6027689536913 + 1979.8344235739798 + -1410.6955266591508 + 1979.8344235739798 + + diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD.cpp b/Views/STATE_ID_SCR_ADD_COLDCARD.cpp new file mode 100644 index 00000000..4f737cfa --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD.cpp @@ -0,0 +1,64 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_ADD_COLDCARD.h" +#include "Models/AppModel.h" +#include "localization/STR_CPP.h" + +void SCR_ADD_COLDCARD_Entry(QVariant msg) { + Q_UNUSED(msg); + AppModel::instance()->setNewKeySignMessage(""); + AppModel::instance()->setAddSignerWizard(0); + AppModel::instance()->setAddSignerPercentage(0); +} + +void SCR_ADD_COLDCARD_Exit(QVariant msg) { + Q_UNUSED(msg); + AppModel::instance()->setNewKeySignMessage(""); + AppModel::instance()->setAddSignerWizard(0); + AppModel::instance()->setAddSignerPercentage(0); +} + +void EVT_SCAN_COLDCARD_DEVICE_REQUEST_HANDLER(QVariant msg) { + Q_UNUSED(msg); + AppModel::instance()->startScanDevices(E::STATE_ID_SCR_ADD_HARDWARE_SIGNER); +} + +void EVT_ADD_COLDCARD_DEVICE_REQUEST_HANDLER(QVariant msg) { + DBG_INFO << msg; + QString signerNameInputted = msg.toMap().value("signerNameInputted").toString(); + int deviceIndexSelected = msg.toMap().value("deviceIndexSelected").toInt(); + if (AppModel::instance()->deviceList()) { + QDevicePtr selectedDv = AppModel::instance()->deviceList()->getDeviceByIndex(deviceIndexSelected); + if (selectedDv) { + if (selectedDv.data()->needsPinSent() || selectedDv.data()->needsPassPhraseSent()) { + AppModel::instance()->showToast(0, + 0, + EWARNING::WarningType::WARNING_MSG, + STR_CPP_095); + } else { + AppModel::instance()->setAddSignerWizard(2);//_LOADING: 2 + AppModel::instance()->startCreateMasterSigner(signerNameInputted, deviceIndexSelected); + } + } + } +} + diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD.h b/Views/STATE_ID_SCR_ADD_COLDCARD.h new file mode 100644 index 00000000..6b3ddc0e --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD.h @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_ADD_COLDCARD_H +#define STATE_ID_SCR_ADD_COLDCARD_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_ADD_COLDCARD_Entry(QVariant msg); +void SCR_ADD_COLDCARD_Exit(QVariant msg); +void EVT_SCAN_COLDCARD_DEVICE_REQUEST_HANDLER(QVariant msg); +void EVT_ADD_COLDCARD_DEVICE_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_ADD_COLDCARD_H diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp b/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp new file mode 100644 index 00000000..665d59e9 --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.cpp @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_ADD_COLDCARD_ASK.h" + +void SCR_ADD_COLDCARD_ASK_Entry(QVariant msg) { + +} + +void SCR_ADD_COLDCARD_ASK_Exit(QVariant msg) { + +} + +void EVT_ADD_COLDCARD_REQUEST_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.h b/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.h new file mode 100644 index 00000000..d5a4d0fa --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD_ASK.h @@ -0,0 +1,34 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_ADD_COLDCARD_ASK_H +#define STATE_ID_SCR_ADD_COLDCARD_ASK_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_ADD_COLDCARD_ASK_Entry(QVariant msg); +void SCR_ADD_COLDCARD_ASK_Exit(QVariant msg); +void EVT_ADD_COLDCARD_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_ADD_COLDCARD_ASK_H diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp b/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp new file mode 100644 index 00000000..96b3e696 --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.cpp @@ -0,0 +1,44 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_ADD_COLDCARD_EXIST.h" +#include "AppModel.h" +#include "Chats/QUserWallets.h" + +void SCR_ADD_COLDCARD_EXIST_Entry(QVariant msg) { + +} + +void SCR_ADD_COLDCARD_EXIST_Exit(QVariant msg) { + +} + +void EVT_ADD_EXIST_COLDCARD_REQUEST_HANDLER(QVariant msg) { + DBG_INFO << msg; + QMasterSignerPtr signer = AppModel::instance()->masterSignerList()->getMasterSignerByXfp(msg.toString()); + AppModel::instance()->setMasterSignerInfo(signer); + QUserWallets::instance()->addKeyRequested(); +} + +void EVT_ADD_NEW_COLDCARD_REQUEST_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.h b/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.h new file mode 100644 index 00000000..ff727e3c --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_COLDCARD_EXIST.h @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_ADD_COLDCARD_EXIST_H +#define STATE_ID_SCR_ADD_COLDCARD_EXIST_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_ADD_COLDCARD_EXIST_Entry(QVariant msg); +void SCR_ADD_COLDCARD_EXIST_Exit(QVariant msg); +void EVT_ADD_EXIST_COLDCARD_REQUEST_HANDLER(QVariant msg); +void EVT_ADD_NEW_COLDCARD_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_ADD_COLDCARD_EXIST_H diff --git a/Views/STATE_ID_SCR_ADD_LEDGER.cpp b/Views/STATE_ID_SCR_ADD_LEDGER.cpp index bf659607..db4700dc 100644 --- a/Views/STATE_ID_SCR_ADD_LEDGER.cpp +++ b/Views/STATE_ID_SCR_ADD_LEDGER.cpp @@ -45,18 +45,19 @@ void EVT_SCAN_LEDGER_DEVICE_REQUEST_HANDLER(QVariant msg) void EVT_ADD_LEDGER_DEVICE_REQUEST_HANDLER(QVariant msg) { + DBG_INFO << msg; QString signerNameInputted = msg.toMap().value("signerNameInputted").toString(); int deviceIndexSelected = msg.toMap().value("deviceIndexSelected").toInt(); - if(AppModel::instance()->deviceList()){ - QDevicePtr selectedDv = AppModel::instance()->deviceList()->getDeviceByIndex(deviceIndexSelected) ; - if(selectedDv){ - if(selectedDv.data()->needsPinSent() || selectedDv.data()->needsPassPhraseSent()){ + if (AppModel::instance()->deviceList()) { + QDevicePtr selectedDv = AppModel::instance()->deviceList()->getDeviceByIndex(deviceIndexSelected); + if (selectedDv) { + if (selectedDv.data()->needsPinSent() || selectedDv.data()->needsPassPhraseSent()) { AppModel::instance()->showToast(0, 0, EWARNING::WarningType::WARNING_MSG, STR_CPP_095); - } - else{ + } else { + AppModel::instance()->setAddSignerWizard(2);//_LOADING: 2 AppModel::instance()->startCreateMasterSigner(signerNameInputted, deviceIndexSelected); } } diff --git a/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp b/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp new file mode 100644 index 00000000..2fea9c23 --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.cpp @@ -0,0 +1,44 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_ADD_LEDGER_EXIST.h" +#include "AppModel.h" +#include "Chats/QUserWallets.h" + +void SCR_ADD_LEDGER_EXIST_Entry(QVariant msg) { + +} + +void SCR_ADD_LEDGER_EXIST_Exit(QVariant msg) { + +} + +void EVT_ADD_EXIST_LEDGER_REQUEST_HANDLER(QVariant msg) { + DBG_INFO << msg; + QMasterSignerPtr signer = AppModel::instance()->masterSignerList()->getMasterSignerByXfp(msg.toString()); + AppModel::instance()->setMasterSignerInfo(signer); + QUserWallets::instance()->addKeyRequested(); +} + +void EVT_ADD_NEW_LEDGER_REQUEST_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.h b/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.h new file mode 100644 index 00000000..06bc4e9b --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_LEDGER_EXIST.h @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_ADD_LEDGER_EXIST_H +#define STATE_ID_SCR_ADD_LEDGER_EXIST_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_ADD_LEDGER_EXIST_Entry(QVariant msg); +void SCR_ADD_LEDGER_EXIST_Exit(QVariant msg); +void EVT_ADD_EXIST_LEDGER_REQUEST_HANDLER(QVariant msg); +void EVT_ADD_NEW_LEDGER_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_ADD_LEDGER_EXIST_H diff --git a/Views/STATE_ID_SCR_ADD_TREZOR.cpp b/Views/STATE_ID_SCR_ADD_TREZOR.cpp index 3366cb14..55cd7889 100644 --- a/Views/STATE_ID_SCR_ADD_TREZOR.cpp +++ b/Views/STATE_ID_SCR_ADD_TREZOR.cpp @@ -45,18 +45,19 @@ void EVT_SCAN_TREZOR_DEVICE_REQUEST_HANDLER(QVariant msg) void EVT_ADD_TREZOR_DEVICE_REQUEST_HANDLER(QVariant msg) { + DBG_INFO; QString signerNameInputted = msg.toMap().value("signerNameInputted").toString(); int deviceIndexSelected = msg.toMap().value("deviceIndexSelected").toInt(); - if(AppModel::instance()->deviceList()){ - QDevicePtr selectedDv = AppModel::instance()->deviceList()->getDeviceByIndex(deviceIndexSelected) ; - if(selectedDv){ + if (AppModel::instance()->deviceList()) { + QDevicePtr selectedDv = AppModel::instance()->deviceList()->getDeviceByIndex(deviceIndexSelected); + if (selectedDv) { if(selectedDv.data()->needsPinSent() || selectedDv.data()->needsPassPhraseSent()){ AppModel::instance()->showToast(0, 0, EWARNING::WarningType::WARNING_MSG, STR_CPP_095); - } - else{ + } else { + AppModel::instance()->setAddSignerWizard(2);//_LOADING: 2 AppModel::instance()->startCreateMasterSigner(signerNameInputted, deviceIndexSelected); } } diff --git a/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp b/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp new file mode 100644 index 00000000..8e0d0168 --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.cpp @@ -0,0 +1,44 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_ADD_TREZOR_EXIST.h" +#include "AppModel.h" +#include "Chats/QUserWallets.h" + +void SCR_ADD_TREZOR_EXIST_Entry(QVariant msg) { + +} + +void SCR_ADD_TREZOR_EXIST_Exit(QVariant msg) { + +} + +void EVT_ADD_EXIST_TREZOR_REQUEST_HANDLER(QVariant msg) { + DBG_INFO << msg; + QMasterSignerPtr signer = AppModel::instance()->masterSignerList()->getMasterSignerByXfp(msg.toString()); + AppModel::instance()->setMasterSignerInfo(signer); + QUserWallets::instance()->addKeyRequested(); +} + +void EVT_ADD_NEW_TREZOR_REQUEST_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.h b/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.h new file mode 100644 index 00000000..ce6f350e --- /dev/null +++ b/Views/STATE_ID_SCR_ADD_TREZOR_EXIST.h @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_ADD_TREZOR_EXIST_H +#define STATE_ID_SCR_ADD_TREZOR_EXIST_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_ADD_TREZOR_EXIST_Entry(QVariant msg); +void SCR_ADD_TREZOR_EXIST_Exit(QVariant msg); +void EVT_ADD_EXIST_TREZOR_REQUEST_HANDLER(QVariant msg); +void EVT_ADD_NEW_TREZOR_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_ADD_TREZOR_EXIST_H diff --git a/Views/STATE_ID_SCR_ADD_WALLET.cpp b/Views/STATE_ID_SCR_ADD_WALLET.cpp index 031ac3ee..c34245a0 100644 --- a/Views/STATE_ID_SCR_ADD_WALLET.cpp +++ b/Views/STATE_ID_SCR_ADD_WALLET.cpp @@ -72,7 +72,7 @@ void EVT_ADD_WALLET_IMPORT_HANDLER(QVariant msg) { if(walletImported && importmsg.type() == (int)EWARNING::WarningType::NONE_MSG){ AppModel::instance()->walletList()->addWallet(walletImported); AppModel::instance()->resetSignersChecked(); - AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_Name_Role, Qt::AscendingOrder); + AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_createDate_Role, Qt::AscendingOrder); int index = AppModel::instance()->walletList()->getWalletIndexById(walletImported.data()->id()); if(-1 != index){ AppModel::instance()->setWalletListCurrentIndex(index); diff --git a/Views/STATE_ID_SCR_ADD_WALLET_CONFIRMATION.cpp b/Views/STATE_ID_SCR_ADD_WALLET_CONFIRMATION.cpp index e4f3aff6..2a078657 100644 --- a/Views/STATE_ID_SCR_ADD_WALLET_CONFIRMATION.cpp +++ b/Views/STATE_ID_SCR_ADD_WALLET_CONFIRMATION.cpp @@ -51,41 +51,57 @@ void EVT_ADD_WALLET_TOP_UP_XPUBS_REQUEST_HANDLER(QVariant msg) { int signer_index = msg.toInt(); if(signer_index >= 0 && AppModel::instance()->newWalletInfo() && AppModel::instance()->newWalletInfo()->singleSignersAssigned()){ QSingleSignerPtr it = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->getSingleSignerByIndex(signer_index); - QWarningMessage warningmsg; - bridge::nunchukCacheMasterSignerXPub(it.data()->masterSignerId(), warningmsg); - if((int)EWARNING::WarningType::NONE_MSG == warningmsg.type()){ - int numberSignerRequired = AppModel::instance()->newWalletInfo()->n(); - bool escrow = AppModel::instance()->newWalletInfo()->escrow(); - ENUNCHUCK::WalletType walletType = escrow ? ENUNCHUCK::WalletType::ESCROW : - numberSignerRequired > 1 ? ENUNCHUCK::WalletType::MULTI_SIG - : ENUNCHUCK::WalletType::SINGLE_SIG; - ENUNCHUCK::AddressType addressType = (ENUNCHUCK::AddressType)AppModel::instance()->newWalletInfo()->addressType().toInt(); - warningmsg.resetWarningMessage(); - QSingleSignerPtr signer = bridge::nunchukGetUnusedSignerFromMasterSigner(it.data()->masterSignerId(), - walletType, - addressType, - warningmsg); - if(signer && warningmsg.type() == (int)EWARNING::WarningType::NONE_MSG){ - AppModel::instance()->newWalletInfo()->singleSignersAssigned()->replaceSingleSigner(msg.toInt(), signer); - AppModel::instance()->showToast(0, - STR_CPP_097, - EWARNING::WarningType::SUCCESS_MSG, - STR_CPP_097); + if(it){ + QWarningMessage warningmsg; + bridge::nunchukCacheMasterSignerXPub(it.data()->masterSignerId(), warningmsg); + if((int)EWARNING::WarningType::NONE_MSG == warningmsg.type()){ + int numberSignerRequired = AppModel::instance()->newWalletInfo()->n(); + bool escrow = AppModel::instance()->newWalletInfo()->escrow(); + ENUNCHUCK::WalletType walletType = escrow ? ENUNCHUCK::WalletType::ESCROW : + numberSignerRequired > 1 ? ENUNCHUCK::WalletType::MULTI_SIG + : ENUNCHUCK::WalletType::SINGLE_SIG; + ENUNCHUCK::AddressType addressType = (ENUNCHUCK::AddressType)AppModel::instance()->newWalletInfo()->addressType().toInt(); + warningmsg.resetWarningMessage(); + QSingleSignerPtr signer{nullptr}; + if(((int)ENUNCHUCK::SignerType::SOFTWARE == it.data()->signerType()) + || (int)ENUNCHUCK::SignerType::HARDWARE == it.data()->signerType() + || (int)ENUNCHUCK::SignerType::NFC == it.data()->signerType()){ + if (AppModel::instance()->getIsPremiumUser() && (int)ENUNCHUCK::SignerType::NFC == it.data()->signerType()) { + signer = bridge::nunchukGetDefaultSignerFromMasterSigner(it.data()->masterSignerId(), + walletType, + addressType, + warningmsg); + } + else { + signer = bridge::nunchukGetUnusedSignerFromMasterSigner(it.data()->masterSignerId(), + walletType, + addressType, + warningmsg); + } + + if(signer && warningmsg.type() == (int)EWARNING::WarningType::NONE_MSG){ + AppModel::instance()->newWalletInfo()->singleSignersAssigned()->replaceSingleSigner(msg.toInt(), signer); + AppModel::instance()->showToast(0, + STR_CPP_097, + EWARNING::WarningType::SUCCESS_MSG, + STR_CPP_097); + } + else{ + it.data()->setNeedTopUpXpub(true); + AppModel::instance()->showToast(warningmsg.code(), + warningmsg.what(), + (EWARNING::WarningType)warningmsg.type(), + STR_CPP_069.arg(it.data()->masterFingerPrint().toUpper())); + } + } } else{ - it.data()->setNeedTopUpXpub(true); AppModel::instance()->showToast(warningmsg.code(), warningmsg.what(), (EWARNING::WarningType)warningmsg.type(), - STR_CPP_069.arg(it.data()->masterFingerPrint().toUpper())); + STR_CPP_070.arg(it.data()->masterFingerPrint().toUpper())); } } - else{ - AppModel::instance()->showToast(warningmsg.code(), - warningmsg.what(), - (EWARNING::WarningType)warningmsg.type(), - STR_CPP_070.arg(it.data()->masterFingerPrint().toUpper())); - } } if(AppModel::instance()->newWalletInfo()){ bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); diff --git a/Views/STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.cpp b/Views/STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.cpp index fb65a034..9d7889c8 100644 --- a/Views/STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.cpp +++ b/Views/STATE_ID_SCR_ADD_WALLET_SIGNER_CONFIGURATION.cpp @@ -45,6 +45,7 @@ void EVT_SIGNER_CONFIGURATION_SELECT_MASTER_SIGNER_HANDLER(QVariant msg) { signer.data()->setDevicetype(ret.data()->device()->type()); signer.data()->setCardId(ret.data()->device()->cardId()); signer.data()->setMasterFingerPrint(ret.data()->fingerPrint()); + signer.data()->setDerivationPath(ret.data()->device()->path()); if(signer){ AppModel::instance()->newWalletInfo()->singleSignersAssigned()->addSingleSigner(signer); } @@ -113,35 +114,36 @@ void EVT_SIGNER_CONFIGURATION_TRY_REVIEW_HANDLER(QVariant msg) { DBG_INFO << msg; if(AppModel::instance()->newWalletInfo() && AppModel::instance()->newWalletInfo()->singleSignersAssigned()){ int numberSignerRequired = AppModel::instance()->newWalletInfo()->n(); - DBG_INFO << "numberSignerRequired " << numberSignerRequired; bool escrow = AppModel::instance()->newWalletInfo()->escrow(); ENUNCHUCK::WalletType walletType = escrow ? ENUNCHUCK::WalletType::ESCROW : numberSignerRequired > 1 ? ENUNCHUCK::WalletType::MULTI_SIG : ENUNCHUCK::WalletType::SINGLE_SIG; ENUNCHUCK::AddressType addressType = (ENUNCHUCK::AddressType)AppModel::instance()->newWalletInfo()->addressType().toInt(); - DBG_INFO << "addressType " << (int)addressType; for (int i = 0; i < AppModel::instance()->newWalletInfo()->singleSignersAssigned()->rowCount(); i++) { QSingleSignerPtr it = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->getSingleSignerByIndex(i); - DBG_INFO << "signerType " << it.data()->signerType() << it.data()->isPrimaryKey(); - if(it && !((int)ENUNCHUCK::SignerType::AIRGAP == it.data()->signerType())){ - if(!(it.data()->needTopUpXpub())){ - // Request cached xpub - QWarningMessage warningmsg; - QSingleSignerPtr signer = bridge::nunchukGetUnusedSignerFromMasterSigner(it.data()->masterSignerId(), - walletType, - addressType, - warningmsg); - if(signer && warningmsg.type() == (int)EWARNING::WarningType::NONE_MSG){ - signer.data()->setIsPrimaryKey(it.data()->isPrimaryKey()); - AppModel::instance()->newWalletInfo()->singleSignersAssigned()->replaceSingleSigner(i, signer); - AppModel::instance()->showToast(0, - STR_CPP_067, - EWARNING::WarningType::SUCCESS_MSG, - STR_CPP_067); - } - else{ - it.data()->setNeedTopUpXpub(true); - } + if((it && (int)ENUNCHUCK::SignerType::SOFTWARE == it.data()->signerType()) + || (int)ENUNCHUCK::SignerType::HARDWARE == it.data()->signerType() + || (int)ENUNCHUCK::SignerType::NFC == it.data()->signerType()){ + QSingleSignerPtr signer{nullptr}; + QWarningMessage warningmsg; + if (AppModel::instance()->getIsPremiumUser() && (int)ENUNCHUCK::SignerType::NFC == it.data()->signerType()) { + signer = bridge::nunchukGetDefaultSignerFromMasterSigner(it.data()->masterSignerId(), + walletType, + addressType, + warningmsg); + } + else { + signer = bridge::nunchukGetUnusedSignerFromMasterSigner(it.data()->masterSignerId(), + walletType, + addressType, + warningmsg); + } + if(signer && warningmsg.type() == (int)EWARNING::WarningType::NONE_MSG){ + signer.data()->setIsPrimaryKey(it.data()->isPrimaryKey()); + AppModel::instance()->newWalletInfo()->singleSignersAssigned()->replaceSingleSigner(i, signer); + } + else{ + it.data()->setNeedTopUpXpub(true); } } } diff --git a/Views/STATE_ID_SCR_CONSOLIDATE_OUTPUT.cpp b/Views/STATE_ID_SCR_CONSOLIDATE_OUTPUT.cpp index 9a16a810..1cf96e16 100644 --- a/Views/STATE_ID_SCR_CONSOLIDATE_OUTPUT.cpp +++ b/Views/STATE_ID_SCR_CONSOLIDATE_OUTPUT.cpp @@ -67,7 +67,8 @@ void EVT_CONSOLIDATE_MAKE_TRANSACTION_HANDLER(QVariant msg) { it.data()->address(), it.data()->amountSats(), it.data()->height(), - it.data()->memo()); + it.data()->memo(), + it.data()->status()); } } } diff --git a/Views/STATE_ID_SCR_CREATE_TRANSACTION.cpp b/Views/STATE_ID_SCR_CREATE_TRANSACTION.cpp index 2ece3603..8656c934 100644 --- a/Views/STATE_ID_SCR_CREATE_TRANSACTION.cpp +++ b/Views/STATE_ID_SCR_CREATE_TRANSACTION.cpp @@ -87,7 +87,8 @@ void EVT_CREATE_TRANSACTION_SIGN_REQUEST_HANDLER(QVariant msg) { it.data()->address(), it.data()->amountSats(), it.data()->height(), - it.data()->memo()); + it.data()->memo(), + it.data()->status()); } } } @@ -208,7 +209,8 @@ void EVT_CREATE_TRANSACTION_MAKE_DRAFT_TX_HANDLER(QVariant msg) { it.data()->address(), it.data()->amountSats(), it.data()->height(), - it.data()->memo()); + it.data()->memo(), + it.data()->status()); } } } diff --git a/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp b/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp new file mode 100644 index 00000000..4173cb76 --- /dev/null +++ b/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.cpp @@ -0,0 +1,51 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h" + +void SCR_EDIT_YOUR_INHERITANCE_PLAN_Entry(QVariant msg) { + +} + +void SCR_EDIT_YOUR_INHERITANCE_PLAN_Exit(QVariant msg) { + +} + +void EVT_UPDATE_ACTIVATION_DATE_REQUEST_HANDLER(QVariant msg) { + +} + +void EVT_UPDATE_MESSAGE_REQUEST_HANDLER(QVariant msg) { + +} + +void EVT_UPDATE_BUFFER_PERIOD_REQUEST_HANDLER(QVariant msg) { + +} + +void EVT_UPDATE_NOTIFICATION_PREFERENCE_REQ_HANDLER(QVariant msg) { + +} + +void EVT_NOT_UPDATE_ANY_NOTI_REQ_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h b/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h new file mode 100644 index 00000000..44b5a46b --- /dev/null +++ b/Views/STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN.h @@ -0,0 +1,38 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_H +#define STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_EDIT_YOUR_INHERITANCE_PLAN_Entry(QVariant msg); +void SCR_EDIT_YOUR_INHERITANCE_PLAN_Exit(QVariant msg); +void EVT_UPDATE_ACTIVATION_DATE_REQUEST_HANDLER(QVariant msg); +void EVT_UPDATE_MESSAGE_REQUEST_HANDLER(QVariant msg); +void EVT_UPDATE_BUFFER_PERIOD_REQUEST_HANDLER(QVariant msg); +void EVT_UPDATE_NOTIFICATION_PREFERENCE_REQ_HANDLER(QVariant msg); +void EVT_NOT_UPDATE_ANY_NOTI_REQ_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_H diff --git a/Views/STATE_ID_SCR_HOME.cpp b/Views/STATE_ID_SCR_HOME.cpp index c7c2a377..c60724af 100644 --- a/Views/STATE_ID_SCR_HOME.cpp +++ b/Views/STATE_ID_SCR_HOME.cpp @@ -141,10 +141,11 @@ void EVT_HOME_ADD_NEW_SIGNER_REQUEST_HANDLER(QVariant msg) { void EVT_HOME_IMPORT_PSBT_HANDLER(QVariant msg) { QString file_path = qUtils::QGetFilePath(msg.toString()); - if (file_path != "" && AppModel::instance()->walletInfo()){ - QString wallet_id = AppModel::instance()->walletInfo()->id(); + QWalletPtr w = AppModel::instance()->walletInfoPtr(); + if (file_path != "" && w){ + QString wallet_id = w->id(); QWarningMessage msgwarning; - QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, msgwarning); + QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, w->isAssistedWallet(), msgwarning); if((int)EWARNING::WarningType::NONE_MSG == msgwarning.type()){ if(trans){ AppModel::instance()->setTransactionInfo(trans); @@ -190,12 +191,20 @@ void EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST_HANDLER(QVariant msg) { } void EVT_ASK_LEDGER_REQ_HANDLER(QVariant msg) { - } +void EVT_ASK_TREZOR_REQ_HANDLER(QVariant msg) { +} +void EVT_ASK_COLDCARD_REQ_HANDLER(QVariant msg) +{ +} -void EVT_ASK_TREZOR_REQ_HANDLER(QVariant msg) { +void EVT_EXIST_LEDGER_REQ_HANDLER(QVariant msg) { +} +void EVT_EXIST_TREZOR_REQ_HANDLER(QVariant msg) { } +void EVT_EXIST_COLDCARD_REQ_HANDLER(QVariant msg) { +} diff --git a/Views/STATE_ID_SCR_HOME.h b/Views/STATE_ID_SCR_HOME.h index d70e47f0..8a34aa68 100644 --- a/Views/STATE_ID_SCR_HOME.h +++ b/Views/STATE_ID_SCR_HOME.h @@ -47,5 +47,9 @@ void EVT_HOME_ADD_NEW_SIGNER_REQUEST_HANDLER(QVariant msg); void EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST_HANDLER(QVariant msg); void EVT_ASK_LEDGER_REQ_HANDLER(QVariant msg); void EVT_ASK_TREZOR_REQ_HANDLER(QVariant msg); +void EVT_ASK_COLDCARD_REQ_HANDLER(QVariant msg); +void EVT_EXIST_LEDGER_REQ_HANDLER(QVariant msg); +void EVT_EXIST_TREZOR_REQ_HANDLER(QVariant msg); +void EVT_EXIST_COLDCARD_REQ_HANDLER(QVariant msg); #endif // STATE_ID_SCR_HOME_H diff --git a/Views/STATE_ID_SCR_REENTER_YOUR_PASSWORD.cpp b/Views/STATE_ID_SCR_REENTER_YOUR_PASSWORD.cpp index 9a77bd6b..f478015d 100644 --- a/Views/STATE_ID_SCR_REENTER_YOUR_PASSWORD.cpp +++ b/Views/STATE_ID_SCR_REENTER_YOUR_PASSWORD.cpp @@ -21,6 +21,7 @@ #include "QQuickViewer.h" #include "Draco.h" #include "Chats/QUserWallets.h" +#include "ServiceSetting.h" static QVariant passWordObject = QVariant(); void SCR_REENTER_YOUR_PASSWORD_Entry(QVariant msg) { @@ -76,6 +77,13 @@ void EVT_INPUT_PASSWORD_REQUEST_HANDLER(QVariant msg) { } } break; + case E::STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN: { + QString walletName = passWordObject.toMap().value("walletName").toString(); + if (QUserWallets::instance()->requestInheritancePlanVerifyPassword(password)) { + ServiceSetting::instance()->setInheritanceWalletName(walletName); + QQuickViewer::instance()->sendEvent(E::EVT_CLOSE_TO_SERVICE_SETTINGS_REQUEST); + } + }break; default: break; } diff --git a/Views/STATE_ID_SCR_SERVICE_SETTINGS.cpp b/Views/STATE_ID_SCR_SERVICE_SETTINGS.cpp index 9702b239..92d53bd4 100644 --- a/Views/STATE_ID_SCR_SERVICE_SETTINGS.cpp +++ b/Views/STATE_ID_SCR_SERVICE_SETTINGS.cpp @@ -81,3 +81,36 @@ void EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED_HANDLER(QVariant msg) QUserWallets::instance()->serverKeyUpdatePoliciesSucceed(); } } + +void EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST_HANLDER(QVariant msg) { + ServiceSetting::instance()->setInheritancePlan(msg.toInt()); +} + +void EVT_SHARE_YOUR_SECRET_REQUEST_HANDLER(QVariant msg) { + +} + +void EVT_SERVICE_SELECT_WALLET_REQUEST_HANDLER(QVariant msg) { + QWalletPtr wallet = AppModel::instance()->walletList()->getWalletById(msg.toString()); + if (!wallet.isNull() && QUserWallets::instance()->inheritanceGetPlan(wallet->id())) { + QMap data; + data["state_id"] = E::STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN; + data["walletName"] = wallet->name(); + ServiceSetting::instance()->setInheritanceWalletId(wallet->id()); + QQuickViewer::instance()->sendEvent(E::EVT_REENTER_YOUR_PASSWORD_REQUEST, data); + } +} + +void EVT_INHERITANCE_PLAN_FINALIZE_REQUEST_HANDLER(QVariant msg) { + int option = msg.toInt(); + if (option == 2) { + emit QUserWallets::instance()->inheritanceDiscardChangeAlert(); + } else if(option == 1) { + QUserWallets::instance()->inheritancePlanFinalizeChanges(); + } else if(option == 3) { + if (QUserWallets::instance()->secQuesAnswer()) { + QUserWallets::instance()->inheritancePlanUpdate(); + } + } +} + diff --git a/Views/STATE_ID_SCR_SERVICE_SETTINGS.h b/Views/STATE_ID_SCR_SERVICE_SETTINGS.h index 39f69058..aa16316a 100644 --- a/Views/STATE_ID_SCR_SERVICE_SETTINGS.h +++ b/Views/STATE_ID_SCR_SERVICE_SETTINGS.h @@ -32,8 +32,12 @@ void SCR_SERVICE_SETTINGS_Exit(QVariant msg); void EVT_CLAIM_INHERITANCE_CHECK_REQUEST_HANDLER(QVariant msg); void EVT_CO_SIGNING_SERVER_KEY_UPDATE_REQUEST_HANDLER(QVariant msg); void EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED_HANDLER(QVariant msg); +void EVT_SERVICE_SELECT_WALLET_REQUEST_HANDLER(QVariant msg); +void EVT_INHERITANCE_PLAN_FINALIZE_REQUEST_HANDLER(QVariant msg); void EVT_REENTER_YOUR_PASSWORD_REQUEST_HANDLER(QVariant msg); void EVT_SERVICE_SUPPORT_REQUEST_HANDLER(QVariant msg); void EVT_INHERITANCE_WITHDRAW_BALANCE_REQUEST_HANDLER(QVariant msg); +void EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST_HANLDER(QVariant msg); +void EVT_SHARE_YOUR_SECRET_REQUEST_HANDLER(QVariant msg); #endif // STATE_ID_SCR_SERVICE_SETTINGS_H diff --git a/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp b/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp new file mode 100644 index 00000000..4d98136c --- /dev/null +++ b/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.cpp @@ -0,0 +1,35 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#include "STATE_ID_SCR_SHARE_YOUR_SECRETS.h" + +void SCR_SHARE_YOUR_SECRETS_Entry(QVariant msg) { + +} + +void SCR_SHARE_YOUR_SECRETS_Exit(QVariant msg) { + +} + +void EVT_UPDATE_YOUR_SECRET_REQUEST_HANDLER(QVariant msg) { + +} + diff --git a/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.h b/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.h new file mode 100644 index 00000000..cc63b075 --- /dev/null +++ b/Views/STATE_ID_SCR_SHARE_YOUR_SECRETS.h @@ -0,0 +1,34 @@ +/************************************************************************* +* This file is part of the Nunchuk software (https://nunchuk.io/) * +* Copyright (C) 2020-2022 Enigmo * +* Copyright (C) 2022 Nunchuk * +* * +* This program is free software; you can redistribute it and/or * +* modify it under the terms of the GNU General Public License * +* as published by the Free Software Foundation; either version 3 * +* of the License, or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +* * +**************************************************************************/ + + +#ifndef STATE_ID_SCR_SHARE_YOUR_SECRETS_H +#define STATE_ID_SCR_SHARE_YOUR_SECRETS_H + +#include +#include +#include "ViewsDefines.h" +#include "ViewsEnums.h" + +void SCR_SHARE_YOUR_SECRETS_Entry(QVariant msg); +void SCR_SHARE_YOUR_SECRETS_Exit(QVariant msg); +void EVT_UPDATE_YOUR_SECRET_REQUEST_HANDLER(QVariant msg); + +#endif // STATE_ID_SCR_SHARE_YOUR_SECRETS_H diff --git a/Views/STATE_ID_SCR_TRANSACTION_INFO.cpp b/Views/STATE_ID_SCR_TRANSACTION_INFO.cpp index a219eb9d..d90f7f7f 100644 --- a/Views/STATE_ID_SCR_TRANSACTION_INFO.cpp +++ b/Views/STATE_ID_SCR_TRANSACTION_INFO.cpp @@ -111,10 +111,11 @@ void EVT_TRANSACTION_EXPORT_REQUEST_HANDLER(QVariant msg) { void EVT_TRANSACTION_IMPORT_REQUEST_HANDLER(QVariant msg) { QString file_path = qUtils::QGetFilePath(msg.toString()); - if (file_path != "" && AppModel::instance()->walletInfo()){ - QString wallet_id = AppModel::instance()->walletInfo()->id(); + QWalletPtr w = AppModel::instance()->walletInfoPtr(); + if (file_path != "" && w){ + QString wallet_id = w->id(); QWarningMessage msgwarning; - QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, msgwarning); + QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, w->isAssistedWallet(), msgwarning); if(trans){ AppModel::instance()->setTransactionInfo(trans); AppModel::instance()->requestSyncWalletDb(wallet_id); diff --git a/Views/STATE_ID_SCR_WALLET_INFO.cpp b/Views/STATE_ID_SCR_WALLET_INFO.cpp index e6820fc4..6db7fbca 100644 --- a/Views/STATE_ID_SCR_WALLET_INFO.cpp +++ b/Views/STATE_ID_SCR_WALLET_INFO.cpp @@ -41,7 +41,7 @@ void EVT_WALLET_INFO_EDIT_NAME_HANDLER(QVariant msg) { AppModel::instance()->walletList()->updateName(AppModel::instance()->walletInfo()->id(), msg.toString()); if(AppModel::instance()->walletList()){ QString wallet_id = AppModel::instance()->walletInfo()->id(); - AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_Name_Role, Qt::AscendingOrder); + AppModel::instance()->walletList()->requestSort(WalletListModel::WalletRoles::wallet_createDate_Role, Qt::AscendingOrder); int index = AppModel::instance()->walletList()->getWalletIndexById(wallet_id); if(-1 != index){ AppModel::instance()->setWalletListCurrentIndex(index); @@ -222,10 +222,11 @@ void EVT_WALLET_INFO_EXPORT_QRCODE_HANDLER(QVariant msg) { void EVT_WALLET_INFO_IMPORT_PSBT_HANDLER(QVariant msg) { QString file_path = qUtils::QGetFilePath(msg.toString()); - if (file_path != "" && AppModel::instance()->walletInfo()){ - QString wallet_id = AppModel::instance()->walletInfo()->id(); + QWalletPtr w = AppModel::instance()->walletInfoPtr(); + if (file_path != "" && w){ + QString wallet_id = w->id(); QWarningMessage msgwarning; - QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, msgwarning); + QTransactionPtr trans = bridge::nunchukImportTransaction(wallet_id, file_path, w->isAssistedWallet(), msgwarning); if((int)EWARNING::WarningType::NONE_MSG == msgwarning.type()){ if(trans){ AppModel::instance()->setTransactionInfo(trans); @@ -258,6 +259,7 @@ void EVT_WALLET_INFO_GAP_LIMIT_REQUEST_HANDLER(QVariant msg) if (AppModel::instance()->walletInfo()){ QString wallet_id = AppModel::instance()->walletInfo()->id(); uint gap_limit = msg.toUInt(); - bridge::nunchukUpdateWalletGapLimit(wallet_id,gap_limit); + bridge::nunchukUpdateWalletGapLimit(wallet_id, gap_limit); + AppModel::instance()->walletInfo()->setGapLimit(gap_limit); } } diff --git a/Views/Views.h b/Views/Views.h index a1835889..5bc0aed2 100644 --- a/Views/Views.h +++ b/Views/Views.h @@ -101,6 +101,13 @@ static const APPLICATION_STATE STATE_ID_SCR_ADD_TREZOR_ASK static const APPLICATION_STATE STATE_ID_SCR_ADD_LEDGER = {E::STATE_ID_SCR_ADD_LEDGER , SCR_ADD_LEDGER_Entry , SCR_ADD_LEDGER_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_LEDGER }; static const APPLICATION_STATE STATE_ID_SCR_ADD_TREZOR = {E::STATE_ID_SCR_ADD_TREZOR , SCR_ADD_TREZOR_Entry , SCR_ADD_TREZOR_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_TREZOR }; static const APPLICATION_STATE STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE = {E::STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE , SCR_SELECT_WALLET_CO_SIGN_POLICE_Entry , SCR_SELECT_WALLET_CO_SIGN_POLICE_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_SELECT_WALLET_CO_SIGN_POLICE }; +static const APPLICATION_STATE STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN = {E::STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN , SCR_EDIT_YOUR_INHERITANCE_PLAN_Entry , SCR_EDIT_YOUR_INHERITANCE_PLAN_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_EDIT_YOUR_INHERITANCE_PLAN }; +static const APPLICATION_STATE STATE_ID_SCR_SHARE_YOUR_SECRETS = {E::STATE_ID_SCR_SHARE_YOUR_SECRETS , SCR_SHARE_YOUR_SECRETS_Entry , SCR_SHARE_YOUR_SECRETS_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_SHARE_YOUR_SECRETS }; +static const APPLICATION_STATE STATE_ID_SCR_ADD_COLDCARD_ASK = {E::STATE_ID_SCR_ADD_COLDCARD_ASK , SCR_ADD_COLDCARD_ASK_Entry , SCR_ADD_COLDCARD_ASK_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_COLDCARD_ASK }; +static const APPLICATION_STATE STATE_ID_SCR_ADD_COLDCARD = {E::STATE_ID_SCR_ADD_COLDCARD , SCR_ADD_COLDCARD_Entry , SCR_ADD_COLDCARD_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_COLDCARD }; +static const APPLICATION_STATE STATE_ID_SCR_ADD_LEDGER_EXIST = {E::STATE_ID_SCR_ADD_LEDGER_EXIST , SCR_ADD_LEDGER_EXIST_Entry , SCR_ADD_LEDGER_EXIST_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_LEDGER_EXIST }; +static const APPLICATION_STATE STATE_ID_SCR_ADD_TREZOR_EXIST = {E::STATE_ID_SCR_ADD_TREZOR_EXIST , SCR_ADD_TREZOR_EXIST_Entry , SCR_ADD_TREZOR_EXIST_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_TREZOR_EXIST }; +static const APPLICATION_STATE STATE_ID_SCR_ADD_COLDCARD_EXIST = {E::STATE_ID_SCR_ADD_COLDCARD_EXIST , SCR_ADD_COLDCARD_EXIST_Entry , SCR_ADD_COLDCARD_EXIST_Exit , LAYER::LAYER_ONSCREEN, LIMIT::NONE , SCR_ADD_COLDCARD_EXIST }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static const STATE_TRIGGER STATE_ID_ROOT_trigger[25] = @@ -135,6 +142,32 @@ static const STATE_TRIGGER STATE_ID_ROOT_trigger[25] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static const STATE_TRIGGER STATE_ID_SCR_ADD_COLDCARD_trigger[2] = +{ + {E::EVT_SCAN_COLDCARD_DEVICE_REQUEST, EVT_SCAN_COLDCARD_DEVICE_REQUEST_HANDLER, NULL }, + {E::EVT_ADD_COLDCARD_DEVICE_REQUEST , EVT_ADD_COLDCARD_DEVICE_REQUEST_HANDLER , NULL }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static const STATE_TRIGGER STATE_ID_SCR_ADD_COLDCARD_ASK_trigger[1] = +{ + {E::EVT_ADD_COLDCARD_REQUEST, EVT_ADD_COLDCARD_REQUEST_HANDLER, &STATE_ID_SCR_ADD_COLDCARD }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static const STATE_TRIGGER STATE_ID_SCR_ADD_COLDCARD_EXIST_trigger[2] = +{ + {E::EVT_ADD_EXIST_COLDCARD_REQUEST, EVT_ADD_EXIST_COLDCARD_REQUEST_HANDLER, NULL }, + {E::EVT_ADD_NEW_COLDCARD_REQUEST , EVT_ADD_NEW_COLDCARD_REQUEST_HANDLER , &STATE_ID_SCR_ADD_COLDCARD }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static const STATE_TRIGGER STATE_ID_SCR_ADD_HARDWARE_SIGNER_trigger[8] = { {E::EVT_ADD_HARDWARE_SIGNER_ADD_MASTER_SIGNER_REQUEST, EVT_ADD_HARDWARE_SIGNER_ADD_MASTER_SIGNER_REQUEST_HANDLER, NULL }, @@ -182,6 +215,15 @@ static const STATE_TRIGGER STATE_ID_SCR_ADD_LEDGER_ASK_trigger[1] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static const STATE_TRIGGER STATE_ID_SCR_ADD_LEDGER_EXIST_trigger[2] = +{ + {E::EVT_ADD_EXIST_LEDGER_REQUEST, EVT_ADD_EXIST_LEDGER_REQUEST_HANDLER, NULL }, + {E::EVT_ADD_NEW_LEDGER_REQUEST , EVT_ADD_NEW_LEDGER_REQUEST_HANDLER , &STATE_ID_SCR_ADD_LEDGER }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static const STATE_TRIGGER STATE_ID_SCR_ADD_MASTER_SIGNER_RESULT_trigger[6] = { {E::EVT_ADD_MASTER_SIGNER_RESULT_RUN_HEALTHCHECK , EVT_ADD_MASTER_SIGNER_RESULT_RUN_HEALTHCHECK_HANDLER , NULL }, @@ -260,6 +302,15 @@ static const STATE_TRIGGER STATE_ID_SCR_ADD_TREZOR_ASK_trigger[1] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static const STATE_TRIGGER STATE_ID_SCR_ADD_TREZOR_EXIST_trigger[2] = +{ + {E::EVT_ADD_EXIST_TREZOR_REQUEST, EVT_ADD_EXIST_TREZOR_REQUEST_HANDLER, NULL }, + {E::EVT_ADD_NEW_TREZOR_REQUEST , EVT_ADD_NEW_TREZOR_REQUEST_HANDLER , &STATE_ID_SCR_ADD_TREZOR }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static const STATE_TRIGGER STATE_ID_SCR_ADD_WALLET_trigger[4] = { {E::EVT_ADD_WALLET_IMPORT , EVT_ADD_WALLET_IMPORT_HANDLER , NULL }, @@ -429,6 +480,18 @@ static const STATE_TRIGGER STATE_ID_SCR_DUMMY_TRANSACTION_INFO_trigger[7] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static const STATE_TRIGGER STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_trigger[5] = +{ + {E::EVT_UPDATE_ACTIVATION_DATE_REQUEST , EVT_UPDATE_ACTIVATION_DATE_REQUEST_HANDLER , NULL }, + {E::EVT_UPDATE_MESSAGE_REQUEST , EVT_UPDATE_MESSAGE_REQUEST_HANDLER , NULL }, + {E::EVT_UPDATE_BUFFER_PERIOD_REQUEST , EVT_UPDATE_BUFFER_PERIOD_REQUEST_HANDLER , NULL }, + {E::EVT_UPDATE_NOTIFICATION_PREFERENCE_REQ, EVT_UPDATE_NOTIFICATION_PREFERENCE_REQ_HANDLER, NULL }, + {E::EVT_NOT_UPDATE_ANY_NOTI_REQ , EVT_NOT_UPDATE_ANY_NOTI_REQ_HANDLER , NULL }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static const STATE_TRIGGER STATE_ID_SCR_ENTER_BACKUP_PASSWORD_trigger[3] = { {E::EVT_INPUT_BACKUP_PASSWORD_REQUEST , EVT_INPUT_BACKUP_PASSWORD_REQUEST_HANDLER , NULL }, @@ -439,7 +502,7 @@ static const STATE_TRIGGER STATE_ID_SCR_ENTER_BACKUP_PASSWORD_trigger[3] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static const STATE_TRIGGER STATE_ID_SCR_HOME_trigger[18] = +static const STATE_TRIGGER STATE_ID_SCR_HOME_trigger[22] = { {E::EVT_HOME_WALLET_SELECTED , EVT_HOME_WALLET_SELECTED_HANDLER , NULL }, {E::EVT_HOME_WALLET_COPY_ADDRESS , EVT_HOME_WALLET_COPY_ADDRESS_HANDLER , NULL }, @@ -459,6 +522,10 @@ static const STATE_TRIGGER STATE_ID_SCR_HOME_trigger[18] = {E::EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST, EVT_HOME_COLDCARD_NFC_SIGNER_INFO_REQUEST_HANDLER, &STATE_ID_SCR_MASTER_SIGNER_INFO }, {E::EVT_ASK_LEDGER_REQ , EVT_ASK_LEDGER_REQ_HANDLER , &STATE_ID_SCR_ADD_LEDGER_ASK }, {E::EVT_ASK_TREZOR_REQ , EVT_ASK_TREZOR_REQ_HANDLER , &STATE_ID_SCR_ADD_TREZOR_ASK }, + {E::EVT_EXIST_LEDGER_REQ , EVT_EXIST_LEDGER_REQ_HANDLER , &STATE_ID_SCR_ADD_LEDGER_EXIST }, + {E::EVT_EXIST_TREZOR_REQ , EVT_EXIST_TREZOR_REQ_HANDLER , &STATE_ID_SCR_ADD_TREZOR_EXIST }, + {E::EVT_EXIST_COLDCARD_REQ , EVT_EXIST_COLDCARD_REQ_HANDLER , &STATE_ID_SCR_ADD_COLDCARD_EXIST }, + {E::EVT_ASK_COLDCARD_REQ , EVT_ASK_COLDCARD_REQ_HANDLER , &STATE_ID_SCR_ADD_COLDCARD_ASK }, }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -770,14 +837,18 @@ static const STATE_TRIGGER STATE_ID_SCR_SEND_trigger[5] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static const STATE_TRIGGER STATE_ID_SCR_SERVICE_SETTINGS_trigger[6] = +static const STATE_TRIGGER STATE_ID_SCR_SERVICE_SETTINGS_trigger[10] = { {E::EVT_CLAIM_INHERITANCE_CHECK_REQUEST , EVT_CLAIM_INHERITANCE_CHECK_REQUEST_HANDLER , NULL }, {E::EVT_CO_SIGNING_SERVER_KEY_UPDATE_REQUEST, EVT_CO_SIGNING_SERVER_KEY_UPDATE_REQUEST_HANDLER, NULL }, {E::EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED, EVT_CO_SIGNING_SERVER_KEY_UPDATE_SUCCEED_HANDLER, NULL }, + {E::EVT_SERVICE_SELECT_WALLET_REQUEST , EVT_SERVICE_SELECT_WALLET_REQUEST_HANDLER , NULL }, + {E::EVT_INHERITANCE_PLAN_FINALIZE_REQUEST , EVT_INHERITANCE_PLAN_FINALIZE_REQUEST_HANDLER , NULL }, {E::EVT_REENTER_YOUR_PASSWORD_REQUEST , EVT_REENTER_YOUR_PASSWORD_REQUEST_HANDLER , &STATE_ID_SCR_REENTER_YOUR_PASSWORD }, {E::EVT_SERVICE_SUPPORT_REQUEST , EVT_SERVICE_SUPPORT_REQUEST_HANDLER , &STATE_ID_SCR_HOME_ONLINE }, {E::EVT_INHERITANCE_WITHDRAW_BALANCE_REQUEST, EVT_INHERITANCE_WITHDRAW_BALANCE_REQUEST_HANDLER, &STATE_ID_SCR_INHERITANCE_WITHDRAW_BALANCE }, + {E::EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST , EVT_EDIT_YOUR_INHERITANCE_PLAN_REQUEST_HANLDER , &STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN }, + {E::EVT_SHARE_YOUR_SECRET_REQUEST , EVT_SHARE_YOUR_SECRET_REQUEST_HANDLER , &STATE_ID_SCR_SHARE_YOUR_SECRETS }, }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -811,6 +882,14 @@ static const STATE_TRIGGER STATE_ID_SCR_SHARED_WL_DEVICE_REGISTRATION_trigger[4] //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static const STATE_TRIGGER STATE_ID_SCR_SHARE_YOUR_SECRETS_trigger[1] = +{ + {E::EVT_UPDATE_YOUR_SECRET_REQUEST, EVT_UPDATE_YOUR_SECRET_REQUEST_HANDLER, NULL }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static const STATE_TRIGGER STATE_ID_SCR_SIGN_IN_trigger[3] = { {E::EVT_SIGN_IN_PASSWORD_REQUEST , EVT_SIGN_IN_PASSWORD_REQUEST_HANDLER , NULL }, @@ -991,7 +1070,7 @@ static const STATE_TRIGGER STATE_ID_TOAST_MESSAGE_DISPLAY_trigger[1] = //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static const STATE_SYSTEM STATE_ALL[73] = +static const STATE_SYSTEM STATE_ALL[80] = { {E::STATE_ID_ROOT , STATE_ID_ROOT_trigger , ALEN(STATE_ID_ROOT_trigger) , &STATE_ID_ROOT }, {E::STATE_ID_SCR_HOME , STATE_ID_SCR_HOME_trigger , ALEN(STATE_ID_SCR_HOME_trigger) , &STATE_ID_SCR_HOME }, @@ -1066,6 +1145,13 @@ static const STATE_SYSTEM STATE_ALL[73] = {E::STATE_ID_SCR_ADD_LEDGER , STATE_ID_SCR_ADD_LEDGER_trigger , ALEN(STATE_ID_SCR_ADD_LEDGER_trigger) , &STATE_ID_SCR_ADD_LEDGER }, {E::STATE_ID_SCR_ADD_TREZOR , STATE_ID_SCR_ADD_TREZOR_trigger , ALEN(STATE_ID_SCR_ADD_TREZOR_trigger) , &STATE_ID_SCR_ADD_TREZOR }, {E::STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE , STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_trigger , ALEN(STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE_trigger) , &STATE_ID_SCR_SELECT_WALLET_CO_SIGN_POLICE }, + {E::STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN , STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_trigger , ALEN(STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN_trigger) , &STATE_ID_SCR_EDIT_YOUR_INHERITANCE_PLAN }, + {E::STATE_ID_SCR_SHARE_YOUR_SECRETS , STATE_ID_SCR_SHARE_YOUR_SECRETS_trigger , ALEN(STATE_ID_SCR_SHARE_YOUR_SECRETS_trigger) , &STATE_ID_SCR_SHARE_YOUR_SECRETS }, + {E::STATE_ID_SCR_ADD_COLDCARD_ASK , STATE_ID_SCR_ADD_COLDCARD_ASK_trigger , ALEN(STATE_ID_SCR_ADD_COLDCARD_ASK_trigger) , &STATE_ID_SCR_ADD_COLDCARD_ASK }, + {E::STATE_ID_SCR_ADD_COLDCARD , STATE_ID_SCR_ADD_COLDCARD_trigger , ALEN(STATE_ID_SCR_ADD_COLDCARD_trigger) , &STATE_ID_SCR_ADD_COLDCARD }, + {E::STATE_ID_SCR_ADD_LEDGER_EXIST , STATE_ID_SCR_ADD_LEDGER_EXIST_trigger , ALEN(STATE_ID_SCR_ADD_LEDGER_EXIST_trigger) , &STATE_ID_SCR_ADD_LEDGER_EXIST }, + {E::STATE_ID_SCR_ADD_TREZOR_EXIST , STATE_ID_SCR_ADD_TREZOR_EXIST_trigger , ALEN(STATE_ID_SCR_ADD_TREZOR_EXIST_trigger) , &STATE_ID_SCR_ADD_TREZOR_EXIST }, + {E::STATE_ID_SCR_ADD_COLDCARD_EXIST , STATE_ID_SCR_ADD_COLDCARD_EXIST_trigger , ALEN(STATE_ID_SCR_ADD_COLDCARD_EXIST_trigger) , &STATE_ID_SCR_ADD_COLDCARD_EXIST }, }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/contrib/libnunchuk b/contrib/libnunchuk index 0b2e64eb..8a0fef6d 160000 --- a/contrib/libnunchuk +++ b/contrib/libnunchuk @@ -1 +1 @@ -Subproject commit 0b2e64ebe357a6f5245fe607f56baa1763f60acf +Subproject commit 8a0fef6d135ce8a8cd95a99494d86ac0b66c1878 diff --git a/ifaces/Chats/matrixbrigde.cpp b/ifaces/Chats/matrixbrigde.cpp index 5aa75ef4..650c4749 100644 --- a/ifaces/Chats/matrixbrigde.cpp +++ b/ifaces/Chats/matrixbrigde.cpp @@ -70,16 +70,8 @@ QNunchukMatrixEvent matrixbrigde::JoinWallet(const QString &room_id, QWarningMessage &msg) { if(signer){ - nunchuk::SingleSigner singlesinger(signer.data()->name().toStdString(), - signer.data()->xpub().toStdString(), - signer.data()->publickey().toStdString(), - signer.data()->derivationPath().toStdString(), - signer.data()->masterFingerPrint().toStdString(), - signer.data()->lastHealthCheckDateTime().toTime_t(), - signer.data()->masterSignerId().toStdString()); - singlesinger.set_type(nunchuk::SignerType(signer.data()->signerType())); nunchuk::NunchukMatrixEvent e = matrixifaces::instance()->JoinWallet(room_id.toStdString(), - singlesinger, + signer->originSingleSigner(), msg); return QNunchukMatrixEvent(e); } @@ -328,9 +320,6 @@ QRoomWalletPtr matrixbrigde::ReloadRoomWallet( QNunchukRoom * const room) for (SignerAssigned signer : ret.data()->walletSigners()->fullList()) { AppModel::instance()->walletList()->updateSignerOfRoomWallet(wallet_id, signer); } - if(AppModel::instance()->walletList()->rowCount() == 1){ - AppModel::instance()->setWalletListCurrentIndex(0); - } } } return ret; @@ -352,8 +341,7 @@ QRoomTransactionModelPtr matrixbrigde::GetPendingTransactions(const QString &roo { QWarningMessage msg; QRoomTransactionModelPtr ret = QRoomTransactionModelPtr(new QRoomTransactionModel()) ; - std::vector results = matrixifaces::instance()->GetPendingTransactions(room_id.toStdString(), - msg); + std::vector results = matrixifaces::instance()->GetPendingTransactions(room_id.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ foreach (nunchuk::RoomTransaction room_tx, results) { QWarningMessage txWarning; diff --git a/ifaces/Draco.cpp b/ifaces/Draco.cpp index 5266b80d..b61c8345 100644 --- a/ifaces/Draco.cpp +++ b/ifaces/Draco.cpp @@ -70,10 +70,12 @@ Draco *Draco::instance() void Draco::refreshContacts() { - CLIENT_INSTANCE->syncContacts(getContacts()); - CLIENT_INSTANCE->syncContactsSent(getContactsSent()); - CLIENT_INSTANCE->syncContactsReceived(getContactsReceived()); - CLIENT_INSTANCE->syncDevices(getDevices()); + QtConcurrent::run([this]() { + CLIENT_INSTANCE->syncContacts(getContacts()); + CLIENT_INSTANCE->syncContactsSent(getContactsSent()); + CLIENT_INSTANCE->syncContactsReceived(getContactsReceived()); + CLIENT_INSTANCE->syncDevices(getDevices()); + }); } bool Draco::getCurrencies(QJsonObject &output, QString &errormsg) @@ -186,7 +188,6 @@ void Draco::verifyNewDevice(const QString &pin) this->setDracoToken(dataObj["tokenId"].toString()); this->setExpireSec(dataObj["expireInSeconds"].toInt()); this->getMe(); - this->getCurrentUserSubscription(); CLIENT_INSTANCE->setIsNewDevice(true); } emit verifyNewDeviceResult(reply_code, response_code, response_msg); @@ -252,14 +253,17 @@ void Draco::cancelFriendRequest(const QString &contact_id) QString reply_msg = ""; QJsonObject jsonObj = deleteSync(commands[CMD_IDX::CANCEL_REQUEST_FRIEND], data, reply_code, reply_msg); if(reply_code == DRACO_CODE::SUCCESSFULL){ +#if 0 //FIXME Performance QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); QString response_msg = errorObj["message"].toString(); +#endif } } QJsonObject Draco::postSync(const QString &cmd, QJsonObject data, int& reply_code, QString &reply_msg) { + FuncTime f(QString("POST %1").arg(cmd)); QJsonObject ret; qApp->setOverrideCursor(Qt::WaitCursor); std::unique_ptr manager(new QNetworkAccessManager); @@ -272,6 +276,8 @@ QJsonObject Draco::postSync(const QString &cmd, QJsonObject data, int& reply_cod requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); manager->setCookieJar(new QNetworkCookieJar(manager.get())); std::unique_ptr> reply(manager->post(requester_, QJsonDocument(data).toJson())); QEventLoop eventLoop; @@ -300,12 +306,22 @@ QJsonObject Draco::postSync(const QString &cmd, QJsonObject data, int& reply_cod return ret; } -QJsonObject Draco::postSync(const QString &cmd, QMap params, QJsonObject data, int &reply_code, QString &reply_msg) +QJsonObject Draco::postSync(const QString &cmd, QMap paramsQuery, QMap paramsHeader, QJsonObject data, int &reply_code, QString &reply_msg) { + FuncTime f(QString("POST %1").arg(cmd)); QJsonObject ret; qApp->setOverrideCursor(Qt::WaitCursor); std::unique_ptr manager(new QNetworkAccessManager); - QNetworkRequest requester_(QUrl::fromUserInput(commandByNetwork(cmd))); + QUrl url = QUrl::fromUserInput(commandByNetwork(cmd)); + if(!paramsQuery.isEmpty()){ + QUrlQuery params; + foreach(const QString& key, paramsQuery.keys()) { + QString value = paramsQuery.value(key); + params.addQueryItem(key, value); + } + url.setQuery(params); + } + QNetworkRequest requester_(url); QString headerData = QString("Bearer %1").arg(this->dracoToken()); requester_.setRawHeader("Authorization", headerData.toLocal8Bit()); requester_.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); @@ -314,9 +330,11 @@ QJsonObject Draco::postSync(const QString &cmd, QMap params, Q requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); // Add addional params - for(QString param : params.keys()) { - requester_.setRawHeader(QByteArray::fromStdString(param.toStdString()), QByteArray::fromStdString(params.value(param).toStdString())); + for(QString param : paramsHeader.keys()) { + requester_.setRawHeader(QByteArray::fromStdString(param.toStdString()), QByteArray::fromStdString(paramsHeader.value(param).toStdString())); } manager->setCookieJar(new QNetworkCookieJar(manager.get())); std::unique_ptr> reply(manager->post(requester_, QJsonDocument(data).toJson())); @@ -348,6 +366,7 @@ QJsonObject Draco::postSync(const QString &cmd, QMap params, Q QJsonObject Draco::getSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg) { + FuncTime f(QString("GET %1").arg(cmd)); QJsonObject ret; OurSharedPointer manager(new QNetworkAccessManager); QUrl url = QUrl::fromUserInput(commandByNetwork(cmd)); @@ -368,6 +387,8 @@ QJsonObject Draco::getSync(const QString &cmd, QJsonObject data, int &reply_code requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); manager->setCookieJar(new QNetworkCookieJar(manager.get())); OurSharedPointer reply(manager->get(requester_)); QEventLoop eventLoop; @@ -397,6 +418,7 @@ QJsonObject Draco::getSync(const QString &cmd, QJsonObject data, int &reply_code QJsonObject Draco::putSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg) { + FuncTime f(QString("PUT %1").arg(cmd)); QJsonObject ret; qApp->setOverrideCursor(Qt::WaitCursor); std::unique_ptr manager(new QNetworkAccessManager); @@ -409,6 +431,8 @@ QJsonObject Draco::putSync(const QString &cmd, QJsonObject data, int &reply_code requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); manager->setCookieJar(new QNetworkCookieJar(manager.get())); std::unique_ptr> reply(manager->put(requester_, QJsonDocument(data).toJson())); QEventLoop eventLoop; @@ -439,6 +463,7 @@ QJsonObject Draco::putSync(const QString &cmd, QJsonObject data, int &reply_code QJsonObject Draco::putSync(const QString &cmd, QMap params, QJsonObject data, int &reply_code, QString &reply_msg) { + FuncTime f(QString("PUT %1").arg(cmd)); QJsonObject ret; qApp->setOverrideCursor(Qt::WaitCursor); std::unique_ptr manager(new QNetworkAccessManager); @@ -452,6 +477,8 @@ QJsonObject Draco::putSync(const QString &cmd, QMap params, QJ requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); // Add addional params for(QString param : params.keys()) { requester_.setRawHeader(QByteArray::fromStdString(param.toStdString()), QByteArray::fromStdString(params.value(param).toStdString())); @@ -486,6 +513,7 @@ QJsonObject Draco::putSync(const QString &cmd, QMap params, QJ QJsonObject Draco::deleteSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg) { + FuncTime f(QString("DELETE %1").arg(cmd)); QJsonObject ret; qApp->setOverrideCursor(Qt::WaitCursor); std::unique_ptr manager(new QNetworkAccessManager); @@ -498,6 +526,8 @@ QJsonObject Draco::deleteSync(const QString &cmd, QJsonObject data, int &reply_c requester_.setRawHeader("x-nc-app-version", qApp->applicationVersion().toUtf8()); requester_.setRawHeader("x-nc-device-class", "Desktop"); requester_.setRawHeader("x-nc-os-name", QSysInfo::productType().toUtf8()); + qint64 maximumBufferSize = 1024 * 1024; + requester_.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, maximumBufferSize); manager->setCookieJar(new QNetworkCookieJar(manager.get())); std::unique_ptr> reply(manager->sendCustomRequest(requester_, "DELETE", QJsonDocument(data).toJson())); QEventLoop eventLoop; @@ -690,7 +720,6 @@ void Draco::singin(const QString& email, const QString& password) this->setExpireSec(dataObj["expireInSeconds"].toInt()); this->setEmailRequested(email); this->getMe(); - this->getCurrentUserSubscription(); } else if(response_code == DRACO_CODE::LOGIN_NEW_DEVICE){ QJsonObject detailsObj = errorObj["details"].toObject(); @@ -776,7 +805,6 @@ void Draco::changePassword(const QString& oldpassword, const QString& newpasswor if(response_code == DRACO_CODE::RESPONSE_OK){ this->setPid(newpassword); this->getMe(); - this->getCurrentUserSubscription(); } emit changePasswordResult(reply_code, response_code, response_msg); } @@ -808,6 +836,10 @@ void Draco::getMe() user.login_type = userObj["login_type"].toString(); AppModel::instance()->startCheckAuthorize(); CLIENT_INSTANCE->setIsNunchukLoggedIn(true); + if(0 != QString::compare(user.email, AppSetting::instance()->groupSetting(), Qt::CaseInsensitive)){ + AppSetting::instance()->setGroupSetting(user.email); + } + getCurrentUserSubscription(); } else if(response_code == DRACO_CODE::UNAUTHORIZED){ CLIENT_INSTANCE->requestSignout(); @@ -817,6 +849,7 @@ void Draco::getMe() DBG_INFO << response_code; } } + CLIENT_INSTANCE->setMe(user); } @@ -847,6 +880,10 @@ void Draco::getMepKey(const QString &public_address) user.login_type = userObj["login_type"].toString(); CLIENT_INSTANCE->setMe(user); AppModel::instance()->startCheckAuthorize(); + CLIENT_INSTANCE->setIsNunchukLoggedIn(true); + if(0 != QString::compare(user.email, AppSetting::instance()->groupSetting(), Qt::CaseInsensitive)){ + AppSetting::instance()->setGroupSetting(user.email); + } } else if(response_code == DRACO_CODE::UNAUTHORIZED){ CLIENT_INSTANCE->requestSignout(); @@ -1364,7 +1401,6 @@ void Draco::pkey_signup(const QString &address, const QString &username, const Q this->setDracoToken(dataObj["tokenId"].toString()); this->setExpireSec(dataObj["expireInSeconds"].toInt()); this->getMe(); - this->getCurrentUserSubscription(); AppModel::instance()->setPrimaryKey(username); } } @@ -1399,7 +1435,6 @@ bool Draco::pkey_signin(const QString &address, const QString &username, const Q this->setDracoToken(dataObj["tokenId"].toString()); this->setExpireSec(dataObj["expireInSeconds"].toInt()); this->getMe(); - this->getCurrentUserSubscription(); AppModel::instance()->setPrimaryKey(username); } else if(response_code == DRACO_CODE::LOGIN_NEW_DEVICE){ @@ -1560,7 +1595,7 @@ void Draco::getCurrentUserSubscription() QString reply_msg = ""; QString cmd = commands[CMD_IDX::USER_SUBCRIPTIONS_CURRENT]; QJsonObject jsonObj = getSync(cmd, QJsonObject(), reply_code, reply_msg); - if(reply_code == DRACO_CODE::SUCCESSFULL){ + if (reply_code == DRACO_CODE::SUCCESSFULL) { QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); if(response_code == DRACO_CODE::RESPONSE_OK){ @@ -1569,10 +1604,39 @@ void Draco::getCurrentUserSubscription() ServiceSetting::instance()->setIsSubscriber(true); return; } + else { + if (AppSetting::instance()->primaryServer() == (int)nunchuk::Chain::TESTNET){ + if (getTestNetUserSubscription()) { + return; + } + } + } } ServiceSetting::instance()->setIsSubscriber(false); } + +bool Draco::getTestNetUserSubscription() +{ + int reply_code = -1; + QString reply_msg = ""; + QString cmd = commands[CMD_IDX::USER_SUBCRIPTIONS_TESTNET]; + QJsonObject jsonObj = getSync(cmd, QJsonObject(), reply_code, reply_msg); + DBG_INFO << jsonObj; + if (reply_code == DRACO_CODE::SUCCESSFULL) { + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + QJsonObject dataObj = jsonObj["data"].toObject(); + CLIENT_INSTANCE->setSubCur(dataObj); + ServiceSetting::instance()->setIsSubscriber(true); + return true; + } + } + ServiceSetting::instance()->setIsSubscriber(false); + return false; +} + QJsonObject Draco::getAssistedWallets() { int reply_code = -1; @@ -1706,7 +1770,6 @@ QJsonObject Draco::assistedWalletGetListTx(const QString &wallet_id) if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); - QString response_msg = errorObj["message"].toString(); if(response_code == DRACO_CODE::RESPONSE_OK){ QJsonObject data = jsonObj.value("data").toObject(); return data; @@ -1756,6 +1819,127 @@ void Draco::assistedSyncTx(const QString &wallet_id, const QString &transaction_ } } +QJsonObject Draco::assistedWalletGetListKey() +{ + QJsonObject data; + data["statuses"] = "PENDING"; + int reply_code = -1; + QString reply_msg = ""; + QJsonObject jsonObj = getSync(commands[CMD_IDX::ASSISTED_WALLET_GET_LIST_KEY], data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + QJsonObject data = jsonObj.value("data").toObject(); + return data; + } + qInfo() << errorObj; + } + return QJsonObject(); +} + +bool Draco::assistedWalletAddKey(const QString &request_id, const QJsonObject& data) +{ + int reply_code = -1; + QString reply_msg = ""; + QMap paramsQuery; + paramsQuery["request_id"] = request_id; + QJsonObject jsonObj = postSync(commands[CMD_IDX::ASSISTED_WALLET_ADD_KEY], paramsQuery, {}, data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + return true; + } + qInfo() << errorObj; + } + return false; +} + +bool Draco::assistedWalletRemoveId(const QString &request_id) +{ + QJsonObject data; + int reply_code = -1; + QString reply_msg = ""; + QString cmd = commands[CMD_IDX::ASSISTED_WALLET_REMOVE_ID]; + cmd.replace("{request_id}", request_id); + QJsonObject jsonObj = deleteSync(cmd, data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + return true; + } + } + return false; +} + +QJsonObject Draco::assistedGetWalletConfig() +{ + int reply_code = -1; + QString reply_msg = ""; + QJsonObject jsonObj = getSync(commands[CMD_IDX::ASSISTED_WALLET_GET_CONFIG], {}, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + QJsonObject data = jsonObj.value("data").toObject(); + return data; + } + DBG_INFO << errorObj; + } + return {}; +} + +bool Draco::assistedWalletUpdateName(const QString &wallet_id, const QString &name, const QString &description, const QStringList& signerNames) +{ + QJsonObject data; + data["name"] = name; + data["description"] = description; + QJsonObject signers; + for(int i = 0; i < signerNames.size(); i++) + { + QJsonObject key; + key["name"] = signerNames.at(i); + signers[QString("additionalProp%1").arg(i+1)] = key; + } + data["signers"] = signers; + int reply_code = -1; + QString reply_msg = ""; + QString cmd = commands[CMD_IDX::ASSISTED_WALLET_UPDATE_NAME]; + cmd.replace("{wallet_id_or_local_id}", wallet_id); + QJsonObject jsonObj = putSync(cmd, data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + return true; + } + DBG_INFO << errorObj; + } + return false; +} + +bool Draco::assistedKeyUpdateName(const QString &fingerPrint, const QString &name) +{ + QJsonObject data; + data["name"] = name; + int reply_code = -1; + QString reply_msg = ""; + QString cmd = commands[CMD_IDX::ASSISTED_KEY_UPDATE_NAME]; + cmd.replace("{xfp}", fingerPrint); + QJsonObject jsonObj = putSync(cmd, data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + return true; + } + DBG_INFO << errorObj; + } + return false; +} + bool Draco::verifyPasswordToken(const QString& password, const int action, QString& errormsg_or_token) { int reply_code = -1; @@ -1949,7 +2133,7 @@ bool Draco::lockdownByAnswerSecQues(const QString &passwordToken, params["Security-Question-token"] = secQuesToken; int reply_code = -1; QString reply_msg = ""; - QJsonObject jsonObj = postSync(commands[CMD_IDX::LOCKDOWN_SET], params, data, reply_code, reply_msg); + QJsonObject jsonObj = postSync(commands[CMD_IDX::LOCKDOWN_SET], {}, params, data, reply_code, reply_msg); if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); @@ -1992,7 +2176,7 @@ bool Draco::lockdownBySignDummyTx(const QStringList &signatures, int reply_code = -1; QString reply_msg = ""; - QJsonObject jsonObj = postSync(commands[CMD_IDX::LOCKDOWN_SET], params, data, reply_code, reply_msg); + QJsonObject jsonObj = postSync(commands[CMD_IDX::LOCKDOWN_SET], {}, params, data, reply_code, reply_msg); qInfo() << jsonObj; if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); @@ -2039,7 +2223,7 @@ bool Draco::userKeysDownloadBackup(const QString &verify_token, int reply_code = -1; QString reply_msg = ""; - QJsonObject jsonObj = postSync(cmd, params, data, reply_code, reply_msg); + QJsonObject jsonObj = postSync(cmd, {}, params, data, reply_code, reply_msg); if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); @@ -2117,7 +2301,7 @@ bool Draco::inheritanceClaimStatus(const QJsonObject& data, const QString& autho QString cmd = commands[CMD_IDX::INHERITANCE_CLAIM_STATUS]; int reply_code = -1; QString reply_msg = ""; - QJsonObject jsonObj = postSync(cmd, params, data, reply_code, reply_msg); + QJsonObject jsonObj = postSync(cmd, {}, params, data, reply_code, reply_msg); if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); @@ -2142,7 +2326,7 @@ bool Draco::inheritanceCreateTx(const QJsonObject& data, const QString& autho, Q QString cmd = commands[CMD_IDX::INHERITANCE_CREATE_TX]; int reply_code = -1; QString reply_msg = ""; - QJsonObject jsonObj = postSync(cmd, params, data, reply_code, reply_msg); + QJsonObject jsonObj = postSync(cmd, {}, params, data, reply_code, reply_msg); if(reply_code == DRACO_CODE::SUCCESSFULL){ QJsonObject errorObj = jsonObj["error"].toObject(); int response_code = errorObj["code"].toInt(); @@ -2207,6 +2391,34 @@ bool Draco::inheritanceGetPlan(const QString& wallet_id, QJsonObject &output, QS return false; } +bool Draco::inheritancePlanUpdate(const QString &passwordToken, const QString &secQuesToken, const QStringList &signatures, const QJsonObject data, QJsonObject &output, QString &errormsg) +{ + int reply_code = -1; + QString reply_msg = ""; + QMap params; + for (int i = 0; i < signatures.count(); i++) { + params[QString("AuthorizationX-%1").arg(i+1)] = signatures.at(i); + } + params["Verify-token"] = passwordToken; + params["Security-Question-token"] = secQuesToken; + + QJsonObject jsonObj = putSync(commands[CMD_IDX::INHERITANCE_PLAN_UPDATE], params, data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + QString response_msg = errorObj["message"].toString(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + output = jsonObj["data"].toObject(); + return true; + } else { + errormsg = response_msg; + return false; + } + } + errormsg = reply_msg; + return false; +} + bool Draco::inheritanceFakeUpdate() { QJsonObject data; @@ -2228,6 +2440,55 @@ bool Draco::inheritanceFakeUpdate() return false; } +bool Draco::inheritancePlanRequiredSignatures(const QJsonObject &data, ReqiredSignaturesInfo& output, QString &errormsg) +{ + int reply_code = -1; + QString reply_msg = ""; + QJsonObject jsonObj = postSync(commands[CMD_IDX::INHERITANCE_PLAN_REQUIRED_SIGNATURES], data, reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + QString response_msg = errorObj["message"].toString(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + QJsonObject dataObj = jsonObj["data"].toObject(); + QJsonObject resultObj = dataObj["result"].toObject(); + DBG_INFO << resultObj; + output.type = required_signatures_type[resultObj["type"].toString()]; + output.required_signatures = resultObj["required_signatures"].toInt(); + output.required_answers = resultObj["required_answers"].toInt(); + return true; + } else { + errormsg = response_msg; + DBG_INFO << response_code << response_msg; + } + } + return false; +} + +bool Draco::inheritancePlanBufferPeriod(QJsonArray& output, QString& errormsg) +{ + int reply_code = -1; + QString reply_msg = ""; + QJsonObject jsonObj = getSync(commands[CMD_IDX::INHERITANCE_PLAN_BUFFER_PERIODS], QJsonObject(), reply_code, reply_msg); + if(reply_code == DRACO_CODE::SUCCESSFULL){ + QJsonObject errorObj = jsonObj["error"].toObject(); + int response_code = errorObj["code"].toInt(); + QString response_msg = errorObj["message"].toString(); + if(response_code == DRACO_CODE::RESPONSE_OK){ + QJsonObject dataObj = jsonObj["data"].toObject(); + QJsonArray periods = dataObj["periods"].toArray(); + output = periods; + return true; + } + else{ + errormsg = response_msg; + return false; + } + } + errormsg = reply_msg; + return false; +} + bool Draco::serverKeysGet(const QString &id_or_xfp, QJsonObject &output, QString &errormsg) { int reply_code = -1; diff --git a/ifaces/Draco.h b/ifaces/Draco.h index 91b6f812..13147825 100644 --- a/ifaces/Draco.h +++ b/ifaces/Draco.h @@ -113,6 +113,7 @@ class Draco : public QObject // USER_SUBSCRIPTION void getCurrentUserSubscription(); + bool getTestNetUserSubscription(); // ASSISTED_WALLETS QJsonObject getAssistedWallets(); @@ -124,6 +125,12 @@ class Draco : public QObject QJsonObject assistedWalletGetListTx(const QString &wallet_id); QJsonObject assistedWalletDeleteListTx(const QString &wallet_id, const int offset, const int limit); void assistedSyncTx(const QString &wallet_id, const QString &transaction_id, const QString &psbt); + QJsonObject assistedWalletGetListKey(); + bool assistedWalletAddKey(const QString &request_id, const QJsonObject& data); + bool assistedWalletRemoveId(const QString &request_id); + QJsonObject assistedGetWalletConfig(); + bool assistedWalletUpdateName(const QString &wallet_id, const QString &name, const QString &description, const QStringList& signerNames); + bool assistedKeyUpdateName(const QString &fingerPrint, const QString &name); bool verifyPasswordToken(const QString &password, const int action, QString &errormsg_or_token); QString randomNonce(); @@ -192,8 +199,19 @@ class Draco : public QObject QJsonObject& output, QString& errormsg); + bool inheritancePlanUpdate(const QString& passwordToken, + const QString& secQuesToken, + const QStringList &signatures, + const QJsonObject data, + QJsonObject& output, + QString& errormsg); + bool inheritanceFakeUpdate(); + bool inheritancePlanRequiredSignatures(const QJsonObject& data, ReqiredSignaturesInfo& output, QString& errormsg); + + bool inheritancePlanBufferPeriod(QJsonArray& output, QString& errormsg); + bool serverKeysGet(const QString & id_or_xfp, QJsonObject& output, QString& errormsg); @@ -215,7 +233,7 @@ class Draco : public QObject Draco(); ~Draco(); QJsonObject postSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg); - QJsonObject postSync(const QString &cmd, QMap params, QJsonObject data, int &reply_code, QString &reply_msg); + QJsonObject postSync(const QString &cmd, QMap paramsQuery, QMap paramsHeader, QJsonObject data, int &reply_code, QString &reply_msg); QJsonObject getSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg); QJsonObject putSync(const QString &cmd, QJsonObject data, int &reply_code, QString &reply_msg); QJsonObject putSync(const QString &cmd, QMap params, QJsonObject data, int &reply_code, QString &reply_msg); diff --git a/ifaces/DracoDefines.h b/ifaces/DracoDefines.h index e9cf60bd..a8938e3a 100644 --- a/ifaces/DracoDefines.h +++ b/ifaces/DracoDefines.h @@ -110,6 +110,7 @@ enum CMD_IDX { // USER_SUBSCRIPTION USER_SUBCRIPTIONS_CURRENT, + USER_SUBCRIPTIONS_TESTNET, // ASSISTED_WALLETS ASSISTED_WALLET_GET, @@ -120,6 +121,12 @@ enum CMD_IDX { ASSISTED_WALLET_GET_TX, ASSISTED_WALLET_GET_LIST_TX, ASSISTED_WALLET_DELETE_LIST_TX, + ASSISTED_WALLET_ADD_KEY, + ASSISTED_WALLET_GET_LIST_KEY, + ASSISTED_WALLET_REMOVE_ID, + ASSISTED_WALLET_GET_CONFIG, + ASSISTED_WALLET_UPDATE_NAME, + ASSISTED_KEY_UPDATE_NAME, // SEC_QUES SEC_QUES_GET, @@ -134,6 +141,7 @@ enum CMD_IDX { LOCKDOWN_REQUIRED_SIGNATURES, LOCKDOWN_GET_PERIOD, + //GET_RANDOM_NONCE GET_RANDOM_NONCE, VERIFY_PASSWORD_TOKEN, @@ -147,6 +155,9 @@ enum CMD_IDX { INHERITANCE_CHECK, INHERITANCE_GET_PLAN, INHERITANCE_FAKE_UPDATE, + INHERITANCE_PLAN_REQUIRED_SIGNATURES, + INHERITANCE_PLAN_UPDATE, + INHERITANCE_PLAN_BUFFER_PERIODS, //SERVER_KEYS SERVER_KEYS_GET, @@ -233,6 +244,7 @@ const QMap commands { // USER_SUBSCRIPTION { CMD_IDX::USER_SUBCRIPTIONS_CURRENT , QString("%1/%2").arg(DRAGON_SUBSCRIPTIONS_URL).arg("current") }, + { CMD_IDX::USER_SUBCRIPTIONS_TESTNET , QString("%1/%2").arg(DRAGON_SUBSCRIPTIONS_URL).arg("testnet") }, // ASSISTED_WALLETS { CMD_IDX::ASSISTED_WALLET_GET , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallets") }, @@ -243,6 +255,12 @@ const QMap commands { { CMD_IDX::ASSISTED_WALLET_SIGN_TX , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallets/{wallet_id_or_local_id}/transactions/{transaction_id}/sign") }, { CMD_IDX::ASSISTED_WALLET_CANCEL_TX , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallets/{wallet_id_or_local_id}/transactions/{transaction_id}") }, { CMD_IDX::ASSISTED_WALLET_GET_TX , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallets/{wallet_id_or_local_id}/transactions/{transaction_id}") }, + { CMD_IDX::ASSISTED_WALLET_ADD_KEY , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("draft-wallets/add-key") }, + { CMD_IDX::ASSISTED_WALLET_GET_LIST_KEY , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("draft-wallets/request-add-key") }, + { CMD_IDX::ASSISTED_WALLET_REMOVE_ID , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("draft-wallets/request-add-key/{request_id}") }, + { CMD_IDX::ASSISTED_WALLET_GET_CONFIG , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("configs") }, + { CMD_IDX::ASSISTED_KEY_UPDATE_NAME , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallet-keys/{xfp}") }, + { CMD_IDX::ASSISTED_WALLET_UPDATE_NAME , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("wallets/{wallet_id_or_local_id}") }, // SEC_QUES { CMD_IDX::SEC_QUES_GET , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("security-questions") }, @@ -270,6 +288,9 @@ const QMap commands { { CMD_IDX::INHERITANCE_CHECK , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance/check") }, { CMD_IDX::INHERITANCE_GET_PLAN , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance") }, { CMD_IDX::INHERITANCE_FAKE_UPDATE , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance/fake-update") }, + { CMD_IDX::INHERITANCE_PLAN_REQUIRED_SIGNATURES , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance/calculate-required-signatures") }, + { CMD_IDX::INHERITANCE_PLAN_UPDATE , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance") }, + { CMD_IDX::INHERITANCE_PLAN_BUFFER_PERIODS , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("inheritance/buffer-period") }, //SERVER_KEYS /v1.1/user-wallets/server-keys/{key_id_or_xfp} { CMD_IDX::SERVER_KEYS_GET , QString("%1/%2").arg(DRAGON_USER_WALLETS_URL).arg("server-keys/{key_id_or_xfp}") }, diff --git a/ifaces/bridgeifaces.cpp b/ifaces/bridgeifaces.cpp index 714ee90a..3dea928d 100644 --- a/ifaces/bridgeifaces.cpp +++ b/ifaces/bridgeifaces.cpp @@ -30,6 +30,7 @@ void bridge::nunchukMakeInstance(const QString& passphrase, QWarningMessage& msg) { + FuncTime f(__PRETTY_FUNCTION__); AppModel::instance()->requestClearData(); bool encrypted = (passphrase == "") ? false : true; AppSetting::instance()->setGroupSetting(""); @@ -113,6 +114,7 @@ void bridge::nunchukMakeInstanceForAccount(const QString &account, const QString &passphrase, QWarningMessage &msg) { + FuncTime f(__PRETTY_FUNCTION__); AppModel::instance()->requestClearData(); bool encrypted = (passphrase == "") ? false : true; AppSetting::instance()->setGroupSetting(account); @@ -210,7 +212,7 @@ QWalletListModelPtr bridge::nunchukGetWallets() { if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ QWalletListModelPtr walletList(new WalletListModel()); for (nunchuk::Wallet it : resultWallets) { - walletList.data()->addWallet(convertWallet(it)); + walletList.data()->addWallet(bridge::convertWallet(it)); } return walletList; } @@ -228,7 +230,7 @@ QWalletListModelPtr bridge::nunchukConvertWallets(std::vector l { QWalletListModelPtr walletList(new WalletListModel()); for (nunchuk::Wallet it : list) { - walletList.data()->addWallet(convertWallet(it)); + walletList.data()->addWallet(bridge::convertWallet(it)); } return walletList; } @@ -236,22 +238,7 @@ QWalletListModelPtr bridge::nunchukConvertWallets(std::vector l QWalletPtr bridge::convertWallet(const nunchuk::Wallet &wallet) { QWalletPtr to = QWalletPtr(new Wallet()); - to.data()->setId(QString::fromStdString(wallet.get_id())); - to.data()->setM(wallet.get_m()); - to.data()->setN(wallet.get_n()); - to.data()->setName(QString::fromStdString(wallet.get_name())); - to.data()->setAddressType(QString::number((int)wallet.get_address_type())); - to.data()->setBalance(wallet.get_unconfirmed_balance()); - to.data()->setCreateDate(QDateTime::fromTime_t(wallet.get_create_date())); - to.data()->setEscrow(wallet.is_escrow()); - to.data()->setGapLimit(wallet.get_gap_limit()); - to.data()->setDescription(QString::fromStdString(wallet.get_description())); - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : wallet.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - to.data()->setSigners(signersAssinged); + to.data()->convert(wallet); return to; } @@ -274,31 +261,7 @@ QMasterSignerListModelPtr bridge::nunchukGetMasterSigners() { QWarningMessage msg; std::vector masterSignerList_result = nunchukiface::instance()->GetMasterSigners(msg); AppModel::instance()->setSoftwareSignerDeviceList(QDeviceListModelPtr(new DeviceListModel())); - if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QMasterSignerListModelPtr masterSignerlist(new MasterSignerListModel()); - for (nunchuk::MasterSigner it : masterSignerList_result) { - QMasterSignerPtr signer = QMasterSignerPtr(new QMasterSigner(it)); - int signer_type = (int)it.get_type(); - if(signer_type == (int)ENUNCHUCK::SignerType::SERVER){ - continue; - } - if(signer_type == (int)ENUNCHUCK::SignerType::SOFTWARE){ - AppModel::instance()->softwareSignerDeviceList()->addDevice(QDevicePtr(new QDevice(it.get_device()))); - } - if(signer_type == (int)ENUNCHUCK::SignerType::NFC){ - QWarningMessage msgGetTap; - nunchuk::TapsignerStatus tapsigner = nunchukiface::instance()->GetTapsignerStatusFromMasterSigner(it.get_device().get_master_fingerprint(), msgGetTap); - if((int)EWARNING::WarningType::NONE_MSG == msgGetTap.type()){ - signer.data()->device()->setCardId(QString::fromStdString(tapsigner.get_card_ident())); - } - } - masterSignerlist.data()->addMasterSigner(signer); - } - return masterSignerlist; - } - else{ - return NULL; - } + return nunchukConvertMasterSigners(masterSignerList_result); } std::vector bridge::nunchukGetOriginMasterSigners(QWarningMessage& msg) @@ -380,15 +343,7 @@ nunchuk::HealthStatus bridge::nunchukHealthCheckSingleSigner(const QSingleSigner QString message = signer.data()->message(); QString signature = signer.data()->signature(); DBG_INFO << message << signature; - nunchuk::SingleSigner singlesinger(signer.data()->name().toStdString(), - signer.data()->xpub().toStdString(), - signer.data()->publickey().toStdString(), - signer.data()->derivationPath().toStdString(), - signer.data()->masterFingerPrint().toStdString(), - signer.data()->lastHealthCheckDateTime().toTime_t(), - signer.data()->masterSignerId().toStdString()); - singlesinger.set_type(nunchuk::SignerType(signer.data()->signerType())); - return nunchukiface::instance()->HealthCheckSingleSigner(singlesinger, + return nunchukiface::instance()->HealthCheckSingleSigner(signer->singleSigner(), message.toStdString(), signature.toStdString(), msg); @@ -497,6 +452,25 @@ QSingleSignerPtr bridge::nunchukGetUnusedSignerFromMasterSigner(const QString &m } } +QSingleSignerPtr bridge::nunchukGetDefaultSignerFromMasterSigner(const QString &mastersigner_id, + const ENUNCHUCK::WalletType &wallet_type, + const ENUNCHUCK::AddressType &address_type, + QWarningMessage &msg) +{ + DBG_INFO << mastersigner_id; + nunchuk::SingleSigner signer = nunchukiface::instance()->GetDefaultSignerFromMasterSigner(mastersigner_id.toStdString(), + (nunchuk::WalletType)wallet_type, + (nunchuk::AddressType)address_type, + msg); + if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ + QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); + return ret; + } + else{ + return QSingleSignerPtr(); + } +} + QSingleSignerPtr bridge::nunchukCreateSigner(const QString &name, const QString &xpub, const QString &public_key, @@ -537,84 +511,13 @@ nunchuk::SingleSigner bridge::nunchukCreateOriginSigner(const QString &name, msg); } -QWalletPtr bridge::nunchukCreateWallet(const QString &name, - int m, - int n, - SingleSignerListModel* signers, - ENUNCHUCK::AddressType address_type, - bool is_escrow, - const QString& desc, - QWarningMessage& msg) -{ - std::vector signerList; - for (int i = 0; i < signers->rowCount(); i++) { - QSingleSignerPtr singlerSigner = signers->getSingleSignerByIndex(i); - nunchuk::SingleSigner nunchukSigner(singlerSigner.data()->name().toStdString(), - singlerSigner.data()->xpub().toStdString(), - singlerSigner.data()->publickey().toStdString(), - singlerSigner.data()->derivationPath().toStdString(), - singlerSigner.data()->masterFingerPrint().toStdString(), - singlerSigner.data()->lastHealthCheckDateTime().toTime_t(), - singlerSigner.data()->masterSignerId().toStdString()); - nunchukSigner.set_type(nunchuk::SignerType(singlerSigner.data()->signerType())); - signerList.push_back(nunchukSigner); - } - nunchuk::Wallet walletResult = nunchukiface::instance()->CreateWallet(name.toStdString(), - m, - n, - signerList, - (nunchuk::AddressType)address_type, - is_escrow, - desc.toStdString(), - msg); - - if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); - return ret; - } - else { - return NULL; - } -} - QWalletPtr bridge::nunchukCreateWallet(const nunchuk::Wallet &wallet, bool allow_used_signer, QWarningMessage &msg) { nunchuk::Wallet walletResult = nunchukiface::instance()->CreateWallet(wallet, allow_used_signer, msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -630,23 +533,10 @@ nunchuk::Wallet bridge::nunchukCreateOriginWallet(const QString &name, const QString &desc, QWarningMessage &msg) { - std::vector signerList; - for (int i = 0; i < signers->rowCount(); i++) { - QSingleSignerPtr singlerSigner = signers->getSingleSignerByIndex(i); - nunchuk::SingleSigner nunchukSigner(singlerSigner.data()->name().toStdString(), - singlerSigner.data()->xpub().toStdString(), - singlerSigner.data()->publickey().toStdString(), - singlerSigner.data()->derivationPath().toStdString(), - singlerSigner.data()->masterFingerPrint().toStdString(), - singlerSigner.data()->lastHealthCheckDateTime().toTime_t(), - singlerSigner.data()->masterSignerId().toStdString()); - nunchukSigner.set_type(nunchuk::SignerType(singlerSigner.data()->signerType())); - signerList.push_back(nunchukSigner); - } return nunchukiface::instance()->CreateWallet(name.toStdString(), m, n, - signerList, + signers->signers(), (nunchuk::AddressType)address_type, is_escrow, desc.toStdString(), @@ -663,23 +553,10 @@ QString bridge::nunchukDraftWallet(const QString &name, const QString &desc, QWarningMessage &msg) { - std::vector signerList; - for (int i = 0; i < signers->rowCount(); i++) { - QSingleSignerPtr singlerSigner = signers->getSingleSignerByIndex(i); - nunchuk::SingleSigner nunchukSigner(singlerSigner.data()->name().toStdString(), - singlerSigner.data()->xpub().toStdString(), - singlerSigner.data()->publickey().toStdString(), - singlerSigner.data()->derivationPath().toStdString(), - singlerSigner.data()->masterFingerPrint().toStdString(), - singlerSigner.data()->lastHealthCheckDateTime().toTime_t(), - singlerSigner.data()->masterSignerId().toStdString()); - nunchukSigner.set_type(nunchuk::SignerType(singlerSigner.data()->signerType())); - signerList.push_back(nunchukSigner); - } string ret = nunchukiface::instance()->DraftWallet(name.toStdString(), m, n, - signerList, + signers->signers(), (nunchuk::AddressType)address_type, is_escrow, desc.toStdString(), @@ -761,25 +638,9 @@ QWalletPtr bridge::nunchukImportWallet(const QString &dbFile, { nunchuk::Wallet walletResult = nunchukiface::instance()->ImportWalletDb(dbFile.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); AppModel::instance()->newWalletInfo()->setCapableCreate(!needTopUp); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -797,25 +658,9 @@ QWalletPtr bridge::nunchukImportWalletDescriptor(const QString &dbFile, description.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); AppModel::instance()->newWalletInfo()->setCapableCreate(!needTopUp); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -879,7 +724,7 @@ bool bridge::nunchukExportTransaction(const QString &wallet_id, msg); } -QTransactionPtr bridge::nunchukImportTransaction(const QString &wallet_id, const QString &file_path, QWarningMessage& msg) +QTransactionPtr bridge::nunchukImportTransaction(const QString &wallet_id, const QString &file_path, bool isAssisted, QWarningMessage& msg) { nunchuk::Transaction trans_result = nunchukiface::instance()->ImportTransaction(wallet_id.toStdString(), file_path.toStdString(), @@ -906,6 +751,12 @@ QTransactionPtr bridge::nunchukImportTransaction(const QString &wallet_id, const } } } + if (isAssisted) { + Draco::instance()->assistedWalletCreateTx(wallet_id, final->psbt(), final->memo()); + QJsonObject data = Draco::instance()->assistedWalletGetTx(wallet_id, final->txid()); + DBG_INFO << data; + final->setServerKeyMessage(data); + } return final; } else{ @@ -1022,13 +873,16 @@ bool bridge::nunchukDeleteRemoteSigner(const QString &master_fingerprint, const return nunchukiface::instance()->DeleteRemoteSigner(master_fingerprint.toStdString(), derivation_path.toStdString(), msg); } -void bridge::nunchukUpdateMasterSigner(const QMasterSignerPtr &signer ) +void bridge::nunchukUpdateMasterSigner(const QMasterSignerPtr &signer, bool sync) { if(signer){ QtConcurrent::run([signer]() { QWarningMessage msg; nunchukiface::instance()->UpdateMasterSigner(signer.data()->originMasterSigner(), msg); }); + if (sync) { + Draco::instance()->assistedKeyUpdateName(signer->fingerPrint(), signer->name()); + } } } @@ -1046,7 +900,7 @@ void bridge::nunchukDeleteAllWallet() } } -void bridge::nunchukUpdateWalletName(const QString &wallet_id, const QString &name) +void bridge::nunchukUpdateWalletName(const QString &wallet_id, const QString &name, bool sync) { QWarningMessage msg; nunchuk::Wallet wallet = nunchukiface::instance()->GetWallet(wallet_id.toStdString(), msg); @@ -1056,6 +910,13 @@ void bridge::nunchukUpdateWalletName(const QString &wallet_id, const QString &na QWarningMessage msgupdate; nunchukiface::instance()->UpdateWallet(wallet, msgupdate); }); + QStringList names {}; + for (nunchuk::SingleSigner signer : wallet.get_signers()) { + names.append(QString::fromStdString(signer.get_name())); + } + if (sync) { + Draco::instance()->assistedWalletUpdateName(wallet_id, QString::fromStdString(wallet.get_name()), QString::fromStdString(wallet.get_description()), names); + } } } @@ -1069,6 +930,11 @@ void bridge::nunchukUpdateWalletDescription(const QString &wallet_id, const QStr QWarningMessage msgupdate; nunchukiface::instance()->UpdateWallet(wallet, msgupdate); }); + QStringList names {}; + for (nunchuk::SingleSigner signer : wallet.get_signers()) { + names.append(QString::fromStdString(signer.get_name())); + } + Draco::instance()->assistedWalletUpdateName(wallet_id, QString::fromStdString(wallet.get_name()), QString::fromStdString(wallet.get_description()), names); } } @@ -1120,12 +986,14 @@ QUTXOListModelPtr bridge::nunchukGetUnspentOutputs(const QString &walletId) if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ QUTXOListModelPtr ret = QUTXOListModelPtr(new UTXOListModel()); for (nunchuk::UnspentOutput it : utxo_result) { + DBG_INFO << it.get_amount() << it.get_height() << (int)it.get_status(); ret.data()->addUTXO(QString::fromStdString(it.get_txid()), it.get_vout(), QString::fromStdString(it.get_address()), it.get_amount(), it.get_height(), - QString::fromStdString(it.get_memo())); + QString::fromStdString(it.get_memo()), + (int)it.get_status()); } return ret; } @@ -1171,6 +1039,13 @@ QTransactionPtr bridge::nunchukDraftTransaction(const QString &wallet_id, if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ QTransactionPtr final = bridge::convertTransaction(trans_result, wallet_id); final.data()->setStatus((int)nunchuk::TransactionStatus::PENDING_SIGNATURES); + nunchuk::Amount packageFeeRate{0}; + if (nunchukiface::instance()->IsCPFP(wallet_id.toStdString(), trans_result, packageFeeRate, msg)) { + // Show package fee rate in UI + final.data()->setPackageFeeRate(packageFeeRate); + } else { + // Do nothing + } return final; } else{ @@ -1368,15 +1243,7 @@ QSingleSignerListModelPtr bridge::nunchukGetRemoteSigners() QWarningMessage msg; std::vector remoteignerList_result = nunchukiface::instance()->GetRemoteSigners(msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr remoteSignerlist(new SingleSignerListModel()); - for (nunchuk::SingleSigner signer : remoteignerList_result) { - if((int)signer.get_type() == (int)ENUNCHUCK::SignerType::SERVER){ - continue; - } - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - remoteSignerlist.data()->addSingleSigner(ret); - } - return remoteSignerlist; + return bridge::nunchukConvertRemoteSigners(remoteignerList_result); } else{ return NULL; @@ -1396,19 +1263,25 @@ QSingleSignerListModelPtr bridge::nunchukConvertRemoteSigners(std::vectoraddSingleSigner(ret); } return remoteSignerlist; } -void bridge::nunchukUpdateRemoteSigner(const QSingleSignerPtr &signer) +void bridge::nunchukUpdateRemoteSigner(const QSingleSignerPtr &signer, bool sync) { if(signer) { QtConcurrent::run([signer]() { QWarningMessage msg; nunchukiface::instance()->UpdateRemoteSigner(signer.data()->originSingleSigner(), msg); }); + if (sync) { + Draco::instance()->assistedKeyUpdateName(signer->masterFingerPrint(), signer->name()); + } } } @@ -1554,25 +1427,9 @@ QWalletPtr bridge::nunchukImportCoboWallet(const QStringList &qr_data, description.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); AppModel::instance()->newWalletInfo()->setCapableCreate(!needTopUp); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -1587,25 +1444,9 @@ QWalletPtr bridge::nunchukImportWalletConfigFile(const QString &file_path, description.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); AppModel::instance()->newWalletInfo()->setCapableCreate(!needTopUp); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -1775,25 +1616,9 @@ QWalletPtr bridge::nunchukImportKeystoneWallet(const QList &qr_data, description.toStdString(), msg); if((int)EWARNING::WarningType::NONE_MSG == msg.type()){ - QSingleSignerListModelPtr signersAssinged( new SingleSignerListModel); - for (nunchuk::SingleSigner signer : walletResult.get_signers()) { - QSingleSignerPtr ret = QSingleSignerPtr(new QSingleSigner(signer)); - signersAssinged.data()->addSingleSigner(ret); - } - - QWalletPtr ret = QWalletPtr(new Wallet(QString::fromStdString(walletResult.get_id()), - walletResult.get_m(), - walletResult.get_n(), - QString::fromStdString(walletResult.get_name()), - QString::number((int)walletResult.get_address_type()), - walletResult.get_unconfirmed_balance(), - QDateTime::fromTime_t(walletResult.get_create_date()), - walletResult.is_escrow(), - signersAssinged, - QString::fromStdString(walletResult.get_description()))); bool needTopUp = AppModel::instance()->newWalletInfo()->singleSignersAssigned()->needTopUpXpubs(); AppModel::instance()->newWalletInfo()->setCapableCreate(!needTopUp); - return ret; + return bridge::convertWallet(walletResult); } else { return NULL; @@ -1997,7 +1822,7 @@ void bridge::assistedWalletUpdateTx(const QString& wallet_id, const nunchuk::Tra QString reject_msg = transaction.value("reject_msg").toString(); - long int broadcast_time_milis = static_cast(transaction.value("broadcast_time_milis").toInt()); + long int broadcast_time_milis = static_cast(transaction.value("broadcast_time_milis").toDouble()); // honey badger feature: schedule broadcast long int current_time_stamp_milis = static_cast(std::time(nullptr)) * 1000; @@ -2006,11 +1831,9 @@ void bridge::assistedWalletUpdateTx(const QString& wallet_id, const nunchuk::Tra nunchukUpdateTransactionSchedule(wallet_id, QString::fromStdString(tx.get_txid()), broadcast_time_milis/1000,msg); } - if (status == "PENDING_CONFIRMATION" || - status == "CONFIRMED" || - status == "NETWORK_REJECTED") { + if (status == "PENDING_CONFIRMATION" || status == "CONFIRMED" || status == "NETWORK_REJECTED") { nunchukImportPsbt(wallet_id, psbt,msg); - nunchukUpdateTransaction(wallet_id, QString::fromStdString(tx.get_txid()), transaction_id, hex, reject_msg,msg); + nunchukUpdateTransaction(wallet_id, QString::fromStdString(tx.get_txid()), transaction_id, hex, reject_msg, msg); } else if (status == "READY_TO_BROADCAST" || status == "PENDING_SIGNATURES") { auto tx = nunchukImportPsbt(wallet_id, psbt,msg); diff --git a/ifaces/bridgeifaces.h b/ifaces/bridgeifaces.h index e5d5cd21..f9610c75 100644 --- a/ifaces/bridgeifaces.h +++ b/ifaces/bridgeifaces.h @@ -62,6 +62,7 @@ class ENUNCHUCK: public QObject WALLET_TAB, SERVICE_TAB, CHAT_TAB, + SETTING_TAB, }; enum class AddressType { @@ -238,7 +239,7 @@ bool nunchukDeleteWallet(const QString& wallet_id, QWarningMessage &msg); void nunchukDeleteAllWallet(); -void nunchukUpdateWalletName(const QString& wallet_id, const QString &name); +void nunchukUpdateWalletName(const QString& wallet_id, const QString &name, bool sync = true); void nunchukUpdateWalletDescription(const QString &wallet_id, const QString &description); @@ -286,15 +287,20 @@ QSingleSignerPtr nunchukGetUnusedSignerFromMasterSigner(const QString& mastersig const ENUNCHUCK::AddressType& address_type, QWarningMessage &msg); +QSingleSignerPtr nunchukGetDefaultSignerFromMasterSigner(const QString& mastersigner_id, + const ENUNCHUCK::WalletType& wallet_type, + const ENUNCHUCK::AddressType& address_type, + QWarningMessage &msg); + bool nunchukDeleteMasterSigner(const QString& mastersigner_id); bool nunchukDeletePrimaryKey(); bool nunchukDeleteRemoteSigner(const QString& master_fingerprint, const QString& derivation_path); -void nunchukUpdateMasterSigner(const QMasterSignerPtr &signer); +void nunchukUpdateMasterSigner(const QMasterSignerPtr &signer, bool sync = true); -void nunchukUpdateRemoteSigner(const QSingleSignerPtr &signer); +void nunchukUpdateRemoteSigner(const QSingleSignerPtr &signer, bool sync = true); bool nunchukHasSinger(const nunchuk::SingleSigner& signer); @@ -318,15 +324,6 @@ nunchuk::SingleSigner nunchukCreateOriginSigner(const QString& name, const QString& master_fingerprint, QWarningMessage &msg); -QWalletPtr nunchukCreateWallet(const QString& name, - int m, - int n, - SingleSignerListModel* signers, - ENUNCHUCK::AddressType address_type, - bool is_escrow, - const QString &desc, - QWarningMessage &msg); - QWalletPtr nunchukCreateWallet(const nunchuk::Wallet& wallet, bool allow_used_signer, QWarningMessage &msg); @@ -396,6 +393,7 @@ bool nunchukExportTransaction(const QString& wallet_id, QTransactionPtr nunchukImportTransaction(const QString& wallet_id, const QString& file_path, + bool isAssisted, QWarningMessage &msg); QTransactionPtr nunchukUpdateTransaction(const QString& wallet_id, diff --git a/ifaces/nunchuckiface.cpp b/ifaces/nunchuckiface.cpp index 3f96cda6..0d570e9d 100644 --- a/ifaces/nunchuckiface.cpp +++ b/ifaces/nunchuckiface.cpp @@ -124,7 +124,7 @@ bool nunchukiface::SetPassphrase(const std::string &passphrase, QWarningMessage& nunchuk::Wallet nunchukiface::CreateWallet(const std::string &name, int m, int n, - std::vector &signers, + const std::vector &signers, nunchuk::AddressType address_type, bool is_escrow, const std::string &desc, @@ -167,7 +167,7 @@ nunchuk::Wallet nunchukiface::CreateWallet(const nunchuk::Wallet &wallet, bool a std::string nunchukiface::DraftWallet(const std::string &name, int m, int n, - std::vector &signers, + const std::vector &signers, nunchuk::AddressType address_type, bool is_escrow, const std::string &desc, @@ -391,6 +391,22 @@ nunchuk::SingleSigner nunchukiface::GetSignerFromMasterSigner(const std::string return ret; } +nunchuk::SingleSigner nunchukiface::GetSignerFromMasterSigner(const std::string &mastersigner_id, + const std::string &derivation_path, + QWarningMessage& msg) +{ + nunchuk::SingleSigner ret("","","","","",0,""); + try { + if(nunchuk_instance_[nunchukMode()]){ + ret = nunchuk_instance_[nunchukMode()]->GetSignerFromMasterSigner(mastersigner_id, derivation_path); + } + } + catch (std::exception &e) { + DBG_INFO << "THROW EXCEPTION" << e.what(); msg.setWarningMessage(-1, e.what(), EWARNING::WarningType::EXCEPTION_MSG); + } + return ret; +} + nunchuk::SingleSigner nunchukiface::CreateSigner(const std::string &name, const std::string &xpub, const std::string &public_key, @@ -2126,13 +2142,31 @@ std::string nunchukiface::SignHealthCheckMessage(const nunchuk::SingleSigner &si return ret; } -nunchuk::SingleSigner nunchukiface::GetDefaultSignerFromMasterSigner(const std::string &mastersigner_id, - QWarningMessage& msg) +nunchuk::SingleSigner nunchukiface::GetDefaultSignerFromMasterSigner(const std::string &mastersigner_id, const nunchuk::WalletType &wallet_type, const nunchuk::AddressType &address_type, QWarningMessage &msg) { nunchuk::SingleSigner ret("","","","","",0,""); try { if(nunchuk_instance_[nunchukMode()]){ - ret = nunchuk_instance_[nunchukMode()]->GetDefaultSignerFromMasterSigner(mastersigner_id, nunchuk::WalletType::MULTI_SIG, nunchuk::AddressType::ANY); + ret = nunchuk_instance_[nunchukMode()]->GetDefaultSignerFromMasterSigner(mastersigner_id, wallet_type, address_type); + } + } + catch (std::exception &e) { + DBG_INFO << "THROW EXCEPTION" << e.what(); msg.setWarningMessage(-1, e.what(), EWARNING::WarningType::EXCEPTION_MSG); + } + return ret; +} + +nunchuk::SingleSigner nunchukiface::GetDefaultSignerFromMasterSigner(const std::string &mastersigner_id, QWarningMessage& msg) +{ + return GetDefaultSignerFromMasterSigner(mastersigner_id, nunchuk::WalletType::MULTI_SIG, nunchuk::AddressType::ANY, msg); +} + +bool nunchukiface::IsCPFP(const std::string &wallet_id, const nunchuk::Transaction &tx, nunchuk::Amount &package_fee_rate, QWarningMessage& msg) +{ + bool ret {false}; + try { + if(nunchuk_instance_[nunchukMode()]){ + ret = nunchuk_instance_[nunchukMode()]->IsCPFP(wallet_id, tx, package_fee_rate); } } catch (std::exception &e) { diff --git a/ifaces/nunchuckiface.h b/ifaces/nunchuckiface.h index 3d77a371..77d3f472 100644 --- a/ifaces/nunchuckiface.h +++ b/ifaces/nunchuckiface.h @@ -57,7 +57,7 @@ class nunchukiface nunchuk::Wallet CreateWallet(const std::string& name, int m, int n, - std::vector& signers, + const std::vector& signers, nunchuk::AddressType address_type, bool is_escrow, const std::string& desc, @@ -70,7 +70,7 @@ class nunchukiface std::string DraftWallet(const std::string& name, int m, int n, - std::vector& signers, + const std::vector& signers, nunchuk::AddressType address_type, bool is_escrow, const std::string& desc, @@ -113,6 +113,10 @@ class nunchukiface int index, QWarningMessage& msg); + nunchuk::SingleSigner GetSignerFromMasterSigner(const std::string &mastersigner_id, + const std::string &derivation_path, + QWarningMessage& msg); + nunchuk::SingleSigner CreateSigner(const std::string& name, const std::string& xpub, const std::string& public_key, @@ -457,9 +461,18 @@ class nunchukiface const std::string& message, QWarningMessage& msg); + nunchuk::SingleSigner GetDefaultSignerFromMasterSigner(const std::string &mastersigner_id, + const nunchuk::WalletType& wallet_type, + const nunchuk::AddressType& address_type, + QWarningMessage& msg); + nunchuk::SingleSigner GetDefaultSignerFromMasterSigner(const std::string &mastersigner_id, QWarningMessage& msg); + bool IsCPFP(const std::string& wallet_id, + const nunchuk::Transaction& tx, + nunchuk::Amount& package_fee_rate, + QWarningMessage& msg); private: nunchukiface(); ~nunchukiface(); diff --git a/ifaces/nunchucklistener.cpp b/ifaces/nunchucklistener.cpp index 2f813e79..488d19ef 100644 --- a/ifaces/nunchucklistener.cpp +++ b/ifaces/nunchucklistener.cpp @@ -30,6 +30,7 @@ void balance_listener(std::string id, nunchuk::Amount balance) void balances_listener(string id, nunchuk::Amount balance, nunchuk::Amount unconfirmed_balance) { + DBG_INFO; bridge::nunchukBalanceChanged(QString::fromStdString(id), static_cast(unconfirmed_balance)); } @@ -40,6 +41,7 @@ void devices_listener(std::string fingerprint, bool connected) void transaction_listener(std::string tx_id, nunchuk::TransactionStatus status, std::string wallet_id) { + DBG_INFO; bridge::nunchukTransactionChanged(QString::fromStdString(tx_id), (int)status, QString::fromStdString(wallet_id)); } diff --git a/ifaces/qUtils.cpp b/ifaces/qUtils.cpp index 7ece802e..068f733b 100644 --- a/ifaces/qUtils.cpp +++ b/ifaces/qUtils.cpp @@ -22,6 +22,7 @@ #include "AppModel.h" #include "QOutlog.h" #include +#include qint64 qUtils::QAmountFromValue(const QString &value, const bool allow_negative) { qint64 ret = -1; @@ -431,3 +432,43 @@ int qUtils::Precision(double input) } return qMax(lastDigit,2); } + +QJsonObject qUtils::GetJsonObject(QString text) +{ + QJsonObject obj; + QJsonDocument doc = QJsonDocument::fromJson(text.toUtf8()); + + // check validity of the document + if(!doc.isNull()) + { + if(doc.isObject()) + { + obj = doc.object(); + } + else + { + qDebug() << "Document is not an object"; + } + } + else + { + qDebug() << "Invalid JSON...\n"; + } + return obj; +} + +uint qUtils::GetTimeSecond(QString time_str) +{ + QStringList list = time_str.split("/"); + QString month = list.at(0); + QString day = list.at(1); + QString year = list.at(2); + QDate date(year.toInt(), month.toInt(), day.toInt()); + QDateTime time(date); + return time.toTime_t(); +} + +uint qUtils::GetCurrentTimeSecond() +{ + return QDateTime::currentDateTime().toTime_t(); +} diff --git a/ifaces/qUtils.h b/ifaces/qUtils.h index 8829e74e..4572a989 100644 --- a/ifaces/qUtils.h +++ b/ifaces/qUtils.h @@ -115,6 +115,11 @@ QString currencyLocale(qint64 amountSats); bool verifyCheckSum(const QByteArray& data, const QByteArray& expectedCheckSum); int Precision(double input); + +QJsonObject GetJsonObject(QString text); + +uint GetTimeSecond(QString time_str); +uint GetCurrentTimeSecond(); } #endif // QUTILS_H diff --git a/localization/STR_CPP.h b/localization/STR_CPP.h index 33660bf7..5b2269aa 100644 --- a/localization/STR_CPP.h +++ b/localization/STR_CPP.h @@ -121,4 +121,6 @@ const static QString STR_CPP_115 = QString("Invalid password. Unable to restore const static QString STR_CPP_116 = QString("The Magic Phrase you entered does not match the one that you requested."); const static QString STR_CPP_117 = QString("Policies have been updated"); const static QString STR_CPP_118 = QString("Could not claim inheritance"); +const static QString STR_CPP_119 = QString("The inheritance plan has been updated"); +const static QString STR_CPP_120 = QString("Invalid activation time"); #endif // STR_CPP_H diff --git a/localization/STR_QML.js b/localization/STR_QML.js index dbc64415..cf0a5b0e 100644 --- a/localization/STR_QML.js +++ b/localization/STR_QML.js @@ -70,7 +70,7 @@ var STR_QML_041 = qsTr("Import DB") var STR_QML_042 = qsTr("NEXT: Key Setup") //SCR_ADD_WALLET_SIGNER_CONFIGURATION.qml -var STR_QML_043 = qsTr("Choose from Existing Keys") +var STR_QML_043 = qsTr("Choose from existing keys") var STR_QML_044 = qsTr("Hardware") var STR_QML_045 = qsTr("Air-gapped") var STR_QML_046 = qsTr("Software") @@ -131,7 +131,7 @@ var STR_QML_096 = qsTr("To unlock the device, you might need to enter a PIN%1 remaining assisted wallets. You can get additional wallets through our website. Sign in and navigate to the Plan and Invoices page.") +var STR_QML_842 = qsTr("You have %1 remaining assisted wallet. You can get additional wallet through our website. Sign in and navigate to the Plan and Invoices page.") +//================= +var STR_QML_843 = qsTr("Review your plan") +var STR_QML_844 = qsTr("Cancel inheritance plan") +var STR_QML_845 = qsTr("Wallet subject to inheritance:") +var STR_QML_846 = qsTr("View claiming instructions") +var STR_QML_847 = qsTr("Share your secrets") +var STR_QML_848 = qsTr("Activation Date") +var STR_QML_849 = qsTr("Edit") +var STR_QML_850 = qsTr("Note to Beneficiary or Trustee") +var STR_QML_851 = qsTr("Buffer period") +var STR_QML_852 = qsTr("Nofication preferences") +var STR_QML_853 = qsTr("Continue to finalize changes") +//=================== +var STR_QML_854 = qsTr("Set up an Activation Date") +var STR_QML_855 = qsTr("Only on or after this date, a Beneficiary or Trustee can claim the inheritance. \n +You can change the Activation Date later via the Services tab.") +var STR_QML_856 = qsTr("Even with the correct Magic Phrase and Backup Password, one cannot claim the inheritance before this date.") +var STR_QML_857 = qsTr("Update activation date") +var STR_QML_858 = qsTr("Would you like to leave a message?") +var STR_QML_859 = qsTr("After the Beneficiary or Trustee claims the inheritance, they will be able to \n \ +see this message.") +var STR_QML_860 = qsTr("Note") +var STR_QML_861 = qsTr("Update message") +var STR_QML_862 = qsTr("Set up buffer period") +var STR_QML_863 = qsTr("A buffer period is extra time that you can add after the claimant has provided \n \ +the secrets and before the inheritance can be claimed. The buffer period \n \ +helps you prevent unauthorized claims. \n \ +\n \ +An email notification will be sent when the buffer period begins.") + +var STR_QML_864 = qsTr("Update buffer period") +var STR_QML_865 = qsTr("Notification preferences") +var STR_QML_866 = qsTr("On the Activation Date, would you like us to notify the Beneficiary or Trustee of the inheritance plan? If so, please provide an email address.") +var STR_QML_867 = qsTr("Beneficiary’s or Trustee’s email address") +var STR_QML_868 = qsTr("Also notify them today") +var STR_QML_869 = qsTr("You are still personally responsible for sharing the Magic Phrase and Backup Password with the Beneficiary or Trustee. The notification email won’t include these information.") +var STR_QML_870 = qsTr("Update notification preferences") +var STR_QML_871 = qsTr("I don’t want any notifications") + +var STR_QML_872 = qsTr("Are you sure want to discard the changes?") +var STR_QML_873 = qsTr("Moving the Activation Date earlier requires signing a dummy transaction. Please do so via the mobile app.") +var STR_QML_874 = qsTr("Canceling the inheritance requires signing a dummy transaction. Please do so via the mobile app.") +var STR_QML_875 = qsTr("View inheritance plan") + +var STR_QML_876 = qsTr("30-day buffer") +var STR_QML_877 = qsTr("7-day buffer") +var STR_QML_878 = qsTr("I don’t need a buffer period") +var STR_QML_879 = qsTr("Recommended") + +var STR_QML_880 = qsTr("The Magic Phrase and Backup Password must be shared with the party or \n \ +parties eligible for the inheritance. Please select your option:") + +var STR_QML_881 = qsTr("Direct inheritance") +var STR_QML_882 = qsTr("The Beneficiary has full control over the inheritance. Upon the \n \ +Activation Date, they can claim the inheritance for themselves.") + +var STR_QML_883 = qsTr("Indirect inheritance") +var STR_QML_884 = qsTr("A Trustee has full control over the inheritance. Upon the Activation \n \ +Date, the Trustee can help the Beneficiary claim the inheritance on their behalf.") + +var STR_QML_885 = qsTr("Joint control") +var STR_QML_886 = qsTr("The Beneficiary and the Trustee have joint control over the \n \ +inheritance. Upon the Activation Date, the Beneficiary and Trustee \n \ +will need to combine their secrets in order to claim the \n \ +inheritance.") + +var STR_QML_887 = qsTr("Please share these two secrets with the \n \ +Beneficiary:") +var STR_QML_888 = qsTr("The plan’s Magic Phrase.") +var STR_QML_889 = qsTr("The Backup Password for the encrypted \n \ +backup, which can be found on the back of \n \ +the TAPSIGNER designated for inheritance. \n \ +(It might be listed under “Backup key”).") +var STR_QML_890 = qsTr("You are solely responsible for sharing \n \ +the Magic Phrase and Backup \n \ +Password with the Beneficiary. Failure to \n \ +share will result in the inheritance \n \ +being unclaimable.") +var STR_QML_891 = qsTr("Please share these two secrets with the Trustee:") +var STR_QML_892 = qsTr("Please share one secret with the Beneficiary and \n \ +the other secret with the Trustee. Neither party \n \ +should have both secrets.") +var STR_QML_893 = qsTr("You are solely responsible for sharing the Magic Phrase and Backup \n \ +Password with the Trustee. Failure to \n \ +share will result in the inheritance \n \ +being unclaimable.") +var STR_QML_894 = qsTr("You are solely responsible for sharing \n \ +the Magic Phrase and Backup \n \ +Password with the Beneficiary and the \n \ +Trustee. Failure to share will result in \n \ +the inheritance being unclaimable.") + +var STR_QML_895 = qsTr("This transaction includes unconfirmed coins.") +var STR_QML_896 = qsTr("Moving the Activation Date earlier requires signing a dummy transaction. Please do so via the mobile app.") +var STR_QML_897 = qsTr("Canceling the inheritance requires signing a dummy transaction. Please do so via the mobile app.") +var STR_QML_898 = qsTr("Wired") +var STR_QML_899 = qsTr("Add existing key") +var STR_QML_900 = qsTr("Take me to add a new key") +var STR_QML_901 = qsTr("Do you want to add an existing key?") +var STR_QML_902 = qsTr("We noticed that you already have a Ledger in your key manager") + +var STR_QML_903 = qsTr("Add COLDCARD to your assisted wallet") +var STR_QML_904 = qsTr("Add COLDCARD") +var STR_QML_905 = qsTr("It looks like you want to add COLDCARD as a hardware key to an assisted wallet. Would you like to do it now?") +var STR_QML_906 = qsTr("No COLDCARD devices have been detected. Please try again.") + +var STR_QML_907 = qsTr("Initialize COLDCARD") +var STR_QML_908 = qsTr("Refer to this starter guide.") +var STR_QML_909 = qsTr("Unlock COLDCARD") +var STR_QML_910 = qsTr("You might need to enter a PIN and/or a PASSPHRASE directly on COLDCARD.") +var STR_QML_911 = qsTr("Please ensure that the COLDCARD device is connected to this computer, and click on Refresh") +var STR_QML_912 = qsTr("Adding COLDCARD...") +var STR_QML_913 = qsTr("COLDCARD added successfully") +var STR_QML_914 = qsTr("No COLDCARD devices have been detected. Please try again.") +var STR_QML_915 = qsTr("We noticed that you already have a Trezor in your key manager") +var STR_QML_916 = qsTr("We noticed that you already have a COLDCARD in your key manager") +var STR_QML_917 = qsTr("(The Backup Password is printed on the back of the \n +inheritance key)") +var STR_QML_918 = qsTr("There no assisted wallet") +var STR_QML_919 = qsTr("Are you sure want to discard the changes?") +var STR_QML_920 = qsTr("Would you like to leave a message?") +var STR_QML_921 = qsTr("No buffer") diff --git a/main.cpp b/main.cpp index 2c315cef..80be572c 100644 --- a/main.cpp +++ b/main.cpp @@ -154,8 +154,9 @@ int main(int argc, char* argv[]) #else QQuickViewer::instance()->registerContextProperty("SIGNET_SERVER", ""); #endif - QQuickViewer::instance()->registerContextProperty("BLOCKSTREAM_TESTNET", BLOCKSTREAM_TESTNET); - QQuickViewer::instance()->registerContextProperty("BLOCKSTREAM_MAINNET", BLOCKSTREAM_MAINNET); + QQuickViewer::instance()->registerContextProperty("EXPLORER_TESTNET", EXPLORER_TESTNET); + QQuickViewer::instance()->registerContextProperty("EXPLORER_MAINNET", EXPLORER_MAINNET); + QQuickViewer::instance()->registerContextProperty("EXPLORER_SIGNNET", EXPLORER_SIGNNET); QQuickViewer::instance()->registerContextProperty("MAX_UNUSED_ADDR", MAX_UNUSED_ADDR); QQuickViewer::instance()->registerContextProperty("AppModel", QVariant::fromValue(AppModel::instance())); QQuickViewer::instance()->registerContextProperty("AppSetting", QVariant::fromValue(AppSetting::instance())); @@ -184,14 +185,16 @@ int main(int argc, char* argv[]) } , Qt::QueuedConnection); QObject::connect(QQuickViewer::instance()->getQuickWindow(), &QQuickView::windowStateChanged, [=](int windowState) { - static int state = -1; - if (state != windowState) { - state = windowState; - if (windowState == Qt::WindowNoState) { - Draco::instance()->checkForUpdate(); + QtConcurrent::run([windowState]() { + static int state = -1; + if (state != windowState) { + state = windowState; + if (windowState == Qt::WindowNoState) { + Draco::instance()->checkForUpdate(); + } } - } }); + }); QQuickViewer::instance()->show(); return app.exec(); } diff --git a/qml.qrc b/qml.qrc index 9b42addd..6052c876 100644 --- a/qml.qrc +++ b/qml.qrc @@ -223,6 +223,28 @@ Qml/Components/customizes/QAddAssistedWalletSigner.qml Qml/Components/customizes/QProgressbarTypeA.qml Qml/Screens/OnlineMode/SCR_SELECT_WALLET_CO_SIGN_POLICE.qml + Qml/Screens/OnlineMode/SCR_EDIT_YOUR_INHERITANCE_PLAN.qml + Qml/Screens/OnlineMode/SCR_SHARE_YOUR_SECRETS.qml + Qml/Components/customizes/services/QViewInheritancePlaning.qml + Qml/Components/customizes/services/QSelectAnAssistedWallet.qml + Qml/Components/customizes/Buttons/QLinearGradient.qml + Qml/Components/customizes/Buttons/QAssistedWalletDelegate.qml + Qml/Components/customizes/Texts/QTextLink.qml + Qml/Components/customizes/Texts/QTextInputBoxTypeE.qml + Qml/Components/customizes/Texts/QTextAreaBoxTypeA.qml + Qml/Components/origins/QTextArea.qml + Qml/Components/customizes/Texts/QTextAreaBoxTypeB.qml + Qml/Components/customizes/Buttons/QRadioButtonTypeE.qml + Qml/Components/customizes/Texts/QTextAreaBoxTypeC.qml + Qml/Components/customizes/Buttons/QCheckBoxButton.qml + Qml/Components/customizes/Buttons/QRadioButtonTypeF.qml + Qml/Components/customizes/services/QInheritanceDetails.qml + Qml/Screens/OnlineMode/SCR_ADD_COLDCARD.qml + Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_ASK.qml + Qml/Screens/OnlineMode/SCR_ADD_COLDCARD_EXIST.qml + Qml/Screens/OnlineMode/SCR_ADD_LEDGER_EXIST.qml + Qml/Screens/OnlineMode/SCR_ADD_TREZOR_EXIST.qml + Qml/Components/customizes/QAddAnExistingKey.qml Images/services-light.svg @@ -453,6 +475,18 @@ Images/OnlineMode/help_outline_24px.svg Images/ExportFile.svg Images/ledger-illustration.svg + Images/more-horizontal-dark.svg + Images/close-24px.svg + Images/calendar-dark.svg + Images/change-password-dark.svg + Images/star-dark.svg + Images/wallet-brand-icon.svg + Images/calendar-dark.png + Images/star-dark.png + Images/inheritance_backup_password.svg + Images/trezor-illustration.svg + Images/Device_Icons/Ledger.svg + Images/coldcard-illustration.svg Info.plist