mirror of
https://github.com/monero-project/monero-gui
synced 2024-11-24 11:17:15 +01: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
@ -39,51 +39,26 @@ import moneroComponents.Clipboard 1.0
|
||||
|
||||
Rectangle {
|
||||
property var daemonAddress
|
||||
property bool viewOnly: false
|
||||
|
||||
color: "#F0EEEE"
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
||||
function initSettings() {
|
||||
//runs on every page load
|
||||
|
||||
|
||||
// Mnemonic seed settings
|
||||
memoTextInput.text = qsTr("Click button to show seed") + translationManager.emptyString
|
||||
showSeedButton.visible = true
|
||||
// Mnemonic seed setting
|
||||
memoTextInput.text = (viewOnly)? qsTr("View only wallets doesn't have a mnemonic seed") : qsTr("Click button to show seed") + translationManager.emptyString
|
||||
showSeedButton.enabled = !viewOnly
|
||||
|
||||
// Daemon settings
|
||||
|
||||
daemonAddress = persistentSettings.daemon_address.split(":");
|
||||
console.log("address: " + persistentSettings.daemon_address)
|
||||
// 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 {
|
||||
id: mainLayout
|
||||
anchors.margins: 40
|
||||
@ -92,17 +67,59 @@ Rectangle {
|
||||
anchors.right: parent.right
|
||||
spacing: 10
|
||||
|
||||
|
||||
Label {
|
||||
id: seedLabel
|
||||
color: "#4A4949"
|
||||
fontSize: 16
|
||||
text: qsTr("Mnemonic seed: ") + translationManager.emptyString
|
||||
Layout.preferredWidth: 100
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
//! Manage wallet
|
||||
RowLayout {
|
||||
Label {
|
||||
id: manageWalletLabel
|
||||
Layout.fillWidth: true
|
||||
color: "#4A4949"
|
||||
text: qsTr("Manage wallet") + translationManager.emptyString
|
||||
fontSize: 16
|
||||
Layout.topMargin: 10
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
enabled: !viewOnly
|
||||
id: memoTextInput
|
||||
textMargin: 6
|
||||
wrapMode: TextEdit.WordWrap
|
||||
@ -113,7 +130,7 @@ Rectangle {
|
||||
Layout.preferredHeight: 100
|
||||
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 {
|
||||
backgroundColor: "#FFFFFF"
|
||||
@ -137,7 +154,9 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
enabled: !viewOnly
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
id: wordsTipText
|
||||
@ -151,37 +170,99 @@ Rectangle {
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
|
||||
id: showSeedButton
|
||||
|
||||
fontSize: 14
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
releasedColor: "#FF6C3C"
|
||||
pressedColor: "#FF4304"
|
||||
text: qsTr("Show seed")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.preferredWidth: 100
|
||||
onClicked: {
|
||||
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 {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
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 {
|
||||
id: daemonAddrRow
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
Layout.topMargin: 40
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
@ -213,12 +294,8 @@ Rectangle {
|
||||
|
||||
StandardButton {
|
||||
id: daemonAddrSave
|
||||
|
||||
Layout.fillWidth: false
|
||||
|
||||
Layout.leftMargin: 30
|
||||
Layout.minimumWidth: 100
|
||||
width: 60
|
||||
text: qsTr("Save") + translationManager.emptyString
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
@ -238,120 +315,19 @@ Rectangle {
|
||||
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
id: closeWalletLabel
|
||||
|
||||
Layout.fillWidth: true
|
||||
color: "#4A4949"
|
||||
text: qsTr("Manage wallet") + translationManager.emptyString
|
||||
text: qsTr("Layout settings") + translationManager.emptyString
|
||||
fontSize: 16
|
||||
anchors.topMargin: 30
|
||||
Layout.topMargin: 30
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
|
||||
Text {
|
||||
id: closeWalletTip
|
||||
font.family: "Arial"
|
||||
font.pointSize: 12
|
||||
color: "#4A4646"
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("Close current wallet and open wizard")
|
||||
+ 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
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: "#DEDEDE"
|
||||
}
|
||||
|
||||
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 {
|
||||
id: guiVersion
|
||||
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
|
||||
function onPageCompleted() {
|
||||
console.log("Settings page loaded");
|
||||
initSettings();
|
||||
viewOnly = currentWallet.viewOnly;
|
||||
}
|
||||
|
||||
// fires only once
|
||||
|
@ -464,6 +464,11 @@ Rectangle {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentWallet.viewOnly) {
|
||||
statusText.text = qsTr("Wallet is view only.")
|
||||
return;
|
||||
}
|
||||
|
||||
switch (currentWallet.connected) {
|
||||
case Wallet.ConnectionStatus_Disconnected:
|
||||
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>components/DaemonManagerDialog.qml</file>
|
||||
<file>version.js</file>
|
||||
<file>wizard/WizardPasswordUI.qml</file>
|
||||
<file>wizard/WizardCreateViewOnlyWallet.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -158,6 +158,15 @@ void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLim
|
||||
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()
|
||||
{
|
||||
return m_walletImpl->connectToDaemon();
|
||||
@ -168,6 +177,11 @@ void Wallet::setTrustedDaemon(bool arg)
|
||||
m_walletImpl->setTrustedDaemon(arg);
|
||||
}
|
||||
|
||||
bool Wallet::viewOnly() const
|
||||
{
|
||||
return m_walletImpl->watchOnly();
|
||||
}
|
||||
|
||||
quint64 Wallet::balance() const
|
||||
{
|
||||
return m_walletImpl->balance();
|
||||
|
@ -36,7 +36,7 @@ class Wallet : public QObject
|
||||
Q_PROPERTY(QString path READ path)
|
||||
Q_PROPERTY(AddressBookModel * addressBookModel READ addressBookModel)
|
||||
Q_PROPERTY(AddressBook * addressBook READ addressBook)
|
||||
|
||||
Q_PROPERTY(bool viewOnly READ viewOnly)
|
||||
|
||||
public:
|
||||
|
||||
@ -98,6 +98,9 @@ public:
|
||||
//! initializes wallet asynchronously
|
||||
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
|
||||
Q_INVOKABLE bool connectToDaemon();
|
||||
|
||||
@ -110,6 +113,9 @@ public:
|
||||
//! returns unlocked balance
|
||||
Q_INVOKABLE quint64 unlockedBalance() const;
|
||||
|
||||
//! returns if view only wallet
|
||||
Q_INVOKABLE bool viewOnly() const;
|
||||
|
||||
//! returns current wallet's block height
|
||||
//! (can be less than daemon's blockchain height when wallet sync in progress)
|
||||
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
|
||||
"create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, finishPage ],
|
||||
"recovery_wallet" : [welcomePage, optionsPage, recoveryWalletPage, passwordPage, finishPage ],
|
||||
"create_view_only_wallet" : [ createViewOnlyWalletPage, passwordPage ],
|
||||
|
||||
}
|
||||
property string currentPath: "create_wallet"
|
||||
@ -89,15 +90,12 @@ Rectangle {
|
||||
currentPage += step_value
|
||||
pages[currentPage].opacity = 1;
|
||||
|
||||
var nextButtonVisible = pages[currentPage] !== optionsPage;
|
||||
var nextButtonVisible = pages[currentPage] !== optionsPage && currentPage < pages.length - 1;
|
||||
nextButton.visible = nextButtonVisible;
|
||||
|
||||
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
|
||||
pages[currentPage].onPageOpened(settings,next)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,6 +128,16 @@ Rectangle {
|
||||
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){
|
||||
|
||||
// Remove trailing slash - (default on windows and mac)
|
||||
@ -274,6 +282,16 @@ Rectangle {
|
||||
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 {
|
||||
id: recoveryWalletPage
|
||||
anchors.top: parent.top
|
||||
@ -356,4 +374,59 @@ Rectangle {
|
||||
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 restoreHeight : restoreHeightItem.text
|
||||
property alias restoreHeightVisible: restoreHeightItem.visible
|
||||
|
||||
property alias walletName : accountName.text
|
||||
property alias progressDotsModel : progressDots.model
|
||||
|
||||
// TODO extend properties if needed
|
||||
|
||||
@ -64,6 +65,7 @@ Item {
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: progressDots
|
||||
model: dotsModel
|
||||
delegate: Rectangle {
|
||||
width: 12; height: 12
|
||||
@ -184,7 +186,7 @@ Item {
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
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
|
||||
spacing: 16
|
||||
|
||||
|
@ -36,8 +36,9 @@ Item {
|
||||
id: passwordPage
|
||||
opacity: 0
|
||||
visible: false
|
||||
|
||||
property alias titleText: titleText.text
|
||||
property alias passwordsMatch: passwordUI.passwordsMatch
|
||||
property alias password: passwordUI.password
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
|
||||
}
|
||||
@ -47,7 +48,7 @@ Item {
|
||||
|
||||
function onPageOpened(settingsObject) {
|
||||
wizard.nextButton.enabled = true
|
||||
handlePassword();
|
||||
passwordUI.handlePassword();
|
||||
|
||||
if (wizard.currentPath === "create_wallet") {
|
||||
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
|
||||
}
|
||||
|
||||
passwordItem.focus = true;
|
||||
passwordUI.focus = true;
|
||||
}
|
||||
|
||||
function onPageClosed(settingsObject) {
|
||||
// TODO: set password on the final page
|
||||
// settingsObject.wallet.setPassword(passwordItem.password)
|
||||
settingsObject['wallet_password'] = passwordItem.password
|
||||
settingsObject['wallet_password'] = passwordUI.password
|
||||
return true
|
||||
}
|
||||
|
||||
function onWizardRestarted(){
|
||||
// Reset password fields
|
||||
passwordItem.password = "";
|
||||
retypePasswordItem.password = "";
|
||||
passwordUI.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 {
|
||||
id: dotsRow
|
||||
anchors.top: parent.top
|
||||
@ -111,6 +90,9 @@ Item {
|
||||
Repeater {
|
||||
model: dotsModel
|
||||
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
|
||||
radius: 6
|
||||
color: dotColor
|
||||
@ -157,39 +139,12 @@ Item {
|
||||
}
|
||||
|
||||
|
||||
WizardPasswordInput {
|
||||
id: passwordItem
|
||||
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
|
||||
WizardPasswordUI {
|
||||
id: passwordUI
|
||||
anchors.right: parent.right
|
||||
anchors.top: retypePasswordItem.bottom
|
||||
anchors.topMargin: 60
|
||||
background: "#F0EEEE"
|
||||
interactive: false
|
||||
anchors.left: parent.left
|
||||
anchors.top: headerColumn.bottom
|
||||
anchors.topMargin: 30
|
||||
}
|
||||
|
||||
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) {
|
||||
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 New Issue
Block a user