wizard: redesign seed page

- move mnemonic seed
- restore height into a separate page
- pdf template
- seed verification
- responsive UI
- accessibility
This commit is contained in:
rating89us 2021-08-23 18:09:22 +02:00 committed by selsta
parent b7ba9437d8
commit 198dfb338c
No known key found for this signature in database
GPG key ID: 2EA0A99A8B07AE5E
30 changed files with 24484 additions and 328 deletions

View file

@ -66,7 +66,7 @@ Item {
anchors.fill: parent
color: buttonArea.containsMouse ? MoneroComponents.Style.buttonInlineBackgroundColorHover : MoneroComponents.Style.buttonInlineBackgroundColor
radius: 4
border.width: parent.focus && parent.enabled ? 1 : 0
MoneroComponents.TextPlain {
id: inlineText

View file

@ -40,6 +40,8 @@ ColumnLayout {
default property alias content: inlineButtons.children
property alias input: input
property bool inputHasFocus: input.activeFocus
property bool tabNavigationEnabled: true
property alias text: input.text
property int inputPaddingLeft: 10
@ -109,6 +111,8 @@ ColumnLayout {
signal editingFinished();
signal accepted();
signal textUpdated();
signal backtabPressed();
signal tabPressed();
onActiveFocusChanged: activeFocus && input.forceActiveFocus()
onTextUpdated: {
@ -212,8 +216,18 @@ ColumnLayout {
MoneroComponents.Input {
id: input
KeyNavigation.backtab: item.KeyNavigation.backtab
KeyNavigation.tab: item.KeyNavigation.tab
Keys.onBacktabPressed: {
item.backtabPressed();
if (item.KeyNavigation.backtab) {
item.KeyNavigation.backtab.forceActiveFocus()
}
}
Keys.onTabPressed: {
item.tabPressed();
if (item.KeyNavigation.tab) {
item.KeyNavigation.tab.forceActiveFocus()
}
}
Layout.fillWidth: true
Layout.preferredHeight: inputHeight

View file

@ -21,6 +21,14 @@ Text {
font.pixelSize: 14
textFormat: Text.PlainText
Rectangle {
width: root.contentWidth
height: root.height
anchors.left: parent.left
anchors.top: parent.top
color: root.focus ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
}
MoneroEffects.ColorTransition {
enabled: root.themeTransition
themeTransition: root.themeTransition

BIN
images/verify-white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 956 B

BIN
images/verify-white@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
images/verify.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

BIN
images/verify@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/write-down-white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/write-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

BIN
images/write-down@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

12
qml.qrc
View file

@ -206,6 +206,7 @@
<file>wizard/WizardCreateWallet2.qml</file>
<file>wizard/WizardCreateWallet3.qml</file>
<file>wizard/WizardCreateWallet4.qml</file>
<file>wizard/WizardCreateWallet5.qml</file>
<file>wizard/WizardCreateDevice1.qml</file>
<file>wizard/WizardDaemonSettings.qml</file>
<file>wizard/WizardHeader.qml</file>
@ -283,5 +284,16 @@
<file>images/trezor.png</file>
<file>images/trezor@2x.png</file>
<file>qtquickcontrols2.conf</file>
<file>images/write-down.png</file>
<file>images/write-down-white.png</file>
<file>images/write-down@2x.png</file>
<file>images/write-down-white@2x.png</file>
<file>images/verify.png</file>
<file>images/verify-white.png</file>
<file>images/verify@2x.png</file>
<file>images/verify-white@2x.png</file>
<file>wizard/SeedListItem.qml</file>
<file>wizard/SeedListGrid.qml</file>
<file>wizard/template.pdf</file>
</qresource>
</RCC>

View file

@ -160,6 +160,18 @@ QList<QString> OSHelper::grabQrCodesFromScreen() const
return codes;
}
bool OSHelper::openFile(const QString &filePath) const
{
QString canonicalFilePath = QFileInfo(filePath).canonicalFilePath();
QUrl url = QUrl::fromLocalFile(canonicalFilePath);
if (!url.isValid())
{
qWarning() << "Malformed file path" << canonicalFilePath << url.errorString();
return false;
}
return QDesktopServices::openUrl(url);
}
bool OSHelper::openContainingFolder(const QString &filePath) const
{
QString canonicalFilePath = QFileInfo(filePath).canonicalFilePath();
@ -313,3 +325,9 @@ quint8 OSHelper::getNetworkTypeFromFile(const QString &keysPath) const
}
return getNetworkTypeAndAddressFromFile(walletPath).first;
}
void OSHelper::openSeedTemplate() const
{
QFile::copy(":/wizard/template.pdf", QDir::tempPath() + "/seed_template.pdf");
openFile(QDir::tempPath() + "/seed_template.pdf");
}

View file

@ -46,6 +46,7 @@ public:
Q_INVOKABLE void createDesktopEntry() const;
Q_INVOKABLE QString downloadLocation() const;
Q_INVOKABLE QList<QString> grabQrCodesFromScreen() const;
Q_INVOKABLE bool openFile(const QString &filePath) const;
Q_INVOKABLE bool openContainingFolder(const QString &filePath) const;
Q_INVOKABLE QString openSaveFileDialog(const QString &title, const QString &folder, const QString &filename) const;
Q_INVOKABLE QString temporaryFilename() const;
@ -53,6 +54,7 @@ public:
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
Q_INVOKABLE bool isCapsLock() const;
Q_INVOKABLE quint8 getNetworkTypeFromFile(const QString &keysPath) const;
Q_INVOKABLE void openSeedTemplate() const;
static std::pair<quint8, QString> getNetworkTypeAndAddressFromFile(const QString &wallet);
private:

26
wizard/SeedListGrid.qml Normal file
View file

@ -0,0 +1,26 @@
import QtQuick 2.9
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
GridLayout {
id: seedGrid
Layout.alignment: Qt.AlignHCenter
flow: GridLayout.TopToBottom
columns: wizardController.layoutScale == 1 ? 5 : wizardController.layoutScale == 2 ? 4 : wizardController.layoutScale == 3 ? 3 : 2
rows: wizardController.layoutScale == 1 ? 5 :wizardController.layoutScale == 2 ? 7 : wizardController.layoutScale == 3 ? 9 : 13
columnSpacing: wizardController.layoutScale == 1 ? 25 : 18
rowSpacing: 0
Component.onCompleted: {
var seed = wizardController.walletOptionsSeed.split(" ");
var component = Qt.createComponent("SeedListItem.qml");
for(var i = 0; i < seed.length; i++) {
component.createObject(seedGrid, {wordNumber: i, word: seed[i]});
}
}
}

153
wizard/SeedListItem.qml Normal file
View file

@ -0,0 +1,153 @@
import "../components" as MoneroComponents;
import QtQuick 2.9
import QtQuick.Layouts 1.2
import FontAwesome 1.0
ColumnLayout {
id: seedListItem
property var wordNumber;
property var word;
property var wordSpelled: (word.split("")).join(". ")
property var acessibleText: (wordNumber + 1) + word
property alias wordText: wordText
property alias lineEdit: lineEdit
property alias icon: icon
spacing: 0
Layout.preferredWidth: 136
Layout.maximumWidth: 136
Layout.minimumWidth: 136
Accessible.role: Accessible.StaticText
Accessible.name: lineEdit.inputHasFocus && !lineEdit.readOnly ? qsTr("Please enter the word number") + " " + (wordNumber + 1) + "." +
(icon.visible ? (icon.wordsMatch ? qsTr("Green check mark") + "."
: qsTr("Red exclamation mark") + ".")
: "")
: (wordNumber + 1) + word + ". " +
(lineEdit.inputHasFocus && lineEdit.readOnly ? qsTr("Green check mark")
: qsTr("This word is spelled ") + " " + wordSpelled + ".") +
translationManager.emptyString
KeyNavigation.up: wordNumber == 0 ? (recoveryPhraseLabel.visible ? recoveryPhraseLabel : header) : parent.children[wordNumber - 1]
KeyNavigation.backtab: wordNumber == 0 ? (recoveryPhraseLabel.visible ? recoveryPhraseLabel : header) : parent.children[wordNumber - 1]
Keys.onUpPressed: focusOnPreviousField()
Keys.onBacktabPressed: focusOnPreviousField()
Keys.onDownPressed: focusOnNextField()
Keys.onTabPressed: focusOnNextField()
function focusOnPreviousField() {
if (wizardCreateWallet2.state == "verify") {
if (wordNumber < 5) {
if (recoveryPhraseLabel.visible) {
return recoveryPhraseLabel.forceActiveFocus();
} else {
return header.forceActiveFocus();
}
} else if (wordNumber >= 5 && wordNumber < 25) {
return parent.children[wizardCreateWallet2.hiddenWords[parseInt(wordNumber / 5) - 1]].lineEdit.forceActiveFocus()
}
} else {
if (wordNumber == 0) {
if (recoveryPhraseLabel.visible) {
return recoveryPhraseLabel.forceActiveFocus();
} else {
return header.forceActiveFocus();
}
} else {
return parent.children[wordNumber - 1].forceActiveFocus()
}
}
}
function focusOnNextField() {
if (wizardCreateWallet2.state == "verify") {
if (wordNumber < 20) {
return parent.children[wizardCreateWallet2.hiddenWords[parseInt(wordNumber / 5) + 1]].lineEdit.forceActiveFocus()
} else {
return navigation.btnPrev.forceActiveFocus()
}
} else {
if (wordNumber == 24) {
if (createNewSeedButton.visible) {
return createNewSeedButton.forceActiveFocus()
} else {
return printPDFTemplate.forceActiveFocus()
}
} else {
return parent.children[wordNumber + 1].forceActiveFocus()
}
}
}
RowLayout {
id: wordRow
spacing: 0
MoneroComponents.Label {
color: lineEdit.inputHasFocus ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
fontSize: 13
text: (wordNumber + 1)
themeTransition: false
}
MoneroComponents.LineEdit {
id: lineEdit
property bool firstUserInput: true
inputHeight: 29
inputPaddingLeft: 10
inputPaddingBottom: 2
inputPaddingRight: 0
borderDisabled: true
visible: !wordText.visible
fontSize: 16
fontBold: true
text: ""
tabNavigationEnabled: false
onTextChanged: {
if (lineEdit.text.length == wordText.text.length) {
firstUserInput = false;
}
}
onBacktabPressed: focusOnPreviousField()
onTabPressed: focusOnNextField()
}
MoneroComponents.Label {
id: wordText
Layout.leftMargin: 10
color: MoneroComponents.Style.defaultFontColor
fontSize: seedListItem.focus ? 19 : 16
fontBold: true
text: word
themeTransition: false
}
MoneroComponents.TextPlain {
id: icon
Layout.leftMargin: wordsMatch ? 10 : 0
property bool wordsMatch: lineEdit.text === wordText.text
property bool partialWordMatches: lineEdit.text === wordText.text.substring(0, lineEdit.text.length)
visible: lineEdit.text.length > 0 && !lineEdit.firstUserInput || lineEdit.firstUserInput && !partialWordMatches
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
font.pixelSize: 15
text: wordsMatch ? FontAwesome.checkCircle : FontAwesome.exclamationCircle
color: wordsMatch ? (MoneroComponents.Style.blackTheme ? "#00FF00" : "#008000") : "#FF0000"
themeTransition: false
onTextChanged: {
if (wizardCreateWallet2.seedListGrid && wordsMatch) {
if (wordNumber < 20) {
focusOnNextField();
}
lineEdit.readOnly = true;
}
}
}
}
Rectangle {
id: underLine
color: lineEdit.inputHasFocus ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.appWindowBorderColor
Layout.fillWidth: true
height: 1
}
}

View file

@ -50,13 +50,14 @@ Rectangle {
signal useMoneroClicked()
signal walletCreatedFromDevice(bool success)
function restart() {
function restart(generatingNewSeed) {
// Clear up any state, including `m_wallet`, which
// is the temp. wallet object whilst creating new wallets.
// This function is called automatically by navigating to `wizardHome`.
wizardStateView.state = "wizardHome"
wizardController.walletOptionsName = defaultAccountName;
wizardController.walletOptionsLocation = '';
if(!generatingNewSeed) {
wizardController.walletOptionsName = defaultAccountName;
wizardController.walletOptionsLocation = '';
}
wizardController.walletOptionsPassword = '';
wizardController.walletOptionsSeed = '';
wizardController.walletOptionsSeedOffset = '';
@ -113,10 +114,18 @@ Rectangle {
property int layoutScale: {
if(appWindow.width < 800){
return 1;
} else {
if (appWindow.width < 506) {
//mobile (25 word mnemonic seed displayed in 2 columns)
return 4;
} else if (appWindow.width < 660) {
//tablet (25 word mnemonic seed displayed in 3 columns)
return 3;
} else if (appWindow.width < 842) {
//tablet (25 word mnemonic seed displayed in 4 columns)
return 2;
} else if (appWindow.width >= 842) {
//desktop (25 word mnemonic seed displayed in 5 columns)
return 1;
}
}
@ -131,6 +140,7 @@ Rectangle {
property WizardCreateWallet2 wizardCreateWallet2View: WizardCreateWallet2 { }
property WizardCreateWallet3 wizardCreateWallet3View: WizardCreateWallet3 { }
property WizardCreateWallet4 wizardCreateWallet4View: WizardCreateWallet4 { }
property WizardCreateWallet5 wizardCreateWallet5View: WizardCreateWallet5 { }
property WizardRestoreWallet1 wizardRestoreWallet1View: WizardRestoreWallet1 { }
property WizardRestoreWallet2 wizardRestoreWallet2View: WizardRestoreWallet2 { }
property WizardRestoreWallet3 wizardRestoreWallet3View: WizardRestoreWallet3 { }
@ -195,6 +205,10 @@ Rectangle {
name: "wizardCreateWallet4"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet4View }
PropertyChanges { target: wizardFlickable; contentHeight: wizardStateView.wizardCreateWallet4View.pageHeight + 80 }
}, State {
name: "wizardCreateWallet5"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet5View }
PropertyChanges { target: wizardFlickable; contentHeight: wizardStateView.wizardCreateWallet5View.pageHeight + 80 }
}, State {
name: "wizardRestoreWallet1"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet1View }
@ -356,6 +370,10 @@ Rectangle {
return;
}
if (wizardStateView.wizardCreateWallet2View.seedListGrid) {
wizardStateView.wizardCreateWallet2View.seedListGrid.destroy();
}
// make sure temporary wallet files are deleted
console.log("Removing temporary wallet: " + wizardController.tmpWalletFilename)
oshelper.removeTemporaryWallet(wizardController.tmpWalletFilename)

View file

@ -282,7 +282,7 @@ Rectangle {
function onCreateWalletFromDeviceCompleted(written){
hideProcessingSplash();
if(written){
wizardStateView.state = "wizardCreateWallet2";
wizardStateView.state = "wizardCreateWallet3";
} else {
errorMsg.text = qsTr("Error writing wallet from hardware device. Check application logs.") + translationManager.emptyString;
}

View file

@ -40,8 +40,8 @@ Rectangle {
color: "transparent"
property alias pageHeight: pageRoot.height
property alias pageRoot: pageRoot
property string viewName: "wizardCreateWallet1"
property alias seed: seed
ColumnLayout {
id: pageRoot
@ -51,6 +51,8 @@ Rectangle {
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 0
KeyNavigation.down: createWalletHeader
KeyNavigation.tab: createWalletHeader
ColumnLayout {
Layout.fillWidth: true
@ -60,6 +62,7 @@ Rectangle {
spacing: 20
WizardHeader {
id: createWalletHeader
title: {
var nettype = persistentSettings.nettype;
return qsTr("Create a new wallet") + (nettype === 2 ? " (" + qsTr("stagenet") + ")"
@ -67,146 +70,42 @@ Rectangle {
: "") + translationManager.emptyString
}
subtitle: qsTr("Creates a new wallet on this computer.") + translationManager.emptyString
Accessible.role: Accessible.StaticText
Accessible.name: title + subtitle
Keys.onUpPressed: wizardNav.btnNext.enabled ? wizardNav.btnNext.forceActiveFocus() : wizardNav.wizardProgress.forceActiveFocus()
Keys.onBacktabPressed: wizardNav.btnNext.enabled ? wizardNav.btnNext.forceActiveFocus() : wizardNav.wizardProgress.forceActiveFocus()
Keys.onDownPressed: walletInput.walletName.forceActiveFocus();
Keys.onTabPressed: walletInput.walletName.forceActiveFocus();
}
WizardWalletInput{
id: walletInput
}
ColumnLayout {
spacing: 0
Layout.topMargin: -10
Layout.fillWidth: true
MoneroComponents.LineEditMulti {
id: seed
spacing: 0
inputPaddingLeft: 16
inputPaddingRight: 16
inputPaddingTop: 20
inputPaddingBottom: 20
inputRadius: 0
fontSize: 18
fontBold: true
wrapMode: Text.WordWrap
backgroundColor: "red"
addressValidation: false
labelText: qsTr("Mnemonic seed") + translationManager.emptyString
labelFontSize: 14
copyButton: false
readOnly: true
placeholderText: "-"
text: wizardController.walletOptionsSeed
}
MoneroComponents.WarningBox {
Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
Rectangle {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
height: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
Rectangle {
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
radius: 0
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 0
text: qsTr("This seed is <b>very</b> important to write down and keep secret. It is all you need to backup and restore your wallet.") + translationManager.emptyString
}
}
ColumnLayout {
spacing: 0
Layout.topMargin: 10
Layout.fillWidth: true
MoneroComponents.LineEditMulti {
id: restoreHeight
spacing: 0
inputPaddingLeft: 16
inputPaddingRight: 16
inputPaddingTop: 20
inputPaddingBottom: 20
inputRadius: 0
fontSize: 18
fontBold: true
wrapMode: Text.WordWrap
labelText: qsTr("Wallet restore height") + translationManager.emptyString
labelFontSize: 14
copyButton: false
readOnly: true
text: Utils.roundDownToNearestThousand(wizardController.m_wallet ? wizardController.m_wallet.walletCreationHeight : 0)
}
MoneroComponents.WarningBox {
Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
Rectangle {
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
height: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
Rectangle {
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 1
color: MoneroComponents.Style.inputBorderColorInActive
}
radius: 0
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 0
text: qsTr("Should you restore your wallet in the future, specifying this block number will recover your wallet quicker.") + translationManager.emptyString
}
rowLayout: false
walletNameKeyNavigationBackTab: createWalletHeader
browseButtonKeyNavigationTab: wizardNav.btnPrev
}
WizardNav {
progressSteps: appWindow.walletMode <= 1 ? 3 : 4
id: wizardNav
progressSteps: appWindow.walletMode <= 1 ? 4 : 5
progress: 0
btnNext.enabled: walletInput.verify();
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
btnPrev.text: appWindow.width <= 506 ? "<" : qsTr("Back to menu") + translationManager.emptyString
onPrevClicked: {
wizardController.wizardStateView.wizardCreateWallet2View.pwField = "";
wizardController.wizardStateView.wizardCreateWallet2View.pwConfirmField = "";
if (wizardStateView.wizardCreateWallet2View.seedListGrid) {
wizardStateView.wizardCreateWallet2View.seedListGrid.destroy();
}
wizardController.wizardStateView.wizardCreateWallet3View.pwField = "";
wizardController.wizardStateView.wizardCreateWallet3View.pwConfirmField = "";
wizardStateView.state = "wizardHome";
}
btnPrevKeyNavigationBackTab: walletInput.errorMessageWalletLocation.text != "" ? walletInput.errorMessageWalletLocation : walletInput.browseButton
btnNextKeyNavigationTab: createWalletHeader
onNextClicked: {
wizardController.walletOptionsName = walletInput.walletName.text;
wizardController.walletOptionsLocation = walletInput.walletLocation.text;
wizardController.walletOptionsLocation = appWindow.walletMode >= 2 ? walletInput.walletLocation.text : appWindow.accountsDir;
wizardStateView.state = "wizardCreateWallet2";
wizardStateView.wizardCreateWallet2View.pageRoot.forceActiveFocus();
}
}
}

View file

@ -27,9 +27,13 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import moneroComponents.Clipboard 1.0
import "../js/Wizard.js" as Wizard
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
Rectangle {
@ -37,9 +41,56 @@ Rectangle {
color: "transparent"
property alias pageHeight: pageRoot.height
property alias pageRoot: pageRoot
property string viewName: "wizardCreateWallet2"
property alias pwField: passwordFields.password
property alias pwConfirmField: passwordFields.passwordConfirm
property var seedArray: wizardController.walletOptionsSeed.split(" ")
property var seedListGrid: ""
property var hiddenWords: [0, 5, 10, 15, 20]
Clipboard { id: clipboard }
state: "default"
states: [
State {
name: "default";
}, State {
name: "verify";
when: typeof currentWallet != "undefined" && wizardStateView.state == "wizardCreateWallet2"
PropertyChanges { target: header; title: qsTr("Verify your recovery phrase") + translationManager.emptyString }
PropertyChanges { target: header; imageIcon: wizardController.layoutScale != 4 ? (MoneroComponents.Style.blackTheme ? "qrc:///images/verify.png" : "qrc:///images/verify-white.png") : "" }
PropertyChanges { target: header; subtitle: qsTr("Please confirm that you have written down your recover phrase by filling in the five blank fields with the correct words. If you have not written down your recovery phrase on a piece of paper, click on the Previous button and write it down right now!") + translationManager.emptyString}
PropertyChanges { target: walletCreationDate; opacity: 0; enabled: false}
PropertyChanges { target: walletCreationDateValue; opacity: 0; enabled: false}
PropertyChanges { target: walletRestoreHeight; opacity: 0; enabled: false}
PropertyChanges { target: walletRestoreHeightValue; opacity: 0; enabled: false}
PropertyChanges { target: createNewSeedButton; opacity: 0; enabled: false}
PropertyChanges { target: copyToClipboardButton; opacity: 0; enabled: false}
PropertyChanges { target: printPDFTemplate; opacity: 0; enabled: false}
PropertyChanges { target: navigation; onPrevClicked: {
seedListGridColumn.clearFields();
wizardCreateWallet2.state = "default";
pageRoot.forceActiveFocus();
}}
PropertyChanges { target: navigation; onNextClicked: {
seedListGridColumn.clearFields();
wizardStateView.state = "wizardCreateWallet3";
wizardCreateWallet2.state = "default";
}}
}
]
MoneroComponents.TextPlain {
//PDF template text
// the translation of these strings is used to create localized PDF templates
visible: false
text: qsTr("Print this paper, fill it out, and keep it in a safe location. Never share your recovery phrase with anybody, especially with strangers offering technical support.") +
qsTr("Recovery phrase (mnemonic seed)") +
qsTr("These words are are a backup of your wallet. They are the only thing needed to access your funds and restore your Monero wallet, so keep this paper in a safe place and do not disclose it to anybody! It is strongly not recommended to store your recovery phrase digitally (in an email, online service, screenshot, photo, or any other type of computer file).") +
qsTr("Wallet creation date") +
qsTr("Wallet restore height") +
qsTr("For instructions on how to restore this wallet, visit www.getmonero.org and go to Resources > User Guides > \"How to restore a wallet from mnemonic seed\". Use only Monero wallets that are trusted and recommended by the Monero community (see a list of them in www.getmonero.org/downloads).") + translationManager.emptyString
}
ColumnLayout {
id: pageRoot
@ -49,39 +100,350 @@ Rectangle {
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 0
KeyNavigation.down: mobileDialog.visible ? mobileHeader : header
KeyNavigation.tab: mobileDialog.visible ? mobileHeader : header
ColumnLayout {
id: mobileDialog
Layout.fillWidth: true
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 0
visible: wizardController.layoutScale == 4
spacing: 60
WizardAskPassword {
id: passwordFields
WizardHeader {
id: mobileHeader
title: qsTr("Write down your recovery phrase") + translationManager.emptyString
Accessible.role: Accessible.StaticText
Accessible.name: qsTr("Write down your recovery phrase") + translationManager.emptyString
Keys.onUpPressed: displaySeedButton.forceActiveFocus()
Keys.onBacktabPressed: displaySeedButton.forceActiveFocus()
KeyNavigation.down: mobileImage
KeyNavigation.tab: mobileImage
}
Image {
id: mobileImage
Layout.alignment: Qt.AlignHCenter
fillMode: Image.PreserveAspectCrop
source: MoneroComponents.Style.blackTheme ? "qrc:///images/write-down@2x.png" : "qrc:///images/write-down-white@2x.png"
width: 125
height: 125
sourceSize.width: 125
sourceSize.height: 125
Accessible.role: Accessible.Graphic
Accessible.name: qsTr("A pencil writing on a piece of paper") + translationManager.emptyString
KeyNavigation.up: mobileHeader
KeyNavigation.backtab: mobileHeader
KeyNavigation.down: mobileText
KeyNavigation.tab: mobileText
Rectangle {
width: mobileImage.width
height: mobileImage.height
color: mobileImage.focus ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
}
}
Text {
id: mobileText
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("The next page will display your recovery phrase, also known as mnemonic seed.") + " " + qsTr("These words are a backup of your wallet. Write these words down now on a piece of paper in the same order displayed. Keep this paper in a safe place and do not disclose it to anybody! Do not store these words digitally, always use a paper!") + translationManager.emptyString
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
wrapMode: Text.WordWrap
leftPadding: 0
topPadding: 0
Accessible.role: Accessible.StaticText
Accessible.name: qsTr("The next page will display your recovery phrase, also known as mnemonic seed.") + " " + qsTr("These words are a backup of your wallet. Write these words down now on a piece of paper in the same order displayed. Keep this paper in a safe place and do not disclose it to anybody! Do not store these words digitally, always use a paper!") + translationManager.emptyString
KeyNavigation.up: mobileImage
KeyNavigation.backtab: mobileImage
KeyNavigation.down: displaySeedButton
KeyNavigation.tab: displaySeedButton
Rectangle {
anchors.fill: parent
color: parent.focus ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
}
}
MoneroComponents.StandardButton {
id: displaySeedButton
Layout.alignment: Qt.AlignHCenter;
text: qsTr("Display recovery phrase") + translationManager.emptyString
onClicked: {
mobileDialog.visible = false;
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("The next page will display your recovery phrase, also known as mnemonic seed. ") + qsTr("These words are a backup of your wallet. Write these words down now on a piece of paper in the same order displayed. Keep this paper in a safe place and do not disclose it to anybody! Do not store these words digitally, always use a paper!") + translationManager.emptyString
KeyNavigation.up: mobileText
KeyNavigation.backtab: mobileText
KeyNavigation.down: mobileHeader
KeyNavigation.tab: mobileHeader
}
}
ColumnLayout {
id: mainPage
Layout.fillWidth: true
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
visible: !mobileDialog.visible
spacing: 15
WizardHeader {
id: header
imageIcon: wizardController.layoutScale != 4 ? (MoneroComponents.Style.blackTheme ? "qrc:///images/write-down.png" : "qrc:///images/write-down-white.png") : ""
title: qsTr("Write down your recovery phrase") + translationManager.emptyString
subtitleVisible: wizardController.layoutScale != 4
subtitle: qsTr("These words are a backup of your wallet. Write these words down now on a piece of paper in the same order displayed. Keep this paper in a safe place and do not disclose it to anybody! Do not store these words digitally, always use a paper!") + translationManager.emptyString
Accessible.role: Accessible.StaticText
Accessible.name: title + ". " + subtitle
Keys.onUpPressed: navigation.btnNext.enabled ? navigation.btnNext.forceActiveFocus() : navigation.wizardProgress.forceActiveFocus()
Keys.onBacktabPressed: navigation.btnNext.enabled ? navigation.btnNext.forceActiveFocus() : navigation.wizardProgress.forceActiveFocus()
Keys.onDownPressed: recoveryPhraseLabel.visible ? recoveryPhraseLabel.forceActiveFocus() : focusOnListGrid()
Keys.onTabPressed: recoveryPhraseLabel.visible ? recoveryPhraseLabel.forceActiveFocus() : focusOnListGrid()
function focusOnListGrid() {
if (wizardCreateWallet2.state == "verify") {
if (seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[0]].lineEdit.visible) {
return seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[0]].lineEdit.forceActiveFocus();
} else {
return seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[0]].forceActiveFocus();
}
} else {
return seedListGridColumn.children[0].children[0].forceActiveFocus();
}
}
}
MoneroComponents.TextPlain {
id: recoveryPhraseLabel
visible: wizardController.layoutScale != 4
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 15
font.bold: false
textFormat: Text.RichText
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("Recovery phrase (mnemonic seed)") + ":" + translationManager.emptyString
themeTransition: false
tooltip: qsTr("These words encode your private spend key in a human readable format.") + "<br>" + qsTr("It is expected that some words may be repeated.") + translationManager.emptyString
tooltipIconVisible: true
Accessible.role: Accessible.StaticText
Accessible.name: qsTr("Recovery phrase (mnemonic seed)") + translationManager.emptyString;
KeyNavigation.up: header
KeyNavigation.backtab: header
Keys.onDownPressed: header.focusOnListGrid()
Keys.onTabPressed: header.focusOnListGrid()
}
ColumnLayout {
id: seedListGridColumn
function clearFields() {
for (var i = 0; i < wizardCreateWallet2.hiddenWords.length; i++) {
seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[i]].wordText.visible = true;
seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[i]].lineEdit.text = "";
seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[i]].lineEdit.readOnly = false;
}
}
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignRight
Timer {
id: checkSeedListGridDestruction
interval: 100; running: false; repeat: true
onTriggered: {
if (!wizardCreateWallet2.seedListGrid) {
var newSeedListGrid = Qt.createComponent("SeedListGrid.qml");
wizardCreateWallet2.seedListGrid = newSeedListGrid.createObject(seedListGridColumn);
appWindow.showStatusMessage(qsTr("New seed generated"),3);
pageRoot.forceActiveFocus();
checkSeedListGridDestruction.stop();
}
}
}
MoneroComponents.StandardButton {
id: createNewSeedButton
visible: appWindow.walletMode >= 2
small: true
primary: false
text: qsTr("Create new seed") + translationManager.emptyString
onClicked: {
wizardController.restart(true);
wizardController.createWallet();
wizardCreateWallet2.seedArray = wizardController.walletOptionsSeed.split(" ")
wizardCreateWallet2.seedListGrid.destroy();
checkSeedListGridDestruction.start();
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Create new seed") + translationManager.emptyString
KeyNavigation.up: (wizardCreateWallet2.seedListGrid && seedListGridColumn.children[0]) ? seedListGridColumn.children[0].children[24] : recoveryPhraseLabel
KeyNavigation.backtab: (wizardCreateWallet2.seedListGrid && seedListGridColumn.children[0]) ? seedListGridColumn.children[0].children[24] : recoveryPhraseLabel
KeyNavigation.down: copyToClipboardButton
KeyNavigation.tab: copyToClipboardButton
}
MoneroComponents.StandardButton {
id: copyToClipboardButton
visible: appWindow.walletMode >= 2
small: true
primary: false
text: qsTr("Copy to clipboard") + translationManager.emptyString
onClicked: {
clipboard.setText(wizardController.walletOptionsSeed);
appWindow.showStatusMessage(qsTr("Recovery phrase copied to clipboard"),3);
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Copy to clipboard") + translationManager.emptyString
KeyNavigation.up: createNewSeedButton
KeyNavigation.backtab: createNewSeedButton
KeyNavigation.down: printPDFTemplate.visible ? printPDFTemplate : walletCreationDate
KeyNavigation.tab: printPDFTemplate.visible ? printPDFTemplate : walletCreationDate
}
MoneroComponents.StandardButton {
id: printPDFTemplate
small: true
primary: false
text: qsTr("Print a template") + translationManager.emptyString
tooltip: qsTr("Print a template to write down your seed") + translationManager.emptyString
onClicked: {
oshelper.openSeedTemplate();
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Print a template to write down your seed") + translationManager.emptyString
KeyNavigation.up: copyToClipboardButton.visible ? copyToClipboardButton : (wizardCreateWallet2.seedListGrid && seedListGridColumn.children[0]) ? seedListGridColumn.children[0].children[24] : recoveryPhraseLabel
KeyNavigation.backtab: copyToClipboardButton.visible ? copyToClipboardButton : (wizardCreateWallet2.seedListGrid && seedListGridColumn.children[0]) ? seedListGridColumn.children[0].children[24] : recoveryPhraseLabel
KeyNavigation.down: walletCreationDate
KeyNavigation.tab: walletCreationDate
}
}
RowLayout {
Layout.topMargin: 0
Layout.fillWidth: true
Layout.maximumWidth: seedListGridColumn.width
spacing: 10
ColumnLayout {
spacing: 5
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: walletCreationDate
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 15
font.bold: false
textFormat: Text.RichText
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("Creation date") + ": " + translationManager.emptyString
themeTransition: false
Accessible.role: Accessible.StaticText
Accessible.name: qsTr("Creation date") + " " + walletCreationDateValue.text + translationManager.emptyString
KeyNavigation.up: printPDFTemplate.visible ? printPDFTemplate : copyToClipboardButton
KeyNavigation.backtab: printPDFTemplate.visible ? printPDFTemplate : copyToClipboardButton
KeyNavigation.down: walletRestoreHeight
KeyNavigation.tab: walletRestoreHeight
}
MoneroComponents.TextPlain {
id: walletCreationDateValue
property var locale: Qt.locale()
property date currentDate: new Date()
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16
font.bold: true
textFormat: Text.RichText
color: MoneroComponents.Style.defaultFontColor
text: currentDate.toLocaleDateString(locale, Locale.ShortFormat)
}
}
ColumnLayout {
spacing: 5
Layout.fillWidth: true
MoneroComponents.TextPlain {
id: walletRestoreHeight
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 15
font.bold: false
textFormat: Text.RichText
color: MoneroComponents.Style.dimmedFontColor
text: qsTr("Restore height") + ":" + translationManager.emptyString
tooltip: wizardController.layoutScale != 4 ? qsTr("Enter this number when restoring the wallet to make your initial wallet synchronization faster.") : "" + translationManager.emptyString
tooltipIconVisible: true
themeTransition: false
Accessible.role: Accessible.StaticText
Accessible.name: qsTr("Restore height") + " " + Utils.roundDownToNearestThousand(wizardController.m_wallet ? wizardController.m_wallet.walletCreationHeight : 0) + translationManager.emptyString
KeyNavigation.up: walletCreationDate
KeyNavigation.backtab: walletCreationDate
Keys.onDownPressed: navigation.btnPrev.forceActiveFocus();
Keys.onTabPressed: navigation.btnPrev.forceActiveFocus();
}
MoneroComponents.TextPlain {
id: walletRestoreHeightValue
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16
font.bold: true
textFormat: Text.RichText
color: MoneroComponents.Style.defaultFontColor
text: Utils.roundDownToNearestThousand(wizardController.m_wallet ? wizardController.m_wallet.walletCreationHeight : 0)
}
}
}
WizardNav {
progressSteps: appWindow.walletMode <= 1 ? 3 : 4
id: navigation
progressSteps: appWindow.walletMode <= 1 ? 4 : 5
progress: 1
btnNext.enabled: passwordFields.calcStrengthAndVerify();
onPrevClicked: {
if(wizardController.walletOptionsIsRecoveringFromDevice){
wizardStateView.state = "wizardCreateDevice1";
} else {
wizardStateView.state = "wizardCreateWallet1";
}
wizardStateView.state = "wizardCreateWallet1";
mobileDialog.visible = Qt.binding(function() { return wizardController.layoutScale == 4 })
}
btnPrevKeyNavigationBackTab: wizardCreateWallet2.state == "default" ? walletRestoreHeight
: seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[4]].lineEdit.visible ? seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[4]].lineEdit
: seedListGridColumn.children[0].children[24]
btnNextKeyNavigationTab: mobileDialog.visible ? mobileHeader : header
btnNext.enabled: walletCreationDate.opacity == 1 || appWindow.ctrlPressed ? true
: seedListGridColumn.children[0].children[hiddenWords[0]].icon.wordsMatch &&
seedListGridColumn.children[0].children[hiddenWords[1]].icon.wordsMatch &&
seedListGridColumn.children[0].children[hiddenWords[2]].icon.wordsMatch &&
seedListGridColumn.children[0].children[hiddenWords[3]].icon.wordsMatch &&
seedListGridColumn.children[0].children[hiddenWords[4]].icon.wordsMatch
onNextClicked: {
wizardController.walletOptionsPassword = passwordFields.password;
if(appWindow.walletMode === 0 || appWindow.walletMode === 1){
wizardStateView.state = "wizardCreateWallet4";
} else {
wizardStateView.state = "wizardCreateWallet3";
//choose five random words to hide
for (var i = 0; i < hiddenWords.length; i++) {
wizardCreateWallet2.hiddenWords[i] = Math.floor(Math.random() * 5) + 5 * i
}
wizardCreateWallet2.state = "verify";
for (var i = 0; i < hiddenWords.length; i++) {
seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[i]].wordText.visible = false;
}
seedListGridColumn.children[0].children[wizardCreateWallet2.hiddenWords[0]].lineEdit.forceActiveFocus();
}
}
}
}
function onPageCompleted(previousView){
wizardCreateWallet2.seedArray = wizardController.walletOptionsSeed.split(" ")
if (!wizardCreateWallet2.seedListGrid) {
var component = Qt.createComponent("SeedListGrid.qml");
wizardCreateWallet2.seedListGrid = component.createObject(seedListGridColumn);
}
}
}

View file

@ -38,6 +38,8 @@ Rectangle {
color: "transparent"
property alias pageHeight: pageRoot.height
property string viewName: "wizardCreateWallet3"
property alias pwField: passwordFields.password
property alias pwConfirmField: passwordFields.passwordConfirm
ColumnLayout {
id: pageRoot
@ -53,26 +55,32 @@ Rectangle {
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 20
spacing: 0
WizardHeader {
title: qsTr("Daemon settings") + translationManager.emptyString
subtitle: qsTr("To be able to communicate with the Monero network your wallet needs to be connected to a Monero node. For best privacy it's recommended to run your own node.") + translationManager.emptyString
}
WizardDaemonSettings {
id: daemonSettings
WizardAskPassword {
id: passwordFields
}
WizardNav {
progressSteps: 4
progressSteps: appWindow.walletMode <= 1 ? 4 : 5
progress: 2
btnNext.enabled: passwordFields.calcStrengthAndVerify();
onPrevClicked: {
wizardStateView.state = "wizardCreateWallet2";
if(wizardController.walletOptionsIsRecoveringFromDevice){
wizardStateView.state = "wizardCreateDevice1";
} else {
wizardStateView.state = "wizardCreateWallet2";
wizardStateView.wizardCreateWallet2View.pageRoot.forceActiveFocus();
}
}
onNextClicked: {
daemonSettings.save();
wizardStateView.state = "wizardCreateWallet4";
wizardController.walletOptionsPassword = passwordFields.password;
if (appWindow.walletMode < 2) {
wizardStateView.state = "wizardCreateWallet5";
} else {
wizardStateView.state = "wizardCreateWallet4";
}
}
}
}

View file

@ -30,7 +30,6 @@ import QtQuick 2.9
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
@ -38,7 +37,6 @@ Rectangle {
color: "transparent"
property alias pageHeight: pageRoot.height
property alias wizardNav: wizardNav
property string viewName: "wizardCreateWallet4"
ColumnLayout {
@ -58,35 +56,23 @@ Rectangle {
spacing: 20
WizardHeader {
title: qsTr("You're all set up!") + translationManager.emptyString
subtitle: qsTr("New wallet details:") + translationManager.emptyString
title: qsTr("Daemon settings") + translationManager.emptyString
subtitle: qsTr("To be able to communicate with the Monero network your wallet needs to be connected to a Monero node. For best privacy it's recommended to run your own node.") + translationManager.emptyString
}
WizardSummary {}
WizardDaemonSettings {
id: daemonSettings
}
WizardNav {
id: wizardNav
Layout.topMargin: 24
btnNextText: qsTr("Create wallet") + translationManager.emptyString
progressSteps: appWindow.walletMode <= 1 ? 3 : 4
progress: appWindow.walletMode <= 1 ? 2 : 3
progressSteps: 5
progress: 3
onPrevClicked: {
if (appWindow.walletMode <= 1){
wizardStateView.state = "wizardCreateWallet1";
} else {
wizardStateView.state = "wizardCreateWallet3";
}
wizardStateView.state = "wizardCreateWallet3";
}
onNextClicked: {
btnNext.enabled = false;
wizardController.wizardStateView.wizardCreateWallet2View.pwField = "";
wizardController.wizardStateView.wizardCreateWallet2View.pwConfirmField = "";
wizardController.writeWallet(function() {
wizardController.useMoneroClicked();
wizardController.walletOptionsIsRecoveringFromDevice = false;
btnNext.enabled = true;
});
daemonSettings.save();
wizardStateView.state = "wizardCreateWallet5";
}
}
}

View file

@ -0,0 +1,94 @@
// Copyright (c) 2014-2019, 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 QtQuick 2.9
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateWallet5
color: "transparent"
property alias pageHeight: pageRoot.height
property alias wizardNav: wizardNav
property string viewName: "wizardCreateWallet5"
ColumnLayout {
id: pageRoot
Layout.alignment: Qt.AlignHCenter;
width: parent.width - 100
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 0
ColumnLayout {
Layout.fillWidth: true
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 20
WizardHeader {
title: qsTr("You're all set up!") + translationManager.emptyString
subtitle: qsTr("New wallet details:") + translationManager.emptyString
}
WizardSummary {}
WizardNav {
id: wizardNav
Layout.topMargin: 24
btnNextText: qsTr("Create wallet") + translationManager.emptyString
progressSteps: appWindow.walletMode <= 1 ? 4 : 5
progress: appWindow.walletMode <= 1 ? 3 : 4
onPrevClicked: {
if (appWindow.walletMode <= 1){
wizardStateView.state = "wizardCreateWallet1";
} else {
wizardStateView.state = "wizardCreateWallet4";
}
}
onNextClicked: {
btnNext.enabled = false;
wizardController.wizardStateView.wizardCreateWallet3View.pwField = "";
wizardController.wizardStateView.wizardCreateWallet3View.pwConfirmField = "";
wizardController.writeWallet(function() {
wizardController.useMoneroClicked();
wizardController.walletOptionsIsRecoveringFromDevice = false;
});
btnNext.enabled = true;
}
}
}
}
}

View file

@ -38,44 +38,60 @@ import QtQuick.Controls 2.0
ColumnLayout {
property string title: ""
property string subtitle: ""
property alias imageIcon: icon.source
property bool subtitleVisible: true
spacing: 4
Layout.maximumWidth: wizardController.wizardSubViewWidth
Text {
text: title
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 34;
} else {
return 28;
}
RowLayout {
spacing: 0
Image {
id: icon
visible: icon.source != ""
source: ""
width: wizardController.layoutScale == 4 ? 35 : 50
height: wizardController.layoutScale == 4 ? 35 : 50
}
wrapMode: Text.WordWrap
leftPadding: 0
topPadding: 0
bottomPadding: 0
Text {
text: title
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
font.pixelSize: {
if (wizardController.layoutScale == 4) {
return 16;
} else if (wizardController.layoutScale == 3) {
return 28;
} else if (wizardController.layoutScale <= 2) {
return 32;
}
}
Rectangle {
anchors.fill: parent
color: parent.parent.focus ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
wrapMode: Text.WordWrap
leftPadding: 0
topPadding: 0
bottomPadding: 0
Rectangle {
anchors.fill: parent
color: parent.parent.parent.focus ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
}
}
}
Text {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
visible: parent.subtitle !== ""
visible: parent.subtitle !== "" && subtitleVisible
color: MoneroComponents.Style.dimmedFontColor
text: subtitle
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
if (wizardController.layoutScale <= 2 ) {
return 16;
} else {
return 14;

View file

@ -86,6 +86,7 @@ Rectangle {
wizardController.restart();
wizardController.createWallet();
wizardStateView.state = "wizardCreateWallet1"
wizardStateView.wizardCreateWallet1View.pageRoot.forceActiveFocus();
}
}

View file

@ -102,10 +102,12 @@ RowLayout {
font.bold: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 22;
} else {
if (wizardController.layoutScale == 4) {
return 16;
} else if (wizardController.layoutScale == 3) {
return 20;
} else if (wizardController.layoutScale <= 2) {
return 22;
}
}
@ -124,7 +126,7 @@ RowLayout {
color: MoneroComponents.Style.dimmedFontColor
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
if (wizardController.layoutScale <= 2 ){
return 16;
} else {
return 14;

View file

@ -43,9 +43,10 @@ RowLayout {
property bool autoTransition: true
property alias btnPrev: btnPrev
property alias btnNext: btnNext
property alias wizardProgress: wizardProgress
property string btnPrevText: qsTr("Previous") + translationManager.emptyString
property string btnNextText: qsTr("Next") + translationManager.emptyString
Layout.topMargin: 20
Layout.topMargin: 0
Layout.preferredHeight: 70
Layout.preferredWidth: parent.width
@ -70,9 +71,11 @@ RowLayout {
MoneroComponents.StandardButton {
id: btnPrev
width: appWindow.width <= 506 ? 45 : appWindow.width <= 660 ? 120 : 180
small: true
text: menuNav.btnPrevText
primary: false
text: appWindow.width <= 506 ? "<" : menuNav.btnPrevText
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
@ -134,8 +137,9 @@ RowLayout {
MoneroComponents.StandardButton {
id: btnNext
width: appWindow.width <= 506 ? 45 : appWindow.width <= 660 ? 120 : 180
small: true
text: menuNav.btnNextText
text: appWindow.width <= 506 ? ">" : menuNav.btnNextText
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right

View file

@ -34,6 +34,7 @@ import QtGraphicalEffects 1.0
import Qt.labs.folderlistmodel 2.1
import moneroComponents.NetworkType 1.0
import moneroComponents.WalletKeysFilesModel 1.0
import FontAwesome 1.0
import "../js/Wizard.js" as Wizard
import "../components"
@ -329,8 +330,9 @@ Rectangle {
id: wizardNav
Layout.topMargin: 0
progressEnabled: false
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
btnNext.text: qsTr("Browse filesystem") + translationManager.emptyString
btnPrev.text: appWindow.width <= 506 ? "<" : qsTr("Back to menu") + translationManager.emptyString
btnNext.text: appWindow.width <= 506 ? qsTr("Browse") : qsTr("Browse filesystem") + translationManager.emptyString
btnNext.width: appWindow.width <= 506 ? 80 : appWindow.width <= 660 ? 120 : 180
btnNext.visible: true
btnPrevKeyNavigationBackTab: recentList.itemAt(recentList.count - 1)
btnNextKeyNavigationTab: openWalletFromFileHeader

View file

@ -41,9 +41,16 @@ GridLayout {
Layout.fillWidth: true
property alias walletName: walletName
property alias walletLocation: walletLocation
property alias browseButton: browseButton
property alias errorMessageWalletName: errorMessageWalletName
property alias errorMessageWalletLocation: errorMessageWalletLocation
property bool rowLayout: true
property var walletNameKeyNavigationBackTab: browseButton
property var browseButtonKeyNavigationTab: walletName
columnSpacing: 20
columns: 2
columnSpacing: rowLayout ? 20 : 0
rowSpacing: rowLayout ? 0 : 20
columns: rowLayout ? 2 : 1
function verify() {
if (walletName.text !== '' && walletLocation.text !== '') {
@ -61,79 +68,163 @@ GridLayout {
walletName.text = Wizard.unusedWalletName(appWindow.accountsDir, defaultAccountName, walletManager);
}
MoneroComponents.LineEdit {
id: walletName
Layout.preferredWidth: grid.width/5
ColumnLayout {
MoneroComponents.LineEdit {
id: walletName
Layout.preferredWidth: grid.width/5
function verify(){
if (walletName.text === "") {
errorMessageWalletName.text = qsTr("Wallet name is empty") + translationManager.emptyString;
return false;
}
if (/[\\\/]/.test(walletName.text)) {
errorMessageWalletName.text = qsTr("Wallet name is invalid") + translationManager.emptyString;
return false;
}
if (walletLocation.text !== "") {
var walletAlreadyExists = Wizard.walletPathExists(appWindow.accountsDir, walletLocation.text, walletName.text, isIOS, walletManager);
if (walletAlreadyExists) {
errorMessageWalletName.text = qsTr("Wallet already exists") + translationManager.emptyString;
function verify(){
if (walletName.text === "") {
errorMessageWalletName.text = qsTr("Wallet name is empty") + translationManager.emptyString;
return false;
}
if (/[\\\/]/.test(walletName.text)) {
errorMessageWalletName.text = qsTr("Wallet name is invalid") + translationManager.emptyString;
return false;
}
if (walletLocation.text !== "") {
var walletAlreadyExists = Wizard.walletPathExists(appWindow.accountsDir, walletLocation.text, walletName.text, isIOS, walletManager);
if (walletAlreadyExists) {
errorMessageWalletName.text = qsTr("Wallet already exists") + translationManager.emptyString;
return false;
}
}
errorMessageWalletName.text = "";
return true;
}
errorMessageWalletName.text = "";
return true;
labelText: qsTr("Wallet name") + translationManager.emptyString
labelFontSize: 14
fontSize: 16
placeholderFontSize: 16
placeholderText: ""
errorWhenEmpty: true
text: defaultAccountName
onTextChanged: walletName.error = !walletName.verify();
Component.onCompleted: walletName.error = !walletName.verify();
Accessible.role: Accessible.EditableText
Accessible.name: labelText + text
KeyNavigation.up: walletNameKeyNavigationBackTab
KeyNavigation.backtab: walletNameKeyNavigationBackTab
KeyNavigation.down: errorMessageWalletName.text != "" ? errorMessageWalletName : appWindow.walletMode >= 2 ? walletLocation : wizardNav.btnPrev
KeyNavigation.tab: errorMessageWalletName.text != "" ? errorMessageWalletName : appWindow.walletMode >= 2 ? walletLocation : wizardNav.btnPrev
}
labelText: qsTr("Wallet name") + translationManager.emptyString
labelFontSize: 14
fontSize: 16
placeholderFontSize: 16
placeholderText: ""
errorWhenEmpty: true
text: defaultAccountName
RowLayout {
Layout.preferredWidth: grid.width/5
onTextChanged: walletName.error = !walletName.verify();
Component.onCompleted: walletName.error = !walletName.verify();
MoneroComponents.TextPlain {
visible: errorMessageWalletName.text != ""
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
font.pixelSize: 15
text: FontAwesome.exclamationCircle
color: "#FF0000"
themeTransition: false
}
MoneroComponents.TextPlain {
id: errorMessageWalletName
textFormat: Text.PlainText
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: "#FF0000"
themeTransition: false
Accessible.role: Accessible.StaticText
Accessible.name: text
KeyNavigation.up: walletName
KeyNavigation.backtab: walletName
KeyNavigation.down: walletLocation
KeyNavigation.tab: walletLocation
}
}
}
MoneroComponents.LineEdit {
id: walletLocation
Layout.preferredWidth: grid.width/3
ColumnLayout {
visible: appWindow.walletMode >= 2
function verify() {
if (walletLocation.text == "") {
errorMessageWalletLocation.text = qsTr("Wallet location is empty") + translationManager.emptyString;
return false;
MoneroComponents.LineEdit {
id: walletLocation
Layout.preferredWidth: grid.width/3
function verify() {
if (walletLocation.text == "") {
errorMessageWalletLocation.text = qsTr("Wallet location is empty") + translationManager.emptyString;
return false;
}
errorMessageWalletLocation.text = "";
return true;
}
labelText: qsTr("Wallet location") + translationManager.emptyString
labelFontSize: 14
fontSize: 16
placeholderText: ""
placeholderFontSize: 16
errorWhenEmpty: true
text: appWindow.accountsDir + "/"
onTextChanged: {
walletLocation.error = !walletLocation.verify();
walletName.error = !walletName.verify();
}
Component.onCompleted: walletLocation.error = !walletLocation.verify();
Accessible.role: Accessible.EditableText
Accessible.name: labelText + text
KeyNavigation.up: errorMessageWalletName.text != "" ? errorMessageWalletName : walletName
KeyNavigation.backtab: errorMessageWalletName.text != "" ? errorMessageWalletName : walletName
KeyNavigation.down: browseButton
KeyNavigation.tab: browseButton
MoneroComponents.InlineButton {
id: browseButton
fontFamily: FontAwesome.fontFamilySolid
fontStyleName: "Solid"
fontPixelSize: 18
text: FontAwesome.folderOpen
tooltip: qsTr("Browse") + translationManager.emptyString
tooltipLeft: true
onClicked: {
fileWalletDialog.folder = walletManager.localPathToUrl(walletLocation.text)
fileWalletDialog.open()
walletLocation.focus = true
}
Accessible.role: Accessible.Button
Accessible.name: qsTr("Browse") + translationManager.emptyString
KeyNavigation.up: walletLocation
KeyNavigation.backtab: walletLocation
KeyNavigation.down: errorMessageWalletLocation.text != "" ? errorMessageWalletLocation : browseButtonKeyNavigationTab
KeyNavigation.tab: errorMessageWalletLocation.text != "" ? errorMessageWalletLocation : browseButtonKeyNavigationTab
}
errorMessageWalletLocation.text = "";
return true;
}
labelText: qsTr("Wallet location") + translationManager.emptyString
labelFontSize: 14
fontSize: 16
placeholderText: ""
placeholderFontSize: 16
errorWhenEmpty: true
text: appWindow.accountsDir + "/"
onTextChanged: {
walletLocation.error = !walletLocation.verify();
walletName.error = !walletName.verify();
}
Component.onCompleted: walletLocation.error = !walletLocation.verify();
RowLayout {
Layout.preferredWidth: grid.width/3
MoneroComponents.InlineButton {
fontFamily: FontAwesome.fontFamilySolid
fontStyleName: "Solid"
fontPixelSize: 18
text: FontAwesome.folderOpen
tooltip: qsTr("Browse") + translationManager.emptyString
tooltipLeft: true
onClicked: {
fileWalletDialog.folder = walletManager.localPathToUrl(walletLocation.text)
fileWalletDialog.open()
walletLocation.focus = true
MoneroComponents.TextPlain {
visible: errorMessageWalletLocation.text != ""
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
font.pixelSize: 15
text: FontAwesome.exclamationCircle
color: "#FF0000"
themeTransition: false
}
MoneroComponents.TextPlain {
id: errorMessageWalletLocation
textFormat: Text.PlainText
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: "#FF0000"
themeTransition: false
Accessible.role: Accessible.StaticText
Accessible.name: text
KeyNavigation.up: browseButton
KeyNavigation.backtab: browseButton
KeyNavigation.down: browseButtonKeyNavigationTab
KeyNavigation.tab: browseButtonKeyNavigationTab
}
}
}
@ -152,50 +243,4 @@ GridLayout {
fileWalletDialog.visible = false;
}
}
RowLayout {
Layout.preferredWidth: grid.width/5
MoneroComponents.TextPlain {
visible: errorMessageWalletName.text != ""
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
font.pixelSize: 15
text: FontAwesome.exclamationCircle
color: "#FF0000"
themeTransition: false
}
MoneroComponents.TextPlain {
id: errorMessageWalletName
textFormat: Text.PlainText
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: "#FF0000"
themeTransition: false
}
}
RowLayout {
Layout.preferredWidth: grid.width/3
MoneroComponents.TextPlain {
visible: errorMessageWalletLocation.text != ""
font.family: FontAwesome.fontFamilySolid
font.styleName: "Solid"
font.pixelSize: 15
text: FontAwesome.exclamationCircle
color: "#FF0000"
themeTransition: false
}
MoneroComponents.TextPlain {
id: errorMessageWalletLocation
textFormat: Text.PlainText
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: "#FF0000"
themeTransition: false
}
}
}

23486
wizard/template.pdf Normal file

File diff suppressed because it is too large Load diff