Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wizard: redesign seed page #3878

Merged
merged 1 commit into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/InlineButton.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 16 additions & 2 deletions components/LineEdit.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -109,6 +111,8 @@ ColumnLayout {
signal editingFinished();
signal accepted();
signal textUpdated();
signal backtabPressed();
signal tabPressed();

onActiveFocusChanged: activeFocus && input.forceActiveFocus()
onTextUpdated: {
Expand Down Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions components/TextPlain.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Binary file added images/verify-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/verify-white@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/verify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/verify@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/write-down-white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/write-down-white@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/write-down.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/write-down@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions qml.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
18 changes: 18 additions & 0 deletions src/main/oshelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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");
}
2 changes: 2 additions & 0 deletions src/main/oshelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ class OSHelper : public QObject
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;
Q_INVOKABLE QString temporaryPath() const;
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:
Expand Down
26 changes: 26 additions & 0 deletions wizard/SeedListGrid.qml
Original file line number Diff line number Diff line change
@@ -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 changes: 153 additions & 0 deletions wizard/SeedListItem.qml
Original file line number Diff line number Diff line change
@@ -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
}
}
32 changes: 25 additions & 7 deletions wizard/WizardController.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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 { }
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion wizard/WizardCreateDevice1.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading