1
mirror of https://github.com/monero-project/monero-gui synced 2024-11-28 09:31:37 +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:
Jaquee 2017-01-04 17:25:22 +01:00
parent 8f56e98397
commit fd983955b4
No known key found for this signature in database
GPG Key ID: 384E52B09F45DC39
11 changed files with 497 additions and 227 deletions

View File

@ -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
//! Manage wallet
RowLayout {
Label {
id: seedLabel
id: manageWalletLabel
Layout.fillWidth: true
color: "#4A4949"
text: qsTr("Manage wallet") + translationManager.emptyString
fontSize: 16
text: qsTr("Mnemonic seed: ") + translationManager.emptyString
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignLeft
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"
Rectangle {
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
}
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

View File

@ -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

View File

@ -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>

View File

@ -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();

View File

@ -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;

View 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)
}
}

View File

@ -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"
}
}
}

View File

@ -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

View File

@ -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: {

View 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)
}
}

View File

@ -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$/, '')
}