mirror of https://github.com/layters/testshop
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1428 lines
81 KiB
1428 lines
81 KiB
// todo: rename this file to LoginPage.qml
|
|
// requires Qt version 5.12 (latest is 5.15 as of this writing). See https://doc.qt.io/qt-5/qt5-intro.html
|
|
import QtQuick 2.12//2.7 //(QtQuick 2.7 is lowest version for Qt 5.7)
|
|
import QtQuick.Controls 2.12//2.0 // (requires at least Qt 5.12 where QtQuick.Controls 1 is deprecated. See https://doc.qt.io/qt-5/qtquickcontrols-index.html#versions) // needed for built-in styles // Page, TextField, TextArea (multi-lined TextField), TextFieldStyle//import QtQuick.Controls.Material 2.12 // Other styles:
|
|
//import QtQuick.Controls.Material 2.0
|
|
//import QtQuick.Controls.Styles 1.4 // ApplicationWindowStyle, TextFieldStyle
|
|
import QtQuick.Layouts 1.12//1.15 // The module is new in Qt 5.1 and requires Qt Quick 2.1. // RowLayout, ColumnLayout, GridLayout, StackLayout, Layout
|
|
import QtQuick.Dialogs 1.3 // MessageDialog (since Qt 5.2)
|
|
import QtGraphicalEffects 1.12 // LinearGradient
|
|
import Qt.labs.platform 1.1 // FileDialog (since Qt 5.8) // change to "import QtQuick.Dialogs" if using Qt 6.2
|
|
|
|
import FontAwesome 1.0
|
|
|
|
import neroshop.Enums 1.0
|
|
|
|
import "../components" as NeroshopComponents
|
|
|
|
Page {
|
|
id: mainPage
|
|
title: qsTr("Main Page")
|
|
Rectangle {
|
|
color: "transparent"
|
|
}
|
|
property int walletGenerationCount: 0
|
|
///////////////////////////
|
|
function onAutoSync() {
|
|
console.log("Auto-sync is turned " + ((settingsDialog.moneroDaemonAutoSync) ? "on" : "off"))
|
|
if(!settingsDialog.moneroDaemonAutoSync) return;
|
|
startWalletSync(); // connects to a monero daemon (either local or remote) then starts the sync process
|
|
}
|
|
///////////////////////////
|
|
function startWalletSync() {
|
|
// Check if daemon is already synced
|
|
if(Wallet.isDaemonSynced()) return;//{ console.log("Daemon is already connected and synced with the network"); return; }
|
|
// SettingsDialog should retrieve data from settings.lua and all other components can retrieve from SettingsDialog
|
|
console.log("******************************************************");
|
|
console.log("Node type: ", (settingsDialog.moneroNodeType == 0) ? "remote node" : "local node")
|
|
console.log("Path to monerod: ", settingsDialog.monerodPath)
|
|
console.log("Selected node address: ", settingsDialog.moneroNodeAddress)
|
|
console.log("Monero data dir: ", settingsDialog.moneroDataDir)
|
|
console.log("Daemon username: ", settingsDialog.moneroDaemonUsername)
|
|
console.log("Daemon Password: ", settingsDialog.moneroDaemonPassword)
|
|
console.log("Confirm external bind: ", settingsDialog.confirmExternalBind)
|
|
console.log("Restricted RPC: ", settingsDialog.restrictedRpc)
|
|
console.log("Auto-sync: ", settingsDialog.moneroDaemonAutoSync)
|
|
console.log("******************************************************");
|
|
// start the monero daemon (local node) (optional)
|
|
if(settingsDialog.moneroNodeType == 1) {
|
|
// Dectect any running monero daemon (local)
|
|
if(Backend.isWalletDaemonRunning()) {
|
|
console.log("monerod is currently running in the background as detected. Now connecting to local node 127.0.0.1:" + settingsDialog.moneroNodeDefaultPort)
|
|
Wallet.daemonConnect();//(moneroDaemonRpcLoginUser.text, moneroDaemonRpcLoginPwd.text)
|
|
return; // exit function and do not proceed any further
|
|
}
|
|
|
|
if(settingsDialog.monerodPath.length < 1) { // Will not show when redirecting to HomePage
|
|
messageBox.text = "You've selected Local node, but the path to monerod has not been specified"
|
|
messageBox.open()
|
|
return; // exit function and do not proceed any further
|
|
}
|
|
|
|
Wallet.daemonExecute(settingsDialog.monerodPath, settingsDialog.confirmExternalBind, settingsDialog.restrictedRpc, settingsDialog.moneroDataDir, 0/*Script.getNumber("neroshop.monero.wallet.restore_height")*/);
|
|
Wallet.daemonConnect();//(moneroDaemonRpcLoginUser.text, moneroDaemonRpcLoginPwd.text)
|
|
// Don't connect to daemon until we are sure that it has been launched/is ready (or else it will crash app)
|
|
// TODO: find a way to figure whether a node is connected/working properly
|
|
if(Wallet.isConnectedToDaemon()) {
|
|
moneroDaemonSyncBar.title = settingsDialog.moneroNodeAddress
|
|
}
|
|
}
|
|
// connect to a remote monero node (default)
|
|
if(settingsDialog.moneroNodeType == 0) {
|
|
// settingsDialog.moneroNodeAddress removes http:// from url
|
|
let remote_node = settingsDialog.moneroNodeAddress//console.log("remote_node", remote_node)
|
|
let remote_node_ip = remote_node.split(":")[0]
|
|
let remote_node_port = remote_node.split(":")[1]
|
|
console.log("connecting to remote node " + remote_node_ip + ":" + remote_node_port)
|
|
// TODO: add option to use custom remote node
|
|
Wallet.nodeConnect(remote_node_ip, remote_node_port)//, moneroDaemonRpcLoginUser.text, moneroDaemonRpcLoginPwd.text);//Wallet.nodeConnect(Script.getString("neroshop.monero.daemon.ip"), Script.getString("neroshop.monero.daemon.port"), moneroDaemonRpcLoginUser.text, moneroDaemonRpcLoginPwd.text);
|
|
if(Wallet.isConnectedToDaemon()) {
|
|
moneroDaemonSyncBar.title = settingsDialog.moneroNodeAddress
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////
|
|
function generateWalletKeys() {
|
|
// Convert folder url to string
|
|
let folder = Backend.urlToLocalFile(walletFolderDialog.folder);////let folder = (isWindows) ? walletFolderDialog.folder.toString().replace("file:///", "") : walletFolderDialog.folder.toString().replace("file://", "")
|
|
// Check whether wallet file exists
|
|
if(Wallet.fileExists((walletNameField.text) ? qsTr(folder + "/%1").arg(walletNameField.text) : qsTr(folder + "/%1").arg(walletNameField.placeholderText))) {
|
|
walletMessageArea.text = qsTr("A wallet file with the same name already exists")
|
|
walletMessageArea.messageCode = 1
|
|
return; // exit function and do not proceed any further
|
|
}
|
|
// In case password does not fit the regex requirements
|
|
if(!walletPasswordField.acceptableInput) {
|
|
walletMessageArea.text = "Wallet password is too short (minimum length: 8)"
|
|
walletMessageArea.messageCode = 1
|
|
return;
|
|
}
|
|
// In case wallet passwords do not match, display error message
|
|
if(walletPasswordConfirmField.text != walletPasswordField.text) {
|
|
walletMessageArea.text = (walletPasswordConfirmField.length > 0) ? qsTr("Wallet passwords do not match") : qsTr("Wallet password must be confirmed")
|
|
walletMessageArea.messageCode = 1
|
|
return;
|
|
}
|
|
// Close (destroy) the current monero_wallet first before re-creating a new monero_wallet (In case user decides to re-generate wallet keys)
|
|
if(Wallet.isOpened()) Wallet.close();
|
|
// Generate wallet
|
|
Wallet.createRandomWallet(walletPasswordField.text, walletPasswordConfirmField.text, (walletNameField.text) ? qsTr(folder + "/%1").arg(walletNameField.text) : qsTr(folder + "/%1").arg(walletNameField.placeholderText))
|
|
// Exit function if wallet fails to generate
|
|
if(!Wallet.isOpened()) return;
|
|
// Increase the number of times a wallet has been generated this session (not necessary)
|
|
walletGenerationCount = walletGenerationCount + 1
|
|
// Display seed phrase in Repeater model
|
|
walletSeedRepeater.model = Wallet.getSeedList()
|
|
// Show wallet-related message(s)
|
|
walletMessageArea.text = qsTr("\"%1\" has been created successfully.").arg((walletNameField.text) ? qsTr(folder + "/%1.keys").arg(walletNameField.text) : qsTr(folder + "/%1.keys").arg(walletNameField.placeholderText))
|
|
walletMessageArea.messageCode = 0
|
|
seedMessageArea.text = qsTr("These %1 words are the key to your account. Please store them safely before proceeding to the registration page.").arg(walletSeedRepeater.count)
|
|
seedMessageArea.messageCode = 0//2
|
|
// Clear wallet password fields
|
|
walletPasswordField.text = ""
|
|
walletPasswordConfirmField.text = ""
|
|
}
|
|
///////////////////////////
|
|
function registerWallet() {
|
|
if(!Wallet.isOpened()) {
|
|
messageBox.text = qsTr("Please generate your wallet keys before registering")
|
|
messageBox.open()
|
|
return; // exit function and do not proceed any further
|
|
}
|
|
// Do a regex check on the username to make sure that it is valid
|
|
// ...
|
|
// Make sure username is not taken (requires a database check)
|
|
// ...
|
|
// Register the wallet primary key to the database
|
|
let register_result = Backend.registerUser(Wallet, optNameField.text, User, (avatarImage.status === Image.Ready) ? Backend.urlToLocalFile(avatarImage.source) : "")
|
|
if(!register_result [0] ) {
|
|
messageBox.text = register_result [1];
|
|
messageBox.open()
|
|
return; // exit function and do not proceed any further
|
|
}
|
|
// Save the avatar image to datastore folder for later use
|
|
let account_key = register_result[1];
|
|
if(avatarImage.status === Image.Ready) {
|
|
Backend.saveAvatarImage(Backend.urlToLocalFile(avatarImage.source), account_key)
|
|
}
|
|
// Switch to HomePage
|
|
pageStack.pushPage("qrc:/qml/pages/HomePage.qml", StackView.Immediate)//stack.push(home_page)
|
|
//console.log("Primary address: ", Wallet.getPrimaryAddress())
|
|
//console.log("Balance: ", Wallet.getBalanceLocked().toFixed(12))
|
|
//console.log("Unlocked balance: ", Wallet.getBalanceUnlocked().toFixed(12))
|
|
// start synching the monero node as soon we hit the register button (this confirms that we are satified with the wallet key that we've generated and won't turn back to re-generate a new one)
|
|
// Todo: Add an auto-connect on login/registration button and only sync automatically if that option is turned on (will be turned on by default)
|
|
onAutoSync()
|
|
}
|
|
///////////////////////////
|
|
// for login page
|
|
FileDialog {
|
|
id: walletFileDialog
|
|
fileMode: FileDialog.OpenFile
|
|
currentFile: walletFileField.text // currentFile is deprecated since Qt 6.3. Use selectedFile instead
|
|
folder: (isWindows) ? StandardPaths.writableLocation(StandardPaths.DocumentsLocation) + "/neroshop" : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/neroshop"//StandardPaths.writableLocation(StandardPaths.AppDataLocation) // refer to https://doc.qt.io/qt-5/qstandardpaths.html#StandardLocation-enum
|
|
nameFilters: ["Wallet files (*.keys)"]
|
|
////options: FileDialog.ReadOnly // will not allow you to create folders while file dialog is opened
|
|
onAccepted: {
|
|
walletFileField.text = Backend.urlToLocalFile(walletFileDialog.file)
|
|
walletPasswordRestoreField.forceActiveFocus()
|
|
}
|
|
}
|
|
///////////////////////////
|
|
// for registration page
|
|
FolderDialog {
|
|
id: walletFolderDialog
|
|
currentFolder: walletPathField.text
|
|
folder: (isWindows) ? StandardPaths.writableLocation(StandardPaths.DocumentsLocation) + "/neroshop" : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/neroshop"
|
|
}
|
|
///////////////////////////
|
|
StackLayout { // Perfect for a stack of items where only one item is visible at a time//ColumnLayout { // From top to bottom
|
|
id: mainPageStack // auth_menu inside home menu
|
|
anchors.fill: parent // will fill entire Window area
|
|
currentIndex: 0//buttonsBar.currentIndex//currentIndex: 1
|
|
|
|
Rectangle {
|
|
// todo: place login section right next to wallet generation section so long as the wallet seed model is not visible
|
|
id: loginPage
|
|
color: NeroshopComponents.Style.getColorsFromTheme()[0]
|
|
//gradient: Gradient {
|
|
// GradientStop { position: 0.0; color: "white" }
|
|
// GradientStop { position: 1.0; color: "black" }
|
|
//}
|
|
//Layout.alignment: Qt.AlignVCenter
|
|
//implicitHeight: 200
|
|
// add spacing from parent (padding - located inside the borders of an element)
|
|
//anchors.margins: 50//anchors.leftPadding: 20
|
|
Button {
|
|
id: loginPageNextButton
|
|
anchors.verticalCenter: parent.verticalCenter//Layout.alignment: Qt.AlignVCenter | Qt::AlignRight
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 20
|
|
implicitWidth: 60; height: implicitWidth
|
|
text: qsTr(FontAwesome.angleRight)
|
|
hoverEnabled: true
|
|
|
|
background: Rectangle {
|
|
color: "#121212"//"#6b5b95"//
|
|
radius: 100
|
|
border.color: parent.contentItem.color//(NeroshopComponents.Style.darkTheme) ? parent.contentItem.color : "#000000"
|
|
border.width: (parent.hovered) ? 1 : 0
|
|
}
|
|
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
font.pixelSize: (parent.width / 2)
|
|
}
|
|
|
|
onClicked: {
|
|
mainPageStack.currentIndex = mainPageStack.currentIndex + 1
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.centerIn: parent//anchors.fill: parent;anchors.margins: 20
|
|
|
|
Text {
|
|
id: loginPageTitle
|
|
text: qsTr("Restore Wallet (Login)")
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
font.bold: true
|
|
font.pointSize: 14
|
|
}
|
|
ButtonGroup {
|
|
id: walletRestoreMethodButtonGroup
|
|
exclusive: true // only one button selected at a time
|
|
onClicked: {
|
|
console.log("Selected", button.text, "button")
|
|
button.checked = true
|
|
if(button.text == restoreFromFileButton.text) {
|
|
walletRestoreStack.currentIndex = 0
|
|
if(walletFileField.text.length > 0) {
|
|
walletPasswordRestoreField.forceActiveFocus()
|
|
}
|
|
}
|
|
if(button.text == restoreFromSeedButton.text) {
|
|
walletRestoreStack.currentIndex = 1
|
|
if(seedInput.text.length > 0) {
|
|
walletRestoreHeightField.forceActiveFocus()
|
|
} else {
|
|
seedInput.forceActiveFocus()
|
|
}
|
|
}
|
|
if(button.text == restoreFromKeysButton.text) {
|
|
walletRestoreStack.currentIndex = 2
|
|
}
|
|
if(button.text == restoreFromHWButton.text) {
|
|
walletRestoreStack.currentIndex = 3
|
|
}
|
|
}
|
|
}
|
|
RowLayout {
|
|
id: walletRestoreButtonsRow
|
|
//Layout.preferredWidth:
|
|
//Layout.preferredHeight:
|
|
Layout.fillWidth: true
|
|
Layout.topMargin: 15
|
|
property real buttonWidth: (500 / 4)
|
|
property real buttonHeight: 40
|
|
// to add a button to the button group (within the Button object itself): ButtonGroup.group: walletRestoreMethodButtonGroup // attaches a button to a button group
|
|
Button {
|
|
id: restoreFromFileButton
|
|
ButtonGroup.group: walletRestoreMethodButtonGroup
|
|
checked: true
|
|
text: qsTr("Restore from file")//.arg("\uf8e9")
|
|
Layout.preferredHeight: parent.buttonHeight
|
|
Layout.preferredWidth: parent.buttonWidth//hovered ? 180 : parent.buttonWidth
|
|
//Layout.maximumWidth: 180//contentWidth + 20
|
|
icon.source: "qrc:/assets/images/file.png" // keys (key.png), seed (sprout.png), file, hardware
|
|
//icon.color: "#ffffff"
|
|
display: AbstractButton.IconOnly//hovered ? AbstractButton.TextBesideIcon : AbstractButton.IconOnly//AbstractButton.TextUnderIcon
|
|
hoverEnabled: true
|
|
background: Rectangle {
|
|
color: (parent.checked) ? "#39304f" : "#6b5b95"
|
|
//border.color:
|
|
//border.width: 1
|
|
radius: 3
|
|
}
|
|
/*contentItem: Text {
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
//font.family: FontAwesome.fontFamilySolid
|
|
}*/
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: !parent.checked ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
}
|
|
NeroshopComponents.Hint {
|
|
id: restoreFileHint
|
|
visible: parent.hovered; delay: 0
|
|
text: parent.text
|
|
pointer.visible: false
|
|
//y: parent.y - (parent.height + pointer.height)//(parent.height - this.height) / 2
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: restoreFromSeedButton
|
|
ButtonGroup.group: walletRestoreMethodButtonGroup
|
|
text: qsTr("Restore from seed")//.arg("\uf8e9")
|
|
Layout.preferredWidth: parent.buttonWidth//width: contentWidth + 20;
|
|
Layout.preferredHeight: parent.buttonHeight
|
|
icon.source: "qrc:/assets/images/sprout.png" // keys (key.png), seed (sprout.png), file, hardware
|
|
//icon.color: "#ffffff"
|
|
display: AbstractButton.IconOnly
|
|
hoverEnabled: true
|
|
background: Rectangle {
|
|
color: (parent.checked) ? "#39304f" : "#6b5b95"
|
|
//border.color:
|
|
//border.width: 1
|
|
radius: 3
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: !parent.checked ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
}
|
|
NeroshopComponents.Hint {
|
|
visible: parent.hovered; delay: 0
|
|
text: parent.text
|
|
pointer.visible: false
|
|
//y: parent.y - (parent.height + pointer.height)//(parent.height - this.height) / 2
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: restoreFromKeysButton
|
|
ButtonGroup.group: walletRestoreMethodButtonGroup
|
|
text: qsTr("Restore from keys")//.arg("\uf8e9")
|
|
Layout.preferredWidth: parent.buttonWidth//width: contentWidth + 20;
|
|
Layout.preferredHeight: parent.buttonHeight
|
|
icon.source: "qrc:/assets/images/key.png" // keys (key.png), seed (sprout.png), file, hardware
|
|
//icon.color: "#ffffff"
|
|
display: AbstractButton.IconOnly
|
|
hoverEnabled: true
|
|
background: Rectangle {
|
|
color: (parent.checked) ? "#39304f" : "#6b5b95"
|
|
//border.color:
|
|
//border.width: 1
|
|
radius: 3
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: !parent.checked ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
}
|
|
NeroshopComponents.Hint {
|
|
visible: parent.hovered; delay: 0
|
|
text: parent.text
|
|
pointer.visible: false
|
|
//y: parent.y - (parent.height + pointer.height)//(parent.height - this.height) / 2
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: restoreFromHWButton
|
|
ButtonGroup.group: walletRestoreMethodButtonGroup
|
|
text: qsTr("Restore from HW")//("Restore from hardware")//.arg("\uf8e9")
|
|
Layout.preferredWidth: parent.buttonWidth//hovered ? Layout.maximumWidth : parent.buttonWidth//width: contentWidth + 20;
|
|
Layout.preferredHeight: parent.buttonHeight
|
|
//Layout.maximumWidth: 180//280
|
|
icon.source: "qrc:/assets/images/usb.png" // keys (key.png), seed (sprout.png), file, hardware
|
|
//icon.color: "#ffffff"
|
|
display: AbstractButton.IconOnly
|
|
hoverEnabled: true
|
|
background: Rectangle {
|
|
color: (parent.checked) ? "#39304f" : "#6b5b95"
|
|
//border.color:
|
|
//border.width: 1
|
|
radius: 3
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: !parent.checked ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
}
|
|
NeroshopComponents.Hint {
|
|
visible: parent.hovered; delay: 0
|
|
text: parent.text
|
|
pointer.visible: false
|
|
//y: parent.y - (parent.height + pointer.height)//(parent.height - this.height) / 2
|
|
}
|
|
}
|
|
} // RowLayout
|
|
// walletRestoreStack
|
|
StackLayout {
|
|
id: walletRestoreStack
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
|
currentIndex: 0
|
|
// WalletFileStackContent
|
|
ColumnLayout { // Replace with Rectangle
|
|
id: restoreFromWalletFile
|
|
Layout.preferredWidth: 500
|
|
Layout.maximumWidth: 600
|
|
//Layout.preferredHeight: 380
|
|
Layout.topMargin: 5//0
|
|
//ColumnLayout here
|
|
Column {
|
|
Layout.fillWidth: true//Layout.alignment: Qt.AlignHCenter
|
|
Layout.preferredWidth: 500
|
|
spacing: 10 // looks more like 5 than 10, but that's fine
|
|
// wallet file field
|
|
TextField {
|
|
id: walletFileField
|
|
width: parent.width
|
|
height: 50
|
|
text: (settingsDialog.rememberWallet) ? settingsDialog.lastOpenedWallet : ""//walletFileDialog.file
|
|
color: "#000000"////(NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
selectByMouse: true
|
|
readOnly: true
|
|
|
|
background: Rectangle {
|
|
color: "#708090"////(NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
radius: 3
|
|
}
|
|
}
|
|
// wallet file upload or browse button
|
|
Button {
|
|
id: walletFileBrowseButton
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
////Layout.fillWidth: true
|
|
width: 125////walletFileBrowseButtonText.contentWidth + 20
|
|
height: walletFileField.height
|
|
text: qsTr("Browse")
|
|
//display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon//AbstractButton.TextOnly//AbstractButton.TextUnderIcon
|
|
//icon.source: "qrc:/assets/images/ellipsis.png"//"/upload.png"
|
|
//icon.color: "#ffffff"
|
|
hoverEnabled: true
|
|
onClicked: walletFileDialog.open()
|
|
|
|
background: Rectangle {
|
|
color: "#808080"
|
|
radius: 5
|
|
border.color: walletFileBrowseButton.hovered ? "#ffffff" : this.color//"#ffffff"//control.down ? "#17a81a" : "#21be2b"
|
|
}
|
|
// this removes the icon unfortunately :( but it gives us more control over the text
|
|
contentItem: Text {
|
|
id: walletFileBrowseButtonText
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
}
|
|
ToolTip.delay: 1000
|
|
ToolTip.visible: hovered
|
|
ToolTip.text: qsTr("Browse wallet file")
|
|
}
|
|
} // Column
|
|
TextField {
|
|
id: walletPasswordRestoreField
|
|
//Layout.alignment: Qt.AlignHCenter//Layout.fillWidth: true
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: 500
|
|
Layout.preferredHeight: 50
|
|
Layout.topMargin: 10
|
|
placeholderText: qsTr("Wallet Password"); placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
echoMode: TextInput.Password
|
|
inputMethodHints: Qt.ImhSensitiveData
|
|
selectByMouse: true
|
|
|
|
background: Rectangle {
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
border.width: walletPasswordRestoreField.activeFocus ? 2 : 1
|
|
radius: 3
|
|
}
|
|
Keys.onEnterPressed: loginButton.activate()
|
|
Keys.onReturnPressed: loginButton.activate()
|
|
}
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: childrenRect.height
|
|
Layout.topMargin: 10
|
|
NeroshopComponents.CheckBox {
|
|
id: rememberWalletCheckBox
|
|
text: qsTr("Remember wallet")
|
|
textColor: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
color: "transparent"
|
|
checked: settingsDialog.rememberWallet
|
|
}
|
|
}
|
|
}
|
|
Rectangle {
|
|
id: restoreFromSeed
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
Layout.topMargin: 5
|
|
color: "transparent"//; border.color: "blue"
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 10
|
|
ScrollView {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true//width: 500; height: 500
|
|
TextArea {
|
|
id: seedInput
|
|
wrapMode: TextEdit.Wrap
|
|
selectByMouse: true
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
background: Rectangle {
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#f0f0f0"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#404040" : "#4d4d4d"
|
|
border.width: seedInput.activeFocus ? 2 : 1
|
|
radius: 3
|
|
}
|
|
}
|
|
}
|
|
|
|
TextField {
|
|
id: walletRestoreHeightField
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 50
|
|
placeholderText: qsTr("Restore Height (default: 1570000)"); placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
selectByMouse: true
|
|
validator: RegExpValidator{ regExp: /[0-9]*/ }
|
|
background: Rectangle {
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
border.width: walletRestoreHeightField.activeFocus ? 2 : 1
|
|
radius: 3
|
|
}
|
|
Keys.onEnterPressed: loginButton.activate()
|
|
Keys.onReturnPressed: loginButton.activate()
|
|
}
|
|
} // ColumnLayout
|
|
}
|
|
Rectangle {
|
|
id: restoreFromKeys
|
|
//ColumnLayout {
|
|
//}
|
|
}
|
|
Rectangle {
|
|
id: restoreFromHardwareWallet
|
|
//ColumnLayout {
|
|
//}
|
|
}
|
|
}
|
|
// confirm button
|
|
Button {
|
|
id: loginButton
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: 500
|
|
Layout.preferredHeight: 50
|
|
Layout.topMargin: 15
|
|
text: qsTr("Confirm")
|
|
hoverEnabled: true
|
|
////onClicked: login()
|
|
background: Rectangle {
|
|
color: "#6b5b95"
|
|
radius: 5
|
|
}
|
|
|
|
contentItem: Text {
|
|
//font.family: "Consolas"; //font.family: NeroshopComponents.Style.fontFiraCodeLight.name
|
|
//font.pointSize: 10
|
|
font.bold: true
|
|
text: loginButton.text
|
|
color: "#ffffff" // white
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
|
|
function activate() {
|
|
// restore from file
|
|
if(walletRestoreStack.currentIndex == 0) {
|
|
// Todo: place this in a seperate function
|
|
if(Wallet.isOpened()) {
|
|
/*messageBox.text = qsTr("Wallet is already opened")
|
|
messageBox.open()
|
|
return;*/
|
|
|
|
/*Wallet.close()
|
|
if(!Wallet.isOpened()) console.log("old wallet closed");*/
|
|
}
|
|
if(walletFileField.text.length == 0) {
|
|
messageBox.text = qsTr("Wallet path must be specified")
|
|
messageBox.open()
|
|
return;
|
|
}
|
|
// Process login credentials
|
|
//if(!Wallet.isOpened()) {
|
|
let loginError = Backend.loginWithWalletFile(Wallet, walletFileField.text, walletPasswordRestoreField.text, User)
|
|
if(loginError != Enum.LoginError.Ok) {
|
|
console.log("loginError", loginError)
|
|
if(loginError == Enum.LoginError.WalletBadNetworkType) {
|
|
messageBox.text = qsTr("Bad network type")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.WrongPassword) {
|
|
messageBox.text = qsTr("Invalid password")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.WalletIsOpenedByAnotherProgram) {
|
|
messageBox.text = qsTr("Wallet is opened by another program")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.WalletBadWalletType) {
|
|
messageBox.text = qsTr("Bad wallet type")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.DaemonIsNotConnected) {
|
|
messageBox.text = qsTr("Daemon (neromon) is not connected")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.UserNotFound) {
|
|
messageBox.text = qsTr("User not found. Please try again or register")
|
|
messageBox.open()
|
|
} else {
|
|
messageBox.text = qsTr("Login error")
|
|
messageBox.open()
|
|
}
|
|
return;
|
|
}
|
|
settingsDialog.rememberWallet = rememberWalletCheckBox.checked
|
|
settingsDialog.lastOpenedWallet = walletFileField.text
|
|
settingsDialog.save()
|
|
// Start synching the monero node as soon we hit the login button only sync automatically if auto-sync option is turned on (will be turned on by default)
|
|
onAutoSync();
|
|
// Switch to HomePage
|
|
pageStack.pushPage("qrc:/qml/pages/HomePage.qml", StackView.Immediate)
|
|
//console.log("Seed:", Wallet.getSeed())
|
|
navBar.messageCounterText = User.messagesCount
|
|
}
|
|
// restore from seed
|
|
if(walletRestoreStack.currentIndex == 1) {
|
|
if(seedInput.text.length == 0) {
|
|
messageBox.text = qsTr("No seed phrase was entered")
|
|
messageBox.open()
|
|
return;
|
|
}
|
|
|
|
let loginError = Backend.loginWithMnemonic(Wallet, seedInput.text, Number(walletRestoreHeightField.text), User)
|
|
if(loginError != Enum.LoginError.Ok) {
|
|
console.log("loginError", loginError)
|
|
if(loginError == Enum.LoginError.WalletBadNetworkType) {
|
|
messageBox.text = qsTr("Bad network type")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.WalletInvalidMnemonic) {
|
|
messageBox.text = qsTr("Invalid mnemonic")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.WalletBadWalletType) {
|
|
messageBox.text = qsTr("Bad wallet type")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.DaemonIsNotConnected) {
|
|
messageBox.text = qsTr("Daemon (neromon) is not connected")
|
|
messageBox.open()
|
|
} else if(loginError == Enum.LoginError.UserNotFound) {
|
|
messageBox.text = qsTr("User not found. Please try again or register")
|
|
messageBox.open()
|
|
} else {
|
|
messageBox.text = qsTr("Login error")
|
|
messageBox.open()
|
|
}
|
|
return;
|
|
}
|
|
onAutoSync();
|
|
// Switch to HomePage
|
|
pageStack.pushPage("qrc:/qml/pages/HomePage.qml", StackView.Immediate)//stack.push(home_page)
|
|
}
|
|
}
|
|
|
|
onClicked: {
|
|
loginButton.activate()
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: newUserButton
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: 500
|
|
Layout.preferredHeight: 50
|
|
Layout.topMargin: 15
|
|
text: qsTr("New user?")
|
|
hoverEnabled: true
|
|
////onClicked: login()
|
|
background: Rectangle {
|
|
color: NeroshopComponents.Style.moneroOrangeColor
|
|
radius: 5
|
|
}
|
|
|
|
contentItem: Text {
|
|
//font.family: "Consolas"; //font.family: NeroshopComponents.Style.fontFiraCodeLight.name
|
|
//font.pointSize: 10
|
|
font.bold: true
|
|
text: newUserButton.text
|
|
color: "#ffffff" // white
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
|
|
function activate() {
|
|
mainPageStack.currentIndex = mainPageStack.currentIndex + 1
|
|
}
|
|
|
|
onClicked: {
|
|
newUserButton.activate()
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
} // ColumnLayout
|
|
} // eof wallet_file_authentication_page
|
|
|
|
// generate auth keys page
|
|
Rectangle {
|
|
id: walletGenerationPage
|
|
color: NeroshopComponents.Style.getColorsFromTheme()[0]
|
|
|
|
Button {
|
|
id: walletPageBackButton
|
|
anchors.verticalCenter: parent.verticalCenter//Layout.alignment: Qt.AlignVCenter | Qt::AlignRight
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 20
|
|
implicitWidth: 60; height: implicitWidth
|
|
text: qsTr(FontAwesome.angleLeft)
|
|
hoverEnabled: true
|
|
visible: (walletSeedRepeater.model == null)
|
|
|
|
background: Rectangle {
|
|
color: "#121212"//"#6b5b95"//
|
|
radius: 100
|
|
border.color: parent.contentItem.color//(NeroshopComponents.Style.darkTheme) ? parent.contentItem.color : "#000000"
|
|
border.width: (parent.hovered) ? 1 : 0
|
|
}
|
|
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
font.pixelSize: (parent.width / 2)
|
|
}
|
|
|
|
onClicked: {
|
|
mainPageStack.currentIndex = mainPageStack.currentIndex - 1
|
|
}
|
|
}
|
|
|
|
Button {
|
|
id: walletPageNextButton
|
|
anchors.verticalCenter: parent.verticalCenter//Layout.alignment: Qt.AlignVCenter | Qt::AlignRight
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 20
|
|
implicitWidth: 60; height: implicitWidth
|
|
text: qsTr(FontAwesome.angleRight)
|
|
hoverEnabled: true
|
|
visible: (walletSeedRepeater.model != null)
|
|
|
|
background: Rectangle {
|
|
color: "#121212"//"#6b5b95"//
|
|
radius: 100
|
|
border.color: parent.contentItem.color//(NeroshopComponents.Style.darkTheme) ? parent.contentItem.color : "#000000"
|
|
border.width: (parent.hovered) ? 1 : 0
|
|
}
|
|
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
font.pixelSize: (parent.width / 2)
|
|
}
|
|
|
|
onClicked: {
|
|
mainPageStack.currentIndex = mainPageStack.currentIndex + 1
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: 20
|
|
/*anchors.horizontalCenter: parent.horizontalCenter//(walletSeedRepeater.model) ? this.horizontalCenter : parent.horizontalCenter
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 20*/
|
|
//anchors.left: parent.left
|
|
//anchors.leftMargin: walletPageNextButton.width + 20
|
|
//width: 800
|
|
////anchors.rightMargin: walletPageNextButton.width + 20//anchors.margins: 50
|
|
/*columns: 2 // Set column limit to 2
|
|
columnSpacing: 100*/ // The default value is 5. Same with rowSpacing
|
|
////rows: 10
|
|
////rowSpacing: 15
|
|
RowLayout {
|
|
// Reminder: Layout. functions work for items inside Layouts but not for the Layout itself!
|
|
// Row Rect 1
|
|
Item {//Rectangle {
|
|
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
/*radius: 3
|
|
color: "transparent"
|
|
border.color: "#ffffff"*/
|
|
|
|
ColumnLayout {
|
|
id: rectColumn1
|
|
anchors.centerIn: parent // Never use "anchors.fill: parent" for this so we have full control over the spacing and margins!//"anchors.margins: 20" - makes no sense if centered in parent
|
|
|
|
states: [
|
|
State {
|
|
name: "expand"
|
|
PropertyChanges {
|
|
target: rectColumn1
|
|
width: 600 // 600 or 540 instead of 500, to leave room for the margins without reducing children size
|
|
}
|
|
},
|
|
State {
|
|
name: "shrink"
|
|
PropertyChanges {
|
|
target: rectColumn1
|
|
width: parent.width
|
|
}
|
|
}
|
|
]
|
|
state: (walletSeedRepeater.model == null) ? "expand" : "shrink"
|
|
|
|
/*Text {
|
|
id: walletGenPageTitle
|
|
text: qsTr("Create Wallet")
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
font.bold: true
|
|
font.pointSize: 14
|
|
}*/
|
|
|
|
Item {
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop // remove this if want to fill width
|
|
Layout.maximumWidth: 500 // remove this too if want to fill width
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: childrenRect.height
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
|
|
// wallet name creation text
|
|
Column {
|
|
spacing: 10
|
|
Text {
|
|
id: walletNameText
|
|
text: qsTr("Wallet name")
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
font.bold: true
|
|
}
|
|
// wallet name creation field
|
|
TextField {
|
|
id: walletNameField
|
|
width: parent.parent.width//500
|
|
height: 50
|
|
placeholderText: qsTr("wallet"); placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
selectByMouse: true
|
|
maximumLength: 255
|
|
// validator regex for preventing special characters like: * . " \ / [ ] : ; < > ^ | , ? from being added to the wallet name
|
|
validator: RegExpValidator {
|
|
regExp: /^(?![. ])(?!.*[. ]$)[^*/"\\[\]:;<>\^|,?]*$/
|
|
}
|
|
|
|
background: Rectangle {
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
radius: 3
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.maximumWidth: 500
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: childrenRect.height
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
// wallet password creation field
|
|
Column {
|
|
spacing: 10
|
|
TextField {
|
|
id: walletPasswordField
|
|
width: parent.parent.width; height: 50
|
|
//visible: !walletSeedRepeater.model
|
|
placeholderText: qsTr("Wallet Password")
|
|
placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
color: NeroshopComponents.Style.moneroOrangeColor // textColor
|
|
echoMode: (!walletPasswordVisibilityToggle.checked) ? TextInput.Normal : TextInput.Password//TextInput.PasswordEchoOnEdit
|
|
inputMethodHints: Qt.ImhSensitiveData
|
|
selectByMouse: true
|
|
validator: RegExpValidator {
|
|
regExp: /^.{8,}$/
|
|
// Explanation of the regex:
|
|
// .{8,} - Minimum 8 characters
|
|
}
|
|
background: Rectangle {
|
|
color: walletNameField.background.color
|
|
border.color: (!parent.acceptableInput && parent.text.length > 0) ? walletPasswordStatusMark.invalidColor : parent.placeholderTextColor//walletPasswordConfirmField.background.border.color////((parent.length > 0 && walletPasswordConfirmField.length == 0) ? ((walletPasswordConfirmField.text != walletPasswordField.text || !walletPasswordField.acceptableInput) ? walletPasswordStatusMark.invalidColor : walletPasswordStatusMark.validColor) : walletPasswordConfirmField.background.border.color)
|
|
border.width: (!parent.acceptableInput && parent.text.length > 0) ? 2 : 1//walletPasswordConfirmField.background.border.width////(parent.length > 0 && walletPasswordConfirmField.length == 0) ? 2 : walletPasswordConfirmField.background.border.width
|
|
radius: 3
|
|
}
|
|
// todo: maybe add a regex validator
|
|
rightPadding: 15 + walletPasswordVisibilityToggle.width
|
|
// wallet password visibility toggle
|
|
Button {
|
|
id: walletPasswordVisibilityToggle
|
|
text: (checked) ? FontAwesome.eye : FontAwesome.eyeSlash//icon.source:
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 15
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
implicitWidth: 24; implicitHeight: 24
|
|
checkable: true
|
|
checked: true//false
|
|
hoverEnabled: true
|
|
// checked = show, unchecked = hide. Passwords are hidden by default
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
}
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: (parent.checked) ? "#a9a9a9" : "#696969"
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
}
|
|
}
|
|
}
|
|
|
|
// wallet password confirmation field
|
|
TextField {
|
|
id: walletPasswordConfirmField
|
|
width: parent.parent.width; height: 50
|
|
//Layout.topMargin: 5
|
|
//rightPadding
|
|
//visible: !walletSeedRepeater.model
|
|
placeholderText: qsTr("Confirm Wallet Password")
|
|
placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
color: walletPasswordField.color//NeroshopComponents.Style.moneroOrangeColor // textColor
|
|
echoMode: (!walletPasswordVisibilityToggle.checked) ? TextInput.Normal : TextInput.Password
|
|
inputMethodHints: Qt.ImhSensitiveData
|
|
selectByMouse: true
|
|
background: Rectangle {
|
|
color: walletPasswordField.background.color//NeroshopComponents.Style.moneroGrayColor
|
|
border.color: (parent.length > 0) ? walletPasswordStatusMark.color : parent.placeholderTextColor
|
|
border.width: (parent.length > 0) ? 2 : 1
|
|
radius: 3
|
|
}
|
|
rightPadding: 30 + walletPasswordStatusMark.contentWidth//double rightmargin size
|
|
// wallet password validation status mark
|
|
Text {
|
|
id: walletPasswordStatusMark
|
|
property string validColor: "#50b954"
|
|
property string invalidColor: "#f17982"
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 15
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: (walletPasswordConfirmField.text != walletPasswordField.text) ? qsTr(FontAwesome.xmark) : qsTr(FontAwesome.check)
|
|
visible: (walletPasswordConfirmField.length > 0)
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
color: (walletPasswordConfirmField.text != walletPasswordField.text) ? invalidColor : validColor
|
|
}
|
|
}
|
|
} // column
|
|
} // wallet password item
|
|
|
|
Item {
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.maximumWidth: 500
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: childrenRect.height
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
Column {
|
|
spacing: 10
|
|
// wallet path text
|
|
Text {
|
|
id: walletPathText
|
|
text: qsTr("Wallet path")
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
font.bold: true
|
|
}
|
|
// wallet path field
|
|
TextField {
|
|
id: walletPathField
|
|
width: parent.parent.width; height: 50
|
|
text: walletFolderDialog.folder////(walletNameField.text) ? qsTr(walletFolderDialog.folder + "/%1.keys").arg(walletNameField.text) : qsTr(walletFolderDialog.folder + "/%1.keys").arg(walletNameField.placeholderText)
|
|
color: "#000000"//(NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
selectByMouse: true
|
|
readOnly: true
|
|
|
|
background: Rectangle {
|
|
color: "#708090"//(NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
radius: 3
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.maximumWidth: 500
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
spacing: 5
|
|
// wallet path change or upload button
|
|
Button {
|
|
id: walletPathChangeButton
|
|
//Layout.topMargin: 10
|
|
width: parent.width / 4//walletPathChangeButtonText.contentWidth + 20
|
|
height: 50//walletPathField.Layout.preferredHeight
|
|
text: qsTr("Change")
|
|
//display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon//AbstractButton.TextOnly
|
|
//icon.source: "qrc:/assets/images/change.png"
|
|
//icon.color: "#ffffff"
|
|
hoverEnabled: true
|
|
onClicked: walletFolderDialog.open()
|
|
|
|
background: Rectangle {
|
|
color: NeroshopComponents.Style.moneroGrayColor
|
|
radius: 5
|
|
border.color: walletPathChangeButton.hovered ? "#ffffff" : this.color//"#ffffff"//control.down ? "#17a81a" : "#21be2b"
|
|
}
|
|
|
|
contentItem: Text {
|
|
id: walletPathChangeButtonText
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
ToolTip.delay: 1000
|
|
ToolTip.visible: hovered
|
|
ToolTip.text: qsTr("Change wallet path")
|
|
}
|
|
// generate key button
|
|
Button {
|
|
id: generateKeysButton
|
|
//Layout.topMargin: 10//20
|
|
width: (walletPathChangeButton.width * 3) - parent.spacing//150
|
|
height: 50
|
|
text: qsTr("Generate")//("Generate Keys")
|
|
hoverEnabled: true
|
|
onClicked: generateWalletKeys()
|
|
|
|
contentItem: Text {
|
|
//id: generateKeysButtonText
|
|
font.bold: true
|
|
text: generateKeysButton.text
|
|
color: "#ffffff" // white
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
|
|
background: Rectangle {
|
|
color: NeroshopComponents.Style.moneroOrangeColor
|
|
radius: 5
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
} // Row containing both walletPathChangeButton and generateKeys button
|
|
// important wallet message box
|
|
TextArea {
|
|
id: walletMessageArea
|
|
visible: true////false
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.fillWidth: true // extends the TextArea's width to the width of the Layout
|
|
Layout.maximumWidth: walletPathField.width // keeps textarea from going past grid bounds when text is added
|
|
Layout.preferredHeight: contentHeight + 20
|
|
Layout.topMargin: 20//15
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
selectByMouse: true
|
|
readOnly: true
|
|
verticalAlignment: TextEdit.AlignVCenter // align the text within the center of TextArea item's height
|
|
wrapMode: TextEdit.Wrap // move text to newline if it reaches the width of the TextArea
|
|
text: qsTr("Please generate your wallet keys before registering your wallet address.")
|
|
color: (messageCode == 1) ? "#b22222" : ((NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#404040")// text color
|
|
property int messageCode: 0 //0 = info; 1 = warning or error
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: (parent.messageCode == 1) ? "#b22222" : "#2196f3"////parent.color//(NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#404040"
|
|
radius: 3
|
|
}
|
|
leftPadding: 30 + circleInfo.contentWidth
|
|
Text {
|
|
id: circleInfo
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 15
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: (parent.messageCode == 1) ? qsTr(FontAwesome.triangleExclamation) : qsTr(FontAwesome.circleInfo)
|
|
color: (parent.messageCode == 1) ? "#b22222" : "#2196f3"
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
}
|
|
}
|
|
} // ColumnLayout for Rect
|
|
} // Row Rect 1
|
|
|
|
// Row Rect 2
|
|
Item {//Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
visible: (walletSeedRepeater.model != null)
|
|
/*radius: 3
|
|
color: "transparent"
|
|
border.color: "#ffffff"*/
|
|
|
|
ColumnLayout {
|
|
anchors.centerIn: parent
|
|
width: parent.width
|
|
|
|
// wallet seed message box
|
|
TextArea {
|
|
id: seedMessageArea
|
|
visible: (walletSeedRepeater.model != null)
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.fillWidth: true // extends the TextArea's width to the width of the Layout
|
|
Layout.maximumWidth: walletSeedDisplay.width////parent.width
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
////implicitHeight: contentHeight + 20////Layout.preferredHeight: contentHeight + 20 // cause of QML TextArea: Binding loop detected for property "implicitWidth" error
|
|
////Layout.topMargin: 20//15
|
|
selectByMouse: true
|
|
readOnly: true
|
|
verticalAlignment: TextEdit.AlignVCenter // align the text within the center of TextArea item's height
|
|
wrapMode: TextEdit.Wrap // move text to newline if it reaches the width of the TextArea
|
|
text: qsTr("")
|
|
//font.bold: true
|
|
color: (messageCode == 1) ? "#b22222" : ((NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#404040")// text color
|
|
property int messageCode: 0 //0 = info; 1 = warning or error
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: (parent.messageCode == 1) ? "#b22222" : ((NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : parent.color)////parent.color
|
|
radius: 3
|
|
}
|
|
leftPadding: 25 + circleInfo.contentWidth
|
|
Text {
|
|
////id: circleInfo
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 15
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: (parent.messageCode == 1) ? qsTr(FontAwesome.triangleExclamation) : qsTr(FontAwesome.circleInfo)//(parent.messageCode == 2) ? qsTr(FontAwesome.seedling) : ((parent.messageCode == 1) ? qsTr(FontAwesome.triangleExclamation) : qsTr(FontAwesome.circleInfo))
|
|
color: (parent.messageCode == 1) ? "#b22222" : "#2196f3"//(parent.messageCode == 2) ? "#228b22" : ((parent.messageCode == 1) ? "#b22222" : "#2196f3")
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
}
|
|
}
|
|
|
|
// testing listview for walletseed display
|
|
Flow {////RowLayout {
|
|
id: walletSeedDisplay
|
|
//Layout.preferredHeight: 200
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.fillWidth: true // no reason to fill width since we set the maximum width
|
|
//Layout.preferredHeight: 40 * Layout.rowSpan // remove
|
|
Layout.maximumWidth: 670////parent.width
|
|
Layout.topMargin: 20//15
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
//orientation: ListView.Horizontal
|
|
spacing: 5
|
|
|
|
Repeater {
|
|
id: walletSeedRepeater
|
|
////model: null
|
|
delegate: Rectangle {
|
|
width: 130; height: 40
|
|
Text {
|
|
text: (index + 1) + ". " + modelData
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
|
|
anchors.verticalCenter: parent.verticalCenter//verticalAlignment: Text.AlignVCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 15
|
|
}
|
|
color: "transparent"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
radius: 3
|
|
//MouseArea {
|
|
// anchors.fill: parent
|
|
// onClicked: {}
|
|
//}
|
|
}
|
|
}
|
|
} // Flow?
|
|
|
|
// wallet seed copy button
|
|
Button {
|
|
id: seedCopyButton
|
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
|
Layout.fillWidth: true////width: contentWidth + 20; height: 40
|
|
Layout.maximumWidth: walletSeedDisplay.width////parent.width
|
|
Layout.leftMargin: 20; Layout.rightMargin: 20
|
|
visible: (walletSeedRepeater.model != null)
|
|
text: qsTr("Copy")
|
|
icon.source: "qrc:/assets/images/copy.png"
|
|
icon.color: "#ffffff"
|
|
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon//AbstractButton.TextOnly//AbstractButton.TextUnderIcon
|
|
hoverEnabled: true
|
|
onClicked: Backend.copyTextToClipboard(Wallet.getSeed())
|
|
|
|
background: Rectangle {
|
|
color: "#404040"
|
|
radius: 5
|
|
border.color: parent.hovered ? "#ffffff" : this.color//"#ffffff"//control.down ? "#17a81a" : "#21be2b"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
ToolTip.delay: 1000
|
|
ToolTip.visible: hovered
|
|
ToolTip.text: qsTr("Copy seed phrase")////qsTr("Copy to clipboard")
|
|
} // copyButton
|
|
} // ColumnLayout for Rect
|
|
} // Row Rectangle 2
|
|
} // ROWLAYOUT
|
|
} // ColumnLayout for walletGenerationPage
|
|
} // eof walletGenerationPage
|
|
Rectangle {
|
|
id: registrationPage
|
|
color: NeroshopComponents.Style.getColorsFromTheme()[0]
|
|
|
|
Button {
|
|
id: registrationPageBackButton
|
|
anchors.verticalCenter: parent.verticalCenter//Layout.alignment: Qt.AlignVCenter | Qt::AlignLeft
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 20
|
|
implicitWidth: 60; height: implicitWidth
|
|
text: qsTr(FontAwesome.angleLeft)
|
|
hoverEnabled: true
|
|
|
|
background: Rectangle {
|
|
color: "#121212"//"#6b5b95"//
|
|
radius: 100
|
|
border.color: parent.contentItem.color
|
|
border.width: (parent.hovered) ? 1 : 0
|
|
}
|
|
|
|
contentItem: Text {
|
|
text: parent.text
|
|
color: "#ffffff"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
font.pixelSize: (parent.width / 2)
|
|
}
|
|
|
|
onClicked: {
|
|
mainPageStack.currentIndex = mainPageStack.currentIndex - 1
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.centerIn: parent
|
|
// avatar image rect
|
|
Rectangle {
|
|
id: avatarImageRect
|
|
Layout.preferredWidth: 192; Layout.preferredHeight: width
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.bottomMargin: 10
|
|
border.color: "#6b5b95"
|
|
border.width: 3
|
|
radius: 5
|
|
Image {
|
|
id: avatarImage
|
|
anchors.centerIn: parent
|
|
width: parent.width - (parent.border.width * 2); height: width
|
|
//source: avatarImageFileDialog.file//"https://api.dicebear.com/6.x/identicon/svg?seed=%1".arg(optNameField.text)
|
|
fillMode: Image.PreserveAspectFit
|
|
mipmap: true
|
|
asynchronous: true
|
|
// Apply rounded rectangle mask (radius)
|
|
layer.enabled: true
|
|
layer.effect: OpacityMask {
|
|
maskSource: avatarImageRect
|
|
}
|
|
}
|
|
Button {
|
|
text: qsTr("Choose")
|
|
visible: (avatarImage.status !== Image.Ready)
|
|
width: parent.width - 20
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: parent.border.width + 7
|
|
onClicked: {
|
|
avatarImageFileDialog.open()
|
|
}
|
|
}
|
|
FileDialog {
|
|
id: avatarImageFileDialog
|
|
fileMode: FileDialog.OpenFile
|
|
folder: (isWindows) ? StandardPaths.writableLocation(StandardPaths.DocumentsLocation) + "/neroshop" : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/neroshop"//StandardPaths.writableLocation(StandardPaths.AppDataLocation) // refer to https://doc.qt.io/qt-5/qstandardpaths.html#StandardLocation-enum
|
|
nameFilters: ["Image files (*.bmp *.gif *.jpeg *.jpg *.png *.tif *.tiff *.svg)"]
|
|
onAccepted: avatarImage.source = currentFile
|
|
}
|
|
// Position the close button
|
|
Button {
|
|
id: removeAvatarImageButton
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.margins: 8
|
|
|
|
width: 20; height: 20//32
|
|
text: qsTr(FontAwesome.xmark)
|
|
hoverEnabled: true
|
|
visible: (avatarImage.status === Image.Ready)
|
|
|
|
contentItem: Text {
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
text: removeAvatarImageButton.text
|
|
color: removeAvatarImageButton.hovered ? "#ffffff" : "#000000"
|
|
font.bold: true
|
|
font.family: FontAwesome.fontFamily
|
|
}
|
|
|
|
background: Rectangle {
|
|
width: parent.width
|
|
height: parent.height
|
|
radius: 5//50
|
|
color: removeAvatarImageButton.hovered ? "firebrick" : "transparent"
|
|
opacity: 0.7
|
|
}
|
|
|
|
onClicked: {
|
|
avatarImage.source = ""
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
}
|
|
// optional pseudonym edit
|
|
TextField {
|
|
id: optNameField
|
|
Layout.preferredWidth: 500
|
|
Layout.preferredHeight: 50
|
|
placeholderText: qsTr("Display name (optional)")
|
|
placeholderTextColor: "#696969" // dim gray
|
|
color: "#6b5b95"////(NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000" // textColor
|
|
selectByMouse: true
|
|
background: Rectangle {
|
|
color: (NeroshopComponents.Style.darkTheme) ? "#101010" : "#ffffff"
|
|
border.color: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
radius: 3
|
|
}
|
|
//validator: RegExpValidator { regExp: /^(?=.{8,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$/ } // validator: RegularExpressionValidator { regularExpression: /[0-9A-F]+/ } // since Qt 5.14
|
|
|
|
////Layout.topMargin: (optNameText.visible) ? 5 : 0
|
|
////placeholderTextColor: (NeroshopComponents.Style.darkTheme) ? "#a9a9a9" : "#696969"
|
|
Keys.onEnterPressed: registerWallet()
|
|
Keys.onReturnPressed: registerWallet()
|
|
}
|
|
// register button
|
|
Button {
|
|
id: registerButton
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 50
|
|
Layout.topMargin: 15
|
|
text: qsTr("Register")
|
|
hoverEnabled: true
|
|
onClicked: registerWallet()
|
|
background: Rectangle {
|
|
color: "#6b5b95"
|
|
radius: 5
|
|
}
|
|
|
|
contentItem: Text {
|
|
//font.family: "Consolas"; //font.family: NeroshopComponents.Style.fontFiraCodeLight.name
|
|
//font.pointSize: 10
|
|
font.bold: true
|
|
text: registerButton.text
|
|
color: "#ffffff" // white
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onPressed: mouse.accepted = false
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
}
|
|
} // GridLayout for registrationPage
|
|
} // eof registrationPage
|
|
// walletfile auth page
|
|
// Upload button with read-only textfield
|
|
}
|
|
}
|