Wizard redesign

pull/2/head
dsc 5 years ago
parent 333f4aaf83
commit f329a71029
No known key found for this signature in database
GPG Key ID: 7BBC83D7A8810AAB

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

@ -33,14 +33,20 @@ import "../components" as MoneroComponents
Item {
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 shadowReleasedColor: "#FF4304"
property string pressedColor: "#FF4304"
property string releasedColor: "#FF6C3C"
property string icon: ""
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 buttonColor: rect.color
signal clicked()
@ -59,14 +65,14 @@ Item {
width: inlineText.text ? (inlineText.width + 22) * scaleRatio : inlineButton.icon ? (inlineImage.width + 16) * scaleRatio : rect.height
radius: 4
anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
Text {
id: inlineText
font.family: MoneroComponents.Style.fontBold.name
font.bold: true
font.pixelSize: 16 * scaleRatio
font.pixelSize: inlineButton.fontSize
color: "black"
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter

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

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

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

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

@ -47,8 +47,13 @@ Rectangle {
}
if (status == Wallet.ConnectionStatus_WrongVersion)
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("Invalid connection status")
}

@ -31,6 +31,7 @@ import QtQuick.Controls.Styles 1.2
import QtQuick 2.2
import QtQuick.Layouts 1.1
import "../js/Utils.js" as Utils
import "../components" as MoneroComponents
GridLayout {
@ -65,7 +66,14 @@ GridLayout {
}
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 {

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

@ -126,37 +126,88 @@ Rectangle {
z: parent.z + 1
}
// collapse left panel
Rectangle {
id: goToBasicVersionButton
property bool containsMouse: titleBar.mouseX >= x && titleBar.mouseX <= x + width
property bool checked: false
anchors.top: parent.top
RowLayout {
anchors.left: parent.left
color: "transparent"
height: titleBar.height
width: height
visible: !titleBar.orange && titleBar.basicButtonVisible
anchors.top: parent.top
width: 40
height: parent.height
spacing: 0
z: parent.z + 2
Image {
width: 14
height: 14
anchors.centerIn: parent
source: "../images/expand.png"
Rectangle {
Layout.preferredHeight: parent.height
Layout.preferredWidth: Layout.preferredHeight
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 {
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)
// language selection
Rectangle {
Layout.preferredHeight: parent.height
Layout.preferredWidth: Layout.preferredHeight
visible: !titleBar.orange && persistentSettings.customDecorations
id: languageSelection
property bool containsMouse: titleBar.mouseX >= x && titleBar.mouseX <= x + width
property bool checked: false
color: "transparent"
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');
}
}
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 KiB

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

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

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

@ -37,8 +37,8 @@ import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0
import "components"
import "components" as MoneroComponents
import "wizard"
import "js/Utils.js" as Utils
import "js/Windows.js" as Windows
@ -73,6 +73,7 @@ ApplicationWindow {
property int blocksToSync: 1
property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true
property bool isMining: false
property int walletMode: persistentSettings.walletMode
property var cameraUi
property bool remoteNodeConnected: false
property bool androidCloseTapped: false;
@ -81,7 +82,21 @@ ApplicationWindow {
readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort(persistentSettings.nettype)
property string currentDaemonAddress;
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
property bool walletInitialized : false
@ -186,10 +201,12 @@ ApplicationWindow {
restoreHeight = 0;
persistentSettings.is_recovering = false
walletPassword = ""
fileDialog.folder = "file://" + moneroAccountsDir
fileDialog.open();
}
function initialize() {
appWindow.viewState = "normal";
console.log("initializing..")
// Use stored log level
@ -213,19 +230,17 @@ ApplicationWindow {
closeWallet();
currentWallet = undefined
} else if (!walletInitialized) {
// set page to transfer if not changing daemon
middlePanel.state = "Transfer";
leftPanel.selectItem(middlePanel.state)
}
// Local daemon settings
walletManager.setDaemonAddress(localDaemonAddress)
// enable user inactivity timer
// enable timers
userInActivityTimer.running = true;
simpleModeConnectionTimer.running = true;
// wallet already opened with wizard, we just need to initialize it
if (typeof wizard.m_wallet !== 'undefined') {
@ -389,8 +404,8 @@ ApplicationWindow {
// Update fee multiplier dropdown on transfer page
middlePanel.transferView.updatePriorityDropdown();
// If wallet isnt connected and no daemon is running - Ask
if(!isMobile && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
if(!isMobile && appWindow.walletMode >= 2 && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
daemonManagerDialog.open();
}
// 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
middlePanel.miningView.update();
}
}
}
function onWalletOpened(wallet) {
walletName = usefulName(wallet.path)
@ -414,6 +429,7 @@ ApplicationWindow {
passwordDialog.onRejectedCallback = function() {
walletPassword = "";
//appWindow.enableUI(false)
wizard.wizardState = "wizardHome";
rootItem.state = "wizard";
}
// opening with password but password doesn't match
@ -426,6 +442,9 @@ ApplicationWindow {
// wallet opened successfully, subscribing for wallet updates
connectWallet(wallet)
// Force switch normal view
rootItem.state = "normal";
}
@ -527,6 +546,9 @@ ApplicationWindow {
// Pause refresh while starting daemon
currentWallet.pauseRefresh();
// Pause simplemode connection timer
simpleModeConnectionTimer.stop();
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress);
persistentSettings.daemonFlags = flags
@ -544,6 +566,8 @@ ApplicationWindow {
currentWallet.connected(true);
// resume refresh
currentWallet.startRefresh();
// resume simplemode connection timer
simpleModeConnectionTimer.start();
}
function onDaemonStopped(){
console.log("daemon stopped");
@ -938,11 +962,13 @@ ApplicationWindow {
closeWallet();
currentWallet = undefined;
wizard.restart();
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
// disable inactivity timer
// disable timers
userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false;
}
function hideMenu() {
@ -1004,6 +1030,7 @@ ApplicationWindow {
initialize(persistentSettings);
}
passwordDialog.onRejectedCallback = function() {
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"
}
passwordDialog.open(usefulName(walletPath()))
@ -1048,12 +1075,15 @@ ApplicationWindow {
property bool useRemoteNode: false
property string remoteNodeAddress: ""
property string bootstrapNodeAddress: ""
property string remoteNodeRegion: ""
property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true
property int segregationHeight: 0
property int kdfRounds: 1
property bool hideBalance: false
property bool lockOnUserInActivity: true
property int walletMode: 2
property string remoteNodeService: ""
property int lockOnUserInActivityInterval: 10 // minutes
property bool showPid: false
}
@ -1116,11 +1146,11 @@ ApplicationWindow {
//Open Wallet from file
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: "file://" +moneroAccountsDir
title: qsTr("Please choose a file")
folder: "file://" + moneroAccountsDir
nameFilters: [ "Wallet files (*.keys)"]
sidebarVisible: false
visible: false
onAccepted: {
persistentSettings.wallet_path = walletManager.urlToLocalPath(fileDialog.fileUrl)
@ -1135,7 +1165,8 @@ ApplicationWindow {
initialize();
}
passwordDialog.onRejectedCallback = function() {
console.log("Canceled")
console.log("Canceled");
wizard.wizardState = "wizardHome";
rootItem.state = "wizard";
}
passwordDialog.open(usefulName(walletPath()));
@ -1150,27 +1181,31 @@ ApplicationWindow {
// Choose blockchain folder
FileDialog {
id: blockchainFileDialog
property string directory: ""
signal changed();
title: "Please choose a folder"
selectFolder: true
folder: "file://" + persistentSettings.blockchainDataDir
onRejected: console.log("data dir selection canceled")
onAccepted: {
var dataDir = walletManager.urlToLocalPath(blockchainFileDialog.fileUrl)
var validator = daemonManager.validateDataDir(dataDir);
if(!validator.valid) {
if(validator.valid) {
persistentSettings.blockchainDataDir = dataDir;
} else {
confirmationDialog.title = qsTr("Warning") + translationManager.emptyString;
confirmationDialog.text = "";
if(validator.readOnly)
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"
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"
if(!validator.lmdbExists)
confirmationDialog.text += qsTr("Note: lmdb folder not found. A new folder will be created.") + "\n\n"
confirmationDialog.icon = StandardIcon.Question
confirmationDialog.cancelText = qsTr("Cancel")
@ -1180,25 +1215,15 @@ ApplicationWindow {
}
// Cancel
confirmationDialog.onRejectedCallback = function() {
};
confirmationDialog.onRejectedCallback = function() { };
confirmationDialog.open()
} else {
persistentSettings.blockchainDataDir = dataDir
}
blockchainFileDialog.directory = blockchainFileDialog.fileUrl;
delete validator;
}
onRejected: {
console.log("data dir selection canceled")
}
}
PasswordDialog {
id: passwordDialog
visible: false
@ -1287,19 +1312,16 @@ ApplicationWindow {
PropertyChanges { target: leftPanel; visible: false }
PropertyChanges { target: rightPanel; visible: false }
PropertyChanges { target: middlePanel; visible: false }
PropertyChanges { target: titleBar; basicButtonVisible: false }
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: resizeArea; visible: true }
PropertyChanges { target: titleBar; showMaximizeButton: 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: titleBar; basicButtonVisible: false }
PropertyChanges { target: titleBar; showMaximizeButton: true }
PropertyChanges { target: titleBar; visible: true }
PropertyChanges { target: titleBar; title: qsTr("Monero") + translationManager.emptyString }
}, State {
name: "normal"
PropertyChanges { target: leftPanel; visible: (isMobile)? false : true }
@ -1573,17 +1595,13 @@ ApplicationWindow {
// }
}
WizardMain {
WizardController {
id: wizard
anchors.fill: parent
onUseMoneroClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow;
rootItem.state = "normal";
appWindow.initialize();
}
onOpenWalletFromFileClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow;
appWindow.openWalletFromFile();
}
}
property int minWidth: 326
@ -1730,6 +1748,50 @@ ApplicationWindow {
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 {
id: statusMessage
z: 99
@ -1873,6 +1935,7 @@ ApplicationWindow {
}
function checkInUserActivity() {
if(rootItem.state !== "normal") return;
if(!persistentSettings.lockOnUserInActivity) return;
// 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
DaemonConsole {
id: daemonConsolePopup
@ -1922,4 +1993,8 @@ ApplicationWindow {
color: "black"
opacity: 0.8
}
MoneroComponents.LanguageSidebar {
id: languageSidebar
}
}

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

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

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

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

@ -39,6 +39,15 @@ Rectangle {
color: "transparent"
height: 1400 * scaleRatio
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 {
id: infoLayout
@ -239,6 +248,36 @@ Rectangle {
font.pixelSize: 14 * scaleRatio
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
@ -261,6 +300,7 @@ Rectangle {
data += currentWallet.walletCreationHeight;
data += "\nWallet log path: " + walletLogPath;
data += "\nWallet mode: " + walletModeString;
console.log("Copied to clipboard");
clipboard.setText(data);

@ -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 {
visible: isMobile
font.pixelSize: 14

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

@ -62,23 +62,13 @@
<file>images/resize@2x.png</file>
<file>images/resizeHovered.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@2x.png</file>
<file>wizard/WizardOptions.qml</file>
<file>images/createWallet.png</file>
<file>images/createWalletFromDevice.png</file>
<file>images/openAccount.png</file>
<file>images/recoverWallet.png</file>
<file>wizard/WizardCreateWallet.qml</file>
<file>wizard/WizardCreateWalletFromDevice.qml</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/flags/bd.png</file>
<file>lang/flags/bg.png</file>
@ -123,10 +113,6 @@
<file>lang/flags/gb.png</file>
<file>lang/flags/us.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/TxKey.qml</file>
<file>pages/SharedRingDB.qml</file>
@ -140,14 +126,11 @@
<file>pages/Sign.qml</file>
<file>components/DaemonManagerDialog.qml</file>
<file>version.js</file>
<file>wizard/WizardPasswordUI.qml</file>
<file>wizard/WizardCreateViewOnlyWallet.qml</file>
<file>components/DaemonConsole.qml</file>
<file>components/QRCodeScanner.qml</file>
<file>components/Notifier.qml</file>
<file>components/MobileHeader.qml</file>
<file>components/TextBlock.qml</file>
<file>wizard/WizardDaemonSettings.qml</file>
<file>components/RemoteNodeEdit.qml</file>
<file>pages/Keys.qml</file>
<file>images/appicon.ico</file>
@ -247,5 +230,45 @@
<file>fonts/FontAwesome/FontAwesome.qml</file>
<file>fonts/FontAwesome/Object.qml</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>
</RCC>

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

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

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

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

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

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

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

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

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

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

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

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018, The Monero Project
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@ -26,171 +26,142 @@
// 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
import QtQuick 2.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
ColumnLayout {
Layout.leftMargin: wizardLeftMargin
Layout.rightMargin: wizardRightMargin
id: passwordPage
opacity: 0
visible: false
property alias titleText: titleText.text
Behavior on opacity {
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
}
onOpacityChanged: visible = opacity !== 0
function onPageOpened(settingsObject) {
}
function onWizardRestarted(){
}
import "../js/Wizard.js" as Wizard
import "../components" as MoneroComponents
function onPageClosed(settingsObject) {
appWindow.persistentSettings.useRemoteNode = remoteNode.checked
appWindow.persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
appWindow.persistentSettings.bootstrapNodeAddress = bootstrapNodeEdit.daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
return true
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: wizardController.wizardSubViewWidth
Layout.alignment: Qt.AlignHCenter
spacing: 10 * scaleRatio
function save(){
persistentSettings.useRemoteNode = remoteNode.checked
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
persistentSettings.bootstrapNodeAddress = bootstrapNodeEdit.daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
}
RowLayout {
id: dotsRow
Layout.alignment: Qt.AlignRight
ListModel {
id: dotsModel
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#36B05B" }
ListElement { dotColor: "#FFE00A" }
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
}
MoneroComponents.RadioButton {
id: localNode
text: qsTr("Start a node automatically in background (recommended)") + translationManager.emptyString
fontSize: 16 * scaleRatio
checked: !appWindow.persistentSettings.useRemoteNode && !isAndroid && !isIOS
visible: !isAndroid && !isIOS
onClicked: {
checked = true;
remoteNode.checked = false;
}
}
ColumnLayout {
id: headerColumn
visible: localNode.checked
id: blockchainFolderRow
spacing: 20 * scaleRatio
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: "Daemon settings"
Layout.topMargin: 8 * scaleRatio
Layout.fillWidth: true
}
Text {
MoneroComponents.LineEdit {
id: blockchainFolder
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;
}
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 {
visible: localNode.checked
id: blockchainFolderRow
Label {
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
ColumnLayout{
Layout.topMargin: 6 * scaleRatio
spacing: 0
TextArea {
text: qsTr("Bootstrap node") + translationManager.emptyString
Layout.topMargin: 10 * 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)
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
font.family: MoneroComponents.Style.fontRegular.name
color: MoneroComponents.Style.defaultFontColor
font.pixelSize: {
if(wizardController.layoutScale === 2 ){
return 22 * scaleRatio;
} else {
return 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
}
Label {
TextArea {
text: qsTr("Additionally, you may specify a bootstrap node to use Monero immediately.") + translationManager.emptyString
Layout.topMargin: 4 * scaleRatio
Layout.fillWidth: true
Layout.topMargin: 20 * scaleRatio
fontSize: 14 * scaleRatio
color: 'black'
text: qsTr("Bootstrap node (leave blank if not wanted)") + translationManager.emptyString
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
}
RemoteNodeEdit {
Layout.minimumWidth: 300 * scaleRatio
opacity: localNode.checked
}
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.bottomMargin: 12 * scaleRatio
MoneroComponents.RemoteNodeEdit {
id: bootstrapNodeEdit
Layout.minimumWidth: 300 * scaleRatio
//labelText: qsTr("Bootstrap node (leave blank if not wanted)") + translationManager.emptyString
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: Style.legacy_placeholderFontColor
placeholderOpacity: 1.0
lineEditBackgroundColor: "transparent"
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()
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 {
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] : ""
placeholderFontBold: true
placeholderFontFamily: "Arial"
placeholderColor: Style.legacy_placeholderFontColor
placeholderOpacity: 1.0
lineEditBorderColor: Qt.rgba(0, 0, 0, 0.15)
lineEditBackgroundColor: "white"
lineEditFontColor: "black"
lineEditFontBold: false
RowLayout {
MoneroComponents.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
}
}
}
Component.onCompleted: {
parent.wizardRestarted.connect(onWizardRestarted)
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] : ""
lineEditBackgroundColor: "transparent"
lineEditFontColor: MoneroComponents.Style.defaultFontColor
lineEditFontBold: false
lineEditBorderColor: Qt.rgba(255, 255, 255, 0.35)
labelFontSize: 14 * scaleRatio
placeholderFontSize: 15 * scaleRatio
}
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,21 +1,21 @@
// Copyright (c) 2014-2018, The Monero Project
//
// 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
@ -26,43 +26,26 @@
// 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.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0
ColumnLayout {
property alias password: password.text
property alias placeholderText: password.placeholderText
signal changed(string password)
import "../components" as MoneroComponents
TextField {
Layout.fillWidth: true
id : password
focus:true
font.family: "Arial"
font.pixelSize: (isMobile) ? 25 * scaleRatio : 26 * scaleRatio
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 {
property bool active: false
Layout.preferredWidth: 30 * scaleRatio
Layout.fillHeight: true
property string activeColor: MoneroComponents.Style.defaultFontColor
property string inactiveColor: "#333333"
color: "transparent"
Rectangle {
Layout.fillWidth:true
height: 1
color: "#DBDBDB"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: 10 * scaleRatio
height: 10 * scaleRatio
radius: 10 * scaleRatio
color: parent.active ? parent.activeColor : parent.inactiveColor
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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