2015-04-01 10:56:05 +02:00
// Copyright (c) 2014-2015, The Monero Project
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// All rights reserved.
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// 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.
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// 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.
2016-11-12 14:28:13 +01:00
//
2015-04-01 10:56:05 +02:00
// 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.
2014-07-07 19:08:30 +02:00
import QtQuick 2.2
import QtQuick . Window 2.0
import QtQuick . Controls 1.1
import QtQuick . Controls . Styles 1.1
2016-06-28 21:37:14 +02:00
import QtQuick . Dialogs 1.2
2016-06-15 15:34:55 +02:00
import Qt . labs . settings 1.0
2016-10-02 20:40:40 +02:00
import moneroComponents . Wallet 1.0
import moneroComponents . PendingTransaction 1.0
2016-06-15 12:25:45 +02:00
2016-07-13 14:24:40 +02:00
2014-07-07 19:08:30 +02:00
import "components"
2014-08-19 14:58:02 +02:00
import "wizard"
2014-07-07 19:08:30 +02:00
ApplicationWindow {
id: appWindow
2017-07-13 17:39:51 +02:00
title: "Monero"
2016-08-17 14:14:43 +02:00
2014-07-09 16:18:48 +02:00
property var currentItem
2014-07-07 19:08:30 +02:00
property bool whatIsEnable: false
2014-07-13 14:27:50 +02:00
property bool ctrlPressed: false
2016-06-20 21:08:09 +02:00
property bool rightPanelExpanded: false
2014-07-16 14:40:09 +02:00
property bool osx: false
2016-06-15 15:34:55 +02:00
property alias persistentSettings : persistentSettings
2016-08-18 20:55:34 +02:00
property var currentWallet ;
2016-06-28 21:37:14 +02:00
property var transaction ;
2016-11-06 00:19:28 +01:00
property var transactionDescription ;
2016-08-17 14:14:43 +02:00
property alias password : passwordDialog . password
2016-10-05 22:34:47 +02:00
property bool isNewWallet: false
2016-10-08 01:37:47 +02:00
property int restoreHeight: 0
2016-11-02 00:17:58 +01:00
property bool daemonSynced: false
2017-05-06 17:49:43 +02:00
property int maxWindowHeight: ( Screen . height < 900 ) ? 720 : 800 ;
2016-11-25 21:09:32 +01:00
property bool daemonRunning: false
2016-12-15 14:09:37 +01:00
property alias toolTip: toolTip
2017-01-13 23:21:58 +01:00
property string walletName
property bool viewOnly: false
property bool foundNewBlock: false
property int timeToUnlock: 0
2017-03-27 19:39:47 +02:00
property bool qrScannerEnabled: ( typeof builtWithScanner != "undefined" ) && builtWithScanner
2017-02-24 21:51:37 +01:00
property int blocksToSync: 1
2017-01-30 10:37:14 +01:00
property var isMobile: ( appWindow . width > 700 ) ? false : true
2017-03-27 19:39:47 +02:00
property var cameraUi
2016-10-08 01:37:47 +02:00
2016-10-06 23:47:28 +02:00
// true if wallet ever synchronized
property bool walletInitialized : false
2016-07-13 14:24:40 +02:00
2014-07-13 14:27:50 +02:00
function altKeyReleased ( ) { ctrlPressed = false ; }
2016-06-15 15:34:55 +02:00
2014-07-13 14:27:50 +02:00
function showPageRequest ( page ) {
middlePanel . state = page
leftPanel . selectItem ( page )
}
2016-06-15 15:34:55 +02:00
2014-07-13 14:27:50 +02:00
function sequencePressed ( obj , seq ) {
2014-07-09 16:18:48 +02:00
if ( seq === undefined )
return
2014-07-13 14:27:50 +02:00
if ( seq === "Ctrl" ) {
ctrlPressed = true
return
}
2017-01-17 22:59:40 +01:00
// Dashboard is not implemented
// if(seq === "Ctrl+") middlePanel.state = "Dashboard"
if ( seq === "Ctrl+S" ) middlePanel . state = "Transfer"
2016-12-18 14:59:24 +01:00
else if ( seq === "Ctrl+R" ) middlePanel . state = "Receive"
else if ( seq === "Ctrl+K" ) middlePanel . state = "TxKey"
2014-07-13 14:27:50 +02:00
else if ( seq === "Ctrl+H" ) middlePanel . state = "History"
else if ( seq === "Ctrl+B" ) middlePanel . state = "AddressBook"
else if ( seq === "Ctrl+M" ) middlePanel . state = "Mining"
2016-12-18 14:59:24 +01:00
else if ( seq === "Ctrl+I" ) middlePanel . state = "Sign"
else if ( seq === "Ctrl+E" ) middlePanel . state = "Settings"
2017-01-17 22:59:40 +01:00
else if ( seq === "Ctrl+D" ) middlePanel . state = "Advanced"
2014-07-16 14:40:09 +02:00
else if ( seq === "Ctrl+Tab" || seq === "Alt+Tab" ) {
2016-12-18 15:24:48 +01:00
/ *
2014-07-13 14:27:50 +02:00
if ( middlePanel . state === "Dashboard" ) middlePanel . state = "Transfer"
2016-12-18 14:59:24 +01:00
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "TxKey"
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "History"
2014-07-13 14:27:50 +02:00
else if ( middlePanel . state === "History" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "Mining"
2016-12-18 14:59:24 +01:00
else if ( middlePanel . state === "Mining" ) middlePanel . state = "Sign"
else if ( middlePanel . state === "Sign" ) middlePanel . state = "Settings"
2014-07-13 14:27:50 +02:00
else if ( middlePanel . state === "Settings" ) middlePanel . state = "Dashboard"
2016-12-18 15:24:48 +01:00
* /
if ( middlePanel . state === "Settings" ) middlePanel . state = "Transfer"
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "TxKey"
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "History"
else if ( middlePanel . state === "History" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "Sign"
else if ( middlePanel . state === "Sign" ) middlePanel . state = "Settings"
2014-07-16 14:40:09 +02:00
} else if ( seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab" ) {
2016-12-18 15:24:48 +01:00
/ *
2014-07-13 14:27:50 +02:00
if ( middlePanel . state === "Dashboard" ) middlePanel . state = "Settings"
2016-12-18 15:24:48 +01:00
if ( middlePanel . state === "Settings" ) middlePanel . state = "Sign"
2016-12-18 14:59:24 +01:00
else if ( middlePanel . state === "Sign" ) middlePanel . state = "Mining"
2014-07-13 14:27:50 +02:00
else if ( middlePanel . state === "Mining" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "History"
2016-12-18 14:59:24 +01:00
else if ( middlePanel . state === "History" ) middlePanel . state = "TxKey"
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "Transfer"
2014-07-13 14:27:50 +02:00
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "Dashboard"
2016-12-18 15:24:48 +01:00
* /
if ( middlePanel . state === "Settings" ) middlePanel . state = "Sign"
else if ( middlePanel . state === "Sign" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "History"
else if ( middlePanel . state === "History" ) middlePanel . state = "TxKey"
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "Transfer"
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "Settings"
2014-07-13 14:27:50 +02:00
}
2014-07-09 18:03:37 +02:00
leftPanel . selectItem ( middlePanel . state )
2014-07-09 16:18:48 +02:00
}
2014-07-13 14:27:50 +02:00
function sequenceReleased ( obj , seq ) {
if ( seq === "Ctrl" )
ctrlPressed = false
}
2016-12-04 13:13:59 +01:00
function mousePressed ( obj , mouseX , mouseY ) { }
function mouseReleased ( obj , mouseX , mouseY ) { }
2014-07-07 19:08:30 +02:00
2017-02-23 19:47:58 +01:00
function loadPage ( page ) {
middlePanel . state = page ;
leftPanel . selectItem ( page ) ;
}
2016-10-29 16:48:10 +02:00
function openWalletFromFile ( ) {
persistentSettings . restore_height = 0
2016-11-23 19:32:30 +01:00
restoreHeight = 0 ;
2016-10-29 16:48:10 +02:00
persistentSettings . is_recovering = false
appWindow . password = ""
fileDialog . open ( ) ;
}
2016-06-15 15:34:55 +02:00
function initialize ( ) {
2016-07-13 14:24:40 +02:00
console . log ( "initializing.." )
2016-11-07 11:27:53 +01:00
walletInitialized = false ;
2016-12-31 11:56:08 +01:00
// Use stored log level
2017-02-05 13:38:43 +01:00
if ( persistentSettings . logLevel == 5 )
walletManager . setLogCategories ( persistentSettings . logCategories )
else
walletManager . setLogLevel ( persistentSettings . logLevel )
2016-12-31 11:56:08 +01:00
2016-07-19 22:45:12 +02:00
// setup language
var locale = persistentSettings . locale
if ( locale !== "" ) {
translationManager . setLanguage ( locale . split ( "_" ) [ 0 ] ) ;
}
2017-03-09 16:46:03 +01:00
// Reload transfer page with translations enabled
middlePanel . transferView . onPageCompleted ( ) ;
2016-12-04 13:13:59 +01:00
// If currentWallet exists, we're just switching daemon - close/reopen wallet
if ( typeof currentWallet !== "undefined" && currentWallet !== null ) {
console . log ( "Daemon change - closing " + currentWallet )
2016-12-15 13:18:04 +01:00
closeWallet ( ) ;
2016-12-14 13:11:20 +01:00
currentWallet = undefined
2016-10-29 16:48:10 +02:00
} else {
// set page to transfer if not changing daemon
middlePanel . state = "Transfer" ;
leftPanel . selectItem ( middlePanel . state )
2016-10-05 00:18:50 +02:00
}
2016-07-19 22:45:12 +02:00
2016-11-24 12:14:46 +01:00
walletManager . setDaemonAddress ( persistentSettings . daemon_address )
2016-08-19 13:44:44 +02:00
// wallet already opened with wizard, we just need to initialize it
2016-06-15 15:34:55 +02:00
if ( typeof wizard . settings [ 'wallet' ] !== 'undefined' ) {
2016-10-05 00:18:50 +02:00
console . log ( "using wizard wallet" )
2016-10-08 01:37:47 +02:00
//Set restoreHeight
2016-10-10 16:37:03 +02:00
if ( persistentSettings . restore_height > 0 ) {
2016-11-23 19:32:30 +01:00
// We store restore height in own variable for performance reasons.
2016-10-10 16:37:03 +02:00
restoreHeight = persistentSettings . restore_height
2016-10-08 01:37:47 +02:00
}
2016-08-19 13:44:44 +02:00
connectWallet ( wizard . settings [ 'wallet' ] )
2016-10-08 01:37:47 +02:00
2016-10-05 22:34:47 +02:00
isNewWallet = true
2016-10-05 00:18:50 +02:00
// We don't need the wizard wallet any more - delete to avoid conflict with daemon adress change
delete wizard . settings [ 'wallet' ]
2016-06-15 15:34:55 +02:00
} else {
2016-08-16 22:21:46 +02:00
var wallet_path = walletPath ( ) ;
2017-04-03 18:51:55 +02:00
if ( isIOS )
wallet_path = moneroAccountsDir + wallet_path ;
2016-09-22 23:07:12 +02:00
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.password);
2016-10-02 20:40:40 +02:00
console . log ( "opening wallet at: " , wallet_path , ", testnet: " , persistentSettings . testnet ) ;
2016-08-18 20:55:34 +02:00
walletManager . openWalletAsync ( wallet_path , appWindow . password ,
2016-08-17 14:14:43 +02:00
persistentSettings . testnet ) ;
2016-06-15 15:34:55 +02:00
}
2016-10-29 16:48:10 +02:00
2016-06-17 15:35:07 +02:00
}
2016-12-15 13:18:04 +01:00
function closeWallet ( ) {
2016-06-17 15:35:07 +02:00
2016-12-15 13:18:04 +01:00
// Disconnect all listeners
2016-12-16 00:12:27 +01:00
if ( typeof currentWallet !== "undefined" && currentWallet !== null ) {
currentWallet . refreshed . disconnect ( onWalletRefresh )
currentWallet . updated . disconnect ( onWalletUpdate )
currentWallet . newBlock . disconnect ( onWalletNewBlock )
currentWallet . moneySpent . disconnect ( onWalletMoneySent )
currentWallet . moneyReceived . disconnect ( onWalletMoneyReceived )
2017-01-12 19:57:30 +01:00
currentWallet . unconfirmedMoneyReceived . disconnect ( onWalletUnconfirmedMoneyReceived )
2016-12-16 00:12:27 +01:00
currentWallet . transactionCreated . disconnect ( onTransactionCreated )
currentWallet . connectionStatusChanged . disconnect ( onWalletConnectionStatusChanged )
middlePanel . paymentClicked . disconnect ( handlePayment ) ;
middlePanel . sweepUnmixableClicked . disconnect ( handleSweepUnmixable ) ;
middlePanel . checkPaymentClicked . disconnect ( handleCheckPayment ) ;
}
2016-12-15 13:18:04 +01:00
currentWallet = undefined ;
2017-04-03 18:51:55 +02:00
if ( isIOS ) {
console . log ( "closing sync - ios" )
walletManager . closeWallet ( ) ;
} else
walletManager . closeWalletAsync ( ) ;
2016-12-15 13:18:04 +01:00
}
function connectWallet ( wallet ) {
currentWallet = wallet
2017-01-30 10:37:14 +01:00
walletName = usefulName ( wallet . path )
2016-12-31 14:47:40 +01:00
updateSyncing ( false )
2016-12-15 13:18:04 +01:00
2017-01-12 20:53:27 +01:00
viewOnly = currentWallet . viewOnly ;
2017-07-31 15:11:01 +02:00
// New wallets saves the testnet flag in keys file.
if ( persistentSettings . testnet != currentWallet . testnet ) {
console . log ( "Using testnet flag from keys file" )
persistentSettings . testnet = currentWallet . testnet ;
}
2016-12-04 13:13:59 +01:00
// connect handlers
2016-08-19 13:44:44 +02:00
currentWallet . refreshed . connect ( onWalletRefresh )
currentWallet . updated . connect ( onWalletUpdate )
2016-09-26 21:55:25 +02:00
currentWallet . newBlock . connect ( onWalletNewBlock )
2016-10-06 23:47:28 +02:00
currentWallet . moneySpent . connect ( onWalletMoneySent )
currentWallet . moneyReceived . connect ( onWalletMoneyReceived )
2017-01-12 19:57:30 +01:00
currentWallet . unconfirmedMoneyReceived . connect ( onWalletUnconfirmedMoneyReceived )
2016-11-08 18:05:33 +01:00
currentWallet . transactionCreated . connect ( onTransactionCreated )
2016-11-26 15:50:04 +01:00
currentWallet . connectionStatusChanged . connect ( onWalletConnectionStatusChanged )
2016-12-04 13:13:59 +01:00
middlePanel . paymentClicked . connect ( handlePayment ) ;
middlePanel . sweepUnmixableClicked . connect ( handleSweepUnmixable ) ;
middlePanel . checkPaymentClicked . connect ( handleCheckPayment ) ;
2016-11-06 23:40:26 +01:00
2016-08-19 13:44:44 +02:00
console . log ( "initializing with daemon address: " , persistentSettings . daemon_address )
2016-10-10 21:40:58 +02:00
console . log ( "Recovering from seed: " , persistentSettings . is_recovering )
console . log ( "restore Height" , persistentSettings . restore_height )
2017-02-25 22:16:58 +01:00
// Use saved daemon rpc login settings
currentWallet . setDaemonLogin ( persistentSettings . daemonUsername , persistentSettings . daemonPassword ) ;
2016-10-10 21:40:58 +02:00
currentWallet . initAsync ( persistentSettings . daemon_address , 0 , persistentSettings . is_recovering , persistentSettings . restore_height ) ;
2016-08-19 13:44:44 +02:00
}
2016-08-16 22:21:46 +02:00
function walletPath ( ) {
2016-10-29 16:48:10 +02:00
var wallet_path = persistentSettings . wallet_path
2016-08-16 22:21:46 +02:00
return wallet_path ;
}
2017-01-03 21:54:40 +01:00
function usefulName ( path ) {
// arbitrary "short enough" limit
if ( path . length < 32 )
return path
return path . replace ( /.*[\/\\]/ , '' ) . replace ( /\.keys$/ , '' )
}
2017-01-31 10:34:18 +01:00
function onWalletConnectionStatusChanged ( status ) {
2017-02-05 13:49:25 +01:00
console . log ( "Wallet connection status changed " + status )
2016-11-26 15:50:04 +01:00
middlePanel . updateStatus ( ) ;
2017-01-31 10:34:18 +01:00
leftPanel . networkStatus . connected = status
leftPanel . progressBar . visible = ( status === Wallet . ConnectionStatus_Connected ) && ! daemonSynced
2017-02-05 13:49:25 +01:00
2017-03-23 22:54:35 +01:00
// Update fee multiplier dropdown on transfer page
middlePanel . transferView . updatePriorityDropdown ( ) ;
2017-02-05 13:49:25 +01:00
// If wallet isnt connected and no daemon is running - Ask
2017-09-04 13:42:46 +02:00
if ( isDaemonLocal ( ) && ! walletInitialized && status === Wallet . ConnectionStatus_Disconnected && ! daemonManager . running ( persistentSettings . testnet ) ) {
2017-02-05 13:49:25 +01:00
daemonManagerDialog . open ( ) ;
}
// initialize transaction history once wallet is initialized first time;
if ( ! walletInitialized ) {
currentWallet . history . refresh ( )
walletInitialized = true
}
2017-01-31 10:34:18 +01:00
}
2016-11-26 15:50:04 +01:00
2016-08-18 20:55:34 +02:00
function onWalletOpened ( wallet ) {
2017-01-03 21:54:40 +01:00
walletName = usefulName ( wallet . path )
2016-08-18 20:55:34 +02:00
console . log ( ">>> wallet opened: " + wallet )
if ( wallet . status !== Wallet . Status_Ok ) {
2016-08-19 13:44:44 +02:00
if ( appWindow . password === '' ) {
2016-08-18 20:55:34 +02:00
console . error ( "Error opening wallet with empty password: " , wallet . errorString ) ;
2016-08-19 13:44:44 +02:00
console . log ( "closing wallet async : " + wallet . address )
2016-12-15 13:18:04 +01:00
closeWallet ( ) ;
2016-08-18 20:55:34 +02:00
// try to open wallet with password;
2017-01-03 21:54:40 +01:00
passwordDialog . open ( walletName ) ;
2016-08-18 20:55:34 +02:00
} else {
// opening with password but password doesn't match
console . error ( "Error opening wallet with password: " , wallet . errorString ) ;
2016-08-19 13:44:44 +02:00
2016-08-18 20:55:34 +02:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Couldn't open wallet: " ) + wallet . errorString ;
informationPopup . icon = StandardIcon . Critical
2016-08-19 13:44:44 +02:00
console . log ( "closing wallet async : " + wallet . address )
2016-12-15 13:18:04 +01:00
closeWallet ( ) ;
2016-08-18 20:55:34 +02:00
informationPopup . open ( )
2016-08-19 13:44:44 +02:00
informationPopup . onCloseCallback = function ( ) {
2017-01-03 21:54:40 +01:00
passwordDialog . open ( walletName )
2016-08-19 13:44:44 +02:00
}
2016-08-18 20:55:34 +02:00
}
return ;
}
// wallet opened successfully, subscribing for wallet updates
2016-08-19 13:44:44 +02:00
connectWallet ( wallet )
2016-08-18 20:55:34 +02:00
}
function onWalletClosed ( walletAddress ) {
console . log ( ">>> wallet closed: " + walletAddress )
}
2016-08-16 22:21:46 +02:00
2016-06-17 15:35:07 +02:00
function onWalletUpdate ( ) {
2016-07-13 14:24:40 +02:00
console . log ( ">>> wallet updated" )
2016-10-09 00:32:03 +02:00
middlePanel . unlockedBalanceText = leftPanel . unlockedBalanceText = walletManager . displayAmount ( currentWallet . unlockedBalance ) ;
middlePanel . balanceText = leftPanel . balanceText = walletManager . displayAmount ( currentWallet . balance ) ;
2017-03-05 00:05:31 +01:00
// Update history if new block found since last update
if ( foundNewBlock ) {
2017-01-13 23:21:58 +01:00
foundNewBlock = false ;
console . log ( "New block found - updating history" )
currentWallet . history . refresh ( )
timeToUnlock = currentWallet . history . minutesToUnlock
2017-03-03 12:30:53 +01:00
leftPanel . minutesToUnlockTxt = ( timeToUnlock > 0 ) ? ( timeToUnlock == 20 ) ? qsTr ( "Unlocked balance (waiting for block)" ) . arg ( timeToUnlock ) : qsTr ( "Unlocked balance (~%1 min)" ) . arg ( timeToUnlock ) : qsTr ( "Unlocked balance" ) ;
2017-01-13 23:21:58 +01:00
}
2016-07-13 14:24:40 +02:00
}
function onWalletRefresh ( ) {
console . log ( ">>> wallet refreshed" )
2016-11-02 00:17:58 +01:00
2016-11-26 17:01:29 +01:00
// Daemon connected
2017-02-23 19:47:58 +01:00
leftPanel . networkStatus . connected = currentWallet . connected ( )
2016-11-26 17:01:29 +01:00
2016-11-02 00:17:58 +01:00
// Check daemon status
2016-10-03 23:29:30 +02:00
var dCurrentBlock = currentWallet . daemonBlockChainHeight ( ) ;
var dTargetBlock = currentWallet . daemonBlockChainTargetHeight ( ) ;
2016-11-02 00:17:58 +01:00
// Daemon fully synced
// TODO: implement onDaemonSynced or similar in wallet API and don't start refresh thread before daemon is synced
2017-02-24 18:07:46 +01:00
// targetBlock = currentBlock = 1 before network connection is established.
daemonSynced = dCurrentBlock >= dTargetBlock && dTargetBlock != 1
2017-01-31 10:34:18 +01:00
// Update daemon sync progress
2016-12-14 13:48:12 +01:00
leftPanel . progressBar . updateProgress ( dCurrentBlock , dTargetBlock ) ;
2017-02-23 19:47:58 +01:00
leftPanel . progressBar . visible = ! daemonSynced && currentWallet . connected ( ) !== Wallet . ConnectionStatus_Disconnected
2017-01-31 10:34:18 +01:00
// Update wallet sync progress
2017-02-23 19:47:58 +01:00
updateSyncing ( ( currentWallet . connected ( ) !== Wallet . ConnectionStatus_Disconnected ) && ! daemonSynced )
2017-01-31 10:34:18 +01:00
// Update transfer page status
2016-11-27 13:35:27 +01:00
middlePanel . updateStatus ( ) ;
2016-11-02 00:17:58 +01:00
2016-11-10 12:11:25 +01:00
// Refresh is succesfull if blockchain height > 1
2016-10-28 00:24:02 +02:00
if ( currentWallet . blockChainHeight ( ) > 1 ) {
2016-11-10 12:11:25 +01:00
// Save new wallet after first refresh
// Wallet is nomrmally saved to disk on app exit. This prevents rescan from block 0 after app crash
if ( isNewWallet ) {
console . log ( "Saving wallet after first refresh" ) ;
2016-11-10 12:23:43 +01:00
currentWallet . store ( )
2016-11-10 12:11:25 +01:00
isNewWallet = false
2017-03-03 23:57:55 +01:00
// Update History
currentWallet . history . refresh ( ) ;
2016-11-10 12:11:25 +01:00
}
2016-10-28 00:24:02 +02:00
// recovering from seed is finished after first refresh
if ( persistentSettings . is_recovering ) {
persistentSettings . is_recovering = false
}
}
2016-07-14 12:09:39 +02:00
onWalletUpdate ( ) ;
2016-06-15 15:34:55 +02:00
}
2016-12-21 14:30:15 +01:00
function startDaemon ( flags ) {
2017-02-25 20:25:16 +01:00
// Pause refresh while starting daemon
currentWallet . pauseRefresh ( ) ;
2016-11-26 11:31:27 +01:00
appWindow . showProcessingSplash ( qsTr ( "Waiting for daemon to start..." ) )
2017-05-04 14:06:29 +02:00
daemonManager . start ( flags , persistentSettings . testnet , persistentSettings . blockchainDataDir ) ;
2016-12-21 14:30:15 +01:00
persistentSettings . daemonFlags = flags
2016-11-26 11:31:27 +01:00
}
2016-11-26 17:01:29 +01:00
2016-11-26 11:31:27 +01:00
function stopDaemon ( ) {
appWindow . showProcessingSplash ( qsTr ( "Waiting for daemon to stop..." ) )
2017-02-23 19:47:58 +01:00
daemonManager . stop ( persistentSettings . testnet ) ;
2016-11-26 11:31:27 +01:00
}
2016-11-25 21:09:32 +01:00
function onDaemonStarted ( ) {
console . log ( "daemon started" ) ;
daemonRunning = true ;
2017-02-23 19:47:58 +01:00
hideProcessingSplash ( ) ;
2017-02-25 14:57:39 +01:00
currentWallet . connected ( true ) ;
2017-02-25 20:25:16 +01:00
// resume refresh
currentWallet . startRefresh ( ) ;
2016-11-25 21:09:32 +01:00
}
function onDaemonStopped ( ) {
console . log ( "daemon stopped" ) ;
2016-12-14 13:48:12 +01:00
hideProcessingSplash ( ) ;
2016-11-25 21:09:32 +01:00
daemonRunning = false ;
2017-02-23 19:47:58 +01:00
currentWallet . connected ( true ) ;
2016-11-25 21:09:32 +01:00
}
2017-02-25 20:25:16 +01:00
function onDaemonStartFailure ( ) {
console . log ( "daemon start failed" ) ;
hideProcessingSplash ( ) ;
// resume refresh
currentWallet . startRefresh ( ) ;
daemonRunning = false ;
informationPopup . title = qsTr ( "Daemon failed to start" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Please check your wallet and daemon log for errors. You can also try to start %1 manually." ) . arg ( ( isWindows ) ? "monerod.exe" : "monerod" )
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( ) ;
}
2017-01-31 10:34:18 +01:00
function onWalletNewBlock ( blockHeight , targetHeight ) {
// Update progress bar
2017-02-24 21:51:37 +01:00
var remaining = targetHeight - blockHeight ;
if ( blocksToSync < remaining ) {
blocksToSync = remaining ;
}
leftPanel . progressBar . updateProgress ( blockHeight , targetHeight , blocksToSync ) ;
2017-01-31 10:34:18 +01:00
foundNewBlock = true ;
2016-09-26 21:55:25 +02:00
}
2016-10-06 23:47:28 +02:00
function onWalletMoneyReceived ( txId , amount ) {
// refresh transaction history here
currentWallet . refresh ( )
currentWallet . history . refresh ( ) // this will refresh model
}
2017-01-12 19:57:30 +01:00
function onWalletUnconfirmedMoneyReceived ( txId , amount ) {
// refresh history
2017-01-13 23:21:58 +01:00
console . log ( "unconfirmed money found" )
2017-01-12 19:57:30 +01:00
currentWallet . history . refresh ( )
}
2016-10-06 23:47:28 +02:00
function onWalletMoneySent ( txId , amount ) {
// refresh transaction history here
currentWallet . refresh ( )
currentWallet . history . refresh ( ) // this will refresh model
}
2016-06-07 15:26:25 +02:00
function walletsFound ( ) {
2016-10-30 17:58:12 +01:00
if ( persistentSettings . wallet_path . length > 0 ) {
2017-04-03 18:51:55 +02:00
if ( isIOS )
return walletManager . walletExists ( moneroAccountsDir + persistentSettings . wallet_path ) ;
else
return walletManager . walletExists ( persistentSettings . wallet_path ) ;
2016-06-07 15:26:25 +02:00
}
2016-11-13 14:14:26 +01:00
return false ;
2016-06-07 15:26:25 +02:00
}
2016-11-08 18:05:33 +01:00
function onTransactionCreated ( pendingTransaction , address , paymentId , mixinCount ) {
console . log ( "Transaction created" ) ;
hideProcessingSplash ( ) ;
transaction = pendingTransaction ;
// validate address;
if ( transaction . status !== PendingTransaction . Status_Ok ) {
console . error ( "Can't create transaction: " , transaction . errorString ) ;
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
2017-02-23 19:47:58 +01:00
if ( currentWallet . connected ( ) == Wallet . ConnectionStatus_WrongVersion )
2016-11-08 18:05:33 +01:00
informationPopup . text = qsTr ( "Can't create transaction: Wrong daemon version: " ) + transaction . errorString
else
informationPopup . text = qsTr ( "Can't create transaction: " ) + transaction . errorString
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( ) ;
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
2016-11-11 22:54:17 +01:00
} else if ( transaction . txCount == 0 ) {
2017-05-03 15:29:23 +02:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString
2016-11-11 22:54:17 +01:00
informationPopup . text = qsTr ( "No unmixable outputs to sweep" ) + translationManager . emptyString
informationPopup . icon = StandardIcon . Information
informationPopup . onCloseCallback = null
informationPopup . open ( )
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
2016-11-08 18:05:33 +01:00
} else {
console . log ( "Transaction created, amount: " + walletManager . displayAmount ( transaction . amount )
+ ", fee: " + walletManager . displayAmount ( transaction . fee ) ) ;
// here we show confirmation popup;
transactionConfirmationPopup . title = qsTr ( "Confirmation" ) + translationManager . emptyString
transactionConfirmationPopup . text = qsTr ( "Please confirm transaction:\n" )
2016-11-11 22:54:17 +01:00
+ ( address === "" ? "" : ( qsTr ( "\nAddress: " ) + address ) )
+ ( paymentId === "" ? "" : ( qsTr ( "\nPayment ID: " ) + paymentId ) )
2016-11-08 18:05:33 +01:00
+ qsTr ( "\n\nAmount: " ) + walletManager . displayAmount ( transaction . amount )
+ qsTr ( "\nFee: " ) + walletManager . displayAmount ( transaction . fee )
2017-02-22 20:20:31 +01:00
+ qsTr ( "\n\nRingsize: " ) + ( mixinCount + 1 )
2016-11-12 14:28:13 +01:00
+ qsTr ( "\n\Number of transactions: " ) + transaction . txCount
2016-11-11 22:54:17 +01:00
+ ( transactionDescription === "" ? "" : ( qsTr ( "\n\nDescription: " ) + transactionDescription ) )
2016-11-08 18:05:33 +01:00
+ translationManager . emptyString
transactionConfirmationPopup . icon = StandardIcon . Question
transactionConfirmationPopup . open ( )
}
}
2016-08-17 14:14:43 +02:00
2016-06-28 21:37:14 +02:00
// called on "transfer"
2017-01-12 20:53:27 +01:00
function handlePayment ( address , paymentId , amount , mixinCount , priority , description , createFile ) {
2016-06-27 14:45:48 +02:00
console . log ( "Creating transaction: " )
console . log ( "\taddress: " , address ,
", payment_id: " , paymentId ,
", amount: " , amount ,
", mixins: " , mixinCount ,
2016-11-06 00:19:28 +01:00
", priority: " , priority ,
", description: " , description ) ;
2016-06-27 14:45:48 +02:00
2016-11-08 18:05:33 +01:00
showProcessingSplash ( "Creating transaction" ) ;
2016-11-12 14:28:13 +01:00
2016-11-08 18:05:33 +01:00
transactionDescription = description ;
2016-11-12 14:28:13 +01:00
2016-08-23 15:07:52 +02:00
// validate amount;
2016-11-09 14:00:43 +01:00
if ( amount !== "(all)" ) {
var amountxmr = walletManager . amountFromString ( amount ) ;
console . log ( "integer amount: " , amountxmr ) ;
console . log ( "integer unlocked" , currentWallet . unlockedBalance )
if ( amountxmr <= 0 ) {
2017-03-20 23:13:03 +01:00
hideProcessingSplash ( )
2016-11-09 14:00:43 +01:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Amount is wrong: expected number from %1 to %2" )
. arg ( walletManager . displayAmount ( 0 ) )
. arg ( walletManager . maximumAllowedAmountAsSting ( ) )
+ translationManager . emptyString
2016-08-23 15:07:52 +02:00
2016-11-09 14:00:43 +01:00
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( )
return ;
} else if ( amountxmr > currentWallet . unlockedBalance ) {
2017-03-20 23:13:03 +01:00
hideProcessingSplash ( )
2016-11-09 14:00:43 +01:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
2017-03-21 02:28:43 +01:00
informationPopup . text = qsTr ( "Insufficient funds. Unlocked balance: %1" )
2016-11-09 14:00:43 +01:00
. arg ( walletManager . displayAmount ( currentWallet . unlockedBalance ) )
+ translationManager . emptyString
2016-10-11 23:02:21 +02:00
2016-11-09 14:00:43 +01:00
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( )
return ;
}
2016-08-23 15:07:52 +02:00
}
2016-11-09 14:00:43 +01:00
if ( amount === "(all)" )
2016-11-18 20:17:13 +01:00
currentWallet . createTransactionAllAsync ( address , paymentId , mixinCount , priority ) ;
2016-11-09 14:00:43 +01:00
else
currentWallet . createTransactionAsync ( address , paymentId , amountxmr , mixinCount , priority ) ;
2016-06-28 21:37:14 +02:00
}
2017-01-12 20:53:27 +01:00
//Choose where to save transaction
FileDialog {
id: saveTxDialog
title: "Please choose a location"
folder: "file://" + moneroAccountsDir
selectExisting: false ;
onAccepted: {
handleTransactionConfirmed ( )
}
onRejected: {
// do nothing
}
}
2016-11-08 21:23:50 +01:00
function handleSweepUnmixable ( ) {
console . log ( "Creating transaction: " )
transaction = currentWallet . createSweepUnmixableTransaction ( ) ;
if ( transaction . status !== PendingTransaction . Status_Ok ) {
console . error ( "Can't create transaction: " , transaction . errorString ) ;
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Can't create transaction: " ) + transaction . errorString
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( ) ;
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
} else if ( transaction . txCount == 0 ) {
2017-05-03 15:29:23 +02:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString
2016-11-08 21:23:50 +01:00
informationPopup . text = qsTr ( "No unmixable outputs to sweep" ) + translationManager . emptyString
informationPopup . icon = StandardIcon . Information
informationPopup . onCloseCallback = null
informationPopup . open ( )
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
} else {
console . log ( "Transaction created, amount: " + walletManager . displayAmount ( transaction . amount )
+ ", fee: " + walletManager . displayAmount ( transaction . fee ) ) ;
// here we show confirmation popup;
transactionConfirmationPopup . title = qsTr ( "Confirmation" ) + translationManager . emptyString
transactionConfirmationPopup . text = qsTr ( "Please confirm transaction:\n" )
+ qsTr ( "\n\nAmount: " ) + walletManager . displayAmount ( transaction . amount )
+ qsTr ( "\nFee: " ) + walletManager . displayAmount ( transaction . fee )
+ translationManager . emptyString
transactionConfirmationPopup . icon = StandardIcon . Question
transactionConfirmationPopup . open ( )
// committing transaction
}
}
2016-06-28 21:37:14 +02:00
// called after user confirms transaction
2017-01-12 20:53:27 +01:00
function handleTransactionConfirmed ( fileName ) {
2016-11-06 00:19:28 +01:00
// grab transaction.txid before commit, since it clears it.
// we actually need to copy it, because QML will incredibly
// call the function multiple times when the variable is used
// after commit, where it returns another result...
// Of course, this loop is also calling the function multiple
// times, but at least with the same result.
var txid = [ ] , txid_org = transaction . txid , txid_text = ""
for ( var i = 0 ; i < txid_org . length ; ++ i )
txid [ i ] = txid_org [ i ]
2017-01-12 20:53:27 +01:00
// View only wallet - we save the tx
if ( viewOnly && saveTxDialog . fileUrl ) {
// No file specified - abort
if ( ! saveTxDialog . fileUrl ) {
currentWallet . disposeTransaction ( transaction )
return ;
}
var path = walletManager . urlToLocalPath ( saveTxDialog . fileUrl )
// Store to file
transaction . setFilename ( path ) ;
}
2016-06-28 21:37:14 +02:00
if ( ! transaction . commit ( ) ) {
console . log ( "Error committing transaction: " + transaction . errorString ) ;
2016-07-20 21:28:11 +02:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString
2016-06-28 21:37:14 +02:00
informationPopup . text = qsTr ( "Couldn't send the money: " ) + transaction . errorString
informationPopup . icon = StandardIcon . Critical
} else {
2016-07-20 21:28:11 +02:00
informationPopup . title = qsTr ( "Information" ) + translationManager . emptyString
2016-11-06 00:19:28 +01:00
for ( var i = 0 ; i < txid . length ; ++ i ) {
if ( txid_text . length > 0 )
txid_text += ", "
txid_text += txid [ i ]
}
2017-01-12 20:53:27 +01:00
informationPopup . text = ( viewOnly ) ? qsTr ( "Transaction saved to file: %1" ) . arg ( path ) : qsTr ( "Money sent successfully: %1 transaction(s) " ) . arg ( txid . length ) + txid_text + translationManager . emptyString
2016-06-28 21:37:14 +02:00
informationPopup . icon = StandardIcon . Information
2016-11-06 00:19:28 +01:00
if ( transactionDescription . length > 0 ) {
for ( var i = 0 ; i < txid . length ; ++ i )
currentWallet . setUserNote ( txid [ i ] , transactionDescription ) ;
}
2017-02-04 14:44:30 +01:00
// Clear tx fields
middlePanel . transferView . clearFields ( )
2016-06-16 16:13:46 +02:00
}
2016-08-17 14:14:43 +02:00
informationPopup . onCloseCallback = null
2016-06-28 21:37:14 +02:00
informationPopup . open ( )
2016-08-23 15:07:52 +02:00
currentWallet . refresh ( )
currentWallet . disposeTransaction ( transaction )
2016-11-19 17:33:30 +01:00
currentWallet . store ( ) ;
2016-06-16 16:13:46 +02:00
}
2016-11-05 15:58:49 +01:00
// called on "checkPayment"
function handleCheckPayment ( address , txid , txkey ) {
console . log ( "Checking payment: " )
console . log ( "\taddress: " , address ,
", txid: " , txid ,
", txkey: " , txkey ) ;
var result = walletManager . checkPayment ( address , txid , txkey , persistentSettings . daemon_address ) ;
var results = result . split ( "|" ) ;
if ( results . length < 4 ) {
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = "internal error" ;
informationPopup . icon = StandardIcon . Critical
2017-03-01 22:03:50 +01:00
informationPopup . onCloseCallback = null
2016-11-05 15:58:49 +01:00
informationPopup . open ( )
return
}
var success = results [ 0 ] == "true" ;
var received = results [ 1 ]
var height = results [ 2 ]
var error = results [ 3 ]
if ( success ) {
informationPopup . title = qsTr ( "Payment check" ) + translationManager . emptyString ;
informationPopup . icon = StandardIcon . Information
if ( received > 0 ) {
received = received / 1 e12
if ( height == 0 ) {
informationPopup . text = qsTr ( "This address received %1 monero, but the transaction is not yet mined" ) . arg ( received ) ;
}
else {
var dCurrentBlock = currentWallet . daemonBlockChainHeight ( ) ;
var confirmations = dCurrentBlock - height
2017-01-15 04:52:04 +01:00
informationPopup . text = qsTr ( "This address received %1 monero, with %2 confirmation(s)." ) . arg ( received ) . arg ( confirmations ) ;
2016-11-05 15:58:49 +01:00
}
}
else {
informationPopup . text = qsTr ( "This address received nothing" ) ;
}
}
else {
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = error ;
informationPopup . icon = StandardIcon . Critical
}
informationPopup . open ( )
}
2016-12-31 14:47:40 +01:00
function updateSyncing ( syncing ) {
var text = ( syncing ? qsTr ( "Balance (syncing)" ) : qsTr ( "Balance" ) ) + translationManager . emptyString
leftPanel . balanceLabelText = text
middlePanel . balanceLabelText = text
}
2016-11-05 15:58:49 +01:00
2016-08-17 14:14:43 +02:00
// blocks UI if wallet can't be opened or no connection to the daemon
function enableUI ( enable ) {
middlePanel . enabled = enable ;
leftPanel . enabled = enable ;
rightPanel . enabled = enable ;
}
2016-08-23 10:55:51 +02:00
function showProcessingSplash ( message ) {
console . log ( "Displaying processing splash" )
if ( typeof message != 'undefined' ) {
2016-11-08 18:05:33 +01:00
splash . messageText = message
splash . heightProgressText = ""
2016-08-23 10:55:51 +02:00
}
splash . show ( )
}
function hideProcessingSplash ( ) {
console . log ( "Hiding processing splash" )
2016-09-01 22:55:30 +02:00
splash . close ( )
2016-08-23 10:55:51 +02:00
}
2016-10-29 16:48:10 +02:00
// close wallet and show wizard
function showWizard ( ) {
2016-10-29 16:59:31 +02:00
walletInitialized = false ;
2016-12-15 13:18:04 +01:00
closeWallet ( ) ;
2016-12-16 00:12:27 +01:00
currentWallet = undefined ;
2016-10-29 16:48:10 +02:00
wizard . restart ( ) ;
rootItem . state = "wizard"
2017-03-04 00:11:26 +01:00
// reset balance
leftPanel . balanceText = leftPanel . unlockedBalanceText = walletManager . displayAmount ( 0 ) ;
2016-10-29 16:48:10 +02:00
}
2017-04-03 18:51:55 +02:00
function hideMenu ( ) {
goToBasicAnimation . start ( ) ;
console . log ( appWindow . width )
}
function showMenu ( ) {
goToProAnimation . start ( ) ;
console . log ( appWindow . width )
}
2016-08-17 14:14:43 +02:00
objectName: "appWindow"
2014-07-07 19:08:30 +02:00
visible: true
2017-04-03 18:51:55 +02:00
// width: Screen.width //rightPanelExpanded ? 1269 : 1269 - 300
// height: 900 //300//maxWindowHeight;
2014-07-07 19:08:30 +02:00
color: "#FFFFFF"
2016-12-09 22:23:43 +01:00
flags: persistentSettings . customDecorations ? ( Qt . FramelessWindowHint | Qt . WindowSystemMenuHint | Qt . Window | Qt . WindowMinimizeButtonHint ) : ( Qt . WindowSystemMenuHint | Qt . Window | Qt . WindowMinimizeButtonHint | Qt . WindowCloseButtonHint | Qt . WindowTitleHint | Qt . WindowMaximizeButtonHint )
2014-07-19 16:07:40 +02:00
onWidthChanged: x -= 0
2016-12-15 01:59:10 +01:00
function setCustomWindowDecorations ( custom ) {
var x = appWindow . x
var y = appWindow . y
if ( x < 0 )
x = 0
if ( y < 0 )
y = 0
persistentSettings . customDecorations = custom
if ( custom )
appWindow . flags = Qt . FramelessWindowHint | Qt . WindowSystemMenuHint | Qt . Window | Qt . WindowMinimizeButtonHint
else
appWindow . flags = Qt . WindowSystemMenuHint | Qt . Window | Qt . WindowMinimizeButtonHint | Qt . WindowCloseButtonHint | Qt . WindowTitleHint | Qt . WindowMaximizeButtonHint
appWindow . hide ( )
appWindow . x = x
appWindow . y = y
appWindow . show ( )
}
2016-08-17 14:14:43 +02:00
2014-07-19 16:07:40 +02:00
Component.onCompleted: {
x = ( Screen . width - width ) / 2
2016-11-21 22:14:49 +01:00
y = ( Screen . height - maxWindowHeight ) / 2
2016-06-07 15:26:25 +02:00
//
2016-08-18 20:55:34 +02:00
walletManager . walletOpened . connect ( onWalletOpened ) ;
walletManager . walletClosed . connect ( onWalletClosed ) ;
2017-08-06 00:10:59 +02:00
walletManager . checkUpdatesComplete . connect ( onWalletCheckUpdatesComplete ) ;
2016-08-18 20:55:34 +02:00
2017-04-03 18:51:55 +02:00
if ( typeof daemonManager != "undefined" ) {
daemonManager . daemonStarted . connect ( onDaemonStarted ) ;
daemonManager . daemonStartFailure . connect ( onDaemonStartFailure ) ;
daemonManager . daemonStopped . connect ( onDaemonStopped ) ;
}
2016-11-25 21:09:32 +01:00
2017-03-01 22:03:50 +01:00
// Connect app exit to qml window exit handling
mainApp . closing . connect ( appWindow . close ) ;
2017-03-27 19:39:47 +02:00
if ( appWindow . qrScannerEnabled ) {
console . log ( "qrScannerEnabled : load component QRCodeScanner" ) ;
var component = Qt . createComponent ( "components/QRCodeScanner.qml" ) ;
if ( component . status == Component . Ready ) {
console . log ( "Camera component ready" ) ;
cameraUi = component . createObject ( appWindow ) ;
} else {
console . log ( "component not READY !!!" ) ;
appWindow . qrScannerEnabled = false ;
}
} else console . log ( "qrScannerEnabled disabled" ) ;
2016-10-30 17:58:12 +01:00
if ( ! walletsFound ( ) ) {
2016-10-29 16:48:10 +02:00
rootItem . state = "wizard"
} else {
rootItem . state = "normal"
initialize ( persistentSettings ) ;
2016-06-15 15:34:55 +02:00
}
2016-10-29 16:48:10 +02:00
2017-02-19 11:38:03 +01:00
checkUpdates ( ) ;
2016-06-15 15:34:55 +02:00
}
2016-06-21 10:58:06 +02:00
onRightPanelExpandedChanged: {
if ( rightPanelExpanded ) {
rightPanel . updateTweets ( )
}
}
2016-08-17 14:14:43 +02:00
2016-06-15 15:34:55 +02:00
Settings {
id: persistentSettings
property string language
2016-07-19 22:45:12 +02:00
property string locale
2016-06-15 15:34:55 +02:00
property string account_name
property string wallet_path
2016-11-12 12:11:24 +01:00
property bool auto_donations_enabled : false
2016-06-15 15:34:55 +02:00
property int auto_donations_amount : 50
2016-11-12 12:11:24 +01:00
property bool allow_background_mining : false
2017-03-02 15:44:37 +01:00
property bool miningIgnoreBattery : true
2016-11-12 12:11:24 +01:00
property bool testnet: false
property string daemon_address: "localhost:18081"
2016-06-26 17:04:45 +02:00
property string payment_id
2016-10-10 21:40:58 +02:00
property int restore_height : 0
property bool is_recovering : false
2016-12-09 22:23:43 +01:00
property bool customDecorations : true
2016-12-21 14:30:15 +01:00
property string daemonFlags
2016-12-31 11:56:08 +01:00
property int logLevel: 0
2017-02-05 13:38:43 +01:00
property string logCategories: ""
2017-02-25 22:16:58 +01:00
property string daemonUsername: ""
property string daemonPassword: ""
2017-02-27 22:05:28 +01:00
property bool transferShowAdvanced: false
2017-05-04 14:06:29 +02:00
property string blockchainDataDir: ""
2014-07-19 16:07:40 +02:00
}
2014-07-07 19:08:30 +02:00
2016-06-28 21:37:14 +02:00
// Information dialog
2016-11-19 15:15:11 +01:00
StandardDialog {
2016-08-17 14:14:43 +02:00
// dynamically change onclose handler
property var onCloseCallback
2016-06-28 21:37:14 +02:00
id: informationPopup
2016-11-19 15:15:11 +01:00
cancelVisible: false
2016-08-17 14:14:43 +02:00
onAccepted: {
if ( onCloseCallback ) {
onCloseCallback ( )
}
}
2016-06-28 21:37:14 +02:00
}
// Confrirmation aka question dialog
2016-11-19 15:15:11 +01:00
StandardDialog {
2016-06-28 21:37:14 +02:00
id: transactionConfirmationPopup
onAccepted: {
2016-11-19 15:15:11 +01:00
close ( ) ;
2017-01-12 20:53:27 +01:00
// Save transaction to file if view only wallet
if ( viewOnly ) {
saveTxDialog . open ( ) ;
return ;
} else
handleTransactionConfirmed ( )
2017-03-02 15:44:37 +01:00
}
2017-01-12 20:53:27 +01:00
}
StandardDialog {
id: confirmationDialog
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if ( onAcceptedCallback )
onAcceptedCallback ( )
}
onRejected: {
if ( onRejectedCallback )
onRejectedCallback ( ) ;
2016-06-28 21:37:14 +02:00
}
}
2017-01-12 20:53:27 +01:00
2016-10-29 16:48:10 +02:00
//Open Wallet from file
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: "file://" + moneroAccountsDir
2016-10-30 17:58:12 +01:00
nameFilters: [ "Wallet files (*.keys)" ]
2016-10-29 16:48:10 +02:00
onAccepted: {
persistentSettings . wallet_path = walletManager . urlToLocalPath ( fileDialog . fileUrl )
initialize ( ) ;
}
onRejected: {
console . log ( "Canceled" )
rootItem . state = "wizard" ;
}
}
2016-08-16 22:21:46 +02:00
PasswordDialog {
id: passwordDialog
2016-11-01 13:01:24 +01:00
2016-08-16 22:21:46 +02:00
onAccepted: {
2016-08-19 13:44:44 +02:00
appWindow . initialize ( ) ;
2016-08-16 22:21:46 +02:00
}
2016-08-17 14:14:43 +02:00
onRejected: {
2016-10-29 16:49:00 +02:00
//appWindow.enableUI(false)
rootItem . state = "wizard"
2016-08-17 14:14:43 +02:00
}
2016-11-01 13:01:24 +01:00
2016-08-16 22:21:46 +02:00
}
2016-11-05 10:54:11 +01:00
DaemonManagerDialog {
id: daemonManagerDialog
2017-02-23 19:47:58 +01:00
onRejected: {
loadPage ( "Settings" ) ;
}
2016-11-05 10:54:11 +01:00
}
2016-08-23 10:55:51 +02:00
ProcessingSplash {
id: splash
2016-10-09 20:49:56 +02:00
width: appWindow . width / 1.5
2016-08-23 10:55:51 +02:00
height: appWindow . height / 2
x: ( appWindow . width - width ) / 2 + appWindow . x
y: ( appWindow . height - height ) / 2 + appWindow . y
2016-09-26 21:55:25 +02:00
messageText: qsTr ( "Please wait..." )
2016-07-13 14:24:40 +02:00
}
2014-07-07 19:08:30 +02:00
Item {
id: rootItem
anchors.fill: parent
2014-07-19 16:07:40 +02:00
clip: true
2014-07-07 19:08:30 +02:00
2014-08-19 14:58:02 +02:00
state: "wizard"
states: [
State {
name: "wizard"
PropertyChanges { target: leftPanel ; visible: false }
PropertyChanges { target: rightPanel ; visible: false }
PropertyChanges { target: middlePanel ; visible: false }
2017-05-06 17:49:43 +02:00
PropertyChanges { target: titleBar ; basicButtonVisible: false }
2014-08-19 14:58:02 +02:00
PropertyChanges { target: wizard ; visible: true }
2017-05-06 17:49:43 +02:00
PropertyChanges { target: appWindow ; width: ( Screen . width < 930 ) ? Screen.width : 930 ; }
PropertyChanges { target: appWindow ; height: maxWindowHeight ; }
2014-08-21 12:09:52 +02:00
PropertyChanges { target: resizeArea ; visible: false }
2016-12-09 22:23:43 +01:00
PropertyChanges { target: titleBar ; maximizeButtonVisible: false }
2017-04-03 18:51:55 +02:00
// PropertyChanges { target: frameArea; blocked: true }
2016-12-10 19:46:04 +01:00
PropertyChanges { target: titleBar ; visible: false }
2016-12-09 22:23:43 +01:00
PropertyChanges { target: titleBar ; y: 0 }
PropertyChanges { target: titleBar ; title: qsTr ( "Program setup wizard" ) + translationManager . emptyString }
2014-08-22 11:03:10 +02:00
} , State {
2014-08-19 14:58:02 +02:00
name: "normal"
2017-04-03 18:51:55 +02:00
PropertyChanges { target: leftPanel ; visible: ( isMobile ) ? false : true }
2014-08-19 14:58:02 +02:00
PropertyChanges { target: rightPanel ; visible: true }
PropertyChanges { target: middlePanel ; visible: true }
2017-05-06 17:49:43 +02:00
PropertyChanges { target: titleBar ; basicButtonVisible: true }
2014-08-19 14:58:02 +02:00
PropertyChanges { target: wizard ; visible: false }
2017-05-06 17:49:43 +02:00
PropertyChanges { target: appWindow ; width: ( Screen . width < 969 ) ? Screen.width : 969 } //rightPanelExpanded ? 1269 : 1269 - 300;
PropertyChanges { target: appWindow ; height: maxWindowHeight ; }
2014-08-21 12:09:52 +02:00
PropertyChanges { target: resizeArea ; visible: true }
2016-12-09 22:23:43 +01:00
PropertyChanges { target: titleBar ; maximizeButtonVisible: true }
2017-05-06 17:49:43 +02:00
// PropertyChanges { target: frameArea; blocked: true }
PropertyChanges { target: titleBar ; visible: true }
2017-04-03 18:51:55 +02:00
// PropertyChanges { target: titleBar; y: 0 }
2016-12-09 22:23:43 +01:00
PropertyChanges { target: titleBar ; title: qsTr ( "Monero" ) + translationManager . emptyString }
2014-08-19 14:58:02 +02:00
}
]
2017-04-03 18:51:55 +02:00
MobileHeader {
id: mobileHeader
visible: isMobile
anchors.left: parent . left
anchors.right: parent . right
height: visible ? 65 : 0
}
2014-07-07 19:08:30 +02:00
LeftPanel {
id: leftPanel
2017-04-03 18:51:55 +02:00
anchors.top: mobileHeader . bottom
2014-07-07 19:08:30 +02:00
anchors.left: parent . left
anchors.bottom: parent . bottom
2017-04-03 18:51:55 +02:00
onDashboardClicked: { middlePanel . state = "Dashboard" ; if ( isMobile ) hideMenu ( ) }
onTransferClicked: { middlePanel . state = "Transfer" ; if ( isMobile ) hideMenu ( ) }
onReceiveClicked: { middlePanel . state = "Receive" ; if ( isMobile ) hideMenu ( ) }
onTxkeyClicked: { middlePanel . state = "TxKey" ; if ( isMobile ) hideMenu ( ) }
onHistoryClicked: { middlePanel . state = "History" ; if ( isMobile ) hideMenu ( ) }
onAddressBookClicked: { middlePanel . state = "AddressBook" ; if ( isMobile ) hideMenu ( ) }
onMiningClicked: { middlePanel . state = "Mining" ; if ( isMobile ) hideMenu ( ) }
onSignClicked: { middlePanel . state = "Sign" ; if ( isMobile ) hideMenu ( ) }
onSettingsClicked: { middlePanel . state = "Settings" ; if ( isMobile ) hideMenu ( ) }
2014-07-07 19:08:30 +02:00
}
RightPanel {
id: rightPanel
anchors.right: parent . right
anchors.bottom: parent . bottom
2014-07-16 10:24:59 +02:00
width: appWindow . rightPanelExpanded ? 300 : 0
visible: appWindow . rightPanelExpanded
2014-07-07 19:08:30 +02:00
}
2016-07-14 12:40:27 +02:00
2014-07-07 19:08:30 +02:00
MiddlePanel {
id: middlePanel
2017-04-03 18:51:55 +02:00
anchors.top: mobileHeader . bottom
2014-07-07 19:08:30 +02:00
anchors.bottom: parent . bottom
2016-10-08 23:50:35 +02:00
anchors.left: leftPanel . visible ? leftPanel.right : parent . left
2017-04-03 18:51:55 +02:00
anchors.right: parent . right
2016-06-26 17:04:45 +02:00
state: "Transfer"
2014-07-07 19:08:30 +02:00
}
TipItem {
id: tipItem
2016-07-20 21:28:11 +02:00
text: qsTr ( "send to the same destination" ) + translationManager . emptyString
2014-07-07 19:08:30 +02:00
visible: false
}
2014-07-15 16:03:39 +02:00
2017-04-03 18:51:55 +02:00
// MouseArea {
// id: frameArea
// property bool blocked: false
// anchors.top: parent.top
// anchors.left: parent.left
// anchors.right: parent.right
// height: 30
// z: 1
// hoverEnabled: true
// propagateComposedEvents: true
// onPressed: mouse.accepted = false
// onReleased: mouse.accepted = false
// onMouseXChanged: titleBar.mouseX = mouseX
// onContainsMouseChanged: titleBar.containsMouse = containsMouse
// }
2014-07-15 16:03:39 +02:00
2014-07-19 16:07:40 +02:00
SequentialAnimation {
id: goToBasicAnimation
2017-04-03 18:51:55 +02:00
// PropertyAction {
// target: appWindow
// properties: "visibility"
// value: Window.Windowed
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: false
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: true
// }
2014-08-22 11:03:10 +02:00
PropertyAction {
target: resizeArea
properties: "visible"
2017-04-03 18:51:55 +02:00
value: true
2014-07-19 16:07:40 +02:00
}
2017-04-03 18:51:55 +02:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
// PropertyAction {
// target: appWindow
// properties: "width"
// value: 326
// }
2014-07-19 16:07:40 +02:00
PropertyAction {
2016-10-08 23:50:35 +02:00
targets: [ leftPanel , rightPanel ]
2014-07-19 16:07:40 +02:00
properties: "visible"
value: false
}
PropertyAction {
2016-10-08 23:50:35 +02:00
target: middlePanel
properties: "basicMode"
2014-07-19 16:07:40 +02:00
value: true
}
2016-10-08 23:50:35 +02:00
2017-04-03 18:51:55 +02:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: middlePanel.height
// }
2014-07-19 16:07:40 +02:00
onStopped: {
2016-10-08 23:50:35 +02:00
// middlePanel.visible = false
2014-07-19 16:07:40 +02:00
rightPanel . visible = false
leftPanel . visible = false
}
}
SequentialAnimation {
id: goToProAnimation
2017-04-03 18:51:55 +02:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
2014-07-19 16:07:40 +02:00
PropertyAction {
2016-10-08 23:50:35 +02:00
target: middlePanel
properties: "basicMode"
2014-07-19 16:07:40 +02:00
value: false
}
PropertyAction {
2014-08-22 11:03:10 +02:00
targets: [ leftPanel , middlePanel , rightPanel , resizeArea ]
2014-07-19 16:07:40 +02:00
properties: "visible"
value: true
}
2017-04-03 18:51:55 +02:00
// PropertyAction {
// target: appWindow
// properties: "width"
// value: rightPanelExpanded ? 1269 : 1269 - 300
// }
// PropertyAction {
// target: appWindow
// properties: "height"
// value: maxWindowHeight
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: false
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: true
// }
2014-07-19 16:07:40 +02:00
}
2014-08-19 14:58:02 +02:00
WizardMain {
id: wizard
anchors.fill: parent
2016-06-15 15:34:55 +02:00
onUseMoneroClicked: {
rootItem . state = "normal" // TODO: listen for this state change in appWindow;
appWindow . initialize ( ) ;
}
2016-10-29 16:48:10 +02:00
onOpenWalletFromFileClicked: {
rootItem . state = "normal" // TODO: listen for this state change in appWindow;
appWindow . openWalletFromFile ( ) ;
}
2014-08-19 14:58:02 +02:00
}
2017-01-30 10:37:14 +01:00
property int minWidth: 326
2017-04-03 18:51:55 +02:00
property int minHeight: 400
2014-07-23 12:39:35 +02:00
MouseArea {
2014-08-21 12:09:52 +02:00
id: resizeArea
2014-07-23 12:39:35 +02:00
hoverEnabled: true
anchors.right: parent . right
anchors.bottom: parent . bottom
2014-07-23 13:27:27 +02:00
height: 30
width: 30
2014-07-23 12:39:35 +02:00
Rectangle {
anchors.fill: parent
2014-07-23 13:59:26 +02:00
color: parent . containsMouse || parent . pressed ? "#111111" : "transparent"
2014-07-23 12:39:35 +02:00
}
Image {
anchors.centerIn: parent
source: parent . containsMouse || parent . pressed ? "images/resizeHovered.png" :
"images/resize.png"
}
2016-02-03 16:37:10 +01:00
property var previousPosition
2016-06-16 16:13:46 +02:00
2014-07-23 12:39:35 +02:00
onPressed: {
2016-02-03 16:37:10 +01:00
previousPosition = globalCursor . getPosition ( )
2014-07-23 12:39:35 +02:00
}
onPositionChanged: {
if ( ! pressed ) return
2016-02-03 16:37:10 +01:00
var pos = globalCursor . getPosition ( )
//var delta = previousPosition - pos
var dx = previousPosition . x - pos . x
var dy = previousPosition . y - pos . y
2014-07-23 12:39:35 +02:00
2017-01-30 10:37:14 +01:00
if ( appWindow . width - dx > parent . minWidth )
2014-07-23 12:39:35 +02:00
appWindow . width -= dx
2017-01-30 10:37:14 +01:00
else appWindow . width = parent . minWidth
2014-07-23 12:39:35 +02:00
2016-11-23 21:17:01 +01:00
if ( appWindow . height - dy > parent . minHeight )
2014-07-23 12:39:35 +02:00
appWindow . height -= dy
2016-11-23 21:17:01 +01:00
else appWindow . height = parent . minHeight
2016-02-03 16:37:10 +01:00
previousPosition = pos
2014-07-23 12:39:35 +02:00
}
}
2014-07-22 16:55:25 +02:00
2014-07-15 16:03:39 +02:00
TitleBar {
id: titleBar
2016-12-09 22:23:43 +01:00
anchors.left: parent . left
anchors.right: parent . right
2016-11-19 15:22:56 +01:00
x: 0
y: 0
2016-12-09 22:23:43 +01:00
customDecorations: persistentSettings . customDecorations
2014-07-19 16:07:40 +02:00
onGoToBasicVersion: {
2016-10-08 23:50:35 +02:00
if ( yes ) {
// basicPanel.currentView = middlePanel.currentView
goToBasicAnimation . start ( )
} else {
// middlePanel.currentView = basicPanel.currentView
goToProAnimation . start ( )
}
2014-07-19 16:07:40 +02:00
}
2016-12-09 22:23:43 +01:00
2017-05-06 17:49:43 +02:00
MouseArea {
enabled: persistentSettings . customDecorations
property var previousPosition
anchors.fill: parent
propagateComposedEvents: true
onPressed: previousPosition = globalCursor . getPosition ( )
onPositionChanged: {
if ( pressedButtons == Qt . LeftButton ) {
var pos = globalCursor . getPosition ( )
var dx = pos . x - previousPosition . x
var dy = pos . y - previousPosition . y
appWindow . x += dx
appWindow . y += dy
previousPosition = pos
}
}
}
2014-07-15 16:03:39 +02:00
}
2016-12-15 14:09:37 +01:00
// new ToolTip
Rectangle {
id: toolTip
property alias text: content . text
width: content . width + 12
height: content . height + 17
color: "#FF6C3C"
//radius: 3
visible: false ;
Image {
id: tip
anchors.top: parent . bottom
anchors.right: parent . right
anchors.rightMargin: 5
source: "../images/tip.png"
}
Text {
id: content
anchors.horizontalCenter: parent . horizontalCenter
y: 6
lineHeight: 0.7
font.family: "Arial"
font.pixelSize: 12
color: "#FFFFFF"
}
}
2017-02-19 11:38:03 +01:00
Notifier {
2017-04-03 18:51:55 +02:00
visible: false
2017-02-19 11:38:03 +01:00
id: notifier
}
2014-07-07 19:08:30 +02:00
}
2017-03-01 22:03:50 +01:00
2016-10-10 21:42:25 +02:00
onClosing: {
2017-03-01 22:03:50 +01:00
// If daemon is running - prompt user before exiting
2017-04-03 18:51:55 +02:00
if ( typeof daemonManager != "undefined" && daemonManager . running ( persistentSettings . testnet ) ) {
2017-03-01 22:03:50 +01:00
close . accepted = false ;
// Show confirmation dialog
confirmationDialog . title = qsTr ( "Daemon is running" ) + translationManager . emptyString ;
confirmationDialog . text = qsTr ( "Daemon will still be running in background when GUI is closed." ) ;
confirmationDialog . icon = StandardIcon . Question
confirmationDialog . cancelText = qsTr ( "Stop daemon" )
confirmationDialog . onAcceptedCallback = function ( ) {
closeAccepted ( ) ;
}
confirmationDialog . onRejectedCallback = function ( ) {
daemonManager . stop ( persistentSettings . testnet ) ;
closeAccepted ( ) ;
} ;
confirmationDialog . open ( )
} else {
closeAccepted ( ) ;
}
}
function closeAccepted ( ) {
2016-12-15 13:18:04 +01:00
// Close wallet non async on exit
2017-02-25 14:57:39 +01:00
daemonManager . exit ( ) ;
2016-12-04 13:13:59 +01:00
walletManager . closeWallet ( ) ;
2017-03-01 22:03:50 +01:00
Qt . quit ( ) ;
2016-10-10 21:42:25 +02:00
}
2017-02-19 11:38:03 +01:00
2017-08-06 00:10:59 +02:00
function onWalletCheckUpdatesComplete ( update ) {
2017-02-19 11:38:03 +01:00
if ( update === "" )
return
print ( "Update found: " + update )
var parts = update . split ( "|" )
if ( parts . length == 4 ) {
var version = parts [ 0 ]
var hash = parts [ 1 ]
var user_url = parts [ 2 ]
var auto_url = parts [ 3 ]
var msg = qsTr ( "New version of monero-wallet-gui is available: %1<br>%2" ) . arg ( version ) . arg ( user_url ) + translationManager . emptyString
notifier . show ( msg )
}
else {
print ( "Failed to parse update spec" )
}
}
2017-08-06 00:10:59 +02:00
function checkUpdates ( ) {
walletManager . checkUpdatesAsync ( "monero-gui" , "gui" )
}
2017-02-19 11:38:03 +01:00
Timer {
id: updatesTimer
interval: 3600 * 1000 ; running: true ; repeat: true
onTriggered: checkUpdates ( )
}
2017-09-04 13:42:46 +02:00
function isDaemonLocal ( ) {
var daemonAddress = appWindow . persistentSettings . daemon_address
if ( daemonAddress === "" )
return false
var daemonHost = daemonAddress . split ( ":" ) [ 0 ]
if ( daemonHost === "127.0.0.1" || daemonHost === "localhost" )
return true
return false
}
2014-07-07 19:08:30 +02:00
}