mirror of
https://github.com/monero-project/monero-gui.git
synced 2025-01-05 18:39:38 +00:00
view only wallets
wizard: fix dots on pw page wizard: fix focus on pw field viewOnly: added success message
This commit is contained in:
parent
8f56e98397
commit
fd983955b4
11 changed files with 497 additions and 227 deletions
|
@ -39,51 +39,26 @@ import moneroComponents.Clipboard 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
property var daemonAddress
|
property var daemonAddress
|
||||||
|
property bool viewOnly: false
|
||||||
|
|
||||||
color: "#F0EEEE"
|
color: "#F0EEEE"
|
||||||
|
|
||||||
Clipboard { id: clipboard }
|
Clipboard { id: clipboard }
|
||||||
|
|
||||||
function initSettings() {
|
function initSettings() {
|
||||||
|
//runs on every page load
|
||||||
|
|
||||||
|
// Mnemonic seed setting
|
||||||
// Mnemonic seed settings
|
memoTextInput.text = (viewOnly)? qsTr("View only wallets doesn't have a mnemonic seed") : qsTr("Click button to show seed") + translationManager.emptyString
|
||||||
memoTextInput.text = qsTr("Click button to show seed") + translationManager.emptyString
|
showSeedButton.enabled = !viewOnly
|
||||||
showSeedButton.visible = true
|
|
||||||
|
|
||||||
// Daemon settings
|
// Daemon settings
|
||||||
|
|
||||||
daemonAddress = persistentSettings.daemon_address.split(":");
|
daemonAddress = persistentSettings.daemon_address.split(":");
|
||||||
console.log("address: " + persistentSettings.daemon_address)
|
console.log("address: " + persistentSettings.daemon_address)
|
||||||
// try connecting to daemon
|
// try connecting to daemon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PasswordDialog {
|
|
||||||
id: settingsPasswordDialog
|
|
||||||
|
|
||||||
onAccepted: {
|
|
||||||
if(appWindow.password === settingsPasswordDialog.password){
|
|
||||||
memoTextInput.text = currentWallet.seed
|
|
||||||
showSeedButton.visible = false
|
|
||||||
} else {
|
|
||||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
|
||||||
informationPopup.text = qsTr("Wrong password");
|
|
||||||
informationPopup.open()
|
|
||||||
informationPopup.onCloseCallback = function() {
|
|
||||||
settingsPasswordDialog.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsPasswordDialog.password = ""
|
|
||||||
}
|
|
||||||
onRejected: {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: mainLayout
|
id: mainLayout
|
||||||
anchors.margins: 40
|
anchors.margins: 40
|
||||||
|
@ -92,17 +67,59 @@ Rectangle {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
|
//! Manage wallet
|
||||||
|
RowLayout {
|
||||||
Label {
|
Label {
|
||||||
id: seedLabel
|
id: manageWalletLabel
|
||||||
|
Layout.fillWidth: true
|
||||||
color: "#4A4949"
|
color: "#4A4949"
|
||||||
|
text: qsTr("Manage wallet") + translationManager.emptyString
|
||||||
fontSize: 16
|
fontSize: 16
|
||||||
text: qsTr("Mnemonic seed: ") + translationManager.emptyString
|
Layout.topMargin: 10
|
||||||
Layout.preferredWidth: 100
|
}
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: "#DEDEDE"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
StandardButton {
|
||||||
|
id: closeWalletButton
|
||||||
|
width: 100
|
||||||
|
text: qsTr("Close wallet") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: true
|
||||||
|
onClicked: {
|
||||||
|
console.log("closing wallet button clicked")
|
||||||
|
appWindow.showWizard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
enabled: !viewOnly
|
||||||
|
id: createViewOnlyWalletButton
|
||||||
|
text: qsTr("Create view only wallet") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: true
|
||||||
|
onClicked: {
|
||||||
|
wizard.openCreateViewOnlyWalletPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! show seed
|
||||||
TextArea {
|
TextArea {
|
||||||
|
enabled: !viewOnly
|
||||||
id: memoTextInput
|
id: memoTextInput
|
||||||
textMargin: 6
|
textMargin: 6
|
||||||
wrapMode: TextEdit.WordWrap
|
wrapMode: TextEdit.WordWrap
|
||||||
|
@ -113,7 +130,7 @@ Rectangle {
|
||||||
Layout.preferredHeight: 100
|
Layout.preferredHeight: 100
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
text: qsTr("Click button to show seed") + translationManager.emptyString
|
text: (viewOnly)? qsTr("View only wallets doesn't have a mnemonic seed") : qsTr("Click button to show seed") + translationManager.emptyString
|
||||||
|
|
||||||
style: TextAreaStyle {
|
style: TextAreaStyle {
|
||||||
backgroundColor: "#FFFFFF"
|
backgroundColor: "#FFFFFF"
|
||||||
|
@ -137,7 +154,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
enabled: !viewOnly
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Text {
|
Text {
|
||||||
id: wordsTipText
|
id: wordsTipText
|
||||||
|
@ -151,37 +170,99 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardButton {
|
StandardButton {
|
||||||
|
|
||||||
id: showSeedButton
|
id: showSeedButton
|
||||||
|
|
||||||
fontSize: 14
|
|
||||||
shadowReleasedColor: "#FF4304"
|
shadowReleasedColor: "#FF4304"
|
||||||
shadowPressedColor: "#B32D00"
|
shadowPressedColor: "#B32D00"
|
||||||
releasedColor: "#FF6C3C"
|
releasedColor: "#FF6C3C"
|
||||||
pressedColor: "#FF4304"
|
pressedColor: "#FF4304"
|
||||||
text: qsTr("Show seed")
|
text: qsTr("Show seed")
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Layout.preferredWidth: 100
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
settingsPasswordDialog.open();
|
settingsPasswordDialog.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Manage daemon
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
id: manageDaemonLabel
|
||||||
|
color: "#4A4949"
|
||||||
|
text: qsTr("Manage daemon") + translationManager.emptyString
|
||||||
|
fontSize: 16
|
||||||
|
anchors.topMargin: 30
|
||||||
|
Layout.topMargin: 30
|
||||||
|
}
|
||||||
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: 1
|
height: 1
|
||||||
color: "#DEDEDE"
|
color: "#DEDEDE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
StandardButton {
|
||||||
|
visible: true
|
||||||
|
enabled: !appWindow.daemonRunning
|
||||||
|
id: startDaemonButton
|
||||||
|
text: qsTr("Start daemon") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
onClicked: {
|
||||||
|
appWindow.startDaemon(daemonFlags.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
visible: true
|
||||||
|
enabled: appWindow.daemonRunning
|
||||||
|
id: stopDaemonButton
|
||||||
|
text: qsTr("Stop daemon") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
onClicked: {
|
||||||
|
appWindow.stopDaemon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
visible: true
|
||||||
|
id: daemonConsolePopupButton
|
||||||
|
text: qsTr("Show log") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
onClicked: {
|
||||||
|
daemonConsolePopup.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: daemonFlagsRow
|
||||||
|
Label {
|
||||||
|
id: daemonFlagsLabel
|
||||||
|
color: "#4A4949"
|
||||||
|
text: qsTr("Daemon startup flags") + translationManager.emptyString
|
||||||
|
fontSize: 16
|
||||||
|
}
|
||||||
|
LineEdit {
|
||||||
|
id: daemonFlags
|
||||||
|
Layout.preferredWidth: 200
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: appWindow.persistentSettings.daemonFlags;
|
||||||
|
placeholderText: qsTr("(optional)") + translationManager.emptyString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: daemonAddrRow
|
id: daemonAddrRow
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 40
|
|
||||||
Layout.topMargin: 40
|
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -213,12 +294,8 @@ Rectangle {
|
||||||
|
|
||||||
StandardButton {
|
StandardButton {
|
||||||
id: daemonAddrSave
|
id: daemonAddrSave
|
||||||
|
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
|
|
||||||
Layout.leftMargin: 30
|
Layout.leftMargin: 30
|
||||||
Layout.minimumWidth: 100
|
|
||||||
width: 60
|
|
||||||
text: qsTr("Save") + translationManager.emptyString
|
text: qsTr("Save") + translationManager.emptyString
|
||||||
shadowReleasedColor: "#FF4304"
|
shadowReleasedColor: "#FF4304"
|
||||||
shadowPressedColor: "#B32D00"
|
shadowPressedColor: "#B32D00"
|
||||||
|
@ -238,120 +315,19 @@ Rectangle {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Label {
|
Label {
|
||||||
id: closeWalletLabel
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: "#4A4949"
|
color: "#4A4949"
|
||||||
text: qsTr("Manage wallet") + translationManager.emptyString
|
text: qsTr("Layout settings") + translationManager.emptyString
|
||||||
fontSize: 16
|
fontSize: 16
|
||||||
|
anchors.topMargin: 30
|
||||||
|
Layout.topMargin: 30
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
Rectangle {
|
||||||
|
|
||||||
Text {
|
|
||||||
id: closeWalletTip
|
|
||||||
font.family: "Arial"
|
|
||||||
font.pointSize: 12
|
|
||||||
color: "#4A4646"
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.WordWrap
|
height: 1
|
||||||
text: qsTr("Close current wallet and open wizard")
|
color: "#DEDEDE"
|
||||||
+ translationManager.emptyString
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
StandardButton {
|
|
||||||
id: closeWalletButton
|
|
||||||
|
|
||||||
// Layout.leftMargin: 30
|
|
||||||
// Layout.minimumWidth: 100
|
|
||||||
width: 100
|
|
||||||
text: qsTr("Close wallet") + translationManager.emptyString
|
|
||||||
shadowReleasedColor: "#FF4304"
|
|
||||||
shadowPressedColor: "#B32D00"
|
|
||||||
releasedColor: "#FF6C3C"
|
|
||||||
pressedColor: "#FF4304"
|
|
||||||
visible: true
|
|
||||||
onClicked: {
|
|
||||||
console.log("closing wallet button clicked")
|
|
||||||
appWindow.showWizard();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Label {
|
|
||||||
id: manageDaemonLabel
|
|
||||||
color: "#4A4949"
|
|
||||||
text: qsTr("Manage daemon") + translationManager.emptyString
|
|
||||||
fontSize: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
StandardButton {
|
|
||||||
visible: true
|
|
||||||
enabled: !appWindow.daemonRunning
|
|
||||||
id: startDaemonButton
|
|
||||||
width: 110
|
|
||||||
text: qsTr("Start daemon") + translationManager.emptyString
|
|
||||||
shadowReleasedColor: "#FF4304"
|
|
||||||
shadowPressedColor: "#B32D00"
|
|
||||||
releasedColor: "#FF6C3C"
|
|
||||||
pressedColor: "#FF4304"
|
|
||||||
onClicked: {
|
|
||||||
appWindow.startDaemon(daemonFlags.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StandardButton {
|
|
||||||
visible: true
|
|
||||||
enabled: appWindow.daemonRunning
|
|
||||||
id: stopDaemonButton
|
|
||||||
width: 110
|
|
||||||
text: qsTr("Stop daemon") + translationManager.emptyString
|
|
||||||
shadowReleasedColor: "#FF4304"
|
|
||||||
shadowPressedColor: "#B32D00"
|
|
||||||
releasedColor: "#FF6C3C"
|
|
||||||
pressedColor: "#FF4304"
|
|
||||||
onClicked: {
|
|
||||||
appWindow.stopDaemon()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StandardButton {
|
|
||||||
visible: true
|
|
||||||
// enabled: appWindow.daemonRunning
|
|
||||||
id: daemonConsolePopupButton
|
|
||||||
width: 110
|
|
||||||
text: qsTr("Show log") + translationManager.emptyString
|
|
||||||
shadowReleasedColor: "#FF4304"
|
|
||||||
shadowPressedColor: "#B32D00"
|
|
||||||
releasedColor: "#FF6C3C"
|
|
||||||
pressedColor: "#FF4304"
|
|
||||||
onClicked: {
|
|
||||||
daemonConsolePopup.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: daemonFlagsRow
|
|
||||||
Label {
|
|
||||||
id: daemonFlagsLabel
|
|
||||||
color: "#4A4949"
|
|
||||||
text: qsTr("Daemon startup flags") + translationManager.emptyString
|
|
||||||
fontSize: 16
|
|
||||||
}
|
|
||||||
LineEdit {
|
|
||||||
id: daemonFlags
|
|
||||||
Layout.preferredWidth: 200
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: appWindow.persistentSettings.daemonFlags;
|
|
||||||
placeholderText: qsTr("(optional)") + translationManager.emptyString
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
@ -386,6 +362,22 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Version
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
color: "#4A4949"
|
||||||
|
text: qsTr("Version") + translationManager.emptyString
|
||||||
|
fontSize: 16
|
||||||
|
anchors.topMargin: 30
|
||||||
|
Layout.topMargin: 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
color: "#DEDEDE"
|
||||||
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: guiVersion
|
id: guiVersion
|
||||||
Layout.topMargin: 8
|
Layout.topMargin: 8
|
||||||
|
@ -414,11 +406,35 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PasswordDialog {
|
||||||
|
id: settingsPasswordDialog
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if(appWindow.password === settingsPasswordDialog.password){
|
||||||
|
memoTextInput.text = currentWallet.seed
|
||||||
|
showSeedButton.enabled = false
|
||||||
|
} else {
|
||||||
|
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||||
|
informationPopup.text = qsTr("Wrong password");
|
||||||
|
informationPopup.open()
|
||||||
|
informationPopup.onCloseCallback = function() {
|
||||||
|
settingsPasswordDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsPasswordDialog.password = ""
|
||||||
|
}
|
||||||
|
onRejected: {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// fires on every page load
|
// fires on every page load
|
||||||
function onPageCompleted() {
|
function onPageCompleted() {
|
||||||
console.log("Settings page loaded");
|
console.log("Settings page loaded");
|
||||||
initSettings();
|
initSettings();
|
||||||
|
viewOnly = currentWallet.viewOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fires only once
|
// fires only once
|
||||||
|
|
|
@ -464,6 +464,11 @@ Rectangle {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentWallet.viewOnly) {
|
||||||
|
statusText.text = qsTr("Wallet is view only.")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (currentWallet.connected) {
|
switch (currentWallet.connected) {
|
||||||
case Wallet.ConnectionStatus_Disconnected:
|
case Wallet.ConnectionStatus_Disconnected:
|
||||||
statusText.text = qsTr("Wallet is not connected to daemon.") + "<br>" + root.startLinkText
|
statusText.text = qsTr("Wallet is not connected to daemon.") + "<br>" + root.startLinkText
|
||||||
|
|
2
qml.qrc
2
qml.qrc
|
@ -122,5 +122,7 @@
|
||||||
<file>pages/Sign.qml</file>
|
<file>pages/Sign.qml</file>
|
||||||
<file>components/DaemonManagerDialog.qml</file>
|
<file>components/DaemonManagerDialog.qml</file>
|
||||||
<file>version.js</file>
|
<file>version.js</file>
|
||||||
|
<file>wizard/WizardPasswordUI.qml</file>
|
||||||
|
<file>wizard/WizardCreateViewOnlyWallet.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -158,6 +158,15 @@ void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLim
|
||||||
m_walletImpl->initAsync(daemonAddress.toStdString(), upperTransactionLimit);
|
m_walletImpl->initAsync(daemonAddress.toStdString(), upperTransactionLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! create a view only wallet
|
||||||
|
bool Wallet::createViewOnly(const QString &path, const QString &password) const
|
||||||
|
{
|
||||||
|
// Create path
|
||||||
|
QDir d = QFileInfo(path).absoluteDir();
|
||||||
|
d.mkpath(d.absolutePath());
|
||||||
|
return m_walletImpl->createWatchOnly(path.toStdString(),password.toStdString(),m_walletImpl->getSeedLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
bool Wallet::connectToDaemon()
|
bool Wallet::connectToDaemon()
|
||||||
{
|
{
|
||||||
return m_walletImpl->connectToDaemon();
|
return m_walletImpl->connectToDaemon();
|
||||||
|
@ -168,6 +177,11 @@ void Wallet::setTrustedDaemon(bool arg)
|
||||||
m_walletImpl->setTrustedDaemon(arg);
|
m_walletImpl->setTrustedDaemon(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wallet::viewOnly() const
|
||||||
|
{
|
||||||
|
return m_walletImpl->watchOnly();
|
||||||
|
}
|
||||||
|
|
||||||
quint64 Wallet::balance() const
|
quint64 Wallet::balance() const
|
||||||
{
|
{
|
||||||
return m_walletImpl->balance();
|
return m_walletImpl->balance();
|
||||||
|
|
|
@ -36,7 +36,7 @@ class Wallet : public QObject
|
||||||
Q_PROPERTY(QString path READ path)
|
Q_PROPERTY(QString path READ path)
|
||||||
Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel)
|
Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel)
|
||||||
Q_PROPERTY(AddressBook * addressBook READ addressBook)
|
Q_PROPERTY(AddressBook * addressBook READ addressBook)
|
||||||
|
Q_PROPERTY(bool viewOnly READ viewOnly)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -98,6 +98,9 @@ public:
|
||||||
//! initializes wallet asynchronously
|
//! initializes wallet asynchronously
|
||||||
Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering = false, quint64 restoreHeight = 0);
|
Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering = false, quint64 restoreHeight = 0);
|
||||||
|
|
||||||
|
//! create a view only wallet
|
||||||
|
Q_INVOKABLE bool createViewOnly(const QString &path, const QString &password) const;
|
||||||
|
|
||||||
//! connects to daemon
|
//! connects to daemon
|
||||||
Q_INVOKABLE bool connectToDaemon();
|
Q_INVOKABLE bool connectToDaemon();
|
||||||
|
|
||||||
|
@ -110,6 +113,9 @@ public:
|
||||||
//! returns unlocked balance
|
//! returns unlocked balance
|
||||||
Q_INVOKABLE quint64 unlockedBalance() const;
|
Q_INVOKABLE quint64 unlockedBalance() const;
|
||||||
|
|
||||||
|
//! returns if view only wallet
|
||||||
|
Q_INVOKABLE bool viewOnly() const;
|
||||||
|
|
||||||
//! returns current wallet's block height
|
//! returns current wallet's block height
|
||||||
//! (can be less than daemon's blockchain height when wallet sync in progress)
|
//! (can be less than daemon's blockchain height when wallet sync in progress)
|
||||||
Q_INVOKABLE quint64 blockChainHeight() const;
|
Q_INVOKABLE quint64 blockChainHeight() const;
|
||||||
|
|
94
wizard/WizardCreateViewOnlyWallet.qml
Normal file
94
wizard/WizardCreateViewOnlyWallet.qml
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Copyright (c) 2014-2015, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import moneroComponents.WalletManager 1.0
|
||||||
|
import QtQuick 2.2
|
||||||
|
import "../components"
|
||||||
|
import "utils.js" as Utils
|
||||||
|
|
||||||
|
Item {
|
||||||
|
|
||||||
|
id: passwordPage
|
||||||
|
opacity: 0
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpacityChanged: visible = opacity !== 0
|
||||||
|
|
||||||
|
|
||||||
|
function onPageOpened(settingsObject) {
|
||||||
|
wizard.nextButton.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPageClosed(settingsObject) {
|
||||||
|
var walletFullPath = wizard.createWalletPath(uiItem.walletPath,uiItem.accountNameText);
|
||||||
|
settingsObject['view_only_wallet_path'] = walletFullPath
|
||||||
|
console.log("wallet path", walletFullPath)
|
||||||
|
return wizard.walletPathValid(walletFullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: dotsRow
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 85
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: dotsModel
|
||||||
|
ListElement { dotColor: "#FFE00A" }
|
||||||
|
ListElement { dotColor: "#DBDBDB" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: dotsModel
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: 12; height: 12
|
||||||
|
radius: 6
|
||||||
|
color: dotColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WizardManageWalletUI {
|
||||||
|
id: uiItem
|
||||||
|
titleText: qsTr("Give your view only wallet a name") + translationManager.emptyString
|
||||||
|
wordsTextItem.visible: false
|
||||||
|
restoreHeightVisible:false
|
||||||
|
walletName: appWindow.walletName + "-viewonly"
|
||||||
|
progressDotsModel: dotsModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
//parent.wizardRestarted.connect(onWizardRestarted)
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ Rectangle {
|
||||||
// disable donation page
|
// disable donation page
|
||||||
"create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, finishPage ],
|
"create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, finishPage ],
|
||||||
"recovery_wallet" : [welcomePage, optionsPage, recoveryWalletPage, passwordPage, finishPage ],
|
"recovery_wallet" : [welcomePage, optionsPage, recoveryWalletPage, passwordPage, finishPage ],
|
||||||
|
"create_view_only_wallet" : [ createViewOnlyWalletPage, passwordPage ],
|
||||||
|
|
||||||
}
|
}
|
||||||
property string currentPath: "create_wallet"
|
property string currentPath: "create_wallet"
|
||||||
|
@ -89,15 +90,12 @@ Rectangle {
|
||||||
currentPage += step_value
|
currentPage += step_value
|
||||||
pages[currentPage].opacity = 1;
|
pages[currentPage].opacity = 1;
|
||||||
|
|
||||||
var nextButtonVisible = pages[currentPage] !== optionsPage;
|
var nextButtonVisible = pages[currentPage] !== optionsPage && currentPage < pages.length - 1;
|
||||||
nextButton.visible = nextButtonVisible;
|
nextButton.visible = nextButtonVisible;
|
||||||
|
|
||||||
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
|
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
|
||||||
pages[currentPage].onPageOpened(settings,next)
|
pages[currentPage].onPageOpened(settings,next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +128,16 @@ Rectangle {
|
||||||
wizard.openWalletFromFileClicked();
|
wizard.openWalletFromFileClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openCreateViewOnlyWalletPage(){
|
||||||
|
pages[currentPage].opacity = 0
|
||||||
|
currentPath = "create_view_only_wallet"
|
||||||
|
pages = paths[currentPath]
|
||||||
|
currentPage = pages.indexOf(createViewOnlyWalletPage)
|
||||||
|
createViewOnlyWalletPage.opacity = 1
|
||||||
|
nextButton.visible = true
|
||||||
|
rootItem.state = "wizard";
|
||||||
|
}
|
||||||
|
|
||||||
function createWalletPath(folder_path,account_name){
|
function createWalletPath(folder_path,account_name){
|
||||||
|
|
||||||
// Remove trailing slash - (default on windows and mac)
|
// Remove trailing slash - (default on windows and mac)
|
||||||
|
@ -274,6 +282,16 @@ Rectangle {
|
||||||
anchors.rightMargin: 50
|
anchors.rightMargin: 50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WizardCreateViewOnlyWallet {
|
||||||
|
id: createViewOnlyWalletPage
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: nextButton.left
|
||||||
|
anchors.left: prevButton.right
|
||||||
|
anchors.leftMargin: 50
|
||||||
|
anchors.rightMargin: 50
|
||||||
|
}
|
||||||
|
|
||||||
WizardRecoveryWallet {
|
WizardRecoveryWallet {
|
||||||
id: recoveryWalletPage
|
id: recoveryWalletPage
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -356,4 +374,59 @@ Rectangle {
|
||||||
wizard.useMoneroClicked();
|
wizard.useMoneroClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
id: createViewOnlyWalletButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: 50
|
||||||
|
width: 110
|
||||||
|
text: qsTr("Create wallet") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: currentPath === "create_view_only_wallet" && parent.paths[currentPath][currentPage] === passwordPage
|
||||||
|
enabled: passwordPage.passwordsMatch
|
||||||
|
onClicked: {
|
||||||
|
if (currentWallet.createViewOnly(settings['view_only_wallet_path'],passwordPage.password)) {
|
||||||
|
console.log("view only wallet created in ",settings['view_only_wallet_path']);
|
||||||
|
informationPopup.title = qsTr("Success") + translationManager.emptyString;
|
||||||
|
informationPopup.text = qsTr('The view only wallet has been created. You can open it by closing this current wallet, clicking the "Open wallet from file" option, and selecting the view wallet in: \n%1')
|
||||||
|
.arg(settings['view_only_wallet_path']);
|
||||||
|
informationPopup.open()
|
||||||
|
informationPopup.onCloseCallback = null
|
||||||
|
rootItem.state = "normal"
|
||||||
|
wizard.restart();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||||
|
informationPopup.text = currentWallet.errorString;
|
||||||
|
informationPopup.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardButton {
|
||||||
|
id: abortViewOnlyButton
|
||||||
|
anchors.right: createViewOnlyWalletButton.left
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: 50
|
||||||
|
width: 110
|
||||||
|
text: qsTr("Abort") + translationManager.emptyString
|
||||||
|
shadowReleasedColor: "#FF4304"
|
||||||
|
shadowPressedColor: "#B32D00"
|
||||||
|
releasedColor: "#FF6C3C"
|
||||||
|
pressedColor: "#FF4304"
|
||||||
|
visible: currentPath === "create_view_only_wallet" && parent.paths[currentPath][currentPage] === passwordPage
|
||||||
|
onClicked: {
|
||||||
|
wizard.restart();
|
||||||
|
rootItem.state = "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@ Item {
|
||||||
property alias wordsTextItem : memoTextItem
|
property alias wordsTextItem : memoTextItem
|
||||||
property alias restoreHeight : restoreHeightItem.text
|
property alias restoreHeight : restoreHeightItem.text
|
||||||
property alias restoreHeightVisible: restoreHeightItem.visible
|
property alias restoreHeightVisible: restoreHeightItem.visible
|
||||||
|
property alias walletName : accountName.text
|
||||||
|
property alias progressDotsModel : progressDots.model
|
||||||
|
|
||||||
// TODO extend properties if needed
|
// TODO extend properties if needed
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
id: progressDots
|
||||||
model: dotsModel
|
model: dotsModel
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: 12; height: 12
|
width: 12; height: 12
|
||||||
|
@ -184,7 +186,7 @@ Item {
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: (restoreHeightItem.visible)? restoreHeightItem.bottom : memoTextItem.bottom
|
anchors.top: (restoreHeightItem.visible)? restoreHeightItem.bottom : (memoTextItem.visible)? memoTextItem.bottom : frameHeader.bottom
|
||||||
anchors.topMargin: 24
|
anchors.topMargin: 24
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,9 @@ Item {
|
||||||
id: passwordPage
|
id: passwordPage
|
||||||
opacity: 0
|
opacity: 0
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
property alias titleText: titleText.text
|
property alias titleText: titleText.text
|
||||||
|
property alias passwordsMatch: passwordUI.passwordsMatch
|
||||||
|
property alias password: passwordUI.password
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
|
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ Item {
|
||||||
|
|
||||||
function onPageOpened(settingsObject) {
|
function onPageOpened(settingsObject) {
|
||||||
wizard.nextButton.enabled = true
|
wizard.nextButton.enabled = true
|
||||||
handlePassword();
|
passwordUI.handlePassword();
|
||||||
|
|
||||||
if (wizard.currentPath === "create_wallet") {
|
if (wizard.currentPath === "create_wallet") {
|
||||||
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
|
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
|
||||||
|
@ -55,44 +56,22 @@ Item {
|
||||||
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
|
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordItem.focus = true;
|
passwordUI.focus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPageClosed(settingsObject) {
|
function onPageClosed(settingsObject) {
|
||||||
// TODO: set password on the final page
|
// TODO: set password on the final page
|
||||||
// settingsObject.wallet.setPassword(passwordItem.password)
|
// settingsObject.wallet.setPassword(passwordItem.password)
|
||||||
settingsObject['wallet_password'] = passwordItem.password
|
settingsObject['wallet_password'] = passwordUI.password
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWizardRestarted(){
|
function onWizardRestarted(){
|
||||||
// Reset password fields
|
// Reset password fields
|
||||||
passwordItem.password = "";
|
passwordUI.password = "";
|
||||||
retypePasswordItem.password = "";
|
passwordUI.confirmPassword = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePassword() {
|
|
||||||
// allow to forward step only if passwords match
|
|
||||||
|
|
||||||
wizard.nextButton.enabled = passwordItem.password === retypePasswordItem.password
|
|
||||||
|
|
||||||
// scorePassword returns value from 0 to... lots
|
|
||||||
var strength = walletManager.getPasswordStrength(passwordItem.password);
|
|
||||||
// consider anything below 10 bits as dire
|
|
||||||
strength -= 10
|
|
||||||
if (strength < 0)
|
|
||||||
strength = 0
|
|
||||||
// use a slight parabola to discourage short passwords
|
|
||||||
strength = strength ^ 1.2 / 3
|
|
||||||
// mapScope does not clamp
|
|
||||||
if (strength > 100)
|
|
||||||
strength = 100
|
|
||||||
// privacyLevel component uses 1..13 scale
|
|
||||||
privacyLevel.fillLevel = Utils.mapScope(1, 100, 1, 13, strength)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: dotsRow
|
id: dotsRow
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -111,6 +90,9 @@ Item {
|
||||||
Repeater {
|
Repeater {
|
||||||
model: dotsModel
|
model: dotsModel
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
|
// Password page is last page when creating view only wallet
|
||||||
|
// TODO: make this dynamic for all pages in wizard
|
||||||
|
visible: (wizard.currentPath != "create_view_only_wallet" || index < 2)
|
||||||
width: 12; height: 12
|
width: 12; height: 12
|
||||||
radius: 6
|
radius: 6
|
||||||
color: dotColor
|
color: dotColor
|
||||||
|
@ -157,39 +139,12 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WizardPasswordInput {
|
WizardPasswordUI {
|
||||||
id: passwordItem
|
id: passwordUI
|
||||||
anchors.top: headerColumn.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 24
|
|
||||||
width: 300
|
|
||||||
height: 62
|
|
||||||
placeholderText : qsTr("Password") + translationManager.emptyString;
|
|
||||||
KeyNavigation.tab: retypePasswordItem
|
|
||||||
onChanged: handlePassword()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
WizardPasswordInput {
|
|
||||||
id: retypePasswordItem
|
|
||||||
anchors.top: passwordItem.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 24
|
|
||||||
width: 300
|
|
||||||
height: 62
|
|
||||||
placeholderText : qsTr("Confirm password") + translationManager.emptyString;
|
|
||||||
KeyNavigation.tab: passwordItem
|
|
||||||
onChanged: handlePassword()
|
|
||||||
}
|
|
||||||
|
|
||||||
PrivacyLevelSmall {
|
|
||||||
id: privacyLevel
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: retypePasswordItem.bottom
|
anchors.left: parent.left
|
||||||
anchors.topMargin: 60
|
anchors.top: headerColumn.bottom
|
||||||
background: "#F0EEEE"
|
anchors.topMargin: 30
|
||||||
interactive: false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
96
wizard/WizardPasswordUI.qml
Normal file
96
wizard/WizardPasswordUI.qml
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
// Copyright (c) 2014-2015, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import moneroComponents.WalletManager 1.0
|
||||||
|
import QtQuick 2.2
|
||||||
|
import "../components"
|
||||||
|
import "utils.js" as Utils
|
||||||
|
|
||||||
|
FocusScope {
|
||||||
|
property alias password: passwordItem.password
|
||||||
|
property alias confirmPassword: retypePasswordItem.password
|
||||||
|
property bool passwordsMatch: passwordItem.password === retypePasswordItem.password
|
||||||
|
|
||||||
|
function handlePassword() {
|
||||||
|
// allow to forward step only if passwords match
|
||||||
|
|
||||||
|
wizard.nextButton.enabled = passwordItem.password === retypePasswordItem.password
|
||||||
|
|
||||||
|
// scorePassword returns value from 0 to... lots
|
||||||
|
var strength = walletManager.getPasswordStrength(passwordItem.password);
|
||||||
|
// consider anything below 10 bits as dire
|
||||||
|
strength -= 10
|
||||||
|
if (strength < 0)
|
||||||
|
strength = 0
|
||||||
|
// use a slight parabola to discourage short passwords
|
||||||
|
strength = strength ^ 1.2 / 3
|
||||||
|
// mapScope does not clamp
|
||||||
|
if (strength > 100)
|
||||||
|
strength = 100
|
||||||
|
// privacyLevel component uses 1..13 scale
|
||||||
|
privacyLevel.fillLevel = Utils.mapScope(1, 100, 1, 13, strength)
|
||||||
|
}
|
||||||
|
|
||||||
|
WizardPasswordInput {
|
||||||
|
id: passwordItem
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.topMargin: 24
|
||||||
|
width: 300
|
||||||
|
height: 62
|
||||||
|
placeholderText : qsTr("Password") + translationManager.emptyString;
|
||||||
|
KeyNavigation.tab: retypePasswordItem
|
||||||
|
onChanged: handlePassword()
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
|
||||||
|
WizardPasswordInput {
|
||||||
|
id: retypePasswordItem
|
||||||
|
anchors.top: passwordItem.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.topMargin: 24
|
||||||
|
width: 300
|
||||||
|
height: 62
|
||||||
|
placeholderText : qsTr("Confirm password") + translationManager.emptyString;
|
||||||
|
KeyNavigation.tab: passwordItem
|
||||||
|
onChanged: handlePassword()
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivacyLevelSmall {
|
||||||
|
id: privacyLevel
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: retypePasswordItem.bottom
|
||||||
|
anchors.topMargin: 60
|
||||||
|
background: "#F0EEEE"
|
||||||
|
interactive: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
//parent.wizardRestarted.connect(onWizardRestarted)
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,3 +15,10 @@ function tr(text) {
|
||||||
function lineBreaksToSpaces(text) {
|
function lineBreaksToSpaces(text) {
|
||||||
return text.trim().replace(/(\r\n|\n|\r)/gm, " ");
|
return text.trim().replace(/(\r\n|\n|\r)/gm, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usefulName(path) {
|
||||||
|
// arbitrary "short enough" limit
|
||||||
|
if (path.length < 32)
|
||||||
|
return path
|
||||||
|
return path.replace(/.*[\/\\]/, '').replace(/\.keys$/, '')
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue