Wizard redesign

This commit is contained in:
dsc 2019-01-14 01:02:44 +01:00
parent 333f4aaf83
commit f329a71029
No known key found for this signature in database
GPG key ID: 7BBC83D7A8810AAB
79 changed files with 4670 additions and 3098 deletions

View file

@ -435,6 +435,7 @@ Rectangle {
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: merchantButton id: merchantButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Merchant") + translationManager.emptyString text: qsTr("Merchant") + translationManager.emptyString
@ -449,7 +450,7 @@ Rectangle {
} }
Rectangle { Rectangle {
visible: merchantButton.present visible: merchantButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -484,6 +485,7 @@ Rectangle {
// ------------- Advanced tab --------------- // ------------- Advanced tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: advancedButton id: advancedButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Advanced") + translationManager.emptyString text: qsTr("Advanced") + translationManager.emptyString
@ -494,8 +496,9 @@ Rectangle {
parent.previousButton = advancedButton parent.previousButton = advancedButton
} }
} }
Rectangle { Rectangle {
visible: advancedButton.present visible: advancedButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -506,7 +509,7 @@ Rectangle {
// ------------- Mining tab --------------- // ------------- Mining tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: miningButton id: miningButton
visible: !isAndroid && !isIOS visible: !isAndroid && !isIOS && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Mining") + translationManager.emptyString text: qsTr("Mining") + translationManager.emptyString
@ -521,7 +524,7 @@ Rectangle {
} }
Rectangle { Rectangle {
visible: miningButton.present visible: miningButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -531,6 +534,7 @@ Rectangle {
// ------------- TxKey tab --------------- // ------------- TxKey tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: txkeyButton id: txkeyButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Prove/check") + translationManager.emptyString text: qsTr("Prove/check") + translationManager.emptyString
@ -544,7 +548,7 @@ Rectangle {
} }
} }
Rectangle { Rectangle {
visible: txkeyButton.present visible: txkeyButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -554,6 +558,7 @@ Rectangle {
// ------------- Shared RingDB tab --------------- // ------------- Shared RingDB tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: sharedringdbButton id: sharedringdbButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Shared RingDB") + translationManager.emptyString text: qsTr("Shared RingDB") + translationManager.emptyString
@ -567,7 +572,7 @@ Rectangle {
} }
} }
Rectangle { Rectangle {
visible: sharedringdbButton.present visible: sharedringdbButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -579,6 +584,7 @@ Rectangle {
// ------------- Sign/verify tab --------------- // ------------- Sign/verify tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: signButton id: signButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Sign/verify") + translationManager.emptyString text: qsTr("Sign/verify") + translationManager.emptyString
@ -592,7 +598,7 @@ Rectangle {
} }
} }
Rectangle { Rectangle {
visible: signButton.present visible: signButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16
@ -624,6 +630,7 @@ Rectangle {
// ------------- Sign/verify tab --------------- // ------------- Sign/verify tab ---------------
MoneroComponents.MenuButton { MoneroComponents.MenuButton {
id: keysButton id: keysButton
visible: appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
text: qsTr("Seed & Keys") + translationManager.emptyString text: qsTr("Seed & Keys") + translationManager.emptyString
@ -637,7 +644,7 @@ Rectangle {
} }
} }
Rectangle { Rectangle {
visible: settingsButton.present visible: settingsButton.present && appWindow.walletMode >= 2
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.leftMargin: 16 anchors.leftMargin: 16

View file

@ -33,14 +33,20 @@ import "../components" as MoneroComponents
Item { Item {
id: inlineButton id: inlineButton
height: rect.height * scaleRatio height: parent.height
anchors.top: parent.top
anchors.bottom: parent.bottom
property bool small: false
property string shadowPressedColor: "#B32D00" property string shadowPressedColor: "#B32D00"
property string shadowReleasedColor: "#FF4304" property string shadowReleasedColor: "#FF4304"
property string pressedColor: "#FF4304" property string pressedColor: "#FF4304"
property string releasedColor: "#FF6C3C" property string releasedColor: "#FF6C3C"
property string icon: "" property string icon: ""
property string textColor: "#FFFFFF" property string textColor: "#FFFFFF"
property int fontSize: 12 * scaleRatio property int fontSize: small ? 14 * scaleRatio : 16 * scaleRatio
property int rectHeight: small ? 24 * scaleRatio : 28 * scaleRatio
property int rectHMargin: small ? 16 * scaleRatio : 22 * scaleRatio
property alias text: inlineText.text property alias text: inlineText.text
property alias buttonColor: rect.color property alias buttonColor: rect.color
signal clicked() signal clicked()
@ -59,14 +65,14 @@ Item {
width: inlineText.text ? (inlineText.width + 22) * scaleRatio : inlineButton.icon ? (inlineImage.width + 16) * scaleRatio : rect.height width: inlineText.text ? (inlineText.width + 22) * scaleRatio : inlineButton.icon ? (inlineImage.width + 16) * scaleRatio : rect.height
radius: 4 radius: 4
anchors.top: parent.top anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
Text { Text {
id: inlineText id: inlineText
font.family: MoneroComponents.Style.fontBold.name font.family: MoneroComponents.Style.fontBold.name
font.bold: true font.bold: true
font.pixelSize: 16 * scaleRatio font.pixelSize: inlineButton.fontSize
color: "black" color: "black"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter

View file

@ -51,6 +51,9 @@ TextArea {
selectionColor: MoneroComponents.Style.dimmedFontColor selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor selectedTextColor: MoneroComponents.Style.defaultFontColor
property int minimumHeight: 100 * scaleRatio
height: contentHeight > minimumHeight ? contentHeight : minimumHeight
onTextChanged: { onTextChanged: {
if(addressValidation){ if(addressValidation){
// js replacement for `RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }` // js replacement for `RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }`

View file

@ -0,0 +1,170 @@
// 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 "../components" as MoneroComponents
import QtQuick 2.7
import QtQuick.XmlListModel 2.0
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
Drawer {
id: sideBar
// @TODO: Qt 5.10 introduces `opened` built-in for Drawer
property bool isOpened: false
onClosed: {
isOpened = false;
}
onOpened: {
isOpened = true;
}
width: 240 * scaleRatio
height: parent.height - (persistentSettings.customDecorations ? 50 : 0)
y: titleBar.height
background: Rectangle {
color: "#0d0d0d"
width: parent.width
}
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: "red"
ListView {
clip: true
Layout.fillHeight: true
Layout.fillWidth: true
boundsBehavior: Flickable.StopAtBounds
width: sideBar.width
height: sideBar.height
model: langModel
delegate: Rectangle {
id: item
color: "transparent"
width: sideBar.width
height: 32 * scaleRatio
Text {
anchors.left: parent.left
anchors.leftMargin: 16 * scaleRatio
font.bold: true
font.pixelSize: 14 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
text: display_name
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
height: 1
}
// button gradient while checked
Image {
anchors.fill: parent
source: "../images/menuButtonGradient.png"
opacity: 0.65
visible: true
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
var locale_spl = locale.split("_");
// reload active translations
console.log(locale_spl[0]);
translationManager.setLanguage(locale_spl[0]);
// set wizard language settings
wizard.language_locale = locale;
wizard.language_wallet = wallet_language;
wizard.language_language = display_name + " (" + locale_spl[1] + ") ";
sideBar.close()
}
hoverEnabled: true
onEntered: {
// item.color = "#26FFFFFF"
parent.opacity = 1
}
onExited: {
// item.color = "transparent"
parent.opacity = 0.65
}
}
}
}
ScrollIndicator.vertical: ScrollIndicator {
// @TODO: QT 5.9 introduces `policy: ScrollBar.AlwaysOn`
active: true
contentItem.opacity: 0.7
onActiveChanged: {
if (!active) {
active = true;
}
}
}
}
}
//Flags model
XmlListModel {
id: langModel
source: "/lang/languages.xml"
query: "/languages/language"
XmlRole { name: "display_name"; query: "@display_name/string()" }
XmlRole { name: "locale"; query: "@locale/string()" }
XmlRole { name: "wallet_language"; query: "@wallet_language/string()" }
XmlRole { name: "flag"; query: "@flag/string()" }
// TODO: XmlListModel is read only, we should store current language somewhere else
// and set current language accordingly
XmlRole { name: "isCurrent"; query: "@enabled/string()" }
onStatusChanged: {
if(status === XmlListModel.Ready){
console.log("languages available: ",count);
}
}
}
}

View file

@ -54,7 +54,9 @@ Item {
property bool borderDisabled: false property bool borderDisabled: false
property string borderColor: { property string borderColor: {
if(input.activeFocus){ if(error && input.text !== ""){
return MoneroComponents.Style.inputBorderColorInvalid;
} else if(input.activeFocus){
return MoneroComponents.Style.inputBorderColorActive; return MoneroComponents.Style.inputBorderColorActive;
} else { } else {
return MoneroComponents.Style.inputBorderColorInActive; return MoneroComponents.Style.inputBorderColorInActive;
@ -211,8 +213,6 @@ Item {
visible: item.inlineButtonText ? true : false visible: item.inlineButtonText ? true : false
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 8 * scaleRatio anchors.rightMargin: 8 * scaleRatio
anchors.top: parent.top
anchors.topMargin: 6 * scaleRatio
} }
} }
} }

View file

@ -42,6 +42,12 @@ ColumnLayout {
property alias labelButtonText: labelButton.text property alias labelButtonText: labelButton.text
property alias placeholderText: placeholderLabel.text property alias placeholderText: placeholderLabel.text
property int inputPaddingLeft: 10 * scaleRatio
property int inputPaddingRight: 10 * scaleRatio
property int inputPaddingTop: 10 * scaleRatio
property int inputPaddingBottom: 10 * scaleRatio
property int inputRadius: 4
property bool placeholderCenter: false property bool placeholderCenter: false
property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name property string placeholderFontFamily: MoneroComponents.Style.fontRegular.name
property bool placeholderFontBold: false property bool placeholderFontBold: false
@ -153,8 +159,12 @@ ColumnLayout {
readOnly: false readOnly: false
addressValidation: false addressValidation: false
Layout.fillWidth: true Layout.fillWidth: true
topPadding: 10 * scaleRatio
bottomPadding: 10 * scaleRatio leftPadding: item.inputPaddingLeft
rightPadding: item.inputPaddingRight
topPadding: item.inputPaddingTop
bottomPadding: item.inputPaddingBottom
wrapMode: item.wrapMode wrapMode: item.wrapMode
fontSize: item.fontSize fontSize: item.fontSize
fontBold: item.fontBold fontBold: item.fontBold
@ -182,7 +192,7 @@ ColumnLayout {
color: "transparent" color: "transparent"
border.width: 1 border.width: 1
border.color: item.borderColor border.color: item.borderColor
radius: 4 radius: item.inputRadius
anchors.fill: parent anchors.fill: parent
visible: !item.borderDisabled visible: !item.borderDisabled
} }

View file

@ -47,8 +47,13 @@ Rectangle {
} }
if (status == Wallet.ConnectionStatus_WrongVersion) if (status == Wallet.ConnectionStatus_WrongVersion)
return qsTr("Wrong version") return qsTr("Wrong version")
if (status == Wallet.ConnectionStatus_Disconnected) if (status == Wallet.ConnectionStatus_Disconnected){
if(appWindow.walletMode <= 1){
return qsTr("Searching node") + translationManager.emptyString;
}
return qsTr("Disconnected") return qsTr("Disconnected")
}
return qsTr("Invalid connection status") return qsTr("Invalid connection status")
} }

View file

@ -31,6 +31,7 @@ import QtQuick.Controls.Styles 1.2
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents import "../components" as MoneroComponents
GridLayout { GridLayout {
@ -65,7 +66,14 @@ GridLayout {
} }
function getAddress() { function getAddress() {
return daemonAddr.text.trim() + ":" + daemonPort.text.trim() var addr = daemonAddr.text.trim();
var port = daemonPort.text.trim();
// validation
if(addr === "" || addr.length < 2) return "";
if(!Utils.isNumeric(port)) return "";
return addr + ":" + port;
} }
LineEdit { LineEdit {

View file

@ -16,6 +16,7 @@ QtObject {
property string defaultFontColor: "white" property string defaultFontColor: "white"
property string dimmedFontColor: "#BBBBBB" property string dimmedFontColor: "#BBBBBB"
property string lightGreyFontColor: "#DFDFDF"
property string errorColor: "#FA6800" property string errorColor: "#FA6800"
property string inputBoxBackground: "black" property string inputBoxBackground: "black"
property string inputBoxBackgroundError: "#FFDDDD" property string inputBoxBackgroundError: "#FFDDDD"

View file

@ -126,37 +126,88 @@ Rectangle {
z: parent.z + 1 z: parent.z + 1
} }
// collapse left panel RowLayout {
Rectangle {
id: goToBasicVersionButton
property bool containsMouse: titleBar.mouseX >= x && titleBar.mouseX <= x + width
property bool checked: false
anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
color: "transparent" anchors.top: parent.top
height: titleBar.height width: 40
width: height height: parent.height
visible: !titleBar.orange && titleBar.basicButtonVisible spacing: 0
z: parent.z + 2 z: parent.z + 2
Image { Rectangle {
width: 14 Layout.preferredHeight: parent.height
height: 14 Layout.preferredWidth: Layout.preferredHeight
anchors.centerIn: parent
source: "../images/expand.png" id: goToBasicVersionButton
property bool containsMouse: titleBar.mouseX >= x && titleBar.mouseX <= x + width
property bool checked: false
color: "transparent"
height: titleBar.height
width: height
visible: !titleBar.orange && titleBar.basicButtonVisible
Image {
width: 14
height: 14
anchors.centerIn: parent
source: "../images/expand.png"
}
MouseArea {
id: basicMouseArea
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onEntered: { goToBasicVersionButton.color = titleBar.orange ? titleBar.buttonHoverColorOrange : titleBar.buttonHoverColor }
onExited: goToBasicVersionButton.color = "transparent";
onClicked: {
releaseFocus()
parent.checked = !parent.checked
titleBar.goToBasicVersion(leftPanel.visible)
}
}
} }
MouseArea { // language selection
id: basicMouseArea Rectangle {
hoverEnabled: true Layout.preferredHeight: parent.height
anchors.fill: parent Layout.preferredWidth: Layout.preferredHeight
cursorShape: Qt.PointingHandCursor visible: !titleBar.orange && persistentSettings.customDecorations
onEntered: { goToBasicVersionButton.color = titleBar.orange ? titleBar.buttonHoverColorOrange : titleBar.buttonHoverColor }
onExited: goToBasicVersionButton.color = "transparent"; id: languageSelection
onClicked: { property bool containsMouse: titleBar.mouseX >= x && titleBar.mouseX <= x + width
releaseFocus() property bool checked: false
parent.checked = !parent.checked color: "transparent"
titleBar.goToBasicVersion(leftPanel.visible) height: titleBar.height
width: height
z: parent.z + 2
Image {
width: 14
height: 14
anchors.centerIn: parent
source: "../images/langFlagGrey.png"
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onEntered: parent.color = "#262626";
onExited: parent.color = "transparent";
onClicked: {
releaseFocus();
// Show welcome screen if on home
if(wizard.wizardState === "wizardHome" || wizard.wizardState === "wizardModeSelection"){
wizard.skipModeSelection = true;
wizard.wizardState = 'wizardLanguage';
return;
}
languageSidebar.isOpened ? languageSidebar.close() : languageSidebar.open();
console.log('change language');
}
} }
} }
} }

View file

@ -28,12 +28,12 @@ Rectangle {
Image { Image {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 33 Layout.preferredHeight: 33 * scaleRatio
Layout.preferredWidth: 33 Layout.preferredWidth: 33 * scaleRatio
Layout.rightMargin: 14 Layout.rightMargin: 12 * scaleRatio
Layout.leftMargin: 14 Layout.leftMargin: 18 * scaleRatio
Layout.topMargin: 12 Layout.topMargin: 12 * scaleRatio
Layout.bottomMargin: 12 Layout.bottomMargin: 12 * scaleRatio
source: "../images/warning.png" source: "../images/warning.png"
} }
@ -44,22 +44,19 @@ Rectangle {
font.family: MoneroComponents.Style.fontRegular.name font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: root.fontSize font.pixelSize: root.fontSize
horizontalAlignment: TextInput.AlignLeft horizontalAlignment: TextInput.AlignLeft
selectionColor: MoneroComponents.Style.dimmedFontColor
selectByMouse: true selectByMouse: true
textFormat: Text.RichText textFormat: Text.RichText
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
textMargin: 0 textMargin: 0
leftPadding: 0 leftPadding: 4 * scaleRatio
topPadding: 6 rightPadding: 18 * scaleRatio
topPadding: 10 * scaleRatio
bottomPadding: 10 * scaleRatio
readOnly: true readOnly: true
onLinkActivated: root.linkActivated(); onLinkActivated: root.linkActivated();
// @TODO: Legacy. Remove after Qt 5.8. selectionColor: MoneroComponents.Style.dimmedFontColor
// https://stackoverflow.com/questions/41990013 selectedTextColor: MoneroComponents.Style.defaultFontColor
MouseArea {
anchors.fill: parent
enabled: false
}
} }
} }
} }

BIN
images/create-wallet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/create-wallet@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
images/langFlagGrey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/local-node-full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/local-node.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

BIN
images/local-node@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/remote-node.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/remote-node@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
images/restore-wallet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,008 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 KiB

View file

@ -12,6 +12,7 @@ function destinationsToAddress(destinations){
} }
function addressTruncate(address, range){ function addressTruncate(address, range){
if(typeof(address) === "undefined") return;
if(typeof(range) === "undefined") range = 8; if(typeof(range) === "undefined") range = 8;
return address.substring(0, range) + "..." + address.substring(address.length-range); return address.substring(0, range) + "..." + address.substring(address.length-range);
} }

View file

@ -87,3 +87,23 @@ function ago(epoch) {
} }
} }
} }
function netTypeToString(){
// 0: mainnet, 1: testnet, 2: stagenet
var nettype = appWindow.persistentSettings.nettype;
return nettype == 1 ? qsTr("Testnet") : nettype == 2 ? qsTr("Stagenet") : qsTr("Mainnet");
}
function randomChoice(arr){
return arr[Math.floor(Math.random() * arr.length)];
}
function filterNodes(nodes, port) {
if(typeof data === 'number')
port = port.toString();
return nodes.filter(function(_){return _.indexOf(port) !== -1});
}
function epoch(){
return Math.floor((new Date).getTime()/1000);
}

179
js/Wizard.js Normal file
View file

@ -0,0 +1,179 @@
.pragma library
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name, extra_parameters) {
// Switch to recover from keys
recoverFromSeedMode = false
spendkey.text = ""
viewKeyLine.text = ""
restoreHeightItem.text = ""
if(typeof extra_parameters.secret_view_key != "undefined") {
viewKeyLine.text = extra_parameters.secret_view_key
}
if(typeof extra_parameters.secret_spend_key != "undefined") {
spendkey.text = extra_parameters.secret_spend_key
}
if(typeof extra_parameters.restore_height != "undefined") {
restoreHeightItem.text = extra_parameters.restore_height
}
addressLine.text = address
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
// Check if keys are correct
checkNextButton();
}
function restart(){
wizard.currentPage = 0;
wizard.settings = ({})
wizard.currentPath = "create_wallet"
wizard.pages = paths[currentPath]
wizardRestarted();
//hide all pages except first
for (var i = 1; i < wizard.pages.length; i++){
wizard.pages[i].opacity = 0;
}
//Show first pages
wizard.pages[0].opacity = 1;
}
function switchPage(next) {
// Android focus workaround
releaseFocus();
// save settings for current page;
if (next && typeof pages[currentPage].onPageClosed !== 'undefined') {
if (pages[currentPage].onPageClosed(settings) !== true) {
print ("Can't go to the next page");
return;
};
}
console.log("switchpage: currentPage: ", currentPage);
// Update prev/next button positions for mobile/desktop
prevButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
prevButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
nextButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
nextButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
if (currentPage > 0 || currentPage < pages.length - 1) {
pages[currentPage].opacity = 0
var step_value = next ? 1 : -1
currentPage += step_value
pages[currentPage].opacity = 1;
var nextButtonVisible = currentPage > 1 && currentPage < pages.length - 1
nextButton.visible = nextButtonVisible
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
pages[currentPage].onPageOpened(settings,next)
}
}
}
function openRecoveryWalletPage() {
wizardRestarted();
print ("show recovery wallet page");
currentPath = "recovery_wallet"
pages = paths[currentPath]
// Create temporary wallet
createWalletPage.createWallet(settings)
wizard.nextButton.visible = true
// goto next page
switchPage(true);
}
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 openCreateWalletFromDevicePage() {
wizardRestarted();
print ("show create wallet from device page");
currentPath = "create_wallet_from_device"
pages = paths[currentPath]
wizard.nextButton.visible = true
// goto next page
switchPage(true);
}
function createWalletPath(isIOS, folder_path,account_name){
// Remove trailing slash - (default on windows and mac)
if (folder_path.substring(folder_path.length -1) === "/"){
folder_path = folder_path.substring(0,folder_path.length -1)
}
// Store releative path on ios.
if(isIOS)
folder_path = "";
return folder_path + "/" + account_name + "/" + account_name
}
function walletPathExists(directory, filename, isIOS, walletManager) {
if(!filename || filename === "") return false;
if(!directory || directory === "") return false;
// make sure directory endswith path seperator
// @TODO: use .endswith() after Qt 5.8
var trailing_path_sep = directory[directory.length-1];
if(trailing_path_sep !== "/" && trailing_path_sep !== "\\")
directory += "/"
if(isIOS)
var path = moneroAccountsDir + filename;
else
var path = directory + filename + "/" + filename;
if (walletManager.walletExists(path))
return true;
return false;
}
function isAscii(str){
for (var i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 127)
return false;
}
return true;
}
function tr(text) {
return qsTr(text) + translationManager.emptyString
}
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$/, '')
}
function checkSeed(seed) {
console.log("Checking seed")
var wordsArray = lineBreaksToSpaces(seed).split(" ");
return wordsArray.length === 25 || wordsArray.length === 24
}
function restoreWalletCheckViewSpendAddress(walletmanager, nettype, viewkey, spendkey, addressline){
var addressOK = (viewkey.length > 0 || spendkey.length > 0) ? walletmanager.addressValid(addressline, nettype) : false
var viewKeyOK = (viewkey.length > 0) ? walletmanager.keyValid(viewkey, addressline, true, nettype) : true
// Spendkey is optional
var spendKeyOK = (spendkey.length > 0) ? walletmanager.keyValid(spendkey, addressline, false, nettype) : true
return addressOK && viewKeyOK && spendKeyOK
}

163
main.qml
View file

@ -37,8 +37,8 @@ import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0 import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0 import moneroComponents.NetworkType 1.0
import "components" import "components"
import "components" as MoneroComponents
import "wizard" import "wizard"
import "js/Utils.js" as Utils import "js/Utils.js" as Utils
import "js/Windows.js" as Windows import "js/Windows.js" as Windows
@ -73,6 +73,7 @@ ApplicationWindow {
property int blocksToSync: 1 property int blocksToSync: 1
property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true
property bool isMining: false property bool isMining: false
property int walletMode: persistentSettings.walletMode
property var cameraUi property var cameraUi
property bool remoteNodeConnected: false property bool remoteNodeConnected: false
property bool androidCloseTapped: false; property bool androidCloseTapped: false;
@ -81,7 +82,21 @@ ApplicationWindow {
readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort(persistentSettings.nettype) readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort(persistentSettings.nettype)
property string currentDaemonAddress; property string currentDaemonAddress;
property bool startLocalNodeCancelled: false property bool startLocalNodeCancelled: false
property int estimatedBlockchainSize: 50 // GB property int disconnectedEpoch: 0
property int estimatedBlockchainSize: 75 // GB
property alias viewState: rootItem.state
property string remoteNodeService: {
// support user-defined remote node aggregators
if(persistentSettings.remoteNodeService){
var service = persistentSettings.remoteNodeService;
if(service.charAt(service.length-1) !== "/")
service += "/";
return service;
}
return "https://autonode.xmr.pm/"; // monero-gui workgroup
}
// true if wallet ever synchronized // true if wallet ever synchronized
property bool walletInitialized : false property bool walletInitialized : false
@ -186,10 +201,12 @@ ApplicationWindow {
restoreHeight = 0; restoreHeight = 0;
persistentSettings.is_recovering = false persistentSettings.is_recovering = false
walletPassword = "" walletPassword = ""
fileDialog.folder = "file://" + moneroAccountsDir
fileDialog.open(); fileDialog.open();
} }
function initialize() { function initialize() {
appWindow.viewState = "normal";
console.log("initializing..") console.log("initializing..")
// Use stored log level // Use stored log level
@ -213,19 +230,17 @@ ApplicationWindow {
closeWallet(); closeWallet();
currentWallet = undefined currentWallet = undefined
} else if (!walletInitialized) { } else if (!walletInitialized) {
// set page to transfer if not changing daemon // set page to transfer if not changing daemon
middlePanel.state = "Transfer"; middlePanel.state = "Transfer";
leftPanel.selectItem(middlePanel.state) leftPanel.selectItem(middlePanel.state)
} }
// Local daemon settings // Local daemon settings
walletManager.setDaemonAddress(localDaemonAddress) walletManager.setDaemonAddress(localDaemonAddress)
// enable user inactivity timer // enable timers
userInActivityTimer.running = true; userInActivityTimer.running = true;
simpleModeConnectionTimer.running = true;
// wallet already opened with wizard, we just need to initialize it // wallet already opened with wizard, we just need to initialize it
if (typeof wizard.m_wallet !== 'undefined') { if (typeof wizard.m_wallet !== 'undefined') {
@ -389,8 +404,8 @@ ApplicationWindow {
// Update fee multiplier dropdown on transfer page // Update fee multiplier dropdown on transfer page
middlePanel.transferView.updatePriorityDropdown(); middlePanel.transferView.updatePriorityDropdown();
// If wallet isnt connected and no daemon is running - Ask // If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
if(!isMobile && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){ if(!isMobile && appWindow.walletMode >= 2 && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
daemonManagerDialog.open(); daemonManagerDialog.open();
} }
// initialize transaction history once wallet is initialized first time; // initialize transaction history once wallet is initialized first time;
@ -401,7 +416,7 @@ ApplicationWindow {
// check if daemon was already mining and add mining logo if true // check if daemon was already mining and add mining logo if true
middlePanel.miningView.update(); middlePanel.miningView.update();
} }
} }
function onWalletOpened(wallet) { function onWalletOpened(wallet) {
walletName = usefulName(wallet.path) walletName = usefulName(wallet.path)
@ -414,6 +429,7 @@ ApplicationWindow {
passwordDialog.onRejectedCallback = function() { passwordDialog.onRejectedCallback = function() {
walletPassword = ""; walletPassword = "";
//appWindow.enableUI(false) //appWindow.enableUI(false)
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"; rootItem.state = "wizard";
} }
// opening with password but password doesn't match // opening with password but password doesn't match
@ -426,6 +442,9 @@ ApplicationWindow {
// wallet opened successfully, subscribing for wallet updates // wallet opened successfully, subscribing for wallet updates
connectWallet(wallet) connectWallet(wallet)
// Force switch normal view
rootItem.state = "normal";
} }
@ -527,6 +546,9 @@ ApplicationWindow {
// Pause refresh while starting daemon // Pause refresh while starting daemon
currentWallet.pauseRefresh(); currentWallet.pauseRefresh();
// Pause simplemode connection timer
simpleModeConnectionTimer.stop();
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start...")) appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress); daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress);
persistentSettings.daemonFlags = flags persistentSettings.daemonFlags = flags
@ -544,6 +566,8 @@ ApplicationWindow {
currentWallet.connected(true); currentWallet.connected(true);
// resume refresh // resume refresh
currentWallet.startRefresh(); currentWallet.startRefresh();
// resume simplemode connection timer
simpleModeConnectionTimer.start();
} }
function onDaemonStopped(){ function onDaemonStopped(){
console.log("daemon stopped"); console.log("daemon stopped");
@ -938,11 +962,13 @@ ApplicationWindow {
closeWallet(); closeWallet();
currentWallet = undefined; currentWallet = undefined;
wizard.restart(); wizard.restart();
wizard.wizardState = "wizardHome";
rootItem.state = "wizard" rootItem.state = "wizard"
// reset balance // reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0); leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
// disable inactivity timer // disable timers
userInActivityTimer.running = false; userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false;
} }
function hideMenu() { function hideMenu() {
@ -1004,6 +1030,7 @@ ApplicationWindow {
initialize(persistentSettings); initialize(persistentSettings);
} }
passwordDialog.onRejectedCallback = function() { passwordDialog.onRejectedCallback = function() {
wizard.wizardState = "wizardHome";
rootItem.state = "wizard" rootItem.state = "wizard"
} }
passwordDialog.open(usefulName(walletPath())) passwordDialog.open(usefulName(walletPath()))
@ -1048,12 +1075,15 @@ ApplicationWindow {
property bool useRemoteNode: false property bool useRemoteNode: false
property string remoteNodeAddress: "" property string remoteNodeAddress: ""
property string bootstrapNodeAddress: "" property string bootstrapNodeAddress: ""
property string remoteNodeRegion: ""
property bool segregatePreForkOutputs: true property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true property bool keyReuseMitigation2: true
property int segregationHeight: 0 property int segregationHeight: 0
property int kdfRounds: 1 property int kdfRounds: 1
property bool hideBalance: false property bool hideBalance: false
property bool lockOnUserInActivity: true property bool lockOnUserInActivity: true
property int walletMode: 2
property string remoteNodeService: ""
property int lockOnUserInActivityInterval: 10 // minutes property int lockOnUserInActivityInterval: 10 // minutes
property bool showPid: false property bool showPid: false
} }
@ -1116,11 +1146,11 @@ ApplicationWindow {
//Open Wallet from file //Open Wallet from file
FileDialog { FileDialog {
id: fileDialog id: fileDialog
title: "Please choose a file" title: qsTr("Please choose a file")
folder: "file://" +moneroAccountsDir folder: "file://" + moneroAccountsDir
nameFilters: [ "Wallet files (*.keys)"] nameFilters: [ "Wallet files (*.keys)"]
sidebarVisible: false sidebarVisible: false
visible: false
onAccepted: { onAccepted: {
persistentSettings.wallet_path = walletManager.urlToLocalPath(fileDialog.fileUrl) persistentSettings.wallet_path = walletManager.urlToLocalPath(fileDialog.fileUrl)
@ -1135,7 +1165,8 @@ ApplicationWindow {
initialize(); initialize();
} }
passwordDialog.onRejectedCallback = function() { passwordDialog.onRejectedCallback = function() {
console.log("Canceled") console.log("Canceled");
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"; rootItem.state = "wizard";
} }
passwordDialog.open(usefulName(walletPath())); passwordDialog.open(usefulName(walletPath()));
@ -1150,27 +1181,31 @@ ApplicationWindow {
// Choose blockchain folder // Choose blockchain folder
FileDialog { FileDialog {
id: blockchainFileDialog id: blockchainFileDialog
property string directory: ""
signal changed();
title: "Please choose a folder" title: "Please choose a folder"
selectFolder: true selectFolder: true
folder: "file://" + persistentSettings.blockchainDataDir folder: "file://" + persistentSettings.blockchainDataDir
onRejected: console.log("data dir selection canceled")
onAccepted: { onAccepted: {
var dataDir = walletManager.urlToLocalPath(blockchainFileDialog.fileUrl) var dataDir = walletManager.urlToLocalPath(blockchainFileDialog.fileUrl)
var validator = daemonManager.validateDataDir(dataDir); var validator = daemonManager.validateDataDir(dataDir);
if(!validator.valid) { if(validator.valid) {
persistentSettings.blockchainDataDir = dataDir;
} else {
confirmationDialog.title = qsTr("Warning") + translationManager.emptyString; confirmationDialog.title = qsTr("Warning") + translationManager.emptyString;
confirmationDialog.text = ""; confirmationDialog.text = "";
if(validator.readOnly) if(validator.readOnly)
confirmationDialog.text += qsTr("Error: Filesystem is read only") + "\n\n" confirmationDialog.text += qsTr("Error: Filesystem is read only") + "\n\n"
if(validator.storageAvailable < 20) if(validator.storageAvailable < estimatedBlockchainSize)
confirmationDialog.text += qsTr("Warning: There's only %1 GB available on the device. Blockchain requires ~%2 GB of data.").arg(validator.storageAvailable).arg(estimatedBlockchainSize) + "\n\n" confirmationDialog.text += qsTr("Warning: There's only %1 GB available on the device. Blockchain requires ~%2 GB of data.").arg(validator.storageAvailable).arg(estimatedBlockchainSize) + "\n\n"
else else
confirmationDialog.text += qsTr("Note: There's %1 GB available on the device. Blockchain requires ~%2 GB of data.").arg(validator.storageAvailable).arg(estimatedBlockchainSize) + "\n\n" confirmationDialog.text += qsTr("Note: There's %1 GB available on the device. Blockchain requires ~%2 GB of data.").arg(validator.storageAvailable).arg(estimatedBlockchainSize) + "\n\n"
if(!validator.lmdbExists) if(!validator.lmdbExists)
confirmationDialog.text += qsTr("Note: lmdb folder not found. A new folder will be created.") + "\n\n" confirmationDialog.text += qsTr("Note: lmdb folder not found. A new folder will be created.") + "\n\n"
confirmationDialog.icon = StandardIcon.Question confirmationDialog.icon = StandardIcon.Question
confirmationDialog.cancelText = qsTr("Cancel") confirmationDialog.cancelText = qsTr("Cancel")
@ -1180,25 +1215,15 @@ ApplicationWindow {
} }
// Cancel // Cancel
confirmationDialog.onRejectedCallback = function() { confirmationDialog.onRejectedCallback = function() { };
};
confirmationDialog.open() confirmationDialog.open()
} else {
persistentSettings.blockchainDataDir = dataDir
} }
blockchainFileDialog.directory = blockchainFileDialog.fileUrl;
delete validator; delete validator;
} }
onRejected: {
console.log("data dir selection canceled")
}
} }
PasswordDialog { PasswordDialog {
id: passwordDialog id: passwordDialog
visible: false visible: false
@ -1287,19 +1312,16 @@ ApplicationWindow {
PropertyChanges { target: leftPanel; visible: false } PropertyChanges { target: leftPanel; visible: false }
PropertyChanges { target: rightPanel; visible: false } PropertyChanges { target: rightPanel; visible: false }
PropertyChanges { target: middlePanel; visible: false } PropertyChanges { target: middlePanel; visible: false }
PropertyChanges { target: titleBar; basicButtonVisible: false }
PropertyChanges { target: wizard; visible: true } PropertyChanges { target: wizard; visible: true }
PropertyChanges { target: appWindow; width: (screenWidth < 930 || isAndroid || isIOS)? screenWidth : 930; } PropertyChanges { target: appWindow; width: (screenWidth < 969 || isAndroid || isIOS)? screenWidth : 969 } //rightPanelExpanded ? 1269 : 1269 - 300;
PropertyChanges { target: appWindow; height: maxWindowHeight; } PropertyChanges { target: appWindow; height: maxWindowHeight; }
PropertyChanges { target: resizeArea; visible: true } PropertyChanges { target: resizeArea; visible: true }
PropertyChanges { target: titleBar; showMaximizeButton: true }
// PropertyChanges { target: frameArea; blocked: true } // PropertyChanges { target: frameArea; blocked: true }
PropertyChanges { target: titleBar; visible: true }
PropertyChanges { target: titleBar; y: 0 }
PropertyChanges { target: titleBar; showMoneroLogo: false }
PropertyChanges { target: titleBar; titleBarGradientImageOpacity: 0.2 }
PropertyChanges { target: titleBar; small: true }
PropertyChanges { target: mobileHeader; visible: false } PropertyChanges { target: mobileHeader; visible: false }
PropertyChanges { target: titleBar; basicButtonVisible: false }
PropertyChanges { target: titleBar; showMaximizeButton: true }
PropertyChanges { target: titleBar; visible: true }
PropertyChanges { target: titleBar; title: qsTr("Monero") + translationManager.emptyString }
}, State { }, State {
name: "normal" name: "normal"
PropertyChanges { target: leftPanel; visible: (isMobile)? false : true } PropertyChanges { target: leftPanel; visible: (isMobile)? false : true }
@ -1573,17 +1595,13 @@ ApplicationWindow {
// } // }
} }
WizardMain { WizardController {
id: wizard id: wizard
anchors.fill: parent anchors.fill: parent
onUseMoneroClicked: { onUseMoneroClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow; rootItem.state = "normal";
appWindow.initialize(); appWindow.initialize();
} }
onOpenWalletFromFileClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow;
appWindow.openWalletFromFile();
}
} }
property int minWidth: 326 property int minWidth: 326
@ -1730,6 +1748,50 @@ ApplicationWindow {
onTriggered: checkInUserActivity() onTriggered: checkInUserActivity()
} }
function checkSimpleModeConnection(){
// auto-connection mechanism for simple mode
if(persistentSettings.nettype != NetworkType.MAINNET) return;
if(appWindow.walletMode >= 2) return;
var disconnected = leftPanel.networkStatus.connected === Wallet.ConnectionStatus_Disconnected;
var disconnectedEpoch = appWindow.disconnectedEpoch;
if(disconnectedEpoch === 0){
appWindow.disconnectedEpoch = Utils.epoch();
}
// disconnected longer than 5 seconds?
if(disconnected && disconnectedEpoch > 0 && (Utils.epoch() - disconnectedEpoch) >= 5){
// for bootstrap mode, first wait until daemon is killed
if(appWindow.walletMode === 1 && appWindow.daemonRunning) {
appWindow.stopDaemon();
return;
}
// fetch new node list
wizard.fetchRemoteNodes(function() {
// fetched node, connect
if(appWindow.walletMode === 0){
appWindow.connectRemoteNode();
} else if(appWindow.walletMode === 1){
appWindow.startDaemon(persistentSettings.daemonFlags);
}
// reset state
appWindow.disconnectedEpoch = 0;
return;
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), simpleModeConnectionTimer.interval / 1000);
});
}
}
Timer {
// Simple mode connection check timer
id: simpleModeConnectionTimer
interval: 2000; running: false; repeat: true
onTriggered: appWindow.checkSimpleModeConnection()
}
Rectangle { Rectangle {
id: statusMessage id: statusMessage
z: 99 z: 99
@ -1873,6 +1935,7 @@ ApplicationWindow {
} }
function checkInUserActivity() { function checkInUserActivity() {
if(rootItem.state !== "normal") return;
if(!persistentSettings.lockOnUserInActivity) return; if(!persistentSettings.lockOnUserInActivity) return;
// prompt password after X seconds of inactivity // prompt password after X seconds of inactivity
@ -1903,6 +1966,14 @@ ApplicationWindow {
} }
} }
function changeWalletMode(mode){
appWindow.walletMode = mode;
persistentSettings.walletMode = mode;
persistentSettings.useRemoteNode = mode === 0 ? true : false;
console.log("walletMode changed: " + (mode === 0 ? "simple": mode === 1 ? "simple (bootstrap)" : "Advanced"));
}
// Daemon console // Daemon console
DaemonConsole { DaemonConsole {
id: daemonConsolePopup id: daemonConsolePopup
@ -1922,4 +1993,8 @@ ApplicationWindow {
color: "black" color: "black"
opacity: 0.8 opacity: 0.8
} }
MoneroComponents.LanguageSidebar {
id: languageSidebar
}
} }

View file

@ -462,10 +462,7 @@ OTHER_FILES += \
DISTFILES += \ DISTFILES += \
notes.txt \ notes.txt \
monero/src/wallet/CMakeLists.txt \ monero/src/wallet/CMakeLists.txt
components/MobileHeader.qml \
pages/merchant/Merchant.qml \
pages/merchant/MerchantCheckbox.qml
# windows application icon # windows application icon

View file

@ -325,6 +325,7 @@ Rectangle {
} }
function clearFields() { function clearFields() {
// @TODO: add fields
} }
function onPageClosed() { function onPageClosed() {

View file

@ -443,6 +443,7 @@ Rectangle {
enabled: !viewOnly || pageRoot.enabled enabled: !viewOnly || pageRoot.enabled
RowLayout { RowLayout {
visible: appWindow.walletMode >= 2
CheckBox2 { CheckBox2 {
id: showAdvancedCheckbox id: showAdvancedCheckbox
checked: persistentSettings.transferShowAdvanced checked: persistentSettings.transferShowAdvanced
@ -454,7 +455,7 @@ Rectangle {
} }
GridLayout { GridLayout {
visible: persistentSettings.transferShowAdvanced visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
columns: (isMobile) ? 2 : 6 columns: (isMobile) ? 2 : 6
StandardButton { StandardButton {
@ -676,9 +677,11 @@ Rectangle {
//TODO: enable send page when we're connected and daemon is synced //TODO: enable send page when we're connected and daemon is synced
function updateStatus() { function updateStatus() {
var messageNotConnected = qsTr("Wallet is not connected to daemon.");
if(appWindow.walletMode >= 2) messageNotConnected += root.startLinkText;
pageRoot.enabled = true; pageRoot.enabled = true;
if(typeof currentWallet === "undefined") { if(typeof currentWallet === "undefined") {
root.warningContent = qsTr("Wallet is not connected to daemon.") + root.startLinkText root.warningContent = messageNotConnected;
return; return;
} }
@ -690,7 +693,7 @@ Rectangle {
switch (currentWallet.connected()) { switch (currentWallet.connected()) {
case Wallet.ConnectionStatus_Disconnected: case Wallet.ConnectionStatus_Disconnected:
root.warningContent = qsTr("Wallet is not connected to daemon.") + root.startLinkText root.warningContent = messageNotConnected;
break break
case Wallet.ConnectionStatus_WrongVersion: case Wallet.ConnectionStatus_WrongVersion:
root.warningContent = qsTr("Connected daemon is not compatible with GUI. \n" + root.warningContent = qsTr("Connected daemon is not compatible with GUI. \n" +
@ -698,7 +701,7 @@ Rectangle {
break break
default: default:
if(!appWindow.daemonSynced){ if(!appWindow.daemonSynced){
root.warningContent = qsTr("Waiting on daemon synchronization to finish") root.warningContent = qsTr("Waiting on daemon synchronization to finish.")
} else { } else {
// everything OK, enable transfer page // everything OK, enable transfer page
// Light wallet is always ready // Light wallet is always ready

View file

@ -182,6 +182,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
// NODE // NODE
id: navNode id: navNode
visible: appWindow.walletMode >= 2
Layout.preferredWidth: navNodeText.width + grid.textMargin Layout.preferredWidth: navNodeText.width + grid.textMargin
Layout.preferredHeight: 32 Layout.preferredHeight: 32
Layout.minimumWidth: 72 * scaleRatio Layout.minimumWidth: 72 * scaleRatio
@ -225,6 +226,7 @@ Rectangle {
} }
} }
Rectangle{ Rectangle{
visible: appWindow.walletMode >= 2
Layout.preferredWidth: 1 Layout.preferredWidth: 1
Layout.preferredHeight: 32 Layout.preferredHeight: 32
color: grid.borderColor color: grid.borderColor
@ -232,6 +234,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
// LOG // LOG
id: navLog id: navLog
visible: appWindow.walletMode >= 2
Layout.preferredWidth: navLogText.width + grid.textMargin Layout.preferredWidth: navLogText.width + grid.textMargin
Layout.preferredHeight: 32 Layout.preferredHeight: 32
Layout.minimumWidth: 72 * scaleRatio Layout.minimumWidth: 72 * scaleRatio
@ -275,6 +278,7 @@ Rectangle {
} }
} }
Rectangle{ Rectangle{
visible: appWindow.walletMode >= 2
Layout.preferredWidth: 1 Layout.preferredWidth: 1
Layout.preferredHeight: 32 Layout.preferredHeight: 32
color: grid.borderColor color: grid.borderColor

View file

@ -39,6 +39,15 @@ Rectangle {
color: "transparent" color: "transparent"
height: 1400 * scaleRatio height: 1400 * scaleRatio
Layout.fillWidth: true Layout.fillWidth: true
property string walletModeString: {
if(appWindow.walletMode === 0){
return qsTr("Simple mode") + translationManager.emptyString;
} else if(appWindow.walletMode === 1){
return qsTr("Simple mode") + " (bootstrap)" + translationManager.emptyString;
} else if(appWindow.walletMode === 2){
return qsTr("Advanced mode") + translationManager.emptyString;
}
}
ColumnLayout { ColumnLayout {
id: infoLayout id: infoLayout
@ -239,6 +248,36 @@ Rectangle {
font.pixelSize: 14 * scaleRatio font.pixelSize: 14 * scaleRatio
text: walletLogPath text: walletLogPath
} }
Rectangle {
height: 1
Layout.topMargin: 2 * scaleRatio
Layout.bottomMargin: 2 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
Rectangle {
height: 1
Layout.topMargin: 2 * scaleRatio
Layout.bottomMargin: 2 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
MoneroComponents.TextBlock {
Layout.fillWidth: true
font.pixelSize: 14 * scaleRatio
text: qsTr("Wallet mode: ") + translationManager.emptyString
}
MoneroComponents.TextBlock {
Layout.fillWidth: true
font.pixelSize: 14 * scaleRatio
text: walletModeString
}
} }
// Copy info to clipboard // Copy info to clipboard
@ -261,6 +300,7 @@ Rectangle {
data += currentWallet.walletCreationHeight; data += currentWallet.walletCreationHeight;
data += "\nWallet log path: " + walletLogPath; data += "\nWallet log path: " + walletLogPath;
data += "\nWallet mode: " + walletModeString;
console.log("Copied to clipboard"); console.log("Copied to clipboard");
clipboard.setText(data); clipboard.setText(data);

View file

@ -164,6 +164,17 @@ Rectangle {
} }
} }
MoneroComponents.StandardButton {
visible: !persistentSettings.customDecorations
Layout.topMargin: 10 * scaleRatio
small: true
text: "Change language"
onClicked: {
languageSidebar.isOpened ? languageSidebar.close() : languageSidebar.open();
}
}
MoneroComponents.TextBlock { MoneroComponents.TextBlock {
visible: isMobile visible: isMobile
font.pixelSize: 14 font.pixelSize: 14

View file

@ -258,6 +258,7 @@ Rectangle {
} }
GridLayout { GridLayout {
visible: appWindow.walletMode >= 2
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: settingsWallet.itemHeight Layout.preferredHeight: settingsWallet.itemHeight
columnSpacing: 0 columnSpacing: 0
@ -326,6 +327,7 @@ Rectangle {
} }
Rectangle { Rectangle {
// divider // divider
visible: appWindow.walletMode >= 2
Layout.preferredHeight: 1 * scaleRatio Layout.preferredHeight: 1 * scaleRatio
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 * scaleRatio Layout.topMargin: 8 * scaleRatio

57
qml.qrc
View file

@ -62,23 +62,13 @@
<file>images/resize@2x.png</file> <file>images/resize@2x.png</file>
<file>images/resizeHovered.png</file> <file>images/resizeHovered.png</file>
<file>images/resizeHovered@2x.png</file> <file>images/resizeHovered@2x.png</file>
<file>wizard/WizardWelcome.qml</file>
<file>wizard/WizardMain.qml</file>
<file>images/nextPage.png</file> <file>images/nextPage.png</file>
<file>images/nextPage@2x.png</file> <file>images/nextPage@2x.png</file>
<file>wizard/WizardOptions.qml</file>
<file>images/createWallet.png</file> <file>images/createWallet.png</file>
<file>images/createWalletFromDevice.png</file> <file>images/createWalletFromDevice.png</file>
<file>images/openAccount.png</file> <file>images/openAccount.png</file>
<file>images/recoverWallet.png</file> <file>images/recoverWallet.png</file>
<file>wizard/WizardCreateWallet.qml</file>
<file>wizard/WizardCreateWalletFromDevice.qml</file>
<file>images/copyToClipboard.png</file> <file>images/copyToClipboard.png</file>
<file>wizard/WizardPassword.qml</file>
<file>wizard/WizardConfigure.qml</file>
<file>wizard/WizardDonation.qml</file>
<file>wizard/WizardFinish.qml</file>
<file>wizard/WizardPasswordInput.qml</file>
<file>lang/languages.xml</file> <file>lang/languages.xml</file>
<file>lang/flags/bd.png</file> <file>lang/flags/bd.png</file>
<file>lang/flags/bg.png</file> <file>lang/flags/bg.png</file>
@ -123,10 +113,6 @@
<file>lang/flags/gb.png</file> <file>lang/flags/gb.png</file>
<file>lang/flags/us.png</file> <file>lang/flags/us.png</file>
<file>lang/flags/pirate.png</file> <file>lang/flags/pirate.png</file>
<file>wizard/WizardManageWalletUI.qml</file>
<file>wizard/WizardRecoveryWallet.qml</file>
<file>wizard/WizardMemoTextInput.qml</file>
<file>wizard/utils.js</file>
<file>pages/Receive.qml</file> <file>pages/Receive.qml</file>
<file>pages/TxKey.qml</file> <file>pages/TxKey.qml</file>
<file>pages/SharedRingDB.qml</file> <file>pages/SharedRingDB.qml</file>
@ -140,14 +126,11 @@
<file>pages/Sign.qml</file> <file>pages/Sign.qml</file>
<file>components/DaemonManagerDialog.qml</file> <file>components/DaemonManagerDialog.qml</file>
<file>version.js</file> <file>version.js</file>
<file>wizard/WizardPasswordUI.qml</file>
<file>wizard/WizardCreateViewOnlyWallet.qml</file>
<file>components/DaemonConsole.qml</file> <file>components/DaemonConsole.qml</file>
<file>components/QRCodeScanner.qml</file> <file>components/QRCodeScanner.qml</file>
<file>components/Notifier.qml</file> <file>components/Notifier.qml</file>
<file>components/MobileHeader.qml</file> <file>components/MobileHeader.qml</file>
<file>components/TextBlock.qml</file> <file>components/TextBlock.qml</file>
<file>wizard/WizardDaemonSettings.qml</file>
<file>components/RemoteNodeEdit.qml</file> <file>components/RemoteNodeEdit.qml</file>
<file>pages/Keys.qml</file> <file>pages/Keys.qml</file>
<file>images/appicon.ico</file> <file>images/appicon.ico</file>
@ -247,5 +230,45 @@
<file>fonts/FontAwesome/FontAwesome.qml</file> <file>fonts/FontAwesome/FontAwesome.qml</file>
<file>fonts/FontAwesome/Object.qml</file> <file>fonts/FontAwesome/Object.qml</file>
<file>fonts/FontAwesome/qmldir</file> <file>fonts/FontAwesome/qmldir</file>
<file>wizard/WizardAskPassword.qml</file>
<file>wizard/WizardController.qml</file>
<file>wizard/WizardCreateWallet1.qml</file>
<file>wizard/WizardCreateWallet2.qml</file>
<file>wizard/WizardCreateWallet3.qml</file>
<file>wizard/WizardCreateWallet4.qml</file>
<file>wizard/WizardCreateDevice1.qml</file>
<file>wizard/WizardDaemonSettings.qml</file>
<file>wizard/WizardHeader.qml</file>
<file>wizard/WizardHome.qml</file>
<file>wizard/WizardLanguage.qml</file>
<file>wizard/WizardNav.qml</file>
<file>wizard/WizardWalletInput.qml</file>
<file>wizard/WizardRestoreWallet1.qml</file>
<file>wizard/WizardRestoreWallet2.qml</file>
<file>wizard/WizardRestoreWallet3.qml</file>
<file>wizard/WizardRestoreWallet4.qml</file>
<file>wizard/WizardSummary.qml</file>
<file>wizard/WizardSummaryItem.qml</file>
<file>wizard/WizardModeSelection.qml</file>
<file>wizard/WizardModeRemoteNodeWarning.qml</file>
<file>wizard/WizardModeBootstrap.qml</file>
<file>wizard/WizardMenuItem.qml</file>
<file>js/Wizard.js</file>
<file>components/LanguageSidebar.qml</file>
<file>images/world-flags-globe.png</file>
<file>images/langFlagGrey.png</file>
<file>images/restore-wallet-from-hardware@2x.png</file>
<file>images/restore-wallet-from-hardware.png</file>
<file>images/open-wallet-from-file@2x.png</file>
<file>images/open-wallet-from-file.png</file>
<file>images/restore-wallet@2x.png</file>
<file>images/restore-wallet.png</file>
<file>images/create-wallet@2x.png</file>
<file>images/create-wallet.png</file>
<file>images/remote-node.png</file>
<file>images/local-node.png</file>
<file>images/local-node-full.png</file>
<file>wizard/WizardNavProgressDot.qml</file>
<file>wizard/WizardOpenWallet1.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -275,9 +275,9 @@ QVariantMap DaemonManager::validateDataDir(const QString &dataDir) const
valid = false; valid = false;
} }
// Make sure there is 20GB storage available // Make sure there is 75GB storage available
storageAvailable = storage.bytesAvailable()/1000/1000/1000; storageAvailable = storage.bytesAvailable()/1000/1000/1000;
if (storageAvailable < 20) { if (storageAvailable < 75) {
valid = false; valid = false;
} }
} else { } else {

View file

@ -0,0 +1,259 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
ColumnLayout {
id: root
Layout.fillWidth: true
property alias password: passwordInput.text
property int passwordFill: 0
property string passwordStrengthText: qsTr("Strength: ") + translationManager.emptyString
function calcStrengthAndVerify(){
calcPasswordStrength();
return passwordInput.text === passwordInputConfirm.text;
}
function calcPasswordStrength(inp) {
if(isAndroid) return;
if(passwordInput.text.length <= 1){
root.passwordFill = 0;
progressText.text = passwordStrengthText + qsTr("Low") + translationManager.emptyString;
}
// scorePassword returns value from 0 to... lots
var strength = walletManager.getPasswordStrength(passwordInput.text);
// 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
strength += 20;
if (strength > 100)
strength = 100;
root.passwordFill = strength;
var strengthString;
if(strength <= 33){
strengthString = qsTr("Low");
} else if(strength <= 66){
strengthString = qsTr("Medium");
} else {
strengthString = qsTr("High");
}
progressText.text = passwordStrengthText + strengthString + translationManager.emptyString;
}
spacing: 20 * scaleRatio
WizardHeader{
title: qsTr("Give your wallet a password") + translationManager.emptyString
subtitle: qsTr("This password cannot be recovered. If you forget it then the wallet will have to be restored from its 25 word mnemonic seed.") + translationManager.emptyString
}
MoneroComponents.WarningBox {
text: qsTr("<b>Enter a strong password</b> (Using letters, numbers, and/or symbols).") + translationManager.emptyString
}
ColumnLayout {
spacing: 0
visible: !isAndroid
Layout.fillWidth: true
TextInput {
id: progressText
anchors.top: parent.top
anchors.topMargin: 6
font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 14 * scaleRatio
font.bold: false
color: MoneroComponents.Style.defaultFontColor
text: root.passwordStrengthText + '-'
height: 18 * scaleRatio
passwordCharacter: "*"
}
TextInput {
id: progressTextValue
font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 13 * scaleRatio
font.bold: true
color: MoneroComponents.Style.defaultFontColor
height:18 * scaleRatio
passwordCharacter: "*"
}
Rectangle {
id: bar
Layout.fillWidth: true
Layout.preferredHeight: 8
radius: 8 * scaleRatio
color: "#333333" // progressbar bg
Rectangle {
id: fillRect
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
height: bar.height
property int maxWidth: bar.width * scaleRatio
width: (maxWidth * root.passwordFill) / 100
radius: 8
color: "#FA6800"
}
Rectangle {
color:"#333"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: 8 * scaleRatio
}
}
}
ColumnLayout {
spacing: 4 * scaleRatio
Layout.fillWidth: true
Label {
text: qsTr("Password")
Layout.fillWidth: true
font.pixelSize: 14 * scaleRatio
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id: passwordInput
Layout.topMargin: 6 * scaleRatio
Layout.fillWidth: true
bottomPadding: 10 * scaleRatio
leftPadding: 10 * scaleRatio
topPadding: 10 * scaleRatio
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
echoMode: TextInput.Password
KeyNavigation.tab: passwordInputConfirm
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 15 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
text: walletOptionsPassword
background: Rectangle {
radius: 4
border.color: Qt.rgba(255, 255, 255, 0.35)
border.width: 1
color: "transparent"
Image {
width: 12 * scaleRatio
height: 16 * scaleRatio
source: "../images/lockIcon.png"
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 20
}
}
}
}
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Label {
text: qsTr("Password (confirm)") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 14 * scaleRatio
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInputConfirm
Layout.topMargin: 6 * scaleRatio
Layout.fillWidth: true
bottomPadding: 10 * scaleRatio
leftPadding: 10 * scaleRatio
topPadding: 10 * scaleRatio
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
echoMode: TextInput.Password
KeyNavigation.tab: passwordInputConfirm
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 15 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
text: walletOptionsPassword
background: Rectangle {
radius: 4
border.color: Qt.rgba(255, 255, 255, 0.35)
border.width: 1
color: "transparent"
Image {
width: 12
height: 16
source: "../images/lockIcon.png"
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 20
}
}
}
}
}

View file

@ -1,175 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import "../components"
Item {
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
Row {
id: dotsRow
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 85
spacing: 6
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
ListElement { dotColor: "#DBDBDB" }
}
Repeater {
model: dotsModel
delegate: Rectangle {
width: 12; height: 12
radius: 6
color: dotColor
}
}
}
Text {
id: headerText
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 74
anchors.leftMargin: 16
width: parent.width - dotsRow.width - 16
font.family: "Arial"
font.pixelSize: 28
wrapMode: Text.Wrap
//renderType: Text.NativeRendering
color: "#3F3F3F"
text: qsTr("Were almost there - lets just configure some Monero preferences") + translationManager.emptyString
}
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: headerText.bottom
anchors.topMargin: 34
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 24
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 12
CheckBox {
text: qsTr("Kickstart the Monero blockchain?") + translationManager.emptyString
anchors.left: parent.left
anchors.right: parent.right
background: "#F0EEEE"
fontColor: "#4A4646"
fontSize: 18
checked: true
}
Text {
anchors.left: parent.left
anchors.right: parent.right
font.family: "Arial"
font.pixelSize: 15
color: "#4A4646"
wrapMode: Text.Wrap
text: qsTr("It is very important to write it down as this is the only backup you will need for your wallet.")
+ translationManager.emptyString
}
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 12
CheckBox {
text: qsTr("Enable disk conservation mode?") + translationManager.emptyString
anchors.left: parent.left
anchors.right: parent.right
background: "#F0EEEE"
fontColor: "#4A4646"
fontSize: 18
checked: true
}
Text {
anchors.left: parent.left
anchors.right: parent.right
font.family: "Arial"
font.pixelSize: 15
color: "#4A4646"
wrapMode: Text.Wrap
text: qsTr("Disk conservation mode uses substantially less disk-space, but the same amount of bandwidth as " +
"a regular Monero instance. However, storing the full blockchain is beneficial to the security " +
"of the Monero network. If you are on a device with limited disk space, then this option is appropriate for you.")
+ translationManager.emptyString
}
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 12
CheckBox {
text: qsTr("Allow background mining?") + translationManager.emptyString
anchors.left: parent.left
anchors.right: parent.right
background: "#F0EEEE"
fontColor: "#4A4646"
fontSize: 18
checked: true
}
Text {
anchors.left: parent.left
anchors.right: parent.right
font.family: "Arial"
font.pixelSize: 15
color: "#4A4646"
wrapMode: Text.Wrap
text: qsTr("Mining secures the Monero network, and also pays a small reward for the work done. This option " +
"will let Monero mine when your computer is on mains power and is idle. It will stop mining when you continue working.")
+ translationManager.emptyString
}
}
}
}

484
wizard/WizardController.qml Normal file
View file

@ -0,0 +1,484 @@
// 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.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.2
import moneroComponents.Wallet 1.0
import "../js/Wizard.js" as Wizard
import "../js/Windows.js" as Windows
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
import "../pages"
Rectangle {
id: wizardController
anchors.fill: parent
signal useMoneroClicked()
function restart() {
wizardStateView.state = "wizardHome"
wizardController.walletOptionsName = defaultAccountName;
wizardController.walletOptionsLocation = '';
wizardController.walletOptionsPassword = '';
wizardController.walletOptionsSeed = '';
wizardController.walletOptionsBackup = '';
wizardController.walletRestoreMode = 'seed';
wizardController.walletOptionsRestoreHeight = 0;
wizardController.walletOptionsIsRecovering = false;
wizardController.walletOptionsIsRecoveringFromDevice = false;
wizardController.walletOptionsDeviceName = '';
wizardController.tmpWalletFilename = '';
wizardController.walletRestoreMode = 'seed'
wizardController.walletOptionsSubaddressLookahead = "";
wizardController.remoteNodes = {};
wizardController.walletOptionsIsRecoveringFromDevice = false;
}
property var m_wallet;
property alias wizardState: wizardStateView.state
property alias wizardStatePrevious: wizardStateView.previousView
property int wizardSubViewWidth: 780 * scaleRatio
property int wizardSubViewTopMargin: persistentSettings.customDecorations ? 90 * scaleRatio : 32 * scaleRatio
property bool skipModeSelection: false
// wallet variables
property string walletOptionsName: ''
property string walletOptionsLocation: ''
property string walletOptionsPassword: ''
property string walletOptionsSeed: ''
property string walletOptionsBackup: ''
property int walletOptionsRestoreHeight: 0
property string walletOptionsBootstrapAddress: persistentSettings.bootstrapNodeAddress
property bool walletOptionsRestoringFromDevice: false
property bool walletOptionsIsRecovering: false
property bool walletOptionsIsRecoveringFromDevice: false
property string walletOptionsSubaddressLookahead: ''
property string walletOptionsDeviceName: ''
property string tmpWalletFilename: ''
property var remoteNodes: ''
// language settings, updated via sidebar
property string language_locale: 'en_US'
property string language_wallet: 'English'
property string language_language: 'English (US)'
// recovery made (restore wallet)
property string walletRestoreMode: 'seed' // seed, keys, qr
property int layoutScale: {
if(isMobile){
return 0;
} else if(appWindow.width < 800){
return 1;
} else {
return 2;
}
}
Image {
opacity: 1.0
anchors.fill: parent
source: "../images/middlePanelBg.jpg"
}
Rectangle {
id: wizardStateView
property Item currentView
property Item previousView
property WizardLanguage wizardLanguageView: WizardLanguage { }
property WizardHome wizardHomeView: WizardHome { }
property WizardCreateWallet1 wizardCreateWallet1View: WizardCreateWallet1 { }
property WizardCreateWallet2 wizardCreateWallet2View: WizardCreateWallet2 { }
property WizardCreateWallet3 wizardCreateWallet3View: WizardCreateWallet3 { }
property WizardCreateWallet4 wizardCreateWallet4View: WizardCreateWallet4 { }
property WizardRestoreWallet1 wizardRestoreWallet1View: WizardRestoreWallet1 { }
property WizardRestoreWallet2 wizardRestoreWallet2View: WizardRestoreWallet2 { }
property WizardRestoreWallet3 wizardRestoreWallet3View: WizardRestoreWallet3 { }
property WizardRestoreWallet4 wizardRestoreWallet4View: WizardRestoreWallet4 { }
property WizardCreateDevice1 wizardCreateDevice1View: WizardCreateDevice1 { }
property WizardOpenWallet1 wizardOpenWallet1View: WizardOpenWallet1 { }
property WizardModeSelection wizardModeSelectionView: WizardModeSelection { }
property WizardModeRemoteNodeWarning wizardModeRemoteNodeWarningView: WizardModeRemoteNodeWarning { }
property WizardModeBootstrap wizardModeBootstrapView: WizardModeBootstrap {}
anchors.fill: parent
signal previousClicked;
color: "transparent"
state: ''
onPreviousClicked: {
if (previousView && previousView.viewName != null){
state = previousView.viewName;
} else {
state = "wizardHome";
}
}
onCurrentViewChanged: {
if (previousView) {
if (typeof previousView.onPageClosed === "function") {
previousView.onPageClosed();
}
// Combined with NumberAnimation to fade out views
previousView.opacity = 0;
}
if (currentView) {
stackView.replace(currentView)
// Calls when view is opened
if (typeof currentView.onPageCompleted === "function") {
currentView.onPageCompleted(previousView);
}
// Combined with NumberAnimation to fade in views
currentView.opacity = 1;
}
previousView = currentView;
}
states: [
State {
name: "wizardLanguage"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardLanguageView }
}, State {
name: "wizardHome"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardHomeView }
}, State {
name: "wizardCreateWallet1"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet1View }
}, State {
name: "wizardCreateWallet2"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet2View }
}, State {
name: "wizardCreateWallet3"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet3View }
}, State {
name: "wizardCreateWallet4"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet4View }
}, State {
name: "wizardRestoreWallet1"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet1View }
}, State {
name: "wizardRestoreWallet2"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet2View }
}, State {
name: "wizardRestoreWallet3"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet3View }
}, State {
name: "wizardRestoreWallet4"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet4View }
}, State {
name: "wizardCreateDevice1"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateDevice1View }
}, State {
name: "wizardOpenWallet1"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardOpenWallet1View }
}, State {
name: "wizardModeSelection"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeSelectionView }
}, State {
name: "wizardModeRemoteNodeWarning"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeRemoteNodeWarningView }
}, State {
name: "wizardModeBootstrap"
PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeBootstrapView }
}
]
StackView {
id: stackView
initialItem: wizardStateView.wizardLanguageView
anchors.fill: parent
clip: false
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
PropertyAnimation {
target: enterItem
property: "x"
from: target.width
to: 0
duration: 300
easing.type: Easing.OutCubic
}
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: 0 - target.width
duration: 300
easing.type: Easing.OutCubic
}
}
}
}
}
//Open Wallet from file
FileDialog {
id: fileDialog
title: qsTr("Please choose a file") + translationManager.emptyString
folder: "file://" + moneroAccountsDir
nameFilters: [ "Wallet files (*.keys)"]
sidebarVisible: false
onAccepted: {
wizardController.openWalletFile(fileDialog.fileUrl);
}
onRejected: {
console.log("Canceled")
appWindow.viewState = "wizard";
}
}
function createWallet() {
// Creates wallet in a temp. location
// Always delete the wallet object before creating new - we could be stepping back from recovering wallet
if (typeof wizardController.m_wallet !== 'undefined') {
walletManager.closeWallet()
console.log("deleting wallet")
}
var tmp_wallet_filename = oshelper.temporaryFilename();
console.log("Creating temporary wallet", tmp_wallet_filename)
var nettype = appWindow.persistentSettings.nettype;
var kdfRounds = appWindow.persistentSettings.kdfRounds;
var wallet = walletManager.createWallet(tmp_wallet_filename, "", wizardController.language_wallet, nettype, kdfRounds)
wizardController.walletOptionsSeed = wallet.seed
// saving wallet in "global" object
// @TODO: wallet should have a property pointing to the file where it stored or loaded from
wizardController.m_wallet = wallet;
wizardController.tmpWalletFilename = tmp_wallet_filename
}
function writeWallet() {
// Save wallet files in user specified location
var new_wallet_filename = Wizard.createWalletPath(
isIOS,
wizardController.walletOptionsLocation,
wizardController.walletOptionsName);
if(isIOS) {
console.log("saving in ios: " + moneroAccountsDir + new_wallet_filename)
wizardController.m_wallet.store(moneroAccountsDir + new_wallet_filename);
} else {
console.log("saving in wizard: " + new_wallet_filename)
wizardController.m_wallet.store(new_wallet_filename);
}
// make sure temporary wallet files are deleted
console.log("Removing temporary wallet: " + wizardController.tmpWalletFilename)
oshelper.removeTemporaryWallet(wizardController.tmpWalletFilename)
// protecting wallet with password
m_wallet.setPassword(walletOptionsPassword);
// Store password in session to be able to use password protected functions (e.g show seed)
appWindow.walletPassword = walletOptionsPassword
// save to persistent settings
persistentSettings.language = wizardController.language_language
persistentSettings.locale = wizardController.language_locale
persistentSettings.account_name = wizardController.walletOptionsName
persistentSettings.wallet_path = new_wallet_filename
persistentSettings.restore_height = (isNaN(walletOptionsRestoreHeight))? 0 : walletOptionsRestoreHeight
persistentSettings.allow_background_mining = false
persistentSettings.is_recovering = (wizardController.walletOptionsIsRecovering === undefined) ? false : wizardController.walletOptionsIsRecovering
persistentSettings.is_recovering_from_device = (wizardController.walletOptionsIsRecoveringFromDevice === undefined) ? false : wizardController.walletOptionsIsRecoveringFromDevice
}
function createWalletFromDevice() {
// TODO: create wallet in temporary filename and a) move it to the path specified by user after the final
// page submitted or b) delete it when program closed before reaching final page
// Always delete the wallet object before creating new - we could be stepping back from recovering wallet
if (typeof wizardController.m_wallet !== 'undefined') {
walletManager.closeWallet()
console.log("deleting wallet")
}
var tmp_wallet_filename = oshelper.temporaryFilename();
console.log("Creating temporary wallet", tmp_wallet_filename)
var nettype = persistentSettings.nettype;
var restoreHeight = wizardController.walletOptionsRestoreHeight;
var subaddressLookahead = wizardController.walletOptionsSubaddressLookahead;
var deviceName = wizardController.walletOptionsDeviceName;
var wallet = walletManager.createWalletFromDevice(tmp_wallet_filename, "", nettype, deviceName, restoreHeight, subaddressLookahead);
var success = wallet.status === Wallet.Status_Ok;
if (success) {
wizardController.m_wallet = wallet;
wizardController.walletOptionsIsRecoveringFromDevice = true;
wizardController.tmpWalletFilename = tmp_wallet_filename;
wizardController.walletOptionsRestoreHeight = wizardController.m_wallet.walletCreationHeight;
} else {
console.log(wallet.errorString)
appWindow.showStatusMessage(qsTr(wallet.errorString), 5);
walletManager.closeWallet();
}
return success;
}
function openWallet(){
if (typeof wizardController.m_wallet !== 'undefined' && wizardController.m_wallet != null) {
walletManager.closeWallet()
}
fileDialog.open();
}
function openWalletFile(fn) {
persistentSettings.restore_height = 0;
persistentSettings.is_recovering = false;
appWindow.restoreHeight = 0;
appWindow.walletPassword = "";
if(typeof fn == 'object')
persistentSettings.wallet_path = walletManager.urlToLocalPath(fn);
else
persistentSettings.wallet_path = fn;
if(isIOS)
persistentSettings.wallet_path = persistentSettings.wallet_path.replace(moneroAccountsDir, "");
console.log(moneroAccountsDir);
console.log(fn);
console.log(persistentSettings.wallet_path);
passwordDialog.onAcceptedCallback = function() {
walletPassword = passwordDialog.password;
appWindow.initialize();
}
passwordDialog.onRejectedCallback = function() {
console.log("Canceled");
appWindow.viewState = "wizard";
}
passwordDialog.open(appWindow.usefulName(appWindow.walletPath()));
}
function fetchRemoteNodes(cb, cb_err){
// Fetch remote nodes, parse JSON, store in result `wizardController.remoteNodes`, call setAutNode(), call callback
var url = appWindow.remoteNodeService + 'api/nodes.json';
console.log("HTTP request: " + url);
var xhr = new XMLHttpRequest();
xhr.timeout = 3500;
// Unfortunately we cannot spoof User-Agent since it is hardcoded in Qt
//xhr.setRequestHeader("User-Agent", "-");
xhr.onreadystatechange = function() {
var msg;
if (xhr.readyState != 4) {
return;
} else if(xhr.status != 200){
msg = "Error fetching remote nodes; status code was not 200";
console.log(msg);
if(typeof cb_err === 'function')
return cb_err(msg);
} else {
var body = xhr.responseText;
if(typeof body === 'undefined' || body === ''){
msg = "Error fetching remote nodes; response body was empty";
console.log(msg);
if(typeof cb_err === 'function')
return cb_err(msg);
}
var data = JSON.parse(body);
wizardController.remoteNodes = data;
console.log("node list updated");
setAutoNode();
return cb();
}
}
xhr.open('GET', url, true);
xhr.send(null);
}
function setAutoNode(){
var node;
var nodes;
var nodeObject = wizardController.remoteNodes;
var region = persistentSettings.remoteNodeRegion;
if(typeof region !== 'undefined' && region !== ""){
if(nodeObject.hasOwnProperty(region) && nodeObject[region].length > 0){
nodes = nodeObject[region];
} else {
console.log("No suitable nodes found for region " + region + ". Defaulting to random node.");
}
}
if(typeof nodes === 'undefined'){
nodes = [];
Object.keys(nodeObject).forEach(function(obj, i){
nodes = nodes.concat(nodeObject[obj]);
});
}
// 18089 has precedence
var filteredNodes = Utils.filterNodes(nodes, "18089");
if(filteredNodes.length > 0){
node = Utils.randomChoice(filteredNodes);
console.log('Choosing remote node \''+ node +'\' from a list of ' + filteredNodes.length);
} else if(nodes.length > 0){
node = Utils.randomChoice(nodes);
console.log('Choosing remote node \''+ node +'\' from a list of ' + nodes.length);
} else {
console.log("No suitable nodes found.")
return ''
}
if(appWindow.walletMode === 0)
persistentSettings.remoteNodeAddress = node;
else if(appWindow.walletMode === 1)
persistentSettings.bootstrapNodeAddress = node;
}
Component.onCompleted: {
//
}
}

View file

@ -0,0 +1,187 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import moneroComponents.Wallet 1.0
import "../js/Wizard.js" as Wizard
import "../components"
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateDevice1
color: "transparent"
property string viewName: "wizardCreateDevice1"
property var deviceName: deviceNameModel.get(deviceNameDropdown.currentIndex).column2
ListModel {
id: deviceNameModel
ListElement { column1: qsTr("Ledger") ; column2: "Ledger"; }
// ListElement { column1: qsTr("Trezor") ; column2: "Trezor"; }
}
function update(){
// update device dropdown
deviceNameDropdown.update();
}
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("Create a new wallet") + translationManager.emptyString
subtitle: qsTr("Using a hardware device.") + translationManager.emptyString
}
WizardWalletInput{
id: walletInput
}
GridLayout {
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
columnSpacing: 20 * scaleRatio
columns: 2
MoneroComponents.LineEdit {
id: restoreHeight
Layout.fillWidth: true
labelText: qsTr("Restore height (optional)") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderFontSize: 16 * scaleRatio
placeholderText: "0"
validator: RegExpValidator { regExp: /(\d+)?$/ }
}
MoneroComponents.LineEdit {
id: lookahead
Layout.fillWidth: true
labelText: qsTr("Subaddress lookahead (optional)") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderText: "<major>:<minor>"
placeholderFontSize: 16 * scaleRatio
validator: RegExpValidator { regExp: /(\d+):(\d+)?$/ }
}
}
ColumnLayout {
spacing: 0
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
ColumnLayout{
MoneroComponents.StandardDropdown {
id: deviceNameDropdown
dataModel: deviceNameModel
Layout.fillWidth: true
Layout.topMargin: 6 * scaleRatio
releasedColor: "#363636"
pressedColor: "#202020"
}
}
}
TextArea {
id: errorMsg
text: qsTr("Error writing wallet from hardware device. Check application logs.") + translationManager.emptyString;
visible: errorMsg.text !== ""
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.errorColor
font.pixelSize: 16 * scaleRatio
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: true
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
bottomPadding: 0
readOnly: true
}
WizardNav {
progressSteps: 4
progress: 1
btnNext.enabled: walletInput.verify();
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
btnNext.text: qsTr("Create wallet") + translationManager.emptyString
onPrevClicked: {
wizardStateView.state = "wizardHome";
}
onNextClicked: {
wizardController.walletOptionsName = walletInput.walletName.text;
wizardController.walletOptionsLocation = walletInput.walletLocation.text;
wizardController.walletOptionsDeviceName = wizardCreateDevice1.deviceName;
if(restoreHeight.text)
wizardController.walletOptionsRestoreHeight = parseInt(restoreHeight.text);
if(lookahead.text)
wizardController.walletOptionsSubaddressLookahead = lookahead.text;
var written = wizardController.createWalletFromDevice();
if(written){
wizardController.walletOptionsIsRecoveringFromDevice = true;
wizardStateView.state = "wizardCreateWallet2";
} else {
errorMsg.text = qsTr("Error writing wallet from hardware device. Check application logs.") + translationManager.emptyString;
}
}
}
}
}
Component.onCompleted: {
errorMsg.text = "";
wizardCreateDevice1.update();
console.log()
}
}

View file

@ -1,112 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import moneroComponents.WalletManager 1.0
import moneroComponents.Wallet 1.0
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import 'utils.js' as Utils
ColumnLayout {
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onWizardRestarted() {
// reset account name field
uiItem.accountNameText = defaultAccountName
}
//! function called each time we display this page
function onPageOpened(settingsOblect) {
checkNextButton()
}
function onPageClosed(settingsObject) {
settingsObject['account_name'] = uiItem.accountNameText
settingsObject['words'] = uiItem.wordsTexttext
settingsObject['wallet_path'] = uiItem.walletPath
console.log("path " +uiItem.walletPath);
var walletFullPath = wizard.createWalletPath(uiItem.walletPath,uiItem.accountNameText);
return wizard.walletPathValid(walletFullPath);
}
function checkNextButton() {
var wordsArray = Utils.lineBreaksToSpaces(uiItem.wordsTextItem.memoText).split(" ");
wizard.nextButton.enabled = wordsArray.length === 25;
}
//! function called each time we hide this page
//
function createWallet(settingsObject) {
// TODO: create wallet in temporary filename and a) move it to the path specified by user after the final
// page submitted or b) delete it when program closed before reaching final page
// Always delete the wallet object before creating new - we could be stepping back from recovering wallet
if (typeof m_wallet !== 'undefined') {
walletManager.closeWallet()
console.log("deleting wallet")
}
var tmp_wallet_filename = oshelper.temporaryFilename();
console.log("Creating temporary wallet", tmp_wallet_filename)
var nettype = appWindow.persistentSettings.nettype;
var kdfRounds = appWindow.persistentSettings.kdfRounds;
var wallet = walletManager.createWallet(tmp_wallet_filename, "", settingsObject.wallet_language,
nettype, kdfRounds)
uiItem.wordsTextItem.memoText = wallet.seed
// saving wallet in "global" settings object
// TODO: wallet should have a property pointing to the file where it stored or loaded from
m_wallet = wallet;
settingsObject['tmp_wallet_filename'] = tmp_wallet_filename
}
WizardManageWalletUI {
id: uiItem
titleText: qsTr("Create a new wallet") + translationManager.emptyString
wordsTextItem.clipboardButtonVisible: true
wordsTextItem.tipTextVisible: true
wordsTextItem.memoTextReadOnly: true
restoreHeightVisible:false
recoverMode: false
}
Component.onCompleted: {
parent.wizardRestarted.connect(onWizardRestarted)
}
}

View file

@ -0,0 +1,147 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateWallet1
color: "transparent"
property string viewName: "wizardCreateWallet1"
property alias seed: seed
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("Create a new wallet") + translationManager.emptyString
subtitle: qsTr("Creates a new wallet on this computer.") + translationManager.emptyString
}
WizardWalletInput{
id: walletInput
}
ColumnLayout {
spacing: 0
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
MoneroComponents.LineEditMulti {
id: seed
spacing: 0
inputPaddingLeft: 16 * scaleRatio
inputPaddingRight: 16 * scaleRatio
inputPaddingTop: 20 * scaleRatio
inputPaddingBottom: 20 * scaleRatio
inputRadius: 0
fontSize: 18 * scaleRatio
fontBold: true
wrapMode: Text.WordWrap
backgroundColor: "red"
addressValidation: false
labelText: qsTr("Mnemonic seed") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
copyButton: false
readOnly: true
placeholderText: qsTr("-") + translationManager.emptyString
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
}
}
WizardNav {
progressSteps: 4
progress: 1
btnNext.enabled: walletInput.verify();
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
onPrevClicked: {
wizardStateView.state = "wizardHome";
}
onNextClicked: {
wizardController.walletOptionsName = walletInput.walletName.text;
wizardController.walletOptionsLocation = walletInput.walletLocation.text;
wizardStateView.state = "wizardCreateWallet2";
}
}
}
}
}

View file

@ -0,0 +1,86 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateWallet2
color: "transparent"
property string viewName: "wizardCreateWallet2"
ColumnLayout {
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: 0 * scaleRatio
WizardAskPassword {
id: passwordFields
}
WizardNav {
progressSteps: 4
progress: 2
btnNext.enabled: passwordFields.calcStrengthAndVerify();
onPrevClicked: {
if(wizardController.walletOptionsIsRecoveringFromDevice){
wizardStateView.state = "wizardCreateDevice1";
} else {
wizardStateView.state = "wizardCreateWallet1";
}
}
onNextClicked: {
if(appWindow.walletMode === 0 || appWindow.walletMode === 1){
wizardController.fetchRemoteNodes(function(){
wizardStateView.state = "wizardCreateWallet4";
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), 5);
wizardStateView.state = "wizardCreateWallet4";
});
} else {
wizardStateView.state = "wizardCreateWallet3";
}
}
}
}
}
}

View file

@ -0,0 +1,78 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateWallet3
color: "transparent"
property string viewName: "wizardCreateWallet3"
ColumnLayout {
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 * scaleRatio
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
}
WizardNav {
progressSteps: 4
progress: 3
onPrevClicked: {
wizardStateView.state = "wizardCreateWallet2";
}
onNextClicked: {
daemonSettings.save();
wizardStateView.state = "wizardCreateWallet4";
}
}
}
}
}

View file

@ -0,0 +1,85 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardCreateWallet4
color: "transparent"
property string viewName: "wizardCreateWallet4"
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("You're all set up!") + translationManager.emptyString
subtitle: qsTr("New wallet details:") + translationManager.emptyString
}
WizardSummary {}
WizardNav {
Layout.topMargin: 24 * scaleRatio
btnNextText: qsTr("Open wallet")
progressSteps: 4
progress: 4
onPrevClicked: {
if (appWindow.walletMode <= 1){
wizardStateView.state = "wizardCreateWallet1";
} else {
wizardStateView.state = "wizardCreateWallet3";
}
}
onNextClicked: {
wizardController.writeWallet();
wizardController.useMoneroClicked();
wizardController.walletOptionsIsRecoveringFromDevice = false;
}
}
}
}
}

View file

@ -1,124 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import moneroComponents.WalletManager 1.0
import moneroComponents.Wallet 1.0
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
import 'utils.js' as Utils
ColumnLayout {
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onWizardRestarted() {
// reset account name field
uiItem.accountNameText = defaultAccountName
}
//! function called each time we display this page
function onPageOpened(settingsOblect) {
uiItem.checkNextButton()
uiItem.deviceNameDropdown.update()
}
function onPageClosed(settingsObject) {
settingsObject['account_name'] = uiItem.accountNameText
settingsObject['wallet_path'] = uiItem.walletPath
var restoreHeight = parseInt(uiItem.restoreHeight);
settingsObject['restore_height'] = isNaN(restoreHeight)? 0 : restoreHeight;
settingsObject['subaddress_lookahead'] = uiItem.subaddressLookahead;
settingsObject['deviceName'] = uiItem.deviceName;
var walletFullPath = wizard.createWalletPath(uiItem.walletPath,uiItem.accountNameText);
if (!wizard.walletPathValid(walletFullPath)) {
return false;
}
return createWalletFromDevice(settingsObject)
}
//! function called each time we hide this page
//
function createWalletFromDevice(settingsObject) {
// TODO: create wallet in temporary filename and a) move it to the path specified by user after the final
// page submitted or b) delete it when program closed before reaching final page
// Always delete the wallet object before creating new - we could be stepping back from recovering wallet
if (typeof m_wallet !== 'undefined') {
walletManager.closeWallet()
console.log("deleting wallet")
}
var tmp_wallet_filename = oshelper.temporaryFilename();
console.log("Creating temporary wallet", tmp_wallet_filename)
var nettype = appWindow.persistentSettings.nettype;
var restoreHeight = settingsObject.restore_height;
var subaddressLookahead = settingsObject.subaddress_lookahead;
var deviceName = settingsObject.deviceName;
var wallet = walletManager.createWalletFromDevice(tmp_wallet_filename, "", nettype, deviceName, restoreHeight, subaddressLookahead);
var success = wallet.status === Wallet.Status_Ok;
if (success) {
m_wallet = wallet;
settingsObject['restore_height'] = m_wallet.walletCreationHeight;
settingsObject['is_recovering_from_device'] = true;
settingsObject['tmp_wallet_filename'] = tmp_wallet_filename
} else {
console.log(wallet.errorString)
walletErrorDialog.text = wallet.errorString;
walletErrorDialog.open();
walletManager.closeWallet();
}
return success;
}
WizardManageWalletUI {
id: uiItem
titleText: qsTr("Create a new wallet from hardware device") + translationManager.emptyString
wordsTextItem.clipboardButtonVisible: false
wordsTextItem.tipTextVisible: false
restoreHeightVisible:true
recoverMode: false
recoverFromDevice: true
}
Component.onCompleted: {
parent.wizardRestarted.connect(onWizardRestarted)
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018, The Monero Project // Copyright (c) 2014-2019, The Monero Project
// //
// All rights reserved. // All rights reserved.
// //
@ -26,171 +26,142 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // 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. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import moneroComponents.WalletManager 1.0 import QtQuick 2.7
import QtQuick 2.2 import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.2
import "../components" import QtQuick.Controls 2.0
import "utils.js" as Utils
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
ColumnLayout { ColumnLayout {
Layout.leftMargin: wizardLeftMargin Layout.fillWidth: true
Layout.rightMargin: wizardRightMargin Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 10 * scaleRatio
id: passwordPage function save(){
opacity: 0 persistentSettings.useRemoteNode = remoteNode.checked
visible: false persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
property alias titleText: titleText.text persistentSettings.bootstrapNodeAddress = bootstrapNodeEdit.daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
} }
onOpacityChanged: visible = opacity !== 0 MoneroComponents.RadioButton {
id: localNode
text: qsTr("Start a node automatically in background (recommended)") + translationManager.emptyString
function onPageOpened(settingsObject) { fontSize: 16 * scaleRatio
} checked: !appWindow.persistentSettings.useRemoteNode && !isAndroid && !isIOS
function onWizardRestarted(){ visible: !isAndroid && !isIOS
} onClicked: {
checked = true;
function onPageClosed(settingsObject) { remoteNode.checked = false;
appWindow.persistentSettings.useRemoteNode = remoteNode.checked
appWindow.persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
appWindow.persistentSettings.bootstrapNodeAddress = bootstrapNodeEdit.daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
return true
}
RowLayout {
id: dotsRow
Layout.alignment: Qt.AlignRight
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
ListElement { dotColor: "#DBDBDB" }
} }
}
Repeater { ColumnLayout {
model: dotsModel visible: localNode.checked
delegate: Rectangle { id: blockchainFolderRow
// Password page is last page when creating view only wallet spacing: 20 * scaleRatio
// TODO: make this dynamic for all pages in wizard
visible: (wizard.currentPath != "create_view_only_wallet" || index < 2) Layout.topMargin: 8 * scaleRatio
width: 12; height: 12 Layout.fillWidth: true
radius: 6
color: dotColor MoneroComponents.LineEdit {
id: blockchainFolder
Layout.fillWidth: true
readOnly: true
labelText: qsTr("Blockchain location (optional)") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderText: qsTr("Default") + translationManager.emptyString
placeholderFontSize: 15 * scaleRatio
text: persistentSettings.blockchainDataDir
inlineButton.small: true
inlineButtonText: qsTr("Browse") + translationManager.emptyString
inlineButton.onClicked: {
if(persistentSettings.blockchainDataDir != "");
blockchainFileDialog.folder = "file://" + persistentSettings.blockchainDataDir;
blockchainFileDialog.open();
blockchainFolder.focus = true;
} }
} }
}
ColumnLayout { ColumnLayout{
id: headerColumn Layout.topMargin: 6 * scaleRatio
spacing: 0
Text { TextArea {
Layout.fillWidth: true text: qsTr("Bootstrap node") + translationManager.emptyString
id: titleText Layout.topMargin: 10 * scaleRatio
font.family: "Arial" Layout.fillWidth: true
font.pixelSize: 28 * scaleRatio font.family: MoneroComponents.Style.fontRegular.name
wrapMode: Text.Wrap color: MoneroComponents.Style.defaultFontColor
horizontalAlignment: Text.AlignHCenter font.pixelSize: {
//renderType: Text.NativeRendering if(wizardController.layoutScale === 2 ){
color: "#3F3F3F" return 22 * scaleRatio;
text: "Daemon settings" } else {
return 16 * scaleRatio;
} }
Text {
Layout.fillWidth: true
Layout.topMargin: 30 * scaleRatio
Layout.bottomMargin: 30 * scaleRatio
font.family: "Arial"
font.pixelSize: 18 * scaleRatio
wrapMode: Text.Wrap
//renderType: Text.NativeRendering
color: "#4A4646"
textFormat: Text.RichText
// horizontalAlignment: Text.AlignHCenter
text: 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. \
<br><br> \
If you don't have the option to run your own node, there's an option to connect to a remote node.")
+ translationManager.emptyString
}
}
ColumnLayout {
RowLayout {
RadioButton {
id: localNode
text: qsTr("Start a node automatically in background (recommended)") + translationManager.emptyString
checkedColor: Qt.rgba(0, 0, 0, 0.75)
borderColor: Qt.rgba(0, 0, 0, 0.45)
fontColor: "#4A4646"
fontSize: 16 * scaleRatio
checked: !appWindow.persistentSettings.useRemoteNode && !isAndroid && !isIOS
visible: !isAndroid && !isIOS
onClicked: {
checked = true;
remoteNode.checked = false;
} }
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: true
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
bottomPadding: 0
readOnly: true
}
TextArea {
text: qsTr("Additionally, you may specify a bootstrap node to use Monero immediately.") + translationManager.emptyString
Layout.topMargin: 4 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.dimmedFontColor
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 16 * scaleRatio;
} else {
return 14 * scaleRatio;
}
}
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: true
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
bottomPadding: 0
readOnly: true
} }
} }
ColumnLayout { ColumnLayout {
visible: localNode.checked spacing: 8
id: blockchainFolderRow Layout.fillWidth: true
Label { Layout.bottomMargin: 12 * scaleRatio
Layout.fillWidth: true
Layout.topMargin: 20 * scaleRatio
fontSize: 14 * scaleRatio
fontColor: "black"
text: qsTr("Blockchain location") + translationManager.emptyString
}
LineEdit {
id: blockchainFolder
Layout.preferredWidth: 200 * scaleRatio
Layout.fillWidth: true
text: persistentSettings.blockchainDataDir
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: Style.legacy_placeholderFontColor
placeholderOpacity: 1.0
placeholderText: qsTr("(optional)") + translationManager.emptyString
borderColor: Qt.rgba(0, 0, 0, 0.15) MoneroComponents.RemoteNodeEdit {
backgroundColor: "white"
fontColor: "black"
fontBold: false
MouseArea {
anchors.fill: parent
onClicked: {
mouse.accepted = false
if(persistentSettings.blockchainDataDir != "")
blockchainFileDialog.folder = "file://" + persistentSettings.blockchainDataDir
blockchainFileDialog.open()
blockchainFolder.focus = true
}
}
}
Label {
Layout.fillWidth: true
Layout.topMargin: 20 * scaleRatio
fontSize: 14 * scaleRatio
color: 'black'
text: qsTr("Bootstrap node (leave blank if not wanted)") + translationManager.emptyString
}
RemoteNodeEdit {
Layout.minimumWidth: 300 * scaleRatio
opacity: localNode.checked
id: bootstrapNodeEdit id: bootstrapNodeEdit
Layout.minimumWidth: 300 * scaleRatio
placeholderFontBold: true //labelText: qsTr("Bootstrap node (leave blank if not wanted)") + translationManager.emptyString
placeholderFontFamily: "Arial"
placeholderColor: Style.legacy_placeholderFontColor lineEditBackgroundColor: "transparent"
placeholderOpacity: 1.0 lineEditFontColor: MoneroComponents.Style.defaultFontColor
lineEditFontBold: false
lineEditBorderColor: Qt.rgba(255, 255, 255, 0.35)
labelFontSize: 14 * scaleRatio
placeholderFontSize: 15 * scaleRatio
daemonAddrText: persistentSettings.bootstrapNodeAddress.split(":")[0].trim() daemonAddrText: persistentSettings.bootstrapNodeAddress.split(":")[0].trim()
daemonPortText: { daemonPortText: {
@ -203,48 +174,41 @@ ColumnLayout {
} }
} }
} }
}
RowLayout {
RadioButton {
id: remoteNode
text: qsTr("Connect to a remote node") + translationManager.emptyString
checkedColor: Qt.rgba(0, 0, 0, 0.75)
borderColor: Qt.rgba(0, 0, 0, 0.45)
Layout.topMargin: 20 * scaleRatio
fontColor: "#4A4646"
fontSize: 16 * scaleRatio
checked: appWindow.persistentSettings.useRemoteNode
onClicked: {
checked = true
localNode.checked = false
}
}
}
RowLayout { RowLayout {
RemoteNodeEdit { MoneroComponents.RadioButton {
Layout.minimumWidth: 300 * scaleRatio id: remoteNode
opacity: remoteNode.checked text: qsTr("Connect to a remote node") + translationManager.emptyString
id: remoteNodeEdit checkedColor: Qt.rgba(0, 0, 0, 0.75)
property var rna: persistentSettings.remoteNodeAddress borderColor: Qt.rgba(0, 0, 0, 0.45)
daemonAddrText: rna.search(":") != -1 ? rna.split(":")[0].trim() : "" Layout.topMargin: 20 * scaleRatio
daemonPortText: rna.search(":") != -1 ? (rna.split(":")[1].trim() == "") ? appWindow.getDefaultDaemonRpcPort(persistentSettings.nettype) : persistentSettings.remoteNodeAddress.split(":")[1] : "" fontColor: "#4A4646"
fontSize: 16 * scaleRatio
placeholderFontBold: true checked: appWindow.persistentSettings.useRemoteNode
placeholderFontFamily: "Arial" onClicked: {
placeholderColor: Style.legacy_placeholderFontColor checked = true
placeholderOpacity: 1.0 localNode.checked = false
lineEditBorderColor: Qt.rgba(0, 0, 0, 0.15)
lineEditBackgroundColor: "white"
lineEditFontColor: "black"
lineEditFontBold: false
} }
} }
} }
RowLayout {
MoneroComponents.RemoteNodeEdit {
Layout.minimumWidth: 300 * scaleRatio
opacity: remoteNode.checked
id: remoteNodeEdit
property var rna: persistentSettings.remoteNodeAddress
daemonAddrText: rna.search(":") != -1 ? rna.split(":")[0].trim() : ""
daemonPortText: rna.search(":") != -1 ? (rna.split(":")[1].trim() == "") ? appWindow.getDefaultDaemonRpcPort(persistentSettings.nettype) : persistentSettings.remoteNodeAddress.split(":")[1] : ""
Component.onCompleted: { lineEditBackgroundColor: "transparent"
parent.wizardRestarted.connect(onWizardRestarted) lineEditFontColor: MoneroComponents.Style.defaultFontColor
lineEditFontBold: false
lineEditBorderColor: Qt.rgba(255, 255, 255, 0.35)
labelFontSize: 14 * scaleRatio
placeholderFontSize: 15 * scaleRatio
}
} }
} }

View file

@ -1,196 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import "../components"
Item {
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onPageOpened(settingsObject) {
enableAutoDonationCheckBox.checked = settingsObject.auto_donations_enabled
autoDonationAmountText.text = settingsObject.auto_donations_amount
allowBackgroundMiningCheckBox.checked = settingsObject.allow_background_mining
}
function onPageClosed(settingsObject) {
settingsObject['auto_donations_enabled'] = enableAutoDonationCheckBox.checked;
settingsObject['auto_donations_amount'] = parseInt(autoDonationAmountText.text);
settingsObject['allow_background_mining'] = allowBackgroundMiningCheckBox.checked;
return true;
}
Row {
id: dotsRow
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 85
spacing: 6
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
}
Repeater {
model: dotsModel
delegate: Rectangle {
width: 12; height: 12
radius: 6
color: dotColor
}
}
}
Text {
id: headerText
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 74
anchors.leftMargin: 16
width: parent.width - dotsRow.width - 16
font.family: "Arial"
font.pixelSize: 28
wrapMode: Text.Wrap
//renderType: Text.NativeRendering
color: "#3F3F3F"
text: qsTr("Monero development is solely supported by donations") + translationManager.emptyString
}
Column {
anchors.top: headerText.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.topMargin: 34
spacing: 12
Row {
anchors.left: parent.left
anchors.right: parent.right
spacing: 2
CheckBox {
id: enableAutoDonationCheckBox
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Enable auto-donations of?") + translationManager.emptyString
background: "#F0EEEE"
fontColor: "#4A4646"
fontSize: 18
checked: true
}
Item {
anchors.verticalCenter: parent.verticalCenter
height: 30
width: 41
TextInput {
id: autoDonationAmountText
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.family: "Arial"
font.pixelSize: 18
color: "#6B0072"
text: "50"
validator: IntValidator { bottom: 0; top: 100 }
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 1
color: "#DBDBDB"
}
}
Text {
anchors.verticalCenter: parent.verticalCenter
font.family: "Arial"
font.pixelSize: 18
color: "#4A4646"
text: qsTr("% of my fee added to each transaction") + translationManager.emptyString
}
}
Text {
anchors.left: parent.left
anchors.right: parent.right
font.family: "Arial"
font.pixelSize: 15
color: "#4A4646"
wrapMode: Text.Wrap
text: qsTr("For every transaction, a small transaction fee is charged. This option lets you add an additional amount, " +
"as a percentage of that fee, to your transaction to support Monero development. For instance, a 50% " +
"autodonation take a transaction fee of 0.005 XMR and add a 0.0025 XMR to support Monero development.")
+ translationManager.emptyString
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 12
CheckBox {
id: allowBackgroundMiningCheckBox
text: qsTr("Allow background mining?") + translationManager.emptyString
anchors.left: parent.left
anchors.right: parent.right
background: "#F0EEEE"
fontColor: "#4A4646"
fontSize: 18
checked: true
}
Text {
anchors.left: parent.left
anchors.right: parent.right
font.family: "Arial"
font.pixelSize: 15
color: "#4A4646"
wrapMode: Text.Wrap
text: qsTr("Mining secures the Monero network, and also pays a small reward for the work done. This option " +
"will let Monero mine when your computer is on mains power and is idle. It will stop mining when you continue working.")
+ translationManager.emptyString
}
}
}
}

View file

@ -1,152 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import QtQuick.Layouts 1.1
import moneroComponents.NetworkType 1.0
ColumnLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function buildSettingsString() {
var trStart = '<tr><td style="padding-top:5px;"><b>',
trMiddle = '</b></td><td style="padding-left:10px;padding-top:5px;">',
trEnd = "</td></tr>",
autoDonationEnabled = wizard.settings['auto_donations_enabled'] === true,
autoDonationText = autoDonationEnabled ? qsTr("Enabled") : qsTr("Disabled"),
autoDonationAmount = wizard.settings["auto_donations_amount"] + " %",
backgroundMiningEnabled = wizard.settings["allow_background_mining"] === true,
backgroundMiningText = backgroundMiningEnabled ? qsTr("Enabled") : qsTr("Disabled"),
nettype = appWindow.persistentSettings.nettype,
networkText = nettype == NetworkType.TESTNET ? qsTr("Testnet") : nettype == NetworkType.STAGENET ? qsTr("Stagenet") : qsTr("Mainnet"),
restoreHeightEnabled = wizard.settings['restore_height'] !== undefined;
var daemonAddress = persistentSettings.daemon_address;
if(persistentSettings.useRemoteNode)
{
daemonAddress = persistentSettings.remoteNodeAddress;
}
return "<table>"
+ trStart + qsTr("Language") + trMiddle + wizard.settings["language"] + trEnd
+ trStart + qsTr("Wallet name") + trMiddle + wizard.settings["account_name"] + trEnd
// TODO: wizard.settings['wallet'].seed doesnt work anymore; yields undefined.
// + trStart + qsTr("Backup seed") + trMiddle + wizard.settings["wallet"].seed + trEnd
+ trStart + qsTr("Backup seed") + trMiddle + '****' + trEnd
+ trStart + qsTr("Wallet path") + trMiddle + wizard.settings["wallet_path"] + trEnd
// + trStart + qsTr("Auto donations") + trMiddle + autoDonationText + trEnd
// + (autoDonationEnabled
// ? trStart + qsTr("Donation amount") + trMiddle + autoDonationAmount + trEnd
// : "")
// + trStart + qsTr("Background mining") + trMiddle + backgroundMiningText + trEnd
+ trStart + qsTr("Daemon address") + trMiddle + daemonAddress + trEnd
+ trStart + qsTr("Network Type") + trMiddle + networkText + trEnd
+ (restoreHeightEnabled
? trStart + qsTr("Restore height") + trMiddle + wizard.settings['restore_height'] + trEnd
: "")
+ "</table>"
+ translationManager.emptyString;
}
function updateSettingsSummary() {
if (!isMobile){
settingsText.text = qsTr("New wallet details:") + translationManager.emptyString
+ "<br>"
+ buildSettingsString();
} else {
settingsText.text = qsTr("Don't forget to write down your seed. You can view your seed and change your settings on settings page.")
}
}
function onPageOpened(settings) {
updateSettingsSummary();
wizard.nextButton.visible = false;
}
RowLayout {
id: dotsRow
Layout.alignment: Qt.AlignRight
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
}
Repeater {
model: dotsModel
delegate: Rectangle {
width: 12; height: 12
radius: 6
color: dotColor
}
}
}
ColumnLayout {
id: headerColumn
Layout.fillWidth: true
Text {
Layout.fillWidth: true
font.family: "Arial"
font.pixelSize: 28 * scaleRatio
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
//renderType: Text.NativeRendering
color: "#3F3F3F"
text: qsTr("Youre all set up!") + translationManager.emptyString
}
Text {
Layout.fillWidth: true
id: settingsText
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
wrapMode: Text.Wrap
textFormat: Text.RichText
horizontalAlignment: Text.AlignHLeft
//renderType: Text.NativeRendering
color: "#4A4646"
}
}
}

96
wizard/WizardHeader.qml Normal file
View file

@ -0,0 +1,96 @@
// 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 "../js/Wizard.js" as Wizard
import "../components"
import "../components" as MoneroComponents
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
ColumnLayout {
property string title: ""
property string subtitle: ""
spacing: 4 * scaleRatio
Layout.maximumWidth: wizardController.wizardSubViewWidth
TextArea {
text: title
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 34 * scaleRatio;
} else {
return 28 * scaleRatio;
}
}
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: true
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
bottomPadding: 0
readOnly: true
}
TextArea {
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter
visible: parent.subtitle !== ""
color: MoneroComponents.Style.dimmedFontColor
text: subtitle
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 16 * scaleRatio;
} else {
return 14 * scaleRatio;
}
}
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: true
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
readOnly: true
}
}

250
wizard/WizardHome.qml Normal file
View file

@ -0,0 +1,250 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import moneroComponents.NetworkType 1.0
import "../components" as MoneroComponents
Rectangle {
id: wizardHome
color: "transparent"
property string viewName: "wizardHome"
ColumnLayout {
Layout.alignment: Qt.AlignHCenter;
width: parent.width - 100
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 10 * scaleRatio
ColumnLayout {
Layout.fillWidth: true
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 0 * scaleRatio
WizardHeader {
Layout.bottomMargin: 20 * scaleRatio
title: qsTr("Welcome to Monero.") + translationManager.emptyString
subtitle: ""
}
WizardMenuItem {
headerText: qsTr("Create a new wallet") + translationManager.emptyString
bodyText: qsTr("Choose this option if this is your first time using Monero.") + translationManager.emptyString
imageIcon: "../images/create-wallet.png"
onMenuClicked: {
wizardController.restart();
wizardController.createWallet();
wizardStateView.state = "wizardCreateWallet1"
}
}
Rectangle {
Layout.preferredHeight: 1
Layout.topMargin: 3 * scaleRatio
Layout.bottomMargin: 3 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
WizardMenuItem {
headerText: qsTr("Create a new wallet from hardware") + translationManager.emptyString
bodyText: qsTr("Connect your hardware wallet to create a new Monero wallet.") + translationManager.emptyString
imageIcon: "../images/restore-wallet-from-hardware.png"
onMenuClicked: {
wizardController.restart();
wizardStateView.state = "wizardCreateDevice1"
}
}
Rectangle {
Layout.preferredHeight: 1
Layout.topMargin: 3 * scaleRatio
Layout.bottomMargin: 3 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
WizardMenuItem {
headerText: qsTr("Open a wallet from file") + translationManager.emptyString
bodyText: qsTr("Import an existing .keys wallet file from your computer.") + translationManager.emptyString
imageIcon: "../images/open-wallet-from-file.png"
onMenuClicked: {
wizardStateView.state = "wizardOpenWallet1"
}
}
Rectangle {
Layout.preferredHeight: 1
Layout.topMargin: 3 * scaleRatio
Layout.bottomMargin: 3 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
WizardMenuItem {
headerText: qsTr("Restore wallet from keys or mnemonic seed") + translationManager.emptyString
bodyText: qsTr("Enter your private keys or 25-word mnemonic seed to restore your wallet.") + translationManager.emptyString
imageIcon: "../images/restore-wallet.png"
onMenuClicked: {
wizardController.restart();
wizardController.createWallet();
wizardStateView.state = "wizardRestoreWallet1"
}
}
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 16 * scaleRatio
spacing: 20 * scaleRatio
MoneroComponents.StandardButton {
small: true
text: qsTr("Change wallet mode") + translationManager.emptyString
onClicked: {
wizardController.wizardState = 'wizardModeSelection';
}
}
MoneroComponents.StandardButton {
visible: !persistentSettings.customDecorations
small: true
text: qsTr("Change language") + translationManager.emptyString
onClicked: {
wizardController.skipModeSelection = true;
wizardController.wizardState = 'wizardLanguage';
languageSidebar.open();
}
}
}
MoneroComponents.CheckBox2 {
id: showAdvancedCheckbox
Layout.topMargin: 30 * scaleRatio
Layout.fillWidth: true
fontSize: 15 * scaleRatio
checked: false
text: qsTr("Advanced options") + translationManager.emptyString
visible: appWindow.walletMode >= 2
}
ListModel {
id: networkTypeModel
// @TODO: try real enums
ListElement {column1: "Mainnet"; column2: ""; nettype: "mainnet"}
ListElement {column1: "Testnet"; column2: ""; nettype: "testnet"}
ListElement {column1: "Stagenet"; column2: ""; nettype: "stagenet"}
}
GridLayout {
visible: showAdvancedCheckbox.checked && appWindow.walletMode >= 2
columns: 4
columnSpacing: 20
MoneroComponents.StandardDropdown {
id: networkTypeDropdown
dataModel: networkTypeModel
Layout.fillWidth: true
Layout.topMargin: 41
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#363636"
pressedColor: "#202020"
onChanged: {
var item = dataModel.get(currentIndex).nettype.toLowerCase();
if(item === "mainnet") {
persistentSettings.nettype = NetworkType.MAINNET
} else if(item === "stagenet"){
persistentSettings.nettype = NetworkType.STAGENET
} else if(item === "testnet"){
persistentSettings.nettype = NetworkType.TESTNET
}
}
}
MoneroComponents.LineEdit {
id: kdfRoundsText
Layout.fillWidth: true
labelText: qsTr("Number of KDF rounds:") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderFontSize: 16 * scaleRatio
placeholderText: "0"
validator: IntValidator { bottom: 1 }
text: persistentSettings.kdfRounds ? persistentSettings.kdfRounds : "1"
onTextChanged: {
console.log('x');
kdfRoundsText.text = persistentSettings.kdfRounds = parseInt(kdfRoundsText.text) >= 1 ? parseInt(kdfRoundsText.text) : 1;
}
}
Item {
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: 200;
easing.type: Easing.InCubic;
}
}
Component.onCompleted: {
networkTypeDropdown.currentIndex = persistentSettings.nettype;
networkTypeDropdown.update();
}
function onPageCompleted(){
wizardController.walletOptionsIsRecoveringFromDevice = false;
}
}

253
wizard/WizardLanguage.qml Normal file
View file

@ -0,0 +1,253 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../components"
import "../components" as MoneroComponents
import "../version.js" as Version
Rectangle {
Layout.fillWidth: true
color: "black"
property string viewName: "wizardLanguage"
Image {
anchors.fill: parent
source: "../images/middlePanelBg.jpg"
}
ColumnLayout {
id: root
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 30 * scaleRatio
Rectangle {
// some margins for the titlebar
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.fillWidth: true
Layout.preferredHeight: 0
color: "transparent"
}
TextArea {
id: textWelcome
opacity: 0
Layout.preferredWidth: parent.width / 1.3
anchors.horizontalCenter: parent.horizontalCenter
color: MoneroComponents.Style.defaultFontColor
text: "Welcome - Wilkommen - Bonvenon - Bienvenido - Bienvenue - Välkommen - Selamat datang - Benvenuto - 歡迎 - Welkom - Bem Vindo - добро пожаловать"
font.family: MoneroComponents.Style.fontRegular.name
font.bold: true
font.pixelSize: 18 * scaleRatio
horizontalAlignment: TextInput.AlignHCenter
selectByMouse: false
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
readOnly: true
Behavior on opacity {
NumberAnimation {
duration: 350;
easing.type: Easing.InCubic;
}
}
}
Image {
id: globe
source: "../images/world-flags-globe.png"
opacity: 0
property bool small: appWindow.width < 700 ? true : false
property int size: {
if(small){
return 196;
} else {
return 312;
}
}
Layout.preferredWidth: size
Layout.preferredHeight: size
anchors.horizontalCenter: parent.horizontalCenter
mipmap: true
property bool animSlow: false
property int animSpeedSlow: 4000
property int animSpeedNormal: 120000
property real animFrom: 0
property real animTo: 360
Rectangle {
visible: !globe.small
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 117 * scaleRatio
anchors.topMargin: 71 * scaleRatio
width: 36 * scaleRatio
height: 40 * scaleRatio
color: "transparent"
MouseArea {
anchors.fill: parent
onClicked: {
anim.stop();
globe.animFrom = globe.rotation;
globe.animTo = globe.animFrom + 360;
anim.duration = globe.animSlow ? globe.animSpeedNormal : globe.animSpeedSlow;
globe.animSlow = !globe.animSlow;
anim.start();
}
}
}
Behavior on opacity {
NumberAnimation {
duration: 450;
easing.type: Easing.InCubic;
}
}
RotationAnimation on rotation {
id: anim
loops: Animation.Infinite
from: globe.animFrom
to: globe.animTo
duration: globe.animSpeedNormal
}
}
GridLayout {
id: buttonsGrid
opacity: 0
columns: isMobile ? 1 : 2
anchors.horizontalCenter: parent.horizontalCenter
Layout.topMargin: 20 * scaleRatio
Layout.fillWidth: true
columnSpacing: 20 * scaleRatio
MoneroComponents.StandardButton {
id: idChangeLang
Layout.minimumWidth: 150 * scaleRatio
text: "Language"
onClicked: {
languageSidebar.open();
}
}
MoneroComponents.StandardButton {
id: btnContinue
Layout.minimumWidth: 150 * scaleRatio
text: "Continue"
onClicked: {
if(wizardController.skipModeSelection){
wizardStateView.state = "wizardHome"
} else {
wizardStateView.state = "wizardModeSelection"
}
}
}
Behavior on opacity {
NumberAnimation {
duration: 350;
easing.type: Easing.InCubic;
}
}
}
Text {
id: versionText
opacity: 0
anchors.horizontalCenter: parent.horizontalCenter
font.bold: true
font.pixelSize: 12 * scaleRatio
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
text: Version.GUI_VERSION + " (Qt " + qtRuntimeVersion + ")"
Behavior on opacity {
NumberAnimation {
duration: 350;
easing.type: Easing.InCubic;
}
}
}
}
Component.onCompleted: {
// opacity effects
delay(textTimer, 100, function() {
textWelcome.opacity = 1;
});
delay(globeTimer, 150, function() {
globe.opacity = 1;
});
delay(buttonTimer, 250, function() {
buttonsGrid.opacity = 1;
});
delay(versionTimer, 350, function() {
versionText.opacity = 1;
});
}
function delay(timer, interval, cb) {
timer.interval = interval;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Timer {
id: globeTimer
}
Timer {
id: textTimer
}
Timer {
id: buttonTimer
}
Timer {
id: versionTimer
}
}

View file

@ -1,435 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import Qt.labs.settings 1.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import "../components"
ColumnLayout {
anchors.fill: parent
Layout.fillHeight: true
id: wizard
property alias nextButton : nextButton
property var settings : ({})
property int currentPage: 0
property int wizardLeftMargin: (!isMobile) ? 150 : 25 * scaleRatio
property int wizardRightMargin: (!isMobile) ? 150 : 25 * scaleRatio
property int wizardBottomMargin: (isMobile) ? 150 : 25 * scaleRatio
property int wizardTopMargin: (isMobile) ? 15 * scaleRatio : 50
// Storing wallet in Settings object doesn't work in qt 5.8 on android
property var m_wallet;
property var paths: {
// "create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, donationPage, finishPage ],
// "recovery_wallet" : [welcomePage, optionsPage, recoveryWalletPage, passwordPage, donationPage, finishPage ],
// disable donation page
"create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, daemonSettingsPage, finishPage ],
"recovery_wallet" : [welcomePage, optionsPage, recoveryWalletPage, passwordPage, daemonSettingsPage, finishPage ],
"create_view_only_wallet" : [ createViewOnlyWalletPage, passwordPage ],
"create_wallet_from_device" : [welcomePage, optionsPage, createWalletFromDevicePage, passwordPage, daemonSettingsPage, finishPage ],
}
property string currentPath: "create_wallet"
property var pages: paths[currentPath]
signal wizardRestarted();
signal useMoneroClicked()
signal openWalletFromFileClicked()
// border.color: "#DBDBDB"
// border.width: 1
// color: "#FFFFFF"
function restart(){
wizard.currentPage = 0;
wizard.settings = ({})
wizard.currentPath = "create_wallet"
wizard.pages = paths[currentPath]
wizardRestarted();
//hide all pages except first
for (var i = 1; i < wizard.pages.length; i++){
wizard.pages[i].opacity = 0;
}
//Show first pages
wizard.pages[0].opacity = 1;
}
function switchPage(next) {
// Android focus workaround
releaseFocus();
// save settings for current page;
if (next && typeof pages[currentPage].onPageClosed !== 'undefined') {
if (pages[currentPage].onPageClosed(settings) !== true) {
print ("Can't go to the next page");
return;
};
}
console.log("switchpage: currentPage: ", currentPage);
// Update prev/next button positions for mobile/desktop
prevButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
prevButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
nextButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
nextButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
if (currentPage > 0 || currentPage < pages.length - 1) {
pages[currentPage].opacity = 0
var step_value = next ? 1 : -1
currentPage += step_value
pages[currentPage].opacity = 1;
var nextButtonVisible = currentPage > 1 && currentPage < pages.length - 1
nextButton.visible = nextButtonVisible
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
pages[currentPage].onPageOpened(settings,next)
}
}
}
function openCreateWalletPage() {
wizardRestarted();
print ("show create wallet page");
currentPath = "create_wallet"
pages = paths[currentPath]
createWalletPage.createWallet(settings)
wizard.nextButton.visible = true
// goto next page
switchPage(true);
}
function openRecoveryWalletPage() {
wizardRestarted();
print ("show recovery wallet page");
currentPath = "recovery_wallet"
pages = paths[currentPath]
// Create temporary wallet
createWalletPage.createWallet(settings)
wizard.nextButton.visible = true
// goto next page
switchPage(true);
}
function openOpenWalletPage() {
console.log("open wallet from file page");
if (typeof m_wallet !== 'undefined' && m_wallet != null) {
walletManager.closeWallet()
}
optionsPage.onPageClosed(settings)
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 openCreateWalletFromDevicePage() {
wizardRestarted();
print ("show create wallet from device page");
currentPath = "create_wallet_from_device"
pages = paths[currentPath]
wizard.nextButton.visible = true
// goto next page
switchPage(true);
}
function createWalletPath(folder_path,account_name){
// Remove trailing slash - (default on windows and mac)
if (folder_path.substring(folder_path.length -1) === "/"){
folder_path = folder_path.substring(0,folder_path.length -1)
}
// Store releative path on ios.
if(isIOS)
folder_path = "";
return folder_path + "/" + account_name + "/" + account_name
}
function walletPathValid(path){
if(isIOS)
path = moneroAccountsDir + path;
if (walletManager.walletExists(path)) {
walletErrorDialog.text = qsTr("A wallet with same name already exists. Please change wallet name") + translationManager.emptyString;
walletErrorDialog.open();
return false;
}
return true;
}
function isAscii(str){
for (var i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 127)
return false;
}
return true;
}
//! actually writes the wallet
function applySettings() {
// Save wallet files in user specified location
var new_wallet_filename = createWalletPath(settings.wallet_path,settings.account_name)
if(isIOS) {
console.log("saving in ios: "+ moneroAccountsDir + new_wallet_filename)
m_wallet.store(moneroAccountsDir + new_wallet_filename);
} else {
console.log("saving in wizard: "+ new_wallet_filename)
m_wallet.store(new_wallet_filename);
}
// make sure temporary wallet files are deleted
console.log("Removing temporary wallet: "+ settings.tmp_wallet_filename)
oshelper.removeTemporaryWallet(settings.tmp_wallet_filename)
// protecting wallet with password
m_wallet.setPassword(settings.wallet_password);
// Store password in session to be able to use password protected functions (e.g show seed)
appWindow.walletPassword = settings.wallet_password
// saving wallet_filename;
settings['wallet_filename'] = new_wallet_filename;
// persist settings
appWindow.persistentSettings.language = settings.language
appWindow.persistentSettings.locale = settings.locale
appWindow.persistentSettings.account_name = settings.account_name
appWindow.persistentSettings.wallet_path = new_wallet_filename
appWindow.persistentSettings.allow_background_mining = false //settings.allow_background_mining
appWindow.persistentSettings.auto_donations_enabled = false //settings.auto_donations_enabled
appWindow.persistentSettings.auto_donations_amount = false //settings.auto_donations_amount
appWindow.persistentSettings.restore_height = (isNaN(settings.restore_height))? 0 : settings.restore_height
appWindow.persistentSettings.is_recovering = (settings.is_recovering === undefined)? false : settings.is_recovering
appWindow.persistentSettings.is_recovering_from_device = (settings.is_recovering_from_device === undefined)? false : settings.is_recovering_from_device
}
// reading settings from persistent storage
Component.onCompleted: {
settings['allow_background_mining'] = appWindow.persistentSettings.allow_background_mining
settings['auto_donations_enabled'] = appWindow.persistentSettings.auto_donations_enabled
settings['auto_donations_amount'] = appWindow.persistentSettings.auto_donations_amount
}
MessageDialog {
id: walletErrorDialog
title: "Error"
onAccepted: {
}
}
WizardWelcome {
id: welcomePage
// Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardOptions {
id: optionsPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
onCreateWalletClicked: wizard.openCreateWalletPage()
onRecoveryWalletClicked: wizard.openRecoveryWalletPage()
onOpenWalletClicked: wizard.openOpenWalletPage();
onCreateWalletFromDeviceClicked: wizard.openCreateWalletFromDevicePage()
}
WizardCreateWallet {
id: createWalletPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardCreateViewOnlyWallet {
id: createViewOnlyWalletPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardRecoveryWallet {
id: recoveryWalletPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardCreateWalletFromDevice {
id: createWalletFromDevicePage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardPassword {
id: passwordPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardDaemonSettings {
id: daemonSettingsPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardDonation {
id: donationPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
WizardFinish {
id: finishPage
Layout.bottomMargin: wizardBottomMargin
Layout.topMargin: wizardTopMargin
}
Rectangle {
id: prevButton
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: isMobile ? 20 : 50
Layout.bottomMargin: isMobile ? 20 * scaleRatio : 50
visible: parent.currentPage > 0
width: 50 * scaleRatio; height: 50 * scaleRatio
radius: 25
color: prevArea.containsMouse ? "#FF4304" : "#FF6C3C"
Image {
anchors.centerIn: parent
anchors.horizontalCenterOffset: -3
source: "qrc:///images/nextPage.png"
transformOrigin: Item.Center
rotation: 180
}
MouseArea {
id: prevArea
anchors.fill: parent
hoverEnabled: true
onClicked: wizard.switchPage(false)
}
}
Rectangle {
id: nextButton
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.rightMargin: isMobile ? 20 * scaleRatio : 50
Layout.bottomMargin: isMobile ? 20 * scaleRatio : 50
visible: currentPage > 1 && currentPage < pages.length - 1
width: 50 * scaleRatio; height: 50 * scaleRatio
radius: 25
color: enabled ? nextArea.containsMouse ? "#FF4304" : "#FF6C3C" : "#DBDBDB"
Image {
anchors.centerIn: parent
anchors.horizontalCenterOffset: 3
source: "qrc:///images/nextPage.png"
}
MouseArea {
id: nextArea
anchors.fill: parent
hoverEnabled: true
onClicked: wizard.switchPage(true)
}
}
StandardButton {
id: sendButton
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
Layout.margins: (isMobile) ? 20 * scaleRatio : 50 * scaleRatio
text: qsTr("USE MONERO") + translationManager.emptyString
visible: parent.paths[currentPath][currentPage] === finishPage
onClicked: {
wizard.applySettings();
wizard.useMoneroClicked();
}
}
StandardButton {
id: createViewOnlyWalletButton
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
Layout.margins: (isMobile) ? 20 * scaleRatio : 50
text: qsTr("Create wallet") + translationManager.emptyString
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
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
Layout.margins: (isMobile) ? 20 * scaleRatio : 50
text: qsTr("Abort") + translationManager.emptyString
visible: currentPath === "create_view_only_wallet" && parent.paths[currentPath][currentPage] === passwordPage
onClicked: {
wizard.restart();
rootItem.state = "normal"
}
}
}

View file

@ -1,415 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import moneroComponents.TranslationManager 1.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import "../components" as MoneroComponents
import 'utils.js' as Utils
// Reusable component for mnaging wallet (account name, path, private key)
ColumnLayout {
id: page
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
property alias titleText: titleText.text
property alias accountNameText: accountName.text
property alias walletPath: fileUrlInput.text
property alias wordsTextItem : memoTextItem
property alias restoreHeight : restoreHeightItem.text
property alias restoreHeightVisible: restoreHeightItem.visible
property alias subaddressLookahead : subaddressLookaheadItem.text
property alias walletName : accountName.text
property alias progressDotsModel : progressDots.model
property alias recoverFromKeysAddress: addressLine.text;
property alias recoverFromKeysViewKey: viewKeyLine.text;
property alias recoverFromKeysSpendKey: spendKeyLine.text;
// recover mode or create new wallet
property bool recoverMode: false
// Recover form seed or keys
property bool recoverFromSeedMode: true
// Recover form hardware device
property bool recoverFromDevice: false
property var deviceName: deviceNameModel.get(deviceNameDropdown.currentIndex).column2
property alias deviceNameDropdown: deviceNameDropdown
property int rowSpacing: 10
function checkFields(){
var addressOK = (viewKeyLine.text.length > 0 || spendKeyLine.text.length > 0)? walletManager.addressValid(addressLine.text, persistentSettings.nettype) : false
var viewKeyOK = (viewKeyLine.text.length > 0)? walletManager.keyValid(viewKeyLine.text, addressLine.text, true, persistentSettings.nettype) : true
// Spendkey is optional
var spendKeyOK = (spendKeyLine.text.length > 0)? walletManager.keyValid(spendKeyLine.text, addressLine.text, false, persistentSettings.nettype) : true
addressLine.error = !addressOK && addressLine.text.length != 0
viewKeyLine.error = !viewKeyOK && viewKeyLine.text.length != 0
spendKeyLine.error = !spendKeyOK && spendKeyLine.text.length != 0
return addressOK && viewKeyOK && spendKeyOK
}
function checkNextButton(){
wizard.nextButton.enabled = false
console.log("check next", recoverFromSeed.visible)
if(recoverMode && !recoverFromSeedMode) {
console.log("checking key fields")
wizard.nextButton.enabled = checkFields();
} else if (recoverMode && recoverFromSeedMode) {
wizard.nextButton.enabled = checkSeed()
} else
wizard.nextButton.enabled = true;
}
function checkSeed() {
console.log("Checking seed")
var wordsArray = Utils.lineBreaksToSpaces(uiItem.wordsTextItem.memoText).split(" ");
return wordsArray.length === 25 || wordsArray.length === 24
}
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name, extra_parameters) {
// Switch to recover from keys
recoverFromSeedMode = false
spendKeyLine.text = ""
viewKeyLine.text = ""
restoreHeightItem.text = ""
if(typeof extra_parameters.secret_view_key != "undefined") {
viewKeyLine.text = extra_parameters.secret_view_key
}
if(typeof extra_parameters.secret_spend_key != "undefined") {
spendKeyLine.text = extra_parameters.secret_spend_key
}
if(typeof extra_parameters.restore_height != "undefined") {
restoreHeightItem.text = extra_parameters.restore_height
}
addressLine.text = address
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
// Check if keys are correct
checkNextButton();
}
RowLayout {
id: dotsRow
Layout.alignment: Qt.AlignRight
spacing: 6
ListModel {
id: dotsModel
ListElement { dotColor: "#FFE00A" }
ListElement { dotColor: "#DBDBDB" }
ListElement { dotColor: "#DBDBDB" }
ListElement { dotColor: "#DBDBDB" }
}
Repeater {
id: progressDots
model: dotsModel
delegate: Rectangle {
width: 12; height: 12
radius: 6
color: dotColor
}
}
}
RowLayout {
id: headerColumn
Layout.fillWidth: true
Text {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
id: titleText
font.family: "Arial"
font.pixelSize: 28 * scaleRatio
wrapMode: Text.Wrap
color: "#3F3F3F"
}
}
ColumnLayout {
Layout.bottomMargin: rowSpacing
MoneroComponents.Label {
Layout.topMargin: 20 * scaleRatio
fontFamily: "Arial"
fontColor: "#555555"
fontSize: 14 * scaleRatio
text: qsTr("Wallet name")
+ translationManager.emptyString
}
MoneroComponents.LineEdit {
id: accountName
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
text: defaultAccountName
onTextUpdated: checkNextButton()
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
MoneroComponents.WarningBox {
color: "#DBDBDB"
textColor: "#4A4646"
visible: !recoverFromDevice && !recoverMode
text: qsTr("WARNING: Copying your seed to clipboard can expose you to malicious software, which may record your seed and steal your Monero. Please write down your seed manually.") + translationManager.emptyString
}
}
GridLayout{
columns: (isMobile)? 2 : 4
visible: recoverMode
MoneroComponents.StandardButton {
id: recoverFromSeedButton
text: qsTr("Restore from seed") + translationManager.emptyString
enabled: recoverFromKeys.visible
onClicked: {
recoverFromSeedMode = true;
checkNextButton();
}
}
MoneroComponents.StandardButton {
id: recoverFromKeysButton
text: qsTr("Restore from keys") + translationManager.emptyString
enabled: recoverFromSeed.visible
onClicked: {
recoverFromSeedMode = false;
checkNextButton();
}
}
MoneroComponents.StandardButton {
id: qrfinderButton
text: qsTr("From QR Code") + translationManager.emptyString
visible : appWindow.qrScannerEnabled
enabled : visible
onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
}
}
// Recover from seed
RowLayout {
id: recoverFromSeed
visible: !recoverFromDevice && (!recoverMode || ( recoverMode && recoverFromSeedMode))
WizardMemoTextInput {
id : memoTextItem
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
}
}
// Recover from keys
GridLayout {
Layout.bottomMargin: page.rowSpacing
rowSpacing: page.rowSpacing
id: recoverFromKeys
visible: recoverMode && !recoverFromSeedMode
columns: 1
MoneroComponents.LineEdit {
Layout.fillWidth: true
id: addressLine
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: MoneroComponents.Style.legacy_placeholderFontColor
placeholderText: qsTr("Account address (public)") + translationManager.emptyString
placeholderOpacity: 1.0
onTextUpdated: checkNextButton()
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
MoneroComponents.LineEdit {
Layout.fillWidth: true
id: viewKeyLine
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: MoneroComponents.Style.legacy_placeholderFontColor
placeholderText: qsTr("View key (private)") + translationManager.emptyString
placeholderOpacity: 1.0
onTextUpdated: checkNextButton()
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
MoneroComponents.LineEdit {
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
id: spendKeyLine
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: MoneroComponents.Style.legacy_placeholderFontColor
placeholderText: qsTr("Spend key (private)") + translationManager.emptyString
placeholderOpacity: 1.0
onTextUpdated: checkNextButton()
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
}
// Restore Height
RowLayout {
MoneroComponents.LineEdit {
id: restoreHeightItem
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: MoneroComponents.Style.legacy_placeholderFontColor
placeholderText: qsTr("Restore height (optional)") + translationManager.emptyString
placeholderOpacity: 1.0
validator: IntValidator {
bottom:0
}
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
}
// Subaddress lookahead
RowLayout {
visible: recoverFromDevice
MoneroComponents.LineEdit {
id: subaddressLookaheadItem
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: MoneroComponents.Style.legacy_placeholderFontColor
placeholderText: qsTr("Subaddress lookahead (optional): <major>:<minor>") + translationManager.emptyString
placeholderOpacity: 1.0
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
}
// Device name
ColumnLayout {
visible: recoverFromDevice
MoneroComponents.Label {
Layout.topMargin: 20 * scaleRatio
fontFamily: "Arial"
fontColor: "#555555"
fontSize: 14 * scaleRatio
text: qsTr("Device name") + translationManager.emptyString
}
ListModel {
id: deviceNameModel
ListElement { column1: qsTr("Ledger") ; column2: "Ledger"; }
// ListElement { column1: qsTr("Trezor") ; column2: "Trezor"; }
}
MoneroComponents.StandardDropdown {
id: deviceNameDropdown
dataModel: deviceNameModel
Layout.fillWidth: true
Layout.topMargin: 6
colorHeaderBackground: "black"
releasedColor: "#363636"
pressedColor: "#202020"
}
}
// Wallet store location
ColumnLayout {
z: deviceNameDropdown.z - 1
MoneroComponents.Label {
Layout.fillWidth: true
Layout.topMargin: 20 * scaleRatio
fontSize: 14
fontFamily: "Arial"
fontColor: "#555555"
text: qsTr("Your wallet is stored in") + ": " + fileUrlInput.text;
}
MoneroComponents.LineEdit {
Layout.fillWidth: true
Layout.maximumWidth: 600 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
id: fileUrlInput
text: moneroAccountsDir + "/"
// workaround for the bug "filechooser only opens once"
MouseArea {
anchors.fill: parent
onClicked: {
mouse.accepted = false
fileDialog.folder = walletManager.localPathToUrl(fileUrlInput.text)
fileDialog.open()
fileUrlInput.focus = true
}
}
borderColor: Qt.rgba(0, 0, 0, 0.15)
backgroundColor: "white"
fontColor: "black"
fontBold: false
}
FileDialog {
id: fileDialog
selectMultiple: false
selectFolder: true
title: qsTr("Please choose a directory") + translationManager.emptyString
onAccepted: {
fileUrlInput.text = walletManager.urlToLocalPath(fileDialog.folder)
fileDialog.visible = false
}
onRejected: {
fileDialog.visible = false
}
}
}
}

View file

@ -1,96 +0,0 @@
import QtQuick 2.0
import moneroComponents.Clipboard 1.0
Column {
property alias memoText : memoTextInput.text
property alias tipText: wordsTipText.text
property alias tipTextVisible: tipRect.visible
property alias memoTextReadOnly : memoTextInput.readOnly
property alias clipboardButtonVisible: clipboardButton.visible
Rectangle {
id: memoTextRect
width: parent.width
height: {
memoTextInput.height
// to have less gap between button and text input we reduce overall height by button height
//+ (clipboardButton.visible ? clipboardButton.height : 0)
+ (tipRect.visible ? tipRect.height : 0)
}
border.width: 1
border.color: "#DBDBDB"
TextEdit {
id: memoTextInput
property alias placeholderText: memoTextPlaceholder.text
textMargin: 8 * scaleRatio
text: ""
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
wrapMode: TextInput.Wrap
width: parent.width
selectByMouse: true
property int minimumHeight: 100 * scaleRatio
height: contentHeight > minimumHeight ? contentHeight : minimumHeight
Text {
id: memoTextPlaceholder
anchors.fill:parent
font.pixelSize: 16 * scaleRatio
anchors.margins: 8 * scaleRatio
font.bold:true
font.family: "Arial"
text: qsTr("Enter your 25 (or 24) word mnemonic seed") + translationManager.emptyString
color: "#BABABA"
visible: !memoTextInput.text/* && !parent.focus*/
}
}
Image {
id : clipboardButton
anchors.right: parent.right
anchors.rightMargin: 5 * scaleRatio
anchors.bottom: tipRect.top
anchors.bottomMargin: 5 * scaleRatio
source: "qrc:///images/copyToClipboard.png"
Clipboard { id: clipboard }
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
clipboard.setText(memoTextInput.text)
appWindow.showStatusMessage(qsTr("Seed copied to clipboard"),3)
}
}
}
Rectangle {
id: tipRect
visible: true
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: memoTextRect.bottom
height: wordsTipText.contentHeight + wordsTipText.anchors.topMargin
color: "#DBDBDB"
property alias text: wordsTipText.text
Text {
id: wordsTipText
anchors.fill: parent
anchors.topMargin : 16 * scaleRatio
anchors.bottomMargin: 16 * scaleRatio
anchors.leftMargin: 16 * scaleRatio
anchors.rightMargin: 16 * scaleRatio
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.family: "Arial"
font.pixelSize: 15 * scaleRatio
color: "#4A4646"
wrapMode: Text.Wrap
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
}
}
}
}

120
wizard/WizardMenuItem.qml Normal file
View file

@ -0,0 +1,120 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../components" as MoneroComponents
RowLayout {
id: rowlayout
Layout.fillWidth: true
Layout.bottomMargin: 10 * scaleRatio
property alias imageIcon: icon.source
property alias headerText: header.text
property alias bodyText: body.text
signal menuClicked();
spacing: 10 * scaleRatio
Item {
Layout.preferredWidth: 70 * scaleRatio
Layout.preferredHeight: 70 * scaleRatio
Image {
id: icon
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
source: ""
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
rowlayout.menuClicked();
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
spacing: 0
Text {
id: header
Layout.fillWidth: true
leftPadding: parent.leftPadding
topPadding: 0
color: MoneroComponents.Style.defaultFontColor
font.bold: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 22 * scaleRatio;
} else {
return 16 * scaleRatio;
}
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
rowlayout.menuClicked();
}
}
}
Text {
id: body
Layout.fillWidth: true
color: MoneroComponents.Style.dimmedFontColor
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 16 * scaleRatio;
} else {
return 14 * scaleRatio;
}
}
topPadding: 4 * scaleRatio
wrapMode: Text.WordWrap;
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
rowlayout.menuClicked();
}
}
}
}
}

View file

@ -0,0 +1,206 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardModeBootstrapWarning
color: "transparent"
property string viewName: "wizardModeRemoteNodeWarning"
property bool understood: false
ColumnLayout {
Layout.alignment: Qt.AlignHCenter;
width: parent.width - 100
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 10 * scaleRatio
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.alignment: Qt.AlignHCenter
spacing: 0 * scaleRatio
WizardHeader {
title: qsTr("About the bootstrap mode") + translationManager.emptyString
subtitle: ""
}
ColumnLayout {
spacing: 20 * scaleRatio
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
Text {
text: qsTr("This mode will use a remote node whilst also syncing the blockchain. This is different from the first menu option (Simple mode), since it will only use the remote node until the blockchain is fully synced locally. It is a reasonable tradeoff for most people who care about privacy but also want the convenience of an automatic fallback option.") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 14 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.lightGreyFontColor
}
Text {
text: qsTr("Temporary use of remote nodes is useful in order to use Monero immediately (hence the name <i>bootstrap</i>), however be aware that when using remote nodes (including with the bootstrap setting), nodes could track your IP address, track your \"restore height\" and associated block request data, and send you inaccurate information to learn more about transactions you make.") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 8 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.lightGreyFontColor
}
MoneroComponents.WarningBox{
Layout.topMargin: 14 * scaleRatio
Layout.bottomMargin: 6 * scaleRatio
text: qsTr("Remain aware of these limitations. <b>Users who prioritize privacy and decentralization must use a full node instead</b>.") + translationManager.emptyString
}
Text {
text: qsTr("For enhanced node performance you may specify your region:") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 8 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
}
GridLayout {
columns: 3
columnSpacing: 20
ColumnLayout {
Layout.fillWidth: true
spacing: 0
MoneroComponents.StandardDropdown {
id: regionDropdown
Layout.fillWidth: true
dataModel: regionModel
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#363636"
pressedColor: "#202020"
currentIndex: 0
onChanged: {
var region = regionModel.get(currentIndex).region;
persistentSettings.remoteNodeRegion = region;
}
}
}
Item {
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
z: parent.z + 1
}
MoneroComponents.CheckBox {
id: understoodCheckbox
Layout.topMargin: 20 * scaleRatio
fontSize: 16 * scaleRatio
text: qsTr("I understand the privacy implications of using a third-party server.") + translationManager.emptyString
onClicked: {
wizardModeBootstrapWarning.understood = !wizardModeBootstrapWarning.understood
}
}
WizardNav {
Layout.topMargin: 4 * scaleRatio
btnNext.enabled: wizardModeBootstrapWarning.understood
progressSteps: 0
onPrevClicked: {
wizardController.wizardState = 'wizardModeSelection';
}
onNextClicked: {
appWindow.changeWalletMode(1);
wizardController.wizardState = 'wizardHome';
}
}
}
}
}
ListModel {
id: regionModel
ListElement {column1: "Unspecified"; region: ""}
ListElement {column1: "Africa"; region: "af"}
ListElement {column1: "Asia"; region: "as"}
ListElement {column1: "Central America"; region: "ca";}
ListElement {column1: "North America"; region: "na";}
ListElement {column1: "Europe"; region: "eu";}
ListElement {column1: "Oceania"; region: "oc";}
ListElement {column1: "South America"; region: "sa";}
}
function onPageCompleted(previousView){
wizardModeBootstrapWarning.understood = false;
understoodCheckbox.checked = false;
}
Component.onCompleted: {
var region = persistentSettings.remoteNodeRegion;
if(region){
for(var i = 0; i !== regionDropdown.dataModel.count; i++){
var item = regionDropdown.dataModel.get(i);
if(item['region'] === region){
regionDropdown.currentIndex = i;
break;
}
}
} else {
regionDropdown.currentIndex = 0;
}
regionDropdown.update();
}
}

View file

@ -0,0 +1,206 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardModeRemoteNodeWarning
color: "transparent"
property string viewName: "wizardModeRemoteNodeWarning"
property bool understood: false
ColumnLayout {
Layout.alignment: Qt.AlignHCenter;
width: parent.width - 100
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 10 * scaleRatio
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.alignment: Qt.AlignHCenter
spacing: 0 * scaleRatio
WizardHeader {
title: qsTr("About the simple mode") + translationManager.emptyString
subtitle: ""
}
ColumnLayout {
spacing: 20 * scaleRatio
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
Text {
text: qsTr("This mode is ideal for managing small amounts of Monero. You have access to basic features for making and managing transactions. It will automatically connect to the Monero network so you can start using Monero immediately.") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 14 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.lightGreyFontColor
}
Text {
text: qsTr("Remote nodes are useful if you are not able/don't want to download the whole blockchain, but be advised that malicious remote nodes could compromise some privacy. They could track your IP address, track your \"restore height\" and associated block request data, and send you inaccurate information to learn more about transactions you make.") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 8 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.lightGreyFontColor
}
MoneroComponents.WarningBox{
Layout.topMargin: 14 * scaleRatio
Layout.bottomMargin: 6 * scaleRatio
text: qsTr("Remain aware of these limitations. <b>Users who prioritize privacy and decentralization must use a full node instead</b>.") + translationManager.emptyString
}
Text {
text: qsTr("For enhanced node performance you may specify your region:") + translationManager.emptyString
wrapMode: Text.Wrap
Layout.topMargin: 8 * scaleRatio
Layout.fillWidth: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
}
GridLayout {
columns: 3
columnSpacing: 20
ColumnLayout {
Layout.fillWidth: true
spacing: 0
MoneroComponents.StandardDropdown {
id: regionDropdown
Layout.fillWidth: true
dataModel: regionModel
shadowReleasedColor: "#FF4304"
shadowPressedColor: "#B32D00"
releasedColor: "#363636"
pressedColor: "#202020"
currentIndex: 0
onChanged: {
var region = regionModel.get(currentIndex).region;
persistentSettings.remoteNodeRegion = region;
}
}
}
Item {
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
z: parent.z + 1
}
MoneroComponents.CheckBox {
id: understoodCheckbox
Layout.topMargin: 20 * scaleRatio
fontSize: 16 * scaleRatio
text: qsTr("I understand the privacy implications of using a third-party server.") + translationManager.emptyString
onClicked: {
wizardModeRemoteNodeWarning.understood = !wizardModeRemoteNodeWarning.understood
}
}
WizardNav {
Layout.topMargin: 4 * scaleRatio
btnNext.enabled: wizardModeRemoteNodeWarning.understood
progressSteps: 0
onPrevClicked: {
wizardController.wizardState = 'wizardModeSelection';
}
onNextClicked: {
appWindow.changeWalletMode(0);
wizardController.wizardState = 'wizardHome';
}
}
}
}
}
ListModel {
id: regionModel
ListElement {column1: "Unspecified"; region: ""}
ListElement {column1: "Africa"; region: "af"}
ListElement {column1: "Asia"; region: "as"}
ListElement {column1: "Central America"; region: "ca";}
ListElement {column1: "North America"; region: "na";}
ListElement {column1: "Europe"; region: "eu";}
ListElement {column1: "Oceania"; region: "oc";}
ListElement {column1: "South America"; region: "sa";}
}
function onPageCompleted(previousView){
wizardModeRemoteNodeWarning.understood = false;
understoodCheckbox.checked = false;
}
Component.onCompleted: {
var region = persistentSettings.remoteNodeRegion;
if(region){
for(var i = 0; i !== regionDropdown.dataModel.count; i++){
var item = regionDropdown.dataModel.get(i);
if(item['region'] === region){
regionDropdown.currentIndex = i;
break;
}
}
} else {
regionDropdown.currentIndex = 0;
}
regionDropdown.update();
}
}

View file

@ -0,0 +1,153 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardModeSelection1
color: "transparent"
property string viewName: "wizardModeSelection1"
ColumnLayout {
Layout.alignment: Qt.AlignHCenter;
width: parent.width - 100
Layout.fillWidth: true
anchors.horizontalCenter: parent.horizontalCenter;
spacing: 10 * scaleRatio
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.topMargin: wizardController.wizardSubViewTopMargin
Layout.alignment: Qt.AlignHCenter
spacing: 0 * scaleRatio
WizardHeader {
title: qsTr("Mode selection.") + translationManager.emptyString
subtitle: qsTr("Please select the statement that best matches you.") + translationManager.emptyString
}
WizardMenuItem {
opacity: appWindow.persistentSettings.nettype == 0 ? 1.0 : 0.5
Layout.topMargin: 20 * scaleRatio
headerText: qsTr("Simple mode") + translationManager.emptyString
bodyText: {
if(appWindow.persistentSettings.nettype == 0){
return qsTr("Easy access to sending, receiving and basic functionality.") + translationManager.emptyString;
} else {
return "Available on mainnet.";
}
}
imageIcon: "../images/remote-node.png"
onMenuClicked: {
if(appWindow.persistentSettings.nettype == 0){
appWindow.changeWalletMode(0);
wizardController.wizardState = 'wizardModeRemoteNodeWarning';
}
}
}
Rectangle {
Layout.preferredHeight: 1
Layout.topMargin: 5 * scaleRatio
Layout.bottomMargin: 10 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
WizardMenuItem {
opacity: appWindow.persistentSettings.nettype == 0 ? 1.0 : 0.5
headerText: qsTr("Simple mode") + " (bootstrap)" + translationManager.emptyString
bodyText: {
if(appWindow.persistentSettings.nettype == 0){
return qsTr("Easy access to sending, receiving and basic functionality. The blockchain is downloaded to your computer.") + translationManager.emptyString;
} else {
return "Available on mainnet.";
}
}
imageIcon: "../images/local-node.png"
onMenuClicked: {
if(appWindow.persistentSettings.nettype == 0){
appWindow.changeWalletMode(1);
wizardController.wizardState = 'wizardModeBootstrap';
}
}
}
Rectangle {
Layout.preferredHeight: 1
Layout.topMargin: 5 * scaleRatio
Layout.bottomMargin: 10 * scaleRatio
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
WizardMenuItem {
headerText: qsTr("Advanced mode") + translationManager.emptyString
bodyText: qsTr("Includes extra features like mining and message verification. The blockchain is downloaded to your computer.") + translationManager.emptyString
imageIcon: "../images/local-node-full.png"
onMenuClicked: {
appWindow.changeWalletMode(2);
wizardController.wizardState = 'wizardHome';
}
}
WizardNav {
Layout.topMargin: 5 * scaleRatio
btnPrevText: qsTr("Change language") + translationManager.emptyString
btnNext.visible: false
progressSteps: 0
onPrevClicked: {
wizardController.wizardState = 'wizardLanguage';
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: 200;
easing.type: Easing.InCubic;
}
}
}

116
wizard/WizardNav.qml Normal file
View file

@ -0,0 +1,116 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
GridLayout {
id: menuNav
property alias progressEnabled: wizardProgress.visible
property int progressSteps: 0
property int progress: 0
property alias btnPrev: btnPrev
property alias btnNext: btnNext
property string btnPrevText: qsTr("Previous") + translationManager.emptyString
property string btnNextText: qsTr("Next") + translationManager.emptyString
Layout.topMargin: 20 * scaleRatio
Layout.preferredHeight: 70 * scaleRatio
Layout.preferredWidth: parent.width
columns: 3
signal nextClicked;
signal prevClicked;
Rectangle {
Layout.preferredHeight: parent.height
Layout.fillWidth: true
color: "transparent"
MoneroComponents.StandardButton {
id: btnPrev
small: true
text: menuNav.btnPrevText
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
onClicked: {
menuNav.prevClicked();
}
}
}
Rectangle {
// progress dots
Layout.preferredHeight: parent.height
Layout.fillWidth: true
color: "transparent"
RowLayout {
id: wizardProgress
spacing: 0
width: 100 // default, dynamically set later
height: 30
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
Rectangle {
Layout.preferredHeight: parent.height
Layout.fillWidth: true
color: "transparent"
MoneroComponents.StandardButton {
id: btnNext
small: true
text: menuNav.btnNextText
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
onClicked: {
menuNav.nextClicked();
}
}
}
Component.onCompleted: {
for(var i =0; i < menuNav.progressSteps; i++) {
var active = i < menuNav.progress ? 'true' : 'false';
Qt.createQmlObject("WizardNavProgressDot { active: " + active + " }", wizardProgress, 'dynamicWizardNavDot');
}
// Set `wizardProgress` width based on amount of progress dots
wizardProgress.width = 30 * menuNav.progressSteps;
}
}

View file

@ -1,21 +1,21 @@
// Copyright (c) 2014-2018, The Monero Project // Copyright (c) 2014-2019, The Monero Project
// //
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, are // Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met: // permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, this list of // 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer. // conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, this list // 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 // of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be // 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 // used to endorse or promote products derived from this software without specific
// prior written permission. // prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // 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 // 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 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
@ -26,43 +26,26 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // 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. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.0 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Layouts 1.2
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls 2.0
import QtQuick.Layouts 1.1
ColumnLayout { import "../components" as MoneroComponents
property alias password: password.text
property alias placeholderText: password.placeholderText
signal changed(string password)
Rectangle {
TextField { property bool active: false
Layout.fillWidth: true Layout.preferredWidth: 30 * scaleRatio
id : password Layout.fillHeight: true
focus:true property string activeColor: MoneroComponents.Style.defaultFontColor
font.family: "Arial" property string inactiveColor: "#333333"
font.pixelSize: (isMobile) ? 25 * scaleRatio : 26 * scaleRatio color: "transparent"
echoMode: TextInput.Password
style: TextFieldStyle {
renderType: Text.NativeRendering
textColor: "#35B05A"
passwordCharacter: "•"
background: Rectangle {
radius: 0
border.width: 0
}
}
onTextChanged: changed(text)
Keys.onReleased: {
changed(text)
}
}
Rectangle { Rectangle {
Layout.fillWidth:true anchors.horizontalCenter: parent.horizontalCenter
height: 1 anchors.verticalCenter: parent.verticalCenter
color: "#DBDBDB" width: 10 * scaleRatio
height: 10 * scaleRatio
radius: 10 * scaleRatio
color: parent.active ? parent.activeColor : parent.inactiveColor
} }
} }

View file

@ -0,0 +1,236 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import Qt.labs.folderlistmodel 2.1
import "../js/Wizard.js" as Wizard
import "../components"
import "../components" as MoneroComponents
Rectangle {
id: wizardOpenWallet1
color: "transparent"
property string viewName: "wizardOpenWallet1"
FolderListModel {
// @TODO: Current implementation only lists the folders in `/home/foo/Monero/wallets`, better
// solution is to actually scan for .keys files.
id: folderModel
nameFilters: ["*"]
folder: "file:" + moneroAccountsDir + "/"
showFiles: false
showHidden: false
sortField: FolderListModel.Time
}
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("Open a wallet from file") + translationManager.emptyString
subtitle: qsTr("Import an existing .keys wallet file from your computer.") + translationManager.emptyString
}
MoneroComponents.StandardButton {
Layout.topMargin: 20 * scaleRatio
id: btnNext
small: true
text: qsTr("Browse filesystem")
onClicked: {
wizardController.openWallet();
}
}
GridLayout {
visible: folderModel.count > 0
Layout.topMargin: 30 * scaleRatio
Layout.fillWidth: true
columnSpacing: 20 * scaleRatio
columns: 2
Text {
text: qsTr("Most recent wallets") + translationManager.emptyString
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 16 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
}
GridLayout {
visible: folderModel.count > 0
Layout.topMargin: 10 * scaleRatio
Layout.fillWidth: true
columnSpacing: 20 * scaleRatio
columns: 2
ListView {
id: recentList
property int itemHeight: 42 * scaleRatio
property int maxItems: 7
clip: true
Layout.fillWidth: true
Layout.preferredHeight: recentList.itemHeight * folderModel.count
Layout.maximumHeight: recentList.itemHeight * recentList.maxItems
interactive: false // disable scrolling
delegate: Rectangle {
height: recentList.itemHeight
width: 200 * scaleRatio
property string activeColor: "#26FFFFFF"
color: "transparent"
RowLayout {
height: recentList.itemHeight
width: parent.width
spacing: 10 * scaleRatio
Rectangle {
Layout.preferredWidth: recentList.itemHeight
Layout.preferredHeight: recentList.itemHeight
color: "transparent"
Image {
height: recentList.itemHeight
width: recentList.itemHeight
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
fillMode: Image.PreserveAspectFit
source: "../images/open-wallet-from-file.png"
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: recentList.itemHeight
color: "transparent"
TextArea {
text: fileName
anchors.verticalCenter: parent.verticalCenter
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
font.pixelSize: 18 * scaleRatio
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
selectByMouse: false
wrapMode: Text.WordWrap
textMargin: 0
leftPadding: 0
topPadding: 0
bottomPadding: 0
readOnly: true
// @TODO: Legacy. Remove after Qt 5.8.
MouseArea {
anchors.fill: parent
enabled: false
}
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: {
parent.color = parent.activeColor;
}
onExited: {
parent.color = "transparent";
}
onClicked: {
// open wallet
if(appWindow.walletMode === 0 || appWindow.walletMode === 1){
wizardController.fetchRemoteNodes(function(){
wizardController.openWalletFile(moneroAccountsDir + "/" + fileName + "/" + fileName + ".keys");
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), 5);
wizardController.openWalletFile(moneroAccountsDir + "/" + fileName + "/" + fileName + ".keys");
});
} else {
wizardController.openWalletFile(moneroAccountsDir + "/" + fileName + "/" + fileName + ".keys");
}
}
}
}
model: folderModel
}
Item {
Layout.fillWidth: true
}
}
WizardNav {
Layout.topMargin: {
if(folderModel.count > 0){
return 40 * scaleRatio;
} else {
return 20 * scaleRatio;
}
}
progressEnabled: false
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
btnNext.visible: false
onPrevClicked: {
wizardStateView.state = "wizardHome";
}
}
}
}
}

View file

@ -1,394 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import QtQml 2.2
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.1
import moneroComponents.NetworkType 1.0
import "../components"
ColumnLayout {
id: page
signal createWalletClicked()
signal recoveryWalletClicked()
signal openWalletClicked()
signal createWalletFromDeviceClicked()
opacity: 0
visible: false
property int buttonSize: (isMobile) ? 80 * scaleRatio : 140 * scaleRatio
property int buttonImageSize: (isMobile) ? buttonSize - 10 * scaleRatio : buttonSize - 30 * scaleRatio
function onPageClosed() {
// Save settings used in open from file.
// other wizard settings are saved on last page in applySettings()
appWindow.persistentSettings.language = wizard.settings.language
appWindow.persistentSettings.locale = wizard.settings.locale
return true;
}
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
ColumnLayout {
id: headerColumn
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
Layout.bottomMargin: (!isMobile) ? 40 * scaleRatio : 20
spacing: 30 * scaleRatio
Text {
Layout.fillWidth: true
font.family: "Arial"
font.pixelSize: 28 * scaleRatio
//renderType: Text.NativeRendering
color: "#3F3F3F"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Welcome to Monero!") + translationManager.emptyString
}
Text {
Layout.fillWidth: true
font.family: "Arial"
font.pixelSize: 18 * scaleRatio
//renderType: Text.NativeRendering
color: "#4A4646"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Please select one of the following options:") + translationManager.emptyString
}
}
GridLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
Layout.alignment: Qt.AlignCenter
id: actionButtons
columnSpacing: 40 * scaleRatio
rowSpacing: 10 * scaleRatio
Layout.fillWidth: true
Layout.fillHeight: true
flow: isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
GridLayout {
Layout.fillHeight: true
Layout.fillWidth: true
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
rowSpacing: 20 * scaleRatio
columnSpacing: 10 * scaleRatio
Rectangle {
Layout.preferredHeight: page.buttonSize
Layout.preferredWidth: page.buttonSize
radius: page.buttonSize
color: createWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
Image {
width: page.buttonImageSize
height: page.buttonImageSize
fillMode: Image.PreserveAspectFit
horizontalAlignment: Image.AlignRight
verticalAlignment: Image.AlignTop
anchors.centerIn: parent
source: "qrc:///images/createWallet.png"
}
MouseArea {
id: createWalletArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
page.createWalletClicked()
}
}
}
Text {
Layout.preferredWidth: page.buttonSize
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
color: "#4A4949"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("Create a new wallet") + translationManager.emptyString
}
}
GridLayout {
Layout.fillWidth: true
Layout.fillHeight: true
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
rowSpacing: 20 * scaleRatio
columnSpacing: 10 * scaleRatio
Rectangle {
Layout.preferredHeight: page.buttonSize
Layout.preferredWidth: page.buttonSize
radius: page.buttonSize
color: recoverWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
Image {
width: page.buttonImageSize
height: page.buttonImageSize
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
source: "qrc:///images/recoverWallet.png"
}
MouseArea {
id: recoverWalletArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
page.recoveryWalletClicked()
}
}
}
Text {
Layout.preferredWidth: page.buttonSize
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
color: "#4A4949"
horizontalAlignment: Text.AlignHCenter
text: qsTr("Restore wallet from keys or mnemonic seed") + translationManager.emptyString
width:page.buttonSize
wrapMode: Text.WordWrap
}
}
GridLayout {
Layout.fillHeight: true
Layout.fillWidth: true
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
rowSpacing: 20 * scaleRatio
columnSpacing: 10 * scaleRatio
Rectangle {
Layout.preferredHeight: page.buttonSize
Layout.preferredWidth: page.buttonSize
radius: page.buttonSize
color: openWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
Image {
width: page.buttonImageSize
height: page.buttonImageSize
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
source: "qrc:///images/openAccount.png"
}
MouseArea {
id: openWalletArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
page.openWalletClicked()
}
}
}
Text {
Layout.preferredWidth: page.buttonSize
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
color: "#4A4949"
horizontalAlignment: Text.AlignHCenter
text: qsTr("Open a wallet from file") + translationManager.emptyString
wrapMode: Text.WordWrap
}
}
GridLayout {
Layout.fillHeight: true
Layout.fillWidth: true
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
rowSpacing: 20 * scaleRatio
columnSpacing: 10 * scaleRatio
Rectangle {
Layout.preferredHeight: page.buttonSize
Layout.preferredWidth: page.buttonSize
radius: page.buttonSize
color: createWalletFromDeviceArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
Image {
width: page.buttonImageSize
height: page.buttonImageSize
fillMode: Image.PreserveAspectFit
horizontalAlignment: Image.AlignRight
verticalAlignment: Image.AlignTop
anchors.centerIn: parent
source: "qrc:///images/createWalletFromDevice.png"
}
MouseArea {
id: createWalletFromDeviceArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
page.createWalletFromDeviceClicked()
}
}
}
Text {
Layout.preferredWidth: page.buttonSize
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
color: "#4A4949"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("Create a new wallet from hardware device") + translationManager.emptyString
}
}
}
ColumnLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
Layout.topMargin: 30 * scaleRatio
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
spacing: 38 * scaleRatio
RowLayout {
CheckBox2 {
id: showAdvancedCheckbox
darkDropIndicator: true
text: qsTr("Advanced options") + translationManager.emptyString
fontColor: "#4A4646"
}
}
Rectangle {
width: 100 * scaleRatio
RadioButton {
visible: showAdvancedCheckbox.checked
enabled: !this.checked
id: mainNet
text: qsTr("Mainnet") + translationManager.emptyString
checkedColor: Qt.rgba(0, 0, 0, 0.75)
borderColor: Qt.rgba(0, 0, 0, 0.45)
fontColor: "#4A4646"
fontSize: 16 * scaleRatio
checked: appWindow.persistentSettings.nettype == NetworkType.MAINNET;
onClicked: {
persistentSettings.nettype = NetworkType.MAINNET
testNet.checked = false;
stageNet.checked = false;
console.log("Network type set to MainNet")
}
}
}
Rectangle {
width: 100 * scaleRatio
RadioButton {
visible: showAdvancedCheckbox.checked
enabled: !this.checked
id: testNet
text: qsTr("Testnet") + translationManager.emptyString
checkedColor: Qt.rgba(0, 0, 0, 0.75)
borderColor: Qt.rgba(0, 0, 0, 0.45)
fontColor: "#4A4646"
fontSize: 16 * scaleRatio
checked: appWindow.persistentSettings.nettype == NetworkType.TESTNET;
onClicked: {
persistentSettings.nettype = testNet.checked ? NetworkType.TESTNET : NetworkType.MAINNET
mainNet.checked = false;
stageNet.checked = false;
console.log("Network type set to ", persistentSettings.nettype == NetworkType.TESTNET ? "Testnet" : "Mainnet")
}
}
}
Rectangle {
width: 100 * scaleRatio
RadioButton {
visible: showAdvancedCheckbox.checked
enabled: !this.checked
id: stageNet
text: qsTr("Stagenet") + translationManager.emptyString
checkedColor: Qt.rgba(0, 0, 0, 0.75)
borderColor: Qt.rgba(0, 0, 0, 0.45)
fontColor: "#4A4646"
fontSize: 16 * scaleRatio
checked: appWindow.persistentSettings.nettype == NetworkType.STAGENET;
onClicked: {
persistentSettings.nettype = stageNet.checked ? NetworkType.STAGENET : NetworkType.MAINNET
mainNet.checked = false;
testNet.checked = false;
console.log("Network type set to ", persistentSettings.nettype == NetworkType.STAGENET ? "Stagenet" : "Mainnet")
}
}
}
}
RowLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
Layout.topMargin: 50 * scaleRatio
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
visible: showAdvancedCheckbox.checked
Text {
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
color: "#4A4949"
text: qsTr("Number of KDF rounds:") + translationManager.emptyString
}
TextField {
id: kdfRoundsText
font.family: "Arial"
font.pixelSize: 16 * scaleRatio
Layout.preferredWidth: 60
horizontalAlignment: TextInput.AlignRight
selectByMouse: true
color: "#4A4949"
text: persistentSettings.kdfRounds
validator: IntValidator { bottom: 1 }
onEditingFinished: {
kdfRoundsText.text = persistentSettings.kdfRounds = parseInt(kdfRoundsText.text) >= 1 ? parseInt(kdfRoundsText.text) : 1;
}
}
}
}

View file

@ -1,143 +0,0 @@
// Copyright (c) 2014-2018, 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 QtQuick.Layouts 1.1
import "../components"
import "utils.js" as Utils
ColumnLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
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 }
}
onOpacityChanged: visible = opacity !== 0
function onPageOpened(settingsObject) {
wizard.nextButton.enabled = true
passwordUI.handlePassword();
if (wizard.currentPath === "create_wallet") {
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
} else {
passwordPage.titleText = qsTr("Give your wallet a password") + translationManager.emptyString
}
passwordUI.resetFocus()
}
function onPageClosed(settingsObject) {
// TODO: set password on the final page
settingsObject['wallet_password'] = passwordUI.password
return true
}
function onWizardRestarted(){
// Reset password fields
passwordUI.password = "";
passwordUI.confirmPassword = "";
}
RowLayout {
id: dotsRow
Layout.alignment: Qt.AlignRight
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
ListElement { dotColor: "#DBDBDB" }
ListElement { dotColor: "#DBDBDB" }
}
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
}
}
}
ColumnLayout {
id: headerColumn
Text {
Layout.fillWidth: true
id: titleText
font.family: "Arial"
font.pixelSize: 28 * scaleRatio
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
//renderType: Text.NativeRendering
color: "#3F3F3F"
}
Text {
Layout.fillWidth: true
Layout.bottomMargin: 30 * scaleRatio
font.family: "Arial"
font.pixelSize: 18 * scaleRatio
wrapMode: Text.Wrap
//renderType: Text.NativeRendering
color: "#4A4646"
horizontalAlignment: Text.AlignHCenter
text: qsTr(" <br>Note: this password cannot be recovered. If you forget it then the wallet will have to be restored from its 25 word mnemonic seed.<br/><br/>
<b>Enter a strong password</b> (using letters, numbers, and/or symbols):")
+ translationManager.emptyString
}
}
ColumnLayout {
Layout.fillWidth: true;
WizardPasswordUI {
id: passwordUI
}
}
Component.onCompleted: {
parent.wizardRestarted.connect(onWizardRestarted)
}
}

View file

@ -1,102 +0,0 @@
// Copyright (c) 2014-2018, 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 QtQuick.Layouts 1.1
import "../components"
import "utils.js" as Utils
ColumnLayout {
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
// TODO: password strength meter segfaults on Android.
if (!isAndroid) {
// 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)
}
}
function resetFocus() {
passwordItem.focus = true
}
WizardPasswordInput {
id: passwordItem
Layout.fillWidth: true
Layout.maximumWidth: 300 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
Layout.alignment: Qt.AlignHCenter
placeholderText : qsTr("Password") + translationManager.emptyString;
KeyNavigation.tab: retypePasswordItem
onChanged: handlePassword()
focus: true
}
WizardPasswordInput {
id: retypePasswordItem
Layout.fillWidth: true
Layout.maximumWidth: 300 * scaleRatio
Layout.minimumWidth: 200 * scaleRatio
Layout.alignment: Qt.AlignHCenter
placeholderText : qsTr("Confirm password") + translationManager.emptyString;
KeyNavigation.tab: passwordItem
onChanged: handlePassword()
}
PrivacyLevelSmall {
visible: !isAndroid //TODO: strength meter doesnt work on Android
Layout.topMargin: isAndroid ? 20 * scaleRatio : 40 * scaleRatio
Layout.fillWidth: true
id: privacyLevel
background: "#F0EEEE"
interactive: false
}
Component.onCompleted: {
//parent.wizardRestarted.connect(onWizardRestarted)
}
}

View file

@ -1,135 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import QtQuick.Dialogs 1.2
import moneroComponents.Wallet 1.0
import QtQuick.Layouts 1.1
import 'utils.js' as Utils
ColumnLayout {
opacity: 0
visible: false
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onWizardRestarted() {
// reset account name field
uiItem.accountNameText = defaultAccountName
// Empty seedText
uiItem.wordsTextItem.memoText = ""
uiItem.recoverFromKeysAddress = ""
uiItem.recoverFromKeysSpendKey = ""
uiItem.recoverFromKeysViewKey = ""
}
function onPageOpened(settingsObject) {
console.log("on page opened")
uiItem.checkNextButton();
}
function onPageClosed(settingsObject) {
settingsObject['account_name'] = uiItem.accountNameText
settingsObject['words'] = Utils.lineBreaksToSpaces(uiItem.wordsTextItem.memoText)
settingsObject['wallet_path'] = uiItem.walletPath
settingsObject['recover_address'] = uiItem.recoverFromKeysAddress
settingsObject['recover_viewkey'] = uiItem.recoverFromKeysViewKey
settingsObject['recover_spendkey'] = uiItem.recoverFromKeysSpendKey
var restoreHeight = parseInt(uiItem.restoreHeight);
settingsObject['restore_height'] = isNaN(restoreHeight)? 0 : restoreHeight
var walletFullPath = wizard.createWalletPath(uiItem.walletPath,uiItem.accountNameText);
if(!wizard.walletPathValid(walletFullPath)){
return false
}
return recoveryWallet(settingsObject, uiItem.recoverFromSeedMode)
}
function recoveryWallet(settingsObject, fromSeed) {
var nettype = appWindow.persistentSettings.nettype;
var kdfRounds = appWindow.persistentSettings.kdfRounds;
var restoreHeight = settingsObject.restore_height;
var tmp_wallet_filename = oshelper.temporaryFilename()
console.log("Creating temporary wallet", tmp_wallet_filename)
// delete the temporary wallet object before creating new
if (typeof m_wallet !== 'undefined') {
walletManager.closeWallet()
console.log("deleting temporary wallet")
}
// From seed or keys
if(fromSeed)
var wallet = walletManager.recoveryWallet(tmp_wallet_filename, settingsObject.words, nettype, restoreHeight, kdfRounds)
else
var wallet = walletManager.createWalletFromKeys(tmp_wallet_filename, settingsObject.wallet_language, nettype,
settingsObject.recover_address, settingsObject.recover_viewkey,
settingsObject.recover_spendkey, restoreHeight, kdfRounds)
var success = wallet.status === Wallet.Status_Ok;
if (success) {
m_wallet = wallet;
settingsObject['is_recovering'] = true;
settingsObject['tmp_wallet_filename'] = tmp_wallet_filename
} else {
console.log(wallet.errorString)
walletErrorDialog.text = wallet.errorString;
walletErrorDialog.open();
walletManager.closeWallet();
}
return success;
}
WizardManageWalletUI {
id: uiItem
accountNameText: defaultAccountName
titleText: qsTr("Restore wallet") + translationManager.emptyString
wordsTextItem.clipboardButtonVisible: false
wordsTextItem.tipTextVisible: false
wordsTextItem.memoTextReadOnly: false
wordsTextItem.memoText: ""
wordsTextItem.visible: true
restoreHeightVisible: true
recoverMode: true
wordsTextItem.onMemoTextChanged: {
checkNextButton();
}
}
Component.onCompleted: {
parent.wizardRestarted.connect(onWizardRestarted)
}
}

View file

@ -0,0 +1,284 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
Rectangle {
id: wizardRestoreWallet1
color: "transparent"
property string viewName: "wizardCreateWallet1"
function verify() {
if(wizardController.walletRestoreMode === "keys") {
var valid = wizardRestoreWallet1.verifyFromKeys();
return valid;
} else if(wizardController.walletRestoreMode === "seed") {
var valid = wizardWalletInput.verify();
if(!valid) return false;
valid = Wizard.checkSeed(seedInput.text);
return valid;
}
return false;
}
function verifyFromKeys() {
var result = Wizard.restoreWalletCheckViewSpendAddress(
walletManager,
persistentSettings.nettype,
viewKeyLine.text,
spendKeyLine.text,
addressLine.text
);
var addressLineLength = addressLine.text.length
var viewKeyLineLength = viewKeyLine.text.length
var spendKeyLineLength = spendKeyLine.text.length
addressLine.error = !result[0] && addressLineLength != 0
viewKeyLine.error = !result[1] && viewKeyLineLength != 0
spendKeyLine.error = !result[2] && spendKeyLineLength != 0
return (!addressLine.error && !viewKeyLine.error && !spendKeyLine.error &&
addressLineLength != 0 && viewKeyLineLength != 0 && spendKeyLineLength != 0)
}
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("Restore wallet") + translationManager.emptyString
subtitle: qsTr("Restore wallet from keys or mnemonic seed.") + translationManager.emptyString
}
WizardWalletInput{
id: wizardWalletInput
}
GridLayout{
columns: 3
MoneroComponents.StandardButton {
text: qsTr("Restore from seed") + translationManager.emptyString
small: true
enabled: wizardController.walletRestoreMode !== 'seed'
onClicked: {
wizardController.walletRestoreMode = 'seed';
}
}
MoneroComponents.StandardButton {
text: qsTr("Restore from keys") + translationManager.emptyString
small: true
enabled: wizardController.walletRestoreMode !== 'keys'
onClicked: {
wizardController.walletRestoreMode = 'keys';
}
}
MoneroComponents.StandardButton {
text: qsTr("From QR Code") + translationManager.emptyString
small: true
visible: appWindow.qrScannerEnabled
enabled: wizardController.walletRestoreMode !== 'qr'
onClicked: {
wizardController.walletRestoreMode = 'qr';
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(Wizard.updateFromQrCode)
}
}
}
ColumnLayout {
// seed textarea
visible: wizardController.walletRestoreMode === 'seed'
Layout.preferredHeight: 100 * scaleRatio
Layout.fillWidth: true
Rectangle {
color: "transparent"
radius: 4
Layout.preferredHeight: 100 * scaleRatio
Layout.fillWidth: true
border.width: 1
border.color: {
if(seedInput.text !== "" && seedInput.error){
return MoneroComponents.Style.inputBorderColorInvalid;
} else if(seedInput.activeFocus){
return MoneroComponents.Style.inputBorderColorActive;
} else {
return MoneroComponents.Style.inputBorderColorInActive;
}
}
TextArea {
id: seedInput
property bool error: false
width: parent.width
height: 100 * scaleRatio
color: MoneroComponents.Style.defaultFontColor
textMargin: 2 * scaleRatio
text: ""
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 16 * scaleRatio
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
wrapMode: TextInput.Wrap
selectByMouse: true
Text {
id: memoTextPlaceholder
opacity: 0.35
anchors.fill:parent
font.pixelSize: 16 * scaleRatio
anchors.margins: 8 * scaleRatio
anchors.leftMargin: 10 * scaleRatio
font.family: MoneroComponents.Style.fontRegular.name
text: qsTr("Enter your 25 (or 24) word mnemonic seed") + translationManager.emptyString
color: MoneroComponents.Style.defaultFontColor
visible: !seedInput.text && !parent.focus
}
}
}
}
MoneroComponents.LineEdit {
id: addressLine
visible: wizardController.walletRestoreMode === 'keys'
Layout.fillWidth: true
placeholderFontSize: 16 * scaleRatio
placeholderText: qsTr("Account address (public)") + translationManager.emptyString
onTextUpdated: {
wizardRestoreWallet1.verifyFromKeys();
}
}
MoneroComponents.LineEdit {
id: viewKeyLine
visible: wizardController.walletRestoreMode === 'keys'
Layout.fillWidth: true
placeholderFontSize: 16 * scaleRatio
placeholderText: qsTr("View key (private)") + translationManager.emptyString
onTextUpdated: {
wizardRestoreWallet1.verifyFromKeys();
}
}
MoneroComponents.LineEdit {
id: spendKeyLine
visible: wizardController.walletRestoreMode === 'keys'
Layout.fillWidth: true
placeholderFontSize: 16 * scaleRatio
placeholderText: qsTr("Spend key (private)") + translationManager.emptyString
onTextUpdated: {
wizardRestoreWallet1.verifyFromKeys();
}
}
GridLayout{
MoneroComponents.LineEdit {
id: restoreHeight
Layout.fillWidth: true
labelText: qsTr("Restore height") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderFontSize: 16 * scaleRatio
placeholderText: qsTr("Restore height") + translationManager.emptyString
validator: RegExpValidator { regExp: /(\d+)?$/ }
text: "0"
}
Item {
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
}
WizardNav {
id: nav
progressSteps: 4
progress: 1
btnNext.enabled: wizardRestoreWallet1.verify();
btnPrev.text: qsTr("Back to menu") + translationManager.emptyString
onPrevClicked: {
wizardStateView.state = "wizardHome";
}
onNextClicked: {
wizardController.walletOptionsName = wizardWalletInput.walletName.text;
wizardController.walletOptionsLocation = wizardWalletInput.walletLocation.text;
wizardController.walletOptionsSeed = seedInput.text;
if(restoreHeight.text)
wizardController.walletOptionsRestoreHeight = parseInt(restoreHeight.text);
wizardStateView.state = "wizardRestoreWallet2";
}
}
}
}
function onPageCompleted(previousView){
if(previousView.viewName == "wizardHome"){
// cleanup
seedInput.text = "";
addressLine.text = "";
spendKeyLine.text = "";
restoreHeight.text = "";
}
}
}

View file

@ -0,0 +1,85 @@
// 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 "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
Rectangle {
id: wizardRestoreWallet2
color: "transparent"
property string viewName: "wizardRestoreWallet2"
property int recoveryMode: 1
ColumnLayout {
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: 0 * scaleRatio
WizardAskPassword {
id: passwordFields
}
WizardNav {
progressSteps: 4
progress: 2
btnNext.enabled: passwordFields.calcStrengthAndVerify();
onPrevClicked: {
wizardStateView.state = "wizardRestoreWallet1";
}
onNextClicked: {
if(appWindow.walletMode === 0 || appWindow.walletMode === 1){
wizardController.fetchRemoteNodes(function(){
wizardStateView.state = "wizardRestoreWallet4";
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), 5);
wizardStateView.state = "wizardRestoreWallet4";
});
} else {
wizardStateView.state = "wizardRestoreWallet3";
}
}
}
}
}
}

View file

@ -0,0 +1,86 @@
// 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 "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
Rectangle {
id: wizardRestoreWallet3
color: "transparent"
property string viewName: "wizardRestoreWallet3"
property int recoveryMode: 1
function verify() {
// @TODO: check if walletName already exists in walletLocation
return walletName.text !== '';
}
ColumnLayout {
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 * scaleRatio
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.\n\nIf you don't have the option to run your own node, there's an option to connect to a remote node.") + translationManager.emptyString
}
WizardDaemonSettings {
id: daemonSettings
}
WizardNav {
progressSteps: 4
progress: 3
onPrevClicked: {
wizardStateView.state = "wizardRestoreWallet2";
}
onNextClicked: {
daemonSettings.save();
wizardStateView.state = "wizardRestoreWallet4";
}
}
}
}
}

View file

@ -0,0 +1,84 @@
// 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 "../components" as MoneroComponents
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
Rectangle {
id: wizardRestoreWallet4
color: "transparent"
property string viewName: "wizardRestoreWallet4"
ColumnLayout {
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 * scaleRatio
WizardHeader {
title: qsTr("You're all set up!") + translationManager.emptyString
subtitle: qsTr("New wallet details:") + translationManager.emptyString
}
WizardSummary {}
WizardNav {
Layout.topMargin: 24 * scaleRatio
btnNextText: "Open wallet"
progressSteps: 4
progress: 4
onPrevClicked: {
if (appWindow.walletMode <= 1){
wizardStateView.state = "wizardRestoreWallet1";
} else {
wizardStateView.state = "wizardRestoreWallet3";
}
}
onNextClicked: {
wizardController.writeWallet();
wizardController.useMoneroClicked();
}
}
}
}
}

91
wizard/WizardSummary.qml Normal file
View file

@ -0,0 +1,91 @@
// 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.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import moneroComponents.NetworkType 1.0
import "../js/Wizard.js" as Wizard
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
ColumnLayout {
Layout.fillWidth: true
spacing: 0
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Wallet name") + translationManager.emptyString
value: wizardController.walletOptionsName
}
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Wallet path") + translationManager.emptyString
value: wizardController.walletOptionsLocation
}
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Language") + translationManager.emptyString
value: wizardController.language_language
}
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Wallet name") + translationManager.emptyString
value: walletOptionsName
}
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Restore height") + translationManager.emptyString
value: wizardController.walletOptionsRestoreHeight
}
WizardSummaryItem {
visible: persistentSettings.remoteNodeAddress !== "" && appWindow.walletMode == 0
Layout.fillWidth: true
header: qsTr("Daemon address") + translationManager.emptyString
value: persistentSettings.remoteNodeAddress
}
WizardSummaryItem {
visible: persistentSettings.bootstrapNodeAddress !== "" && appWindow.walletMode == 1
Layout.fillWidth: true
header: qsTr("Bootstrap address") + translationManager.emptyString
value: persistentSettings.bootstrapNodeAddress
}
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Network Type") + translationManager.emptyString
value: Utils.netTypeToString()
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018, The Monero Project // Copyright (c) 2014-2019, The Monero Project
// //
// All rights reserved. // All rights reserved.
// //
@ -26,54 +26,60 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // 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. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import moneroComponents.WalletManager 1.0 import QtQuick 2.7
import QtQuick 2.2 import QtQuick.Layouts 1.2
import QtQuick.Layouts 1.1 import QtQuick.Controls 2.0
import "../components"
import "utils.js" as Utils import "../js/Wizard.js" as Wizard
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
ColumnLayout { ColumnLayout {
property alias header: key.text
property alias value: val.text
Layout.bottomMargin: 10
Layout.fillWidth: true
id: passwordPage GridLayout {
opacity: 0 Layout.fillWidth: true
visible: false columns: 2
columnSpacing: 0
Behavior on opacity { Rectangle {
NumberAnimation { duration: 100; easing.type: Easing.InQuad } Layout.fillWidth: true
Layout.preferredHeight: 20 * scaleRatio
color: "transparent"
MoneroComponents.TextBlock {
id: key
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
font.pixelSize: 16
text: "test"
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 20 * scaleRatio
color: "transparent"
MoneroComponents.TextBlock {
id: val
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
font.pixelSize: 16
text: ""
}
}
} }
onOpacityChanged: visible = opacity !== 0 Rectangle {
Layout.preferredHeight: 1 * scaleRatio
Layout.topMargin: 2 * scaleRatio
function onPageOpened(settingsObject) { Layout.bottomMargin: 2 * scaleRatio
wizard.nextButton.enabled = true Layout.fillWidth: true
wizard.nextButton.visible = true color: MoneroComponents.Style.dividerColor
} opacity: MoneroComponents.Style.dividerOpacity
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);
}
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#DBDBDB" }
}
WizardManageWalletUI {
id: uiItem
titleText: qsTr("Create view only wallet") + translationManager.emptyString
wordsTextItem.visible: false
restoreHeightVisible:false
walletName: appWindow.walletName + "-viewonly"
progressDotsModel: dotsModel
recoverMode: false
}
Component.onCompleted: {
//parent.wizardRestarted.connect(onWizardRestarted)
} }
} }

View file

@ -0,0 +1,111 @@
// 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.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
import "../js/Wizard.js" as Wizard
import "../components"
import "../components" as MoneroComponents
GridLayout {
Layout.fillWidth: true
property alias walletName: walletName
property alias walletLocation: walletLocation
columnSpacing: 20 * scaleRatio
columns: 3
function verify() {
if(walletName.text !== '' && walletLocation.text !== ''){
if(!walletName.error){
return true;
}
}
return false;
}
MoneroComponents.LineEdit {
id: walletName
Layout.fillWidth: true
function verify(){
if(walletLocation === "") return false;
var exists = Wizard.walletPathExists(walletLocation.text, walletName.text, isIOS, walletManager);
return !exists && walletLocation.error === false;
}
labelText: qsTr("Wallet name") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderFontSize: 16 * scaleRatio
placeholderText: "-"
text: defaultAccountName
onTextChanged: walletName.error = !walletName.verify();
Component.onCompleted: walletName.error = !walletName.verify();
}
MoneroComponents.LineEdit {
id: walletLocation
Layout.fillWidth: true
labelText: qsTr("Wallet location") + translationManager.emptyString
labelFontSize: 14 * scaleRatio
placeholderText: "..."
placeholderFontSize: 16 * scaleRatio
text: moneroAccountsDir + "/"
inlineButton.small: true
inlineButtonText: qsTr("Browse") + translationManager.emptyString
inlineButton.onClicked: {
fileWalletDialog.folder = walletManager.localPathToUrl(walletLocation.text)
fileWalletDialog.open()
walletLocation.focus = true
}
onTextChanged: {
walletLocation.error = walletLocation.text === "";
}
}
FileDialog {
id: fileWalletDialog
selectMultiple: false
selectFolder: true
title: qsTr("Please choose a directory") + translationManager.emptyString
onAccepted: {
walletLocation.text = walletManager.urlToLocalPath(fileWalletDialog.folder);
fileWalletDialog.visible = false;
walletName.error = !walletName.verify();
}
onRejected: {
fileWalletDialog.visible = false;
}
}
}

View file

@ -1,195 +0,0 @@
// Copyright (c) 2014-2018, 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.2
import QtQuick.XmlListModel 2.0
import QtQuick.Layouts 1.1
import QtQml 2.2
import "../components" as MoneroComponents
ColumnLayout {
// anchors.fill:parent
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onPageClosed(settingsObject) {
// set default language to first item if none selected
if(gridView.currentIndex === -1) {
gridView.currentIndex = 0
}
var lang = languagesModel.get(gridView.currentIndex);
settingsObject['language'] = lang.display_name;
settingsObject['wallet_language'] = lang.wallet_language;
settingsObject['locale'] = lang.locale;
console.log("Language chosen: ",lang.display_name)
return true
}
ColumnLayout {
id: headerColumn
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
Layout.bottomMargin: 40 * scaleRatio
spacing: 20 * scaleRatio
Text {
Layout.fillWidth: true
font.family: "Arial"
font.pixelSize: 28 * scaleRatio
color: "#3F3F3F"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Welcome to Monero!") + translationManager.emptyString
}
Text {
Layout.fillWidth: true
font.family: "Arial"
font.pixelSize: 18 * scaleRatio
color: "#4A4646"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: qsTr("Please choose a language and regional format.") + translationManager.emptyString
}
}
// Flags model
XmlListModel {
id: languagesModel
source: "/lang/languages.xml"
query: "/languages/language"
XmlRole { name: "display_name"; query: "@display_name/string()" }
XmlRole { name: "locale"; query: "@locale/string()" }
XmlRole { name: "wallet_language"; query: "@wallet_language/string()" }
XmlRole { name: "flag"; query: "@flag/string()" }
// TODO: XmlListModel is read only, we should store current language somewhere else
// and set current language accordingly
XmlRole { name: "isCurrent"; query: "@enabled/string()" }
onStatusChanged: {
if(status === XmlListModel.Ready){
console.log("languages availible: ",count);
if(count === 1){
console.log("Skipping language page until more languages are availible")
wizard.switchPage(true);
}
}
}
}
ColumnLayout{
// Flags view
GridView {
property int margin: (isMobile) ? 0 : Math.floor(appWindow.width/12);
id: gridView
cellWidth: 140 * scaleRatio
cellHeight: 120 * scaleRatio
model: languagesModel
// Hack to center the flag grid
property int columns: Math.floor(appWindow.width/cellWidth)
Layout.leftMargin: margin + (appWindow.width - cellWidth*columns) /2
Layout.rightMargin: margin
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
delegate: Item {
id: flagDelegate
height: gridView.cellHeight
width: gridView.cellWidth
ColumnLayout {
width: gridView.cellWidth
Rectangle {
id: flagRect
height: 60 * scaleRatio
width: 60 * scaleRatio
radius: 30 * scaleRatio
Layout.alignment: Qt.AlignHCenter
color: {
if (gridView.currentIndex === index) {
return MoneroComponents.Style.buttonBackgroundColor;
} else if (delegateArea.containsMouse) {
return MoneroComponents.Style.dimmedFontColor;
} else {
return MoneroComponents.Style.buttonTextColor;
}
}
Image {
anchors.fill: parent
source: flag
}
}
Text {
font.family: "Arial"
font.pixelSize: 18 * scaleRatio
font.bold: gridView.currentIndex === index
color: "#3F3F3F"
text: display_name
Layout.alignment: Qt.AlignHCenter
}
}
MouseArea {
id: delegateArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
gridView.currentIndex = index
var data = languagesModel.get(gridView.currentIndex);
if (data !== null || data !== undefined) {
var locale = data.locale
translationManager.setLanguage(locale.split("_")[0]);
wizard.switchPage(true)
}
}
}
} // delegate
}
}
}

View file

@ -1,24 +0,0 @@
.pragma library
function mapScope (inputScopeFrom, inputScopeTo, outputScopeFrom, outputScopeTo, value) {
var x = (value - inputScopeFrom) / (inputScopeTo - inputScopeFrom);
var result = outputScopeFrom + ((outputScopeTo - outputScopeFrom) * x);
return result;
}
function tr(text) {
return qsTr(text) + translationManager.emptyString
}
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$/, '')
}