Compare commits

..

2 Commits

Author SHA1 Message Date
luigi1111
a77a5909cf Merge pull request #2215 (again)
bf785bb build: checkout v0.14.1.0 tag (selsta)
2019-06-25 14:33:46 -05:00
selsta
bf785bb388 build: checkout v0.14.1.0 tag 2019-06-14 16:15:36 +02:00
54 changed files with 899 additions and 1056 deletions

19
.gitignore vendored
View File

@@ -13,22 +13,3 @@ monero-wallet-gui_plugin_import.cpp
monero-wallet-gui_qml_plugin_import.cpp
*.qmlc
*.jsc
### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

View File

@@ -114,12 +114,13 @@ Rectangle {
anchors.top: parent.top
anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0
Item {
RowLayout {
Item {
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 20
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490
width: 260
@@ -229,6 +230,7 @@ Rectangle {
anchors.top: parent.top
anchors.topMargin: 20
anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490
width: 50

View File

@@ -34,7 +34,6 @@
#include <QDebug>
#include "Logger.h"
#include "src/qt/TailsOS.h"
#include "wallet/api/wallet2_api.h"
// default log path by OS (should be writable)
@@ -67,9 +66,6 @@ const QString getLogPath(const QString logPath)
{
const QFileInfo fi(logPath);
if(TailsOS::detect() && TailsOS::usePersistence)
return QDir::homePath() + "/Persistent/Monero/logs/" + defaultLogName;
if(!logPath.isEmpty() && !fi.isDir())
return fi.absoluteFilePath();
else {

View File

@@ -209,13 +209,13 @@ Rectangle {
clip: true
ScrollBar.vertical: ScrollBar {
parent: root
parent: mainFlickable.parent
anchors.left: parent.right
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width
anchors.leftMargin: 3
anchors.top: parent.top
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10
anchors.topMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10
anchors.bottomMargin: persistentSettings.customDecorations ? 4 : 0
}
onFlickingChanged: {

View File

@@ -165,8 +165,9 @@ The executable can be found in the build/release/bin folder.
5. Add the Qt bin directory to your path
- Example for Qt: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
- Example for Homebrew: `export PATH=$PATH:/usr/local/opt/qt/bin`
Example: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
This is the directory where Qt 5.x is installed on **your** system
6. Grab an up-to-date copy of the monero-gui repository

View File

@@ -34,6 +34,8 @@ import "../components/effects/" as MoneroEffects
Label {
id: item
fontSize: 18
anchors.left: parent.left
anchors.right: parent.right
Rectangle {
anchors.top: item.bottom

View File

@@ -88,7 +88,6 @@ Rectangle {
}
MouseArea {
anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor
onClicked: {
if(!appWindow.isMining) {
@@ -134,7 +133,6 @@ Rectangle {
MouseArea {
anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor
onClicked: {
if(!appWindow.isMining) {

View File

@@ -0,0 +1,287 @@
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias password: passwordInput1.text
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open() {
isHidden = true
passwordInput1.echoMode = TextInput.Password;
passwordInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passwordInput1.text = "";
passwordInput2.text = "";
passwordInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: qsTr("Please enter new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passwordInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
Label {
text: qsTr("Please confirm new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passwordInput1.text === passwordInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passwordInput1.text === passwordInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
// 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 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias passphrase: passphaseInput1.text
property string walletName
property string errorText
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open(walletName, errorText) {
isHidden = true
passphaseInput1.echoMode = TextInput.Password;
passphaseInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
root.walletName = walletName ? walletName : ""
root.errorText = errorText ? errorText : "";
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passphaseInput1.text = "";
passphaseInput2.text = "";
passphaseInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passphaseInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passphaseInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
function showError(errorText) {
open(root.walletName, errorText);
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: (root.walletName.length > 0 ? qsTr("Please enter wallet device passphrase for: ") + root.walletName : qsTr("Please enter wallet device passphrase")) + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
Label {
text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: 14
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.warningColor
}
Label {
text: root.errorText
visible: root.errorText
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
}
TextField {
id : passphaseInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passphaseInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "transparent"
}
Label {
text: qsTr("Please re-enter") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passphaseInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passphaseInput1.text === passphaseInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passphaseInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passphaseInput1.text === passphaseInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

@@ -44,63 +44,34 @@ Item {
z: parent.z + 2
property bool isHidden: true
property alias password: passwordInput1.text
property alias password: passwordInput.text
property string walletName
property string errorText
property bool passwordDialogMode
property bool passphraseDialogMode
property bool newPasswordDialogMode
property bool shiftIsPressed: false
property bool isCapsLocksActive: false
property bool backspaceIsPressed: false
// same signals as Dialog has
signal accepted()
signal acceptedNewPassword()
signal acceptedPassphrase()
signal rejected()
signal rejectedNewPassword()
signal rejectedPassphrase()
signal closeCallback()
function _openInit(walletName, errorText) {
function open(walletName, errorText) {
isHidden = true
capsLockTextLabel.visible = oshelper.isCapsLock();
passwordInput1.echoMode = TextInput.Password
passwordInput2.echoMode = TextInput.Password
passwordInput1.text = ""
passwordInput2.text = ""
passwordInput1.forceActiveFocus();
passwordInput.echoMode = TextInput.Password
passwordInput.text = ""
passwordInput.forceActiveFocus();
inactiveOverlay.visible = true // draw appwindow inactive
root.walletName = walletName ? walletName : ""
errorTextLabel.text = errorText ? errorText : "";
leftPanel.enabled = false
middlePanel.enabled = false
wizard.enabled = false
titleBar.state = "essentials"
root.visible = true;
appWindow.hideBalanceForced = true;
appWindow.updateBalance();
}
function open(walletName, errorText) {
passwordDialogMode = true;
passphraseDialogMode = false;
newPasswordDialogMode = false;
_openInit(walletName, errorText);
}
function openPassphraseDialog() {
passwordDialogMode = false;
passphraseDialogMode = true;
newPasswordDialogMode = false;
_openInit("", "");
}
function openNewPasswordDialog() {
passwordDialogMode = false;
passphraseDialogMode = false;
newPasswordDialogMode = true;
_openInit("", "");
}
function showError(errorText) {
open(root.walletName, errorText);
}
@@ -109,7 +80,6 @@ Item {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
wizard.enabled = true
titleBar.state = "default"
root.visible = false;
@@ -118,12 +88,6 @@ Item {
closeCallback();
}
function toggleIsHidden() {
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
@@ -138,14 +102,7 @@ Item {
Layout.maximumWidth: 400
Label {
text: {
if (newPasswordDialogMode) {
return qsTr("Please enter new wallet password") + translationManager.emptyString;
} else {
var device = passwordDialogMode ? qsTr("wallet password") : qsTr("wallet device passphrase");
return (root.walletName.length > 0 ? qsTr("Please enter %1 for: ").arg(device) + root.walletName : qsTr("Please enter %1").arg(device)) + translationManager.emptyString;
}
}
text: (root.walletName.length > 0 ? qsTr("Please enter wallet password for: ") + root.walletName : qsTr("Please enter wallet password")) + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
@@ -154,41 +111,19 @@ Item {
color: MoneroComponents.Style.defaultFontColor
}
Label {
text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
visible: passphraseDialogMode
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: 14
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.warningColor
}
Label {
id: errorTextLabel
visible: root.errorText || text !== ""
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Label {
id: capsLockTextLabel
visible: false
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
text: qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
}
TextField {
id: passwordInput1
id : passwordInput
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
@@ -196,20 +131,24 @@ Item {
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: {
if (passwordDialogMode) {
return okButton
} else {
return passwordInput2
}
}
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
onTextChanged: {
var letter = text[passwordInput.text.length - 1];
isCapsLocksActive = Utils.isUpperLock(shiftIsPressed, letter);
if(isCapsLocksActive && !backspaceIsPressed){
errorTextLabel.text = qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
}
else{
errorTextLabel.text = "";
}
}
background: Rectangle {
radius: 2
@@ -238,7 +177,8 @@ Item {
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden();
passwordInput.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
onEntered: {
parent.opacity = 0.9
@@ -255,129 +195,28 @@ Item {
Keys.enabled: root.visible
Keys.onReturnPressed: {
root.close()
if (passwordDialogMode) {
root.accepted()
} else if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
root.accepted()
}
Keys.onEscapePressed: {
root.close()
if (passwordDialogMode) {
root.rejected()
} else if (newPasswordDialogMode) {
root.rejectedNewPassword()
} else if (passphraseDialogMode) {
root.rejectedPassphrase()
root.rejected()
}
Keys.onPressed: {
if(event.key === Qt.Key_Shift){
shiftIsPressed = true;
}
if(event.key === Qt.Key_Backspace){
backspaceIsPressed = true;
}
}
}
// padding
Rectangle {
visible: !passwordDialogMode
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
Label {
visible: !passwordDialogMode
text: newPasswordDialogMode ? qsTr("Please confirm new password") : qsTr("Please confirm wallet device passphrase") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id: passwordInput2
visible: !passwordDialogMode
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
Keys.onReleased: {
if(event.key === Qt.Key_Shift){
shiftIsPressed = false;
}
if(event.key === Qt.Key_Backspace){
backspaceIsPressed =false;
}
}
Keys.onReturnPressed: {
if (passwordInput1.text === passwordInput2.text) {
root.close()
if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
}
}
Keys.onEscapePressed: {
root.close()
if (newPasswordDialogMode) {
root.rejectedNewPassword()
} else if (passphraseDialogMode) {
root.rejectedPassphrase()
}
}
}
// padding
Rectangle {
visible: !passwordDialogMode
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
@@ -390,38 +229,26 @@ Item {
MoneroComponents.StandardButton {
id: cancelButton
small: true
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput1
text: root.walletName.length > 0 ? qsTr("Change wallet") + translationManager.emptyString : qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput
onClicked: {
root.close()
if (passwordDialogMode) {
root.rejected()
} else if (newPasswordDialogMode) {
root.rejectedNewPassword()
} else if (passphraseDialogMode) {
root.rejectedPassphrase()
}
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
small: true
text: qsTr("Ok") + translationManager.emptyString
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: (passwordDialogMode == true) ? true : passwordInput1.text === passwordInput2.text
onClicked: {
root.close()
if (passwordDialogMode) {
root.accepted()
} else if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
root.accepted()
}
}
}
}
}
}

View File

@@ -17,7 +17,7 @@ if [ ! -d $MONERO_DIR/src ]; then
fi
git submodule update --remote
git -C $MONERO_DIR fetch
git -C $MONERO_DIR checkout v0.14.1.2
git -C $MONERO_DIR checkout v0.14.1.0
# get monero core tag
pushd $MONERO_DIR

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,30 +0,0 @@
# Building the Installer Deterministically
This file contains info about building the Windows installer deterministically, i.e. how different people on different Windows machines or VMs can build it and arrive at a result that is bit-for-bit identical. This approach is also known as *reproducible builds*, see e.g. [this Wikipedia article](https://en.wikipedia.org/wiki/Reproducible_builds).
The steps to build the Windows installer deterministically by a group of people are the following (for some details about the build process in general see `README.md`):
* Agree on a particular version of Inno Setup, and everybody install that
* Get the zip file for the Windows GUI wallet and unpack it, plus make sure / check that the file timestamps are preserved, i.e. upacked timestamp = timestamp in zip file
* Build using Inno Setup and the `Monero.iss` script file
* Success: All people arrive at a bit-for-bit identical installer .exe file, which they can verify by calculating and exchanging SHA256 hashes
Some background info why this process is relatively simple:
The tool used to build the Windows installer, Inno Setup, avoids many issues that make reproducible builds very challenging with many other compilers and similar tools: It does not store current date and time in the installer .exe file, and it does not seem to depend on the Windows version it runs on (tried with Windows 7 and two different editions of Windows 10), nor on the locale and display language.
So fortunately no complicated things as faked current system time or use of VMs with exactly prescribed versions of Windows are necessary.
The version of Inno Setup **is** important however: People wanting to reproducibly build the installer must agree on a particular version to use. This should not be hard to do however.
Also important are the **timestamps** of the source files because they go into the installer file, to be restored at install time.
You would think timestamp preservation is no problem when unpacking the zip archive with the files for the Windows GUI wallet from getmonero.org, but if you use the zip folder unpack functionality of the Windows 7 GUI, the files get the current date, **not** the file recorded in the zip file. (The Windows 10 GUI seems better here, and also the 7zip app.)
In any case, after unpacking, check the file dates in the `bin` directory where the installer script looks for them with the dates of the files in the zip file: They must be identical.
Note that the the following line in `Monero.iss` is also important regarding file timestamps:
TimeStampsInUTC=yes
Without this line the **timezone** of the machine used to build the installer would matter, with different timezones leading to different installer files.

View File

@@ -8,7 +8,7 @@ AppName=Monero GUI Wallet
; Thus it's important to keep this stable over releases
; With a different "AppName" InnoSetup would treat a mere update as a completely new application and thus mess up
AppVersion=0.14.1.2
AppVersion=0.14.1.0
DefaultDirName={pf}\Monero GUI Wallet
DefaultGroupName=Monero GUI Wallet
UninstallDisplayIcon={app}\monero-wallet-gui.exe
@@ -21,8 +21,6 @@ DisableWelcomePage=no
LicenseFile=LICENSE
AppPublisher=The Monero Developer Community
AppPublisherURL=https://getmonero.org
TimeStampsInUTC=yes
CompressionThreads=1
UsedUserAreasWarning=no
; The above directive silences the following compiler warning:
@@ -70,7 +68,7 @@ Source: "FinishImage.bmp"; Flags: dontcopy
; Monero GUI wallet exe and guide
Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "bin\monero-gui-wallet-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
Source: "bin\monero-GUI-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
; Monero CLI wallet
Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion

View File

@@ -34,13 +34,11 @@ You can only build on Windows, and the result is always a
Windows .exe file that can act as a standalone installer for the
Boron Butterfly GUI wallet.
Note that the installer build process is now reproducible / deterministic. For details check the file [Deterministic.md](Deterministic.md).
The build steps in detail:
1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php)
2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally you may have to checkout a specific branch, like `release-v0.14`.
3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.14.1.2`) to this `bin` subdirectory
3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.14.1.0`) to this `bin` subdirectory
4. Start Inno Setup, load `Monero.iss` and compile it
5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory

View File

@@ -7,7 +7,7 @@
<h1>Monero Boron Butterfly GUI Wallet</h1>
<p>Copyright (c) 2014-2019, The Monero Project<br>
Date: July 20, 2019</p>
Date: May 7, 2019</p>
<h2>Preface</h2>
@@ -23,7 +23,7 @@
<h2>Content of the Package</h2>
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Boron Butterfly, version 0.14.1.2.
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Boron Butterfly, version 0.14.1.0.
The wallet enables you to send and receive Moneroj in a secure and very private way.
</p>
@@ -61,7 +61,7 @@
provides the most security and privacy possible for you.</p>
<p>However if your Internet access makes it difficult to run a full node, or if you have simply no room to store
the blockchain locally (somewhat over 70 GB in July 2019, and of course growing), you can compromise and try to connect
the blockchain locally (somewhat over 70 GB in May 2019, and of course growing), you can compromise and try to connect
to a remote node. One way of finding such a node is checking
<a href="https://moneroworld.com/#nodes">this page</a>.
</p>

View File

@@ -0,0 +1 @@
-----

View File

@@ -12,13 +12,13 @@ function destinationsToAddress(destinations){
}
function addressTruncate(address, range){
if(typeof(address) === "undefined") return "";
if(typeof(address) === "undefined") return;
if(typeof(range) === "undefined") range = 8;
return address.substring(0, range) + "..." + address.substring(address.length-range);
}
function addressTruncatePretty(address, blocks){
if(typeof(address) === "undefined") return "";
if(typeof(address) === "undefined") return;
if(typeof(blocks) === "undefined") blocks = 2;
blocks = blocks <= 1 ? 1 : blocks >= 23 ? 23 : blocks;
var ret = "";

View File

@@ -112,6 +112,25 @@ function roundDownToNearestThousand(_num){
return Math.floor(_num/1000.0)*1000
}
function isAlpha(letter){ return letter.match(/^[A-Za-z0-9]+$/) !== null; }
function isLowerCaseChar(letter){ return letter === letter.toLowerCase(); }
function isUpperLock(shift, letter){
if(!isAlpha((letter))) return false;
if(shift) {
if(isLowerCaseChar(letter))
return true;
else
return false;
} else {
if(isLowerCaseChar(letter))
return false;
else
return true;
}
}
function qmlEach(item, properties, ignoredObjectNames, arr){
// Traverse QML object tree and return components that match
// via property names. Similar to jQuery("myclass").each(...

View File

@@ -51,12 +51,4 @@ SCRIPT_DIR="\$(dirname "\$(test -L "\${BASH_SOURCE[0]}" && readlink "\${BASH_SOU
"\$SCRIPT_DIR"/$GUI_EXEC "\$@"
EOL
# Create start script
cat > $TARGET/start-tails.AppImage <<EOL
#!/bin/bash
# Silly hack to provide a launcher that is double clickable
bash ./start-gui.sh
EOL
chmod +x $TARGET/start-gui.sh
chmod +x $TARGET/start-tails.AppImage

View File

@@ -64,9 +64,8 @@
#include "MainApp.h"
#include "qt/ipc.h"
#include "qt/utils.h"
#include "src/qt/TailsOS.h"
#include "qt/mime.h"
#include "src/qt/KeysFiles.h"
#include "src/qt/MoneroSettings.h"
#include "qt/prices.h"
// IOS exclusions
@@ -83,7 +82,6 @@ bool isAndroid = false;
bool isWindows = false;
bool isMac = false;
bool isLinux = false;
bool isTails = false;
bool isDesktop = false;
bool isOpenGL = true;
@@ -103,7 +101,6 @@ int main(int argc, char *argv[])
bool isWindows = true;
#elif defined(Q_OS_LINUX)
bool isLinux = true;
bool isTails = TailsOS::detect();
#elif defined(Q_OS_MAC)
bool isMac = true;
#endif
@@ -125,40 +122,25 @@ int main(int argc, char *argv[])
// qDebug() << "High DPI auto scaling - enabled";
//#endif
MainApp app(argc, argv);
app.setApplicationName("monero-core");
app.setOrganizationDomain("getmonero.org");
app.setOrganizationName("monero-project");
// Ask to enable Tails OS persistence mode, it affects:
// - Log file location
// - QML Settings file location (monero-core.conf)
// - Default wallets path
// Target directory is: ~/Persistent/Monero
if (isTails) {
if (!TailsOS::detectDataPersistence())
TailsOS::showDataPersistenceDisabledWarning();
else
TailsOS::askPersistence();
}
QString moneroAccountsDir;
#if defined(Q_OS_WIN) || defined(Q_OS_IOS)
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
#else
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
#endif
if(isTails && TailsOS::usePersistence){
moneroAccountsDir = QDir::homePath() + "/Persistent/Monero/wallets";
} else if (!moneroAccountsRootDir.empty()) {
if (!moneroAccountsRootDir.empty()) {
moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets";
} else {
qCritical() << "Error: accounts root directory could not be set";
return 1;
}
MainApp app(argc, argv);
app.setApplicationName("monero-core");
app.setOrganizationDomain("getmonero.org");
app.setOrganizationName("monero-project");
#if defined(Q_OS_LINUX)
if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico"));
#endif
@@ -191,8 +173,9 @@ int main(int argc, char *argv[])
}
qWarning().noquote() << "app startd" << "(log: " + logPath + ")";
// Desktop entry
#ifdef Q_OS_LINUX
registerXdgMime(app);
#endif
IPC *ipc = new IPC(&app);
QStringList posArgs = parser.positionalArguments();
@@ -241,9 +224,6 @@ int main(int argc, char *argv[])
// registering types for QML
qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard");
// Temporary Qt.labs.settings replacement
qmlRegisterType<MoneroSettings>("moneroComponents.Settings", 1, 0, "MoneroSettings");
qmlRegisterUncreatableType<Wallet>("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
@@ -333,8 +313,6 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("walletLogPath", logPath);
engine.rootContext()->setContextProperty("tailsUsePersistence", TailsOS::usePersistence);
// Exclude daemon manager from IOS
#ifndef Q_OS_IOS
const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0);
@@ -348,7 +326,7 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("isIOS", isIOS);
engine.rootContext()->setContextProperty("isAndroid", isAndroid);
engine.rootContext()->setContextProperty("isOpenGL", isOpenGL);
engine.rootContext()->setContextProperty("isTails", isTails);
engine.rootContext()->setContextProperty("isLinux", isLinux);
engine.rootContext()->setContextProperty("screenWidth", geo.width());
engine.rootContext()->setContextProperty("screenHeight", geo.height());
@@ -372,7 +350,6 @@ int main(int argc, char *argv[])
accountName = "My monero Account";
engine.rootContext()->setContextProperty("defaultAccountName", accountName);
engine.rootContext()->setContextProperty("homePath", QDir::homePath());
engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());

120
main.qml
View File

@@ -31,11 +31,11 @@ import QtQuick.Window 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0
import moneroComponents.Settings 1.0
import "components"
import "components" as MoneroComponents
@@ -283,7 +283,7 @@ ApplicationWindow {
titleBar.visible = persistentSettings.customDecorations;
}
function closeWallet(callback) {
function closeWallet() {
// Disconnect all listeners
if (typeof currentWallet !== "undefined" && currentWallet !== null) {
@@ -306,17 +306,8 @@ ApplicationWindow {
}
currentWallet = undefined;
walletManager.closeWallet();
appWindow.showProcessingSplash(qsTr("Closing wallet..."));
if (callback) {
walletManager.closeWalletAsync(function() {
hideProcessingSplash();
callback();
});
} else {
walletManager.closeWallet();
hideProcessingSplash();
}
}
function connectWallet(wallet) {
@@ -567,21 +558,26 @@ ApplicationWindow {
}
}
function onWalletClosed(walletAddress) {
hideProcessingSplash();
console.log(">>> wallet closed: " + walletAddress)
}
function onWalletPassphraseNeeded(){
if(rootItem.state !== "normal") return;
hideProcessingSplash();
console.log(">>> wallet passphrase needed: ")
passwordDialog.onAcceptedPassphraseCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password);
passphraseDialog.onAcceptedCallback = function() {
walletManager.onPassphraseEntered(passphraseDialog.passphrase);
this.onWalletOpening();
}
passwordDialog.onRejectedPassphraseCallback = function() {
passphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", true);
this.onWalletOpening();
}
passwordDialog.openPassphraseDialog()
passphraseDialog.open()
}
function onWalletUpdate() {
@@ -1109,30 +1105,27 @@ ApplicationWindow {
console.log("Hiding processing splash")
splash.close();
if (!passwordDialog.visible) {
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.enabled = true
inactiveOverlay.visible = false;
}
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.enabled = true
inactiveOverlay.visible = false;
}
// close wallet and show wizard
function showWizard(){
clearMoneroCardLabelText();
walletInitialized = false;
closeWallet(function() {
currentWallet = undefined;
wizard.restart();
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
fiatApiUpdateBalance(0, 0);
// disable timers
userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false;
});
closeWallet();
currentWallet = undefined;
wizard.restart();
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
fiatApiUpdateBalance(0, 0);
// disable timers
userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false;
}
function hideMenu() {
@@ -1296,6 +1289,7 @@ ApplicationWindow {
y = (Screen.height - maxWindowHeight) / 2
//
walletManager.walletOpened.connect(onWalletOpened);
walletManager.walletClosed.connect(onWalletClosed);
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
@@ -1347,14 +1341,8 @@ ApplicationWindow {
}
}
MoneroSettings {
Settings {
id: persistentSettings
fileName: {
if(isTails && tailsUsePersistence)
return homePath + "/Persistent/Monero/monero-core.conf";
return "";
}
property string language
property string locale
property string account_name
@@ -1506,15 +1494,13 @@ ApplicationWindow {
}
}
PasswordDialog {
id: passwordDialog
PassphraseDialog {
id: passphraseDialog
visible: false
z: parent.z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
property var onAcceptedPassphraseCallback
property var onRejectedPassphraseCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
@@ -1523,9 +1509,33 @@ ApplicationWindow {
if (onRejectedCallback)
onRejectedCallback();
}
onAcceptedNewPassword: {
if (currentWallet.setPassword(passwordDialog.password)) {
appWindow.walletPassword = passwordDialog.password;
}
PasswordDialog {
id: passwordDialog
visible: false
z: parent.z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
}
onRejected: {
if (onRejectedCallback)
onRejectedCallback();
}
}
NewPasswordDialog {
id: newPasswordDialog
z: parent.z + 1
visible:false
anchors.fill: parent
onAccepted: {
if (currentWallet.setPassword(newPasswordDialog.password)) {
appWindow.walletPassword = newPasswordDialog.password;
informationPopup.title = qsTr("Information") + translationManager.emptyString;
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information;
@@ -1537,14 +1547,7 @@ ApplicationWindow {
informationPopup.onCloseCallback = null;
informationPopup.open();
}
onRejectedNewPassword: {}
onAcceptedPassphrase: {
if (onAcceptedPassphraseCallback)
onAcceptedPassphraseCallback();
}
onRejectedPassphrase: {
if (onRejectedPassphraseCallback)
onRejectedPassphraseCallback();
onRejected: {
}
}
@@ -2128,8 +2131,8 @@ ApplicationWindow {
console.log("close accepted");
// Close wallet non async on exit
daemonManager.exit();
closeWallet(Qt.quit);
walletManager.closeWallet();
Qt.quit();
}
function onWalletCheckUpdatesComplete(update) {
@@ -2198,7 +2201,6 @@ ApplicationWindow {
function checkInUserActivity() {
if(rootItem.state !== "normal") return;
if(!persistentSettings.lockOnUserInActivity) return;
if(passwordDialog.visible) return;
// prompt password after X seconds of inactivity
var epoch = Math.floor((new Date).getTime() / 1000);

View File

@@ -1,6 +1,6 @@
# qml components require at least QT 5.9.0
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 9) {
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.9.0")
# qml components require at least QT 5.7.0
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 7) {
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.7.0")
}
TEMPLATE = app
@@ -65,12 +65,10 @@ HEADERS += \
MainApp.h \
src/qt/FutureScheduler.h \
src/qt/ipc.h \
src/qt/mime.h \
src/qt/KeysFiles.h \
src/qt/utils.h \
src/qt/prices.h \
src/qt/macoshelper.h \
src/qt/MoneroSettings.h \
src/qt/TailsOS.h
src/qt/prices.h
SOURCES += main.cpp \
filter.cpp \
@@ -101,11 +99,10 @@ SOURCES += main.cpp \
MainApp.cpp \
src/qt/FutureScheduler.cpp \
src/qt/ipc.cpp \
src/qt/mime.cpp \
src/qt/KeysFiles.cpp \
src/qt/utils.cpp \
src/qt/prices.cpp \
src/qt/MoneroSettings.cpp \
src/qt/TailsOS.cpp
src/qt/prices.cpp
CONFIG(DISABLE_PASS_STRENGTH_METER) {
HEADERS -= src/zxcvbn-c/zxcvbn.h
@@ -337,8 +334,7 @@ linux {
-llmdb \
-lsodium \
-lhidapi-libusb \
-lcrypto $$TREZOR_LINKER \
-lX11
-lcrypto $$TREZOR_LINKER
if(!android) {
LIBS+= \
@@ -363,8 +359,6 @@ macx {
# message("using static libraries")
# LIBS+= -Wl,-Bstatic
# }
QT += macextras
OBJECTIVE_SOURCES += src/qt/macoshelper.mm
LIBS+= \
-L/usr/local/lib \
-L/usr/local/opt/openssl/lib \
@@ -378,7 +372,6 @@ macx {
-lboost_chrono \
-lboost_program_options \
-framework CoreFoundation \
-framework AppKit \
-lhidapi \
-lssl \
-lsodium \

View File

@@ -31,20 +31,6 @@
#include <QDir>
#include <QDebug>
#include <QString>
#ifdef Q_OS_MAC
#include "qt/macoshelper.h"
#endif
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <X11/XKBlib.h>
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
// #undef those Xlib #defines that conflict with QEvent::Type enum
#endif
OSHelper::OSHelper(QObject *parent) : QObject(parent)
{
@@ -72,27 +58,6 @@ bool OSHelper::removeTemporaryWallet(const QString &fileName) const
return cache_deleted && address_deleted && keys_deleted;
}
// https://stackoverflow.com/a/3006934
bool OSHelper::isCapsLock() const
{
// platform dependent method of determining if CAPS LOCK is on
#if defined(Q_OS_WIN32) // MS Windows version
return GetKeyState(VK_CAPITAL) == 1;
#elif defined(Q_OS_LINUX) // X11 version
Display * d = XOpenDisplay((char*)0);
bool caps_state = false;
if (d) {
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
}
return caps_state;
#elif defined(Q_OS_MAC)
return MacOSHelper::isCapsLock();
#endif
return false;
}
QString OSHelper::temporaryPath() const
{
return QDir::tempPath();

View File

@@ -42,7 +42,6 @@ public:
Q_INVOKABLE QString temporaryFilename() const;
Q_INVOKABLE QString temporaryPath() const;
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
Q_INVOKABLE bool isCapsLock() const;
signals:

View File

@@ -101,7 +101,8 @@ Rectangle {
id: balanceAll
font.family: MoneroComponents.Style.fontMonoRegular.name;
font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor
color: MoneroComponents.Style.dimmedFontColor
themeTransition: false
MouseArea {
hoverEnabled: true
@@ -134,7 +135,8 @@ Rectangle {
id: unlockedBalanceAll
font.family: MoneroComponents.Style.fontMonoRegular.name;
font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor
color: MoneroComponents.Style.dimmedFontColor
themeTransition: false
MouseArea {
hoverEnabled: true
@@ -175,7 +177,7 @@ Rectangle {
ListView {
id: subaddressAccountListView
Layout.fillWidth: true
Layout.fillHeight: true
anchors.fill: parent
clip: true
boundsBehavior: ListView.StopAtBounds
interactive: false
@@ -363,7 +365,6 @@ Rectangle {
appWindow.currentWallet.subaddressAccount.addRow(inputDialog.inputText)
appWindow.currentWallet.switchSubaddressAccount(appWindow.currentWallet.numSubaddressAccounts() - 1)
current_subaddress_account_table_index = appWindow.currentWallet.numSubaddressAccounts() - 1
subaddressAccountListView.currentIndex = current_subaddress_account_table_index
appWindow.onWalletUpdate();
}
inputDialog.onRejectedCallback = null;

View File

@@ -145,7 +145,7 @@ Rectangle {
ListView {
id: addressBookListView
Layout.fillWidth: true
Layout.fillHeight: true
anchors.fill: parent
clip: true
boundsBehavior: ListView.StopAtBounds
interactive: false

View File

@@ -49,9 +49,9 @@ Rectangle {
property var model
property int sideMargin: 50
property var initialized: false
property int txMax: Math.max(5, ((appWindow.height - 250) / 60))
property int txMax: 5
property int txOffset: 0
property int txPage: (txOffset / txMax) + 1
property int txPage: (txOffset / 5) + 1
property int txCount: 0
property var sortSearchString: null
property bool sortDirection: true // true = desc, false = asc
@@ -67,8 +67,6 @@ Rectangle {
color: "transparent"
onTxMaxChanged: root.updateDisplay(root.txOffset, root.txMax);
ColumnLayout {
id: pageRoot
anchors.topMargin: 40
@@ -251,6 +249,7 @@ Rectangle {
font.pixelSize: 15
text: qsTr("Blockheight") + translationManager.emptyString
color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
themeTransition: false
}
@@ -311,6 +310,7 @@ Rectangle {
text: qsTr("Date") + translationManager.emptyString
color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false
anchors.verticalCenter: parent.verticalCenter
}
MoneroEffects.ImageMask {
@@ -370,6 +370,7 @@ Rectangle {
text: qsTr("Amount") + translationManager.emptyString
color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false
anchors.verticalCenter: parent.verticalCenter
}
MoneroEffects.ImageMask {
@@ -1342,14 +1343,13 @@ Rectangle {
root.updateDisplay(root.txOffset, root.txMax);
}
function reset(keepDate) {
function reset() {
root.txOffset = 0;
root.txMax = 5;
if (typeof root.model !== 'undefined' && root.model != null) {
if (!keepDate) {
root.model.dateFromFilter = "2014-04-18" // genesis block
root.model.dateToFilter = "9999-09-09" // fix before september 9999
}
root.model.dateFromFilter = "2014-04-18" // genesis block
root.model.dateToFilter = "9999-09-09" // fix before september 9999
// negative values disable filters here;
root.model.amountFromFilter = -1;
root.model.amountToFilter = -1;
@@ -1387,8 +1387,6 @@ Rectangle {
txs.push(item);
} else if(item.blockheight.toString().startsWith(root.sortSearchString)) {
txs.push(item);
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
txs.push(item);
} else if (item.hash.startsWith(root.sortSearchString)){
txs.push(item);
}
@@ -1706,6 +1704,6 @@ Rectangle {
function onPageClosed(){
root.initialized = false;
root.reset(true);
root.reset();
}
}

View File

@@ -116,11 +116,11 @@ Rectangle {
MoneroComponents.LineEdit {
Layout.fillWidth: true
id: walletCreationHeight
readOnly: true
copyButton: true
labelText: qsTr("Block #") + translationManager.emptyString
fontSize: 16
text: currentWallet.walletCreationHeight
}
}
@@ -261,7 +261,6 @@ Rectangle {
function onPageCompleted() {
console.log("keys page loaded");
walletCreationHeight.text = currentWallet.walletCreationHeight
secretViewKey.text = currentWallet.secretViewKey
publicViewKey.text = currentWallet.publicViewKey
secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : ""

View File

@@ -101,7 +101,7 @@ Rectangle {
ListView {
id: subaddressListView
Layout.fillWidth: true
Layout.fillHeight: true
anchors.fill: parent
clip: true
boundsBehavior: ListView.StopAtBounds
interactive: false
@@ -256,7 +256,6 @@ Rectangle {
inputDialog.onAcceptedCallback = function() {
appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText)
current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1
subaddressListView.currentIndex = current_subaddress_table_index
}
inputDialog.onRejectedCallback = null;
inputDialog.open()

View File

@@ -93,8 +93,9 @@ Item {
anchors.right: parent.right
Item {
Layout.preferredHeight: 220
Layout.fillWidth: true
height: 220
anchors.left: parent.left
anchors.right: parent.right
Rectangle {
id: tracker
@@ -257,7 +258,8 @@ Item {
Item {
Layout.preferredHeight: 40
Layout.fillWidth: true
anchors.left: parent.left
anchors.right: parent.right
Item {
width: (parent.width - qrImg.width) - (50)
@@ -522,7 +524,8 @@ Item {
Item {
Layout.topMargin: 32
Layout.preferredHeight: 40
Layout.fillWidth: true
anchors.left: parent.left
anchors.right: parent.right
ColumnLayout {
spacing: 16
@@ -627,7 +630,7 @@ Item {
in_txpool = true;
} else {
if (blockchainHeight == null)
blockchainHeight = walletManager.blockchainHeight()
blockchainHeight = appWindow.currentWallet.blockChainHeight()
confirmations = blockchainHeight - blockHeight - 1
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
}

View File

@@ -208,11 +208,10 @@ Rectangle {
confirmationDialog.icon = StandardIcon.Question
confirmationDialog.cancelText = qsTr("Cancel")
confirmationDialog.onAcceptedCallback = function() {
appWindow.closeWallet(function() {
walletManager.clearWalletCache(persistentSettings.wallet_path);
walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword,
persistentSettings.nettype, persistentSettings.kdfRounds);
});
walletManager.closeWallet();
walletManager.clearWalletCache(persistentSettings.wallet_path);
walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword,
persistentSettings.nettype, persistentSettings.kdfRounds);
}
confirmationDialog.onRejectedCallback = null;
@@ -326,41 +325,6 @@ Rectangle {
font.pixelSize: 14
text: isOpenGL ? "OpenGL" : "Low graphics mode"
}
Rectangle {
visible: isTails
height: 1
Layout.topMargin: 2
Layout.bottomMargin: 2
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
Rectangle {
visible: isTails
height: 1
Layout.topMargin: 2
Layout.bottomMargin: 2
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
MoneroComponents.TextBlock {
visible: isTails
Layout.fillWidth: true
font.pixelSize: 14
text: qsTr("Tails: ") + translationManager.emptyString
}
MoneroComponents.TextBlock {
visible: isTails
Layout.fillWidth: true
color: MoneroComponents.Style.dimmedFontColor
font.pixelSize: 14
text: tailsUsePersistence ? qsTr("persistent") + translationManager.emptyString : qsTr("persistence disabled") + translationManager.emptyString;
}
}
// Copy info to clipboard

View File

@@ -339,7 +339,7 @@ Rectangle {
onClicked: {
passwordDialog.onAcceptedCallback = function() {
if(appWindow.walletPassword === passwordDialog.password){
passwordDialog.openNewPasswordDialog()
newPasswordDialog.open()
} else {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;

View File

@@ -96,7 +96,9 @@
<file>pages/SharedRingDB.qml</file>
<file>components/effects/ImageMask.qml</file>
<file>components/IconButton.qml</file>
<file>components/PassphraseDialog.qml</file>
<file>components/PasswordDialog.qml</file>
<file>components/NewPasswordDialog.qml</file>
<file>components/InputDialog.qml</file>
<file>components/ProcessingSplash.qml</file>
<file>components/ProgressBar.qml</file>
@@ -251,6 +253,5 @@
<file>images/copy.svg</file>
<file>images/edit.svg</file>
<file>images/arrow-right-in-circle-outline-medium-white.svg</file>
<file>images/tails-grey.png</file>
</qresource>
</RCC>

View File

@@ -524,8 +524,7 @@ bool Wallet::submitTxFile(const QString &fileName) const
void Wallet::commitTransactionAsync(PendingTransaction *t)
{
m_scheduler.run([this, t] {
auto txIdList = t->txid(); // retrieve before commit
emit transactionCommitted(t->commit(), t, txIdList);
emit transactionCommitted(t->commit(), t, t->txid());
});
}

View File

@@ -351,7 +351,7 @@ signals:
void walletCreationHeightChanged();
void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed();
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
void transactionCommitted(bool status, PendingTransaction *t, QStringList txid);
void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
// emitted when transaction is created async

View File

@@ -66,7 +66,7 @@ public:
}
auto tmpPass = m_mgr->m_passphrase.toStdString();
m_mgr->m_passphrase = QString();
m_mgr->m_passphrase = QString::null;
return Monero::optional<std::string>(tmpPass);
}
@@ -228,11 +228,11 @@ QString WalletManager::closeWallet()
return result;
}
void WalletManager::closeWalletAsync(const QJSValue& callback)
void WalletManager::closeWalletAsync()
{
m_scheduler.run([this] {
return QJSValueList({closeWallet()});
}, callback);
emit walletClosed(closeWallet());
});
}
bool WalletManager::walletExists(const QString &path) const

View File

@@ -117,7 +117,7 @@ public:
/*!
* \brief closeWalletAsync - asynchronous version of "closeWallet"
*/
Q_INVOKABLE void closeWalletAsync(const QJSValue& callback);
Q_INVOKABLE void closeWalletAsync();
//! checks is given filename is a wallet;
Q_INVOKABLE bool walletExists(const QString &path) const;
@@ -192,6 +192,7 @@ signals:
void walletPassphraseNeeded();
void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed();
void walletClosed(const QString &walletAddress);
void checkUpdatesComplete(const QString &result) const;
void miningStatus(bool isMining) const;

View File

@@ -1,208 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// 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.
#include <QtCore>
#include <QMetaObject>
#include <QSettings>
#include <QPointer>
#include <QJSValue>
#include <QHash>
#include <QMetaProperty>
#include "src/qt/MoneroSettings.h"
/*!
\qmlmodule moneroSettings 1.0
\title Monero Settings QML Component
\ingroup qmlmodules
\brief Provides persistent platform-independent application settings.
This component was introduced in order to have control over where the
configuration file is written. This is needed for Tails OS and
portable installations.
For more information, see: https://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html and
https://github.com/qt/qtdeclarative/blob/v5.12.0/src/imports/settings/qqmlsettings.cpp
To use this module, import the module with the following line:
\code
import moneroComponents.Settings 1.0
\endcode
Usage:
\code
MoneroSettings { id: persistentSettings, property bool foo: true }
\endcode
@TODO: Remove this QML component after migrating to Qt >= 5.12.0, as
`Qt.labs.settings` provides the fileName via a Q_PROPERTY
*/
void MoneroSettings::load()
{
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
QMetaProperty property = mo->property(i);
const QVariant previousValue = readProperty(property);
const QVariant currentValue = this->m_settings->value(property.name(), previousValue);
if (!currentValue.isNull() && (!previousValue.isValid()
|| (currentValue.canConvert(previousValue.type()) && previousValue != currentValue))) {
property.write(this, currentValue);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue;
#endif
}
// ensure that a non-existent setting gets written
// even if the property wouldn't change later
if (!this->m_settings->contains(property.name()))
this->_q_propertyChanged();
// setup change notifications on first load
if (!this->m_initialized && property.hasNotifySignal()) {
static const int propertyChangedIndex = mo->indexOfSlot("_q_propertyChanged()");
int signalIndex = property.notifySignalIndex();
QMetaObject::connect(this, signalIndex, this, propertyChangedIndex);
}
}
}
void MoneroSettings::_q_propertyChanged()
{
// Called on QML property change
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
const QMetaProperty &property = mo->property(i);
const QVariant value = readProperty(property);
this->m_changedProperties.insert(property.name(), value);
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: cache" << property.name() << ":" << value;
#endif
}
if (this->m_timerId != 0)
this->killTimer(this->m_timerId);
this->m_timerId = this->startTimer(settingsWriteDelay);
}
QVariant MoneroSettings::readProperty(const QMetaProperty &property) const
{
QVariant var = property.read(this);
if (var.userType() == qMetaTypeId<QJSValue>())
var = var.value<QJSValue>().toVariant();
return var;
}
void MoneroSettings::init()
{
if (!this->m_initialized) {
this->m_settings = this->m_fileName.isEmpty() ? new QSettings() : new QSettings(this->m_fileName, QSettings::IniFormat);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: stored at" << this->m_settings->fileName();
#endif
this->load();
this->m_initialized = true;
}
}
void MoneroSettings::reset()
{
if (this->m_initialized && this->m_settings && !this->m_changedProperties.isEmpty())
this->store();
if (this->m_settings)
delete this->m_settings;
}
void MoneroSettings::store()
{
QHash<const char *, QVariant>::const_iterator it = this->m_changedProperties.constBegin();
while (it != this->m_changedProperties.constEnd()) {
this->m_settings->setValue(it.key(), it.value());
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: store" << it.key() << ":" << it.value();
#endif
++it;
}
this->m_changedProperties.clear();
}
void MoneroSettings::setFileName(const QString &fileName)
{
if (fileName != this->m_fileName) {
this->reset();
this->m_fileName = fileName;
if (this->m_initialized)
this->load();
}
}
QString MoneroSettings::fileName() const
{
return this->m_fileName;
}
void MoneroSettings::timerEvent(QTimerEvent *event)
{
if (event->timerId() == this->m_timerId) {
killTimer(this->m_timerId);
this->m_timerId = 0;
this->store();
}
QObject::timerEvent(event);
}
void MoneroSettings::componentComplete()
{
this->init();
}
void MoneroSettings::classBegin()
{
}
MoneroSettings::MoneroSettings(QObject *parent) :
QObject(parent)
{
}

View File

@@ -1,81 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// 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.
#ifndef MONEROSETTINGS_H
#define MONEROSETTINGS_H
#include <QtQml/qqmlparserstatus.h>
#include <QGuiApplication>
#include <QClipboard>
#include <QObject>
#include <QDebug>
#include <qsettings.h>
static const int settingsWriteDelay = 500; // ms
class MoneroSettings : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL)
public:
explicit MoneroSettings(QObject *parent = nullptr);
QString fileName() const;
void setFileName(const QString &fileName);
public slots:
void _q_propertyChanged();
protected:
void timerEvent(QTimerEvent *event) override;
void classBegin() override;
void componentComplete() override;
private:
QVariant readProperty(const QMetaProperty &property) const;
void init();
void reset();
void load();
void store();
QHash<const char *, QVariant> m_changedProperties;
QSettings *m_settings = NULL;
QString m_fileName = QString("");
bool m_initialized = false;
int m_timerId = 0;
};
#endif // MONEROSETTINGS_H

View File

@@ -1,100 +0,0 @@
#include <QRegExp>
#include <QMessageBox>
#include <QPixmap>
#include <QTranslator>
#include "TailsOS.h"
#include "utils.h"
bool TailsOS::usePersistence = false;
QString TailsOS::tailsPathData = QString("/live/persistence/TailsData_unlocked/");
bool TailsOS::detect()
{
if (!fileExists("/etc/os-release"))
return false;
QByteArray data = fileOpen("/etc/os-release");
QRegularExpression re("TAILS_PRODUCT_NAME=\"Tails\"");
QRegularExpressionMatch os_match = re.match(data);
bool matched = os_match.hasMatch();
#ifdef QT_DEBUG
if (matched)
qDebug() << "Tails OS detected";
#endif
return matched;
}
bool TailsOS::detectDataPersistence()
{
return QDir(QDir::homePath() + "/Persistent").exists();
}
bool TailsOS::detectDotPersistence()
{
return QDir(tailsPathData + "dotfiles").exists();
}
void TailsOS::showDataPersistenceDisabledWarning()
{
QMessageBox msgBox;
msgBox.setText(QObject::tr("Warning: persistence disabled"));
msgBox.setWindowTitle(QObject::tr("Warning: persistence disabled"));
msgBox.setInformativeText(
QObject::tr("Monero GUI has detected that Tails persistence is "
"currently disabled. Any configurations you make inside "
"the Monero GUI will not be saved."
"\n\n"
"In addition, make sure to not save your wallet on the "
"filesystem, as it will be lost at shutdown."
"\n\n"
"To enable Tails persistence, setup an encrypted volume "
"and restart Tails. To gain a startup menu item, "
"enable the Tails \"dotfiles\" feature."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
msgBox.exec();
}
void TailsOS::askPersistence()
{
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("Monero GUI"));
msgBox.setText(QObject::tr("Use Tails persistence?"));
msgBox.setInformativeText(
QObject::tr("Persist wallet files and configuration on the encrypted volume?"
"\n\n"
"In addition, you can enable Tails dotfiles persistence "
"to gain a start menu entry.\n"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
TailsOS::usePersistence = (msgBox.exec() == QMessageBox::Yes);
}
void TailsOS::persistXdgMime(QString filePath, QString data)
{
QFileInfo file(filePath);
QString tailsPath = tailsPathData + "dotfiles/.local/share/applications/";
// write to persistent volume
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << tailsPath + file.fileName();
#endif
QDir().mkpath(tailsPath); // ensure directory exists
fileWrite(tailsPath + file.fileName(), data);
// write to current session
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << file.filePath();
#endif
QDir().mkpath(file.path()); // ensure directory exists
fileWrite(file.filePath(), data);
}

View File

@@ -1,23 +0,0 @@
#ifndef TAILSOS_H
#define TAILSOS_H
#include <QApplication>
class TailsOS
{
public:
TailsOS();
static bool detect();
static bool detectDataPersistence();
static bool detectDotPersistence();
static void showDataPersistenceDisabledWarning();
static void askPersistence();
static void persistXdgMime(QString filePath, QString data);
static bool usePersistence;
static QString tailsPathData;
};
#endif // TAILSOS_H

View File

@@ -99,8 +99,8 @@ bool IPC::saveCommand(QString cmdString){
return true;
}
bool IPC::saveCommand(const QUrl &url){
return this->saveCommand(url.toString());
bool IPC::saveCommand(const QUrl &url){;
this->saveCommand(url.toString());
}
void IPC::handleConnection(){

View File

@@ -27,23 +27,44 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
#include <QtGui>
#include <QtMac>
#include "macoshelper.h"
#include <QApplication>
#include <QFile>
#include <QTextStream>
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Availability.h>
#include "mime.h"
#include "utils.h"
bool MacOSHelper::isCapsLock()
{
#ifdef __MAC_10_12
NSUInteger flags = [NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
return (flags == NSEventModifierFlagCapsLock);
#else
NSUInteger flags = [NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
return (flags & NSAlphaShiftKeyMask);
#endif
void registerXdgMime(QApplication &app){
// MacOS handled via Info.plist
// Windows handled in the installer by rbrunner7
QString xdg = QString(
"[Desktop Entry]\n"
"Name=Monero GUI\n"
"GenericName=Monero-GUI\n"
"X-GNOME-FullName=Monero-GUI\n"
"Comment=Monero GUI\n"
"Keywords=Monero;\n"
"Exec=%1 %u\n"
"Terminal=false\n"
"Type=Application\n"
"Icon=monero\n"
"Categories=Network;GNOME;Qt;\n"
"MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
"StartupNotify=true\n"
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
"X-GNOME-UsesNotifications=true\n"
).arg(app.applicationFilePath());
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
qDebug() << QString("Writing %1").arg(filePath);
QFile file(filePath);
if(file.open(QIODevice::WriteOnly)){
QTextStream out(&file); out << xdg << endl;
file.close();
}
else
file.close();
}

View File

@@ -26,15 +26,11 @@
// 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.
#ifndef MACOSHELPER_H
#define MACOSHELPER_H
#ifndef MIME_H
#define MIME_H
class MacOSHelper
{
MacOSHelper() {}
#include <QApplication>
public:
static bool isCapsLock();
};
void registerXdgMime(QApplication &app);
#endif //MACOSHELPER_H
#endif // MIME_H

View File

@@ -53,7 +53,7 @@ void Prices::getJSON(const QString url) {
void Prices::gotJSON() {
// Check connectivity
if (!m_reply || m_reply->error() != QNetworkReply::NoError){
this->gotError("Problem with reply from server. Check connectivity.");
this->gotError();
m_reply->deleteLater();
return;
}
@@ -105,6 +105,6 @@ void Prices::gotError() {
}
void Prices::gotError(const QString &message) {
qCritical() << "[Fiat API] Error:" << message;
qCritical() << __FUNCTION__ << ": Error: " << message;
emit priceJsonError(message);
}

View File

@@ -27,35 +27,15 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
#include <QApplication>
#include "src/qt/TailsOS.h"
#include "utils.h"
bool fileExists(QString path) {
QFileInfo check_file(path);
return check_file.exists() && check_file.isFile();
}
QByteArray fileOpen(QString path) {
QFile file(path);
if(!file.open(QFile::ReadOnly | QFile::Text))
return QByteArray();
QByteArray data = file.readAll();
file.close();
return data;
}
bool fileWrite(QString path, QString data) {
QFile file(path);
if(file.open(QIODevice::WriteOnly)){
QTextStream out(&file); out << data << endl;
file.close();
if (check_file.exists() && check_file.isFile())
return true;
}
return false;
else
return false;
}
QString getAccountName(){
@@ -67,53 +47,6 @@ QString getAccountName(){
return accountName;
}
QString xdgMime(QApplication &app){
return QString(
"[Desktop Entry]\n"
"Name=Monero GUI\n"
"GenericName=Monero-GUI\n"
"X-GNOME-FullName=Monero-GUI\n"
"Comment=Monero GUI\n"
"Keywords=Monero;\n"
"Exec=%1 %u\n"
"Terminal=false\n"
"Type=Application\n"
"Icon=monero\n"
"Categories=Network;GNOME;Qt;\n"
"MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
"StartupNotify=true\n"
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
"X-GNOME-UsesNotifications=true\n"
).arg(app.applicationFilePath());
}
void registerXdgMime(QApplication &app){
#ifdef Q_OS_LINUX
// Register desktop entry
// - MacOS handled via Info.plist
// - Windows handled in the installer by rbrunner7
// - Linux written to `QStandardPaths::ApplicationsLocation`
// - Tails written to persistent dotfiles
QString mime = xdgMime(app);
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) {
TailsOS::persistXdgMime(filePath, mime);
return;
}
QFileInfo file(filePath);
QDir().mkpath(file.path()); // ensure directory exists
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << filePath;
#endif
fileWrite(filePath, mime);
#endif
}
QString randomUserAgent(){
QStringList urand;
urand << "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"

View File

@@ -31,14 +31,9 @@
#include <QtCore>
#include <QRegExp>
#include <QApplication>
bool fileExists(QString path);
QByteArray fileOpen(QString path);
bool fileWrite(QString path, QString data);
QString getAccountName();
QString xdgMime(QApplication &app);
void registerXdgMime(QApplication &app);
const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)");
QString randomUserAgent();

View File

@@ -83,7 +83,7 @@ ColumnLayout {
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 your %1.").arg(!wizardController.walletOptionsIsRecoveringFromDevice ? qsTr("25 word mnemonic seed") : qsTr("hardware wallet"))+ 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 {
@@ -97,12 +97,23 @@ ColumnLayout {
TextInput {
id: progressText
Layout.topMargin: 6
Layout.bottomMargin: 6
anchors.top: parent.top
anchors.topMargin: 6
font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 14
font.bold: false
color: MoneroComponents.Style.defaultFontColor
text: root.passwordStrengthText + '-'
height: 18
passwordCharacter: "*"
}
TextInput {
id: progressTextValue
font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 13
font.bold: true
color: MoneroComponents.Style.defaultFontColor
height: 18
passwordCharacter: "*"
}

View File

@@ -273,13 +273,12 @@ Rectangle {
clip: true
ScrollBar.vertical: ScrollBar {
parent: wizardController
parent: wizardFlickable.parent
anchors.left: parent.right
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width
anchors.leftMargin: 3
anchors.top: parent.top
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10
anchors.topMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10
}
onFlickingChanged: {
@@ -499,15 +498,15 @@ Rectangle {
splash.close()
console.log(">>> wallet passphrase needed: ");
passwordDialog.onAcceptedPassphraseCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password);
passphraseDialog.onAcceptedCallback = function() {
walletManager.onPassphraseEntered(passphraseDialog.passphrase);
creatingWalletDeviceSplash();
}
passwordDialog.onRejectedPassphraseCallback = function() {
passphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", true);
creatingWalletDeviceSplash();
}
passwordDialog.openPassphraseDialog()
passphraseDialog.open()
}
function onDeviceButtonRequest(code){

View File

@@ -151,7 +151,7 @@ Rectangle {
labelFontSize: 14
copyButton: false
readOnly: true
text: Utils.roundDownToNearestThousand(wizardController.m_wallet ? wizardController.m_wallet.walletCreationHeight : 0)
text: Utils.roundDownToNearestThousand(wizardController.m_wallet.walletCreationHeight)
}
MoneroComponents.WarningBox {

View File

@@ -69,7 +69,7 @@ ColumnLayout {
TextArea {
Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
visible: parent.subtitle !== ""
color: MoneroComponents.Style.dimmedFontColor

View File

@@ -60,7 +60,7 @@ Rectangle {
id: textWelcome
opacity: 0
Layout.preferredWidth: parent.width / 1.3
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
color: MoneroComponents.Style.defaultFontColor
text: "Welcome - Wilkommen - Bonvenon - Bienvenido - Bienvenue - Välkommen - Selamat datang - Benvenuto - 歡迎 - Welkom - Bem Vindo - добро пожаловать"
@@ -97,7 +97,7 @@ Rectangle {
}
Layout.preferredWidth: size
Layout.preferredHeight: size
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
mipmap: true
property bool animSlow: false
@@ -149,7 +149,7 @@ Rectangle {
id: buttonsGrid
opacity: 0
columns: isMobile ? 1 : 2
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
Layout.topMargin: 20
Layout.fillWidth: true
columnSpacing: 20
@@ -190,7 +190,7 @@ Rectangle {
MoneroComponents.TextPlain {
id: versionText
opacity: 0
Layout.alignment: Qt.AlignCenter
anchors.horizontalCenter: parent.horizontalCenter
font.bold: true
font.pixelSize: 12
font.family: MoneroComponents.Style.fontRegular.name

View File

@@ -57,6 +57,12 @@ ColumnLayout {
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