2019-03-13 01:53:56 +00:00
// Copyright (c) 2014-2019, The Monero Project
2016-11-12 13:28:13 +00:00
//
2015-04-01 08:56:05 +00:00
// All rights reserved.
2016-11-12 13:28:13 +00:00
//
2015-04-01 08:56:05 +00: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 13:28:13 +00:00
//
2015-04-01 08:56:05 +00:00
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
2016-11-12 13:28:13 +00:00
//
2015-04-01 08:56:05 +00: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 13:28:13 +00:00
//
2015-04-01 08:56:05 +00: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 13:28:13 +00:00
//
2015-04-01 08:56:05 +00: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.
2021-04-14 15:34:05 +00:00
import QtQml . Models 2.2
2019-04-11 01:17:29 +00:00
import QtQuick 2.9
2014-07-07 17:08:30 +00:00
import QtQuick . Window 2.0
import QtQuick . Controls 1.1
import QtQuick . Controls . Styles 1.1
2016-06-28 19:37:14 +00:00
import QtQuick . Dialogs 1.2
2019-12-13 17:26:04 +00:00
import QtGraphicalEffects 1.0
2016-10-02 18:40:40 +00:00
2020-09-24 14:08:33 +00:00
import FontAwesome 1.0
2020-07-29 17:43:02 +00:00
import moneroComponents . Network 1.0
2016-10-02 18:40:40 +00:00
import moneroComponents . Wallet 1.0
2020-07-20 14:47:13 +00:00
import moneroComponents . WalletManager 1.0
2016-10-02 18:40:40 +00:00
import moneroComponents . PendingTransaction 1.0
2018-03-05 16:19:45 +00:00
import moneroComponents . NetworkType 1.0
2019-07-02 23:27:25 +00:00
import moneroComponents . Settings 1.0
2016-06-15 10:25:45 +00:00
2014-07-07 17:08:30 +00:00
import "components"
2019-01-14 00:02:44 +00:00
import "components" as MoneroComponents
2019-04-11 01:17:29 +00:00
import "components/effects" as MoneroEffects
import "pages/merchant" as MoneroMerchant
2014-08-19 12:58:02 +00:00
import "wizard"
2018-12-07 07:48:20 +00:00
import "js/Utils.js" as Utils
2018-04-21 19:58:00 +00:00
import "js/Windows.js" as Windows
2020-04-23 14:19:20 +00:00
import "version.js" as Version
2014-07-07 17:08:30 +00:00
ApplicationWindow {
id: appWindow
2021-01-12 12:59:28 +00:00
title: "Monero" +
( persistentSettings . displayWalletNameInTitleBar && walletName
? " - " + walletName
: "" )
2019-12-21 21:43:37 +00:00
minimumWidth: 750
minimumHeight: 450
2016-08-17 12:14:43 +00:00
2014-07-09 14:18:48 +00:00
property var currentItem
2018-12-15 04:02:01 +00:00
property bool hideBalanceForced: false
2014-07-13 12:27:50 +00:00
property bool ctrlPressed: false
2016-06-15 13:34:55 +00:00
property alias persistentSettings : persistentSettings
2020-07-28 17:42:59 +00:00
property string accountsDir: ! persistentSettings . portable ? moneroAccountsDir : persistentSettings . portableFolderName + "/wallets"
2016-08-18 18:55:34 +00:00
property var currentWallet ;
2020-01-28 04:43:31 +00:00
property bool disconnected: currentWallet ? currentWallet.disconnected : false
2016-06-28 19:37:14 +00:00
property var transaction ;
2017-11-17 01:16:35 +00:00
property var walletPassword
2016-10-07 23:37:47 +00:00
property int restoreHeight: 0
2016-11-01 23:17:58 +00:00
property bool daemonSynced: false
2018-03-20 18:19:30 +00:00
property bool walletSynced: false
2021-04-15 19:00:36 +00:00
property int maxWindowHeight: ( isAndroid || isIOS ) ? screenAvailableHeight : ( screenAvailableHeight < 900 ) ? 720 : 800 ;
2020-01-28 04:43:31 +00:00
property bool daemonRunning: ! persistentSettings . useRemoteNode && ! disconnected
2020-10-14 02:24:22 +00:00
property int daemonStartStopInProgress: 0
2016-12-15 13:09:37 +00:00
property alias toolTip: toolTip
2017-01-13 22:21:58 +00:00
property string walletName
property bool viewOnly: false
property bool foundNewBlock: false
2017-03-27 17:39:47 +00:00
property bool qrScannerEnabled: ( typeof builtWithScanner != "undefined" ) && builtWithScanner
2017-02-24 20:51:37 +00:00
property int blocksToSync: 1
2020-05-02 14:34:54 +00:00
property int firstBlockSeen
2018-12-16 04:10:12 +00:00
property bool isMining: false
2019-01-14 00:02:44 +00:00
property int walletMode: persistentSettings . walletMode
2017-03-27 17:39:47 +00:00
property var cameraUi
2017-08-08 09:29:02 +00:00
property bool androidCloseTapped: false ;
2018-12-13 18:02:02 +00:00
property int userLastActive ; // epoch
2017-08-07 15:03:34 +00:00
// Default daemon addresses
2019-02-17 14:33:12 +00:00
readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort ( persistentSettings . nettype )
2017-08-07 15:03:34 +00:00
property string currentDaemonAddress ;
2019-01-14 00:02:44 +00:00
property int disconnectedEpoch: 0
2021-04-21 17:04:55 +00:00
property int estimatedBlockchainSize: 105 // GB
2019-01-14 00:02:44 +00:00
property alias viewState: rootItem . state
2019-03-27 08:28:42 +00:00
property string prevSplashText ;
property bool splashDisplayedBeforeButtonRequest ;
2019-04-11 01:17:29 +00:00
property int appEpoch: Math . floor ( ( new Date ) . getTime ( ) / 1000 )
property bool themeTransition: false
2019-01-14 00:02:44 +00:00
2019-05-01 02:05:16 +00:00
// fiat price conversion
2019-11-13 06:34:33 +00:00
property real fiatPriceXMRUSD: 0
property real fiatPriceXMREUR: 0
2019-05-01 02:05:16 +00:00
property var fiatPriceAPIs: {
return {
"kraken" : {
"xmrusd" : "https://api.kraken.com/0/public/Ticker?pair=XMRUSD" ,
"xmreur" : "https://api.kraken.com/0/public/Ticker?pair=XMREUR"
} ,
"coingecko" : {
"xmrusd" : "https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=usd" ,
"xmreur" : "https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=eur"
} ,
"cryptocompare" : {
"xmrusd" : "https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=USD" ,
"xmreur" : "https://min-api.cryptocompare.com/data/price?fsym=XMR&tsyms=EUR" ,
}
}
}
2016-10-06 21:47:28 +00:00
// true if wallet ever synchronized
property bool walletInitialized : false
2016-07-13 12:24:40 +00:00
2019-01-14 12:25:59 +00:00
// Current selected address / subaddress / (Receive/Account page)
2018-12-08 15:55:29 +00:00
property var current_address
property var current_address_label: "Primary"
property int current_subaddress_table_index: 0
2014-07-13 12:27:50 +00:00
function showPageRequest ( page ) {
middlePanel . state = page
leftPanel . selectItem ( page )
}
2016-06-15 13:34:55 +00:00
2014-07-13 12:27:50 +00:00
function sequencePressed ( obj , seq ) {
2017-12-08 15:33:56 +00:00
if ( seq === undefined || ! leftPanel . enabled )
2014-07-09 14:18:48 +00:00
return
2014-07-13 12:27:50 +00:00
if ( seq === "Ctrl" ) {
ctrlPressed = true
return
}
2017-01-17 21:59:40 +00:00
if ( seq === "Ctrl+S" ) middlePanel . state = "Transfer"
2016-12-18 13:59:24 +00:00
else if ( seq === "Ctrl+R" ) middlePanel . state = "Receive"
2014-07-13 12:27:50 +00:00
else if ( seq === "Ctrl+H" ) middlePanel . state = "History"
else if ( seq === "Ctrl+B" ) middlePanel . state = "AddressBook"
2016-12-18 13:59:24 +00:00
else if ( seq === "Ctrl+E" ) middlePanel . state = "Settings"
2017-01-17 21:59:40 +00:00
else if ( seq === "Ctrl+D" ) middlePanel . state = "Advanced"
2019-01-14 12:25:59 +00:00
else if ( seq === "Ctrl+T" ) middlePanel . state = "Account"
2014-07-16 12:40:09 +00:00
else if ( seq === "Ctrl+Tab" || seq === "Alt+Tab" ) {
2016-12-18 14:24:48 +00:00
/ *
2019-01-10 05:58:43 +00:00
if ( middlePanel . state === "Transfer" ) middlePanel . state = "Receive"
2016-12-18 13:59:24 +00:00
else if ( middlePanel . state === "Receive" ) middlePanel . state = "TxKey"
2018-03-07 00:01:53 +00:00
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "SharedRingDB"
else if ( middlePanel . state === "SharedRingDB" ) middlePanel . state = "History"
2014-07-13 12:27:50 +00:00
else if ( middlePanel . state === "History" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "Mining"
2016-12-18 13:59:24 +00:00
else if ( middlePanel . state === "Mining" ) middlePanel . state = "Sign"
else if ( middlePanel . state === "Sign" ) middlePanel . state = "Settings"
2016-12-18 14:24:48 +00:00
* /
2019-01-14 12:25:59 +00:00
if ( middlePanel . state === "Settings" ) middlePanel . state = "Account"
else if ( middlePanel . state === "Account" ) middlePanel . state = "Transfer"
2018-05-08 17:00:30 +00:00
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "History"
2021-03-20 09:12:15 +00:00
else if ( middlePanel . state === "History" ) middlePanel . state = "Advanced"
else if ( middlePanel . state === "Advanced" ) middlePanel . state = "Settings"
2014-07-16 12:40:09 +00:00
} else if ( seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab" ) {
2016-12-18 14:24:48 +00:00
/ *
if ( middlePanel . state === "Settings" ) middlePanel . state = "Sign"
2016-12-18 13:59:24 +00:00
else if ( middlePanel . state === "Sign" ) middlePanel . state = "Mining"
2014-07-13 12:27:50 +00:00
else if ( middlePanel . state === "Mining" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "History"
2018-03-07 00:01:53 +00:00
else if ( middlePanel . state === "History" ) middlePanel . state = "SharedRingDB"
else if ( middlePanel . state === "SharedRingDB" ) middlePanel . state = "TxKey"
2016-12-18 13:59:24 +00:00
else if ( middlePanel . state === "TxKey" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "Transfer"
2016-12-18 14:24:48 +00:00
* /
2021-03-20 09:12:15 +00:00
if ( middlePanel . state === "Settings" ) middlePanel . state = "Advanced"
else if ( middlePanel . state === "Advanced" ) middlePanel . state = "History"
2018-05-11 20:30:40 +00:00
else if ( middlePanel . state === "History" ) middlePanel . state = "Receive"
else if ( middlePanel . state === "Receive" ) middlePanel . state = "AddressBook"
else if ( middlePanel . state === "AddressBook" ) middlePanel . state = "Transfer"
2019-01-14 12:25:59 +00:00
else if ( middlePanel . state === "Transfer" ) middlePanel . state = "Account"
else if ( middlePanel . state === "Account" ) middlePanel . state = "Settings"
2014-07-13 12:27:50 +00:00
}
2017-12-11 11:15:16 +00:00
if ( middlePanel . state !== "Advanced" ) updateBalance ( ) ;
2014-07-09 16:03:37 +00:00
leftPanel . selectItem ( middlePanel . state )
2014-07-09 14:18:48 +00:00
}
2014-07-13 12:27:50 +00:00
function sequenceReleased ( obj , seq ) {
if ( seq === "Ctrl" )
ctrlPressed = false
}
2016-12-04 12:13:59 +00:00
function mousePressed ( obj , mouseX , mouseY ) { }
function mouseReleased ( obj , mouseX , mouseY ) { }
2014-07-07 17:08:30 +00:00
2017-02-23 18:47:58 +00:00
function loadPage ( page ) {
middlePanel . state = page ;
leftPanel . selectItem ( page ) ;
}
2019-12-13 14:30:25 +00:00
function openWallet ( prevState ) {
passwordDialog . onAcceptedCallback = function ( ) {
walletPassword = passwordDialog . password ;
initialize ( ) ;
}
passwordDialog . onRejectedCallback = function ( ) {
if ( prevState ) {
appWindow . viewState = prevState ;
}
} ;
2020-04-24 00:43:40 +00:00
passwordDialog . open ( usefulName ( persistentSettings . wallet_path ) ) ;
2019-12-13 14:30:25 +00:00
}
2016-06-15 13:34:55 +00:00
function initialize ( ) {
2016-07-13 12:24:40 +00:00
console . log ( "initializing.." )
2016-11-07 10:27:53 +00:00
2016-12-31 10:56:08 +00:00
// Use stored log level
2017-02-05 12:38:43 +00:00
if ( persistentSettings . logLevel == 5 )
walletManager . setLogCategories ( persistentSettings . logCategories )
else
walletManager . setLogLevel ( persistentSettings . logLevel )
2016-12-31 10:56:08 +00:00
2017-03-09 15:46:03 +00:00
// Reload transfer page with translations enabled
middlePanel . transferView . onPageCompleted ( ) ;
2016-12-04 12:13:59 +00: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 12:18:04 +00:00
closeWallet ( ) ;
2017-08-07 15:03:34 +00:00
} else if ( ! walletInitialized ) {
2016-10-29 14:48:10 +00:00
// set page to transfer if not changing daemon
middlePanel . state = "Transfer" ;
leftPanel . selectItem ( middlePanel . state )
2016-10-04 22:18:50 +00:00
}
2016-07-19 20:45:12 +00:00
2017-08-07 15:03:34 +00:00
// Local daemon settings
2019-05-27 22:13:53 +00:00
walletManager . setDaemonAddressAsync ( localDaemonAddress ) ;
2017-08-07 15:03:34 +00:00
2019-01-14 00:02:44 +00:00
// enable timers
2018-12-13 18:02:02 +00:00
userInActivityTimer . running = true ;
2017-08-07 15:03:34 +00:00
2016-08-19 11:44:44 +00:00
// wallet already opened with wizard, we just need to initialize it
2020-04-24 00:43:40 +00:00
var wallet_path = persistentSettings . wallet_path ;
2019-12-13 14:30:25 +00:00
if ( isIOS )
2020-07-28 17:42:59 +00:00
wallet_path = appWindow . accountsDir + wallet_path ;
2019-12-13 14:30:25 +00:00
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.walletPassword);
console . log ( "opening wallet at: " , wallet_path , ", network type: " , persistentSettings . nettype == NetworkType . MAINNET ? "mainnet" : persistentSettings . nettype == NetworkType . TESTNET ? "testnet" : "stagenet" ) ;
this . onWalletOpening ( ) ;
walletManager . openWalletAsync (
wallet_path ,
walletPassword ,
persistentSettings . nettype ,
persistentSettings . kdfRounds ) ;
2016-10-29 14:48:10 +00:00
2017-12-07 16:01:16 +00:00
// Hide titlebar based on persistentSettings.customDecorations
titleBar . visible = persistentSettings . customDecorations ;
2016-06-17 13:35:07 +00:00
}
2017-12-07 16:01:16 +00:00
2019-07-02 10:57:37 +00:00
function closeWallet ( callback ) {
2016-06-17 13:35:07 +00:00
2016-12-15 12:18:04 +00:00
// Disconnect all listeners
2019-08-06 10:50:26 +00:00
if ( typeof currentWallet === "undefined" || currentWallet === null ) {
if ( callback ) {
callback ( ) ;
}
return ;
2016-12-15 23:12:27 +00:00
}
2017-08-08 09:40:54 +00:00
2019-08-06 10:50:26 +00:00
currentWallet . heightRefreshed . disconnect ( onHeightRefreshed ) ;
currentWallet . refreshed . disconnect ( onWalletRefresh )
currentWallet . updated . disconnect ( onWalletUpdate )
currentWallet . newBlock . disconnect ( onWalletNewBlock )
currentWallet . moneySpent . disconnect ( onWalletMoneySent )
currentWallet . moneyReceived . disconnect ( onWalletMoneyReceived )
currentWallet . unconfirmedMoneyReceived . disconnect ( onWalletUnconfirmedMoneyReceived )
currentWallet . transactionCreated . disconnect ( onTransactionCreated )
currentWallet . connectionStatusChanged . disconnect ( onWalletConnectionStatusChanged )
currentWallet . deviceButtonRequest . disconnect ( onDeviceButtonRequest ) ;
currentWallet . deviceButtonPressed . disconnect ( onDeviceButtonPressed ) ;
2020-04-11 10:43:21 +00:00
currentWallet . walletPassphraseNeeded . disconnect ( onWalletPassphraseNeededWallet ) ;
2019-08-06 10:50:26 +00:00
currentWallet . transactionCommitted . disconnect ( onTransactionCommitted ) ;
middlePanel . paymentClicked . disconnect ( handlePayment ) ;
middlePanel . sweepUnmixableClicked . disconnect ( handleSweepUnmixable ) ;
middlePanel . getProofClicked . disconnect ( handleGetProof ) ;
middlePanel . checkProofClicked . disconnect ( handleCheckProof ) ;
2019-09-04 23:31:41 +00:00
appWindow . walletName = "" ;
2016-12-15 12:18:04 +00:00
currentWallet = undefined ;
2017-08-08 09:40:54 +00:00
2019-07-02 10:57:37 +00:00
appWindow . showProcessingSplash ( qsTr ( "Closing wallet..." ) ) ;
if ( callback ) {
walletManager . closeWalletAsync ( function ( ) {
hideProcessingSplash ( ) ;
callback ( ) ;
} ) ;
} else {
walletManager . closeWallet ( ) ;
hideProcessingSplash ( ) ;
}
2016-12-15 12:18:04 +00:00
}
function connectWallet ( wallet ) {
currentWallet = wallet
2018-03-21 02:07:38 +00:00
// TODO:
// When the wallet variable is undefined, it yields a zero balance.
// This can scare users, restart the GUI (as a quick fix).
//
// To reproduce, follow these steps:
// 1) Open the GUI, load up a wallet that has a balance
// 2) Settings -> close wallet
// 3) Create a new wallet
// 4) Settings -> close wallet
// 5) Open the wallet from step 1
if ( ! wallet || wallet === undefined || wallet . path === undefined ) {
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Couldn't open wallet: " ) + 'please restart GUI.' ;
informationPopup . icon = StandardIcon . Critical
informationPopup . open ( )
informationPopup . onCloseCallback = function ( ) {
appWindow . close ( ) ;
}
}
2017-01-30 09:37:14 +00:00
walletName = usefulName ( wallet . path )
2016-12-15 12:18:04 +00:00
2017-01-12 19:53:27 +00:00
viewOnly = currentWallet . viewOnly ;
2017-07-31 13:11:01 +00:00
// New wallets saves the testnet flag in keys file.
2018-03-05 16:19:45 +00:00
if ( persistentSettings . nettype != currentWallet . nettype ) {
console . log ( "Using network type from keys file" )
persistentSettings . nettype = currentWallet . nettype ;
2017-07-31 13:11:01 +00:00
}
2016-12-04 12:13:59 +00:00
// connect handlers
2019-06-13 12:19:52 +00:00
currentWallet . heightRefreshed . connect ( onHeightRefreshed ) ;
2016-08-19 11:44:44 +00:00
currentWallet . refreshed . connect ( onWalletRefresh )
currentWallet . updated . connect ( onWalletUpdate )
2016-09-26 19:55:25 +00:00
currentWallet . newBlock . connect ( onWalletNewBlock )
2016-10-06 21:47:28 +00:00
currentWallet . moneySpent . connect ( onWalletMoneySent )
currentWallet . moneyReceived . connect ( onWalletMoneyReceived )
2017-01-12 18:57:30 +00:00
currentWallet . unconfirmedMoneyReceived . connect ( onWalletUnconfirmedMoneyReceived )
2016-11-08 17:05:33 +00:00
currentWallet . transactionCreated . connect ( onTransactionCreated )
2016-11-26 14:50:04 +00:00
currentWallet . connectionStatusChanged . connect ( onWalletConnectionStatusChanged )
2019-03-27 08:28:42 +00:00
currentWallet . deviceButtonRequest . connect ( onDeviceButtonRequest ) ;
currentWallet . deviceButtonPressed . connect ( onDeviceButtonPressed ) ;
2020-04-11 10:43:21 +00:00
currentWallet . walletPassphraseNeeded . connect ( onWalletPassphraseNeededWallet ) ;
2019-05-02 08:11:43 +00:00
currentWallet . transactionCommitted . connect ( onTransactionCommitted ) ;
2020-07-30 21:26:40 +00:00
currentWallet . proxyAddress = Qt . binding ( persistentSettings . getWalletProxyAddress ) ;
2016-12-04 12:13:59 +00:00
middlePanel . paymentClicked . connect ( handlePayment ) ;
middlePanel . sweepUnmixableClicked . connect ( handleSweepUnmixable ) ;
2017-11-20 07:24:29 +00:00
middlePanel . getProofClicked . connect ( handleGetProof ) ;
middlePanel . checkProofClicked . connect ( handleCheckProof ) ;
2016-11-06 22:40:26 +00:00
2017-08-07 15:03:34 +00:00
2016-10-10 19:40:58 +00:00
console . log ( "Recovering from seed: " , persistentSettings . is_recovering )
console . log ( "restore Height" , persistentSettings . restore_height )
2017-02-25 21:16:58 +00:00
2021-04-03 10:45:02 +00:00
if ( persistentSettings . useRemoteNode ) {
const remoteNode = remoteNodesModel . currentRemoteNode ( ) ;
currentDaemonAddress = remoteNode . address ;
currentWallet . setDaemonLogin ( remoteNode . username , remoteNode . password ) ;
} else {
currentDaemonAddress = localDaemonAddress ;
}
2017-02-25 21:16:58 +00:00
2017-08-07 15:03:34 +00:00
console . log ( "initializing with daemon address: " , currentDaemonAddress )
2019-08-06 15:36:35 +00:00
currentWallet . initAsync (
currentDaemonAddress ,
isTrustedDaemon ( ) ,
0 ,
persistentSettings . is_recovering ,
persistentSettings . is_recovering_from_device ,
2020-07-30 21:26:40 +00:00
persistentSettings . restore_height ,
persistentSettings . getWalletProxyAddress ( ) ) ;
2018-06-04 08:05:29 +00:00
// save wallet keys in case wallet settings have been changed in the init
currentWallet . setPassword ( walletPassword ) ;
2016-08-19 11:44:44 +00:00
}
2019-08-06 15:36:35 +00:00
function isTrustedDaemon ( ) {
2021-04-03 10:45:02 +00:00
return ! persistentSettings . useRemoteNode || remoteNodesModel . currentRemoteNode ( ) . trusted ;
2019-08-06 15:36:35 +00:00
}
2017-01-03 20:54:40 +00:00
function usefulName ( path ) {
// arbitrary "short enough" limit
if ( path . length < 32 )
return path
return path . replace ( /.*[\/\\]/ , '' ) . replace ( /\.keys$/ , '' )
}
2019-12-19 00:16:00 +00:00
function getUnlockedBalance ( ) {
if ( ! currentWallet ) {
return 0
}
return currentWallet . unlockedBalance ( )
}
2017-12-11 11:15:16 +00:00
function updateBalance ( ) {
2017-07-04 03:34:09 +00:00
if ( ! currentWallet )
return ;
2018-12-12 08:33:24 +00:00
2019-09-06 13:52:45 +00:00
var balance = "?.??" ;
var balanceU = "?.??" ;
2020-06-24 02:02:27 +00:00
if ( ! hideBalanceForced && ! persistentSettings . hideBalance ) {
2019-12-19 00:16:00 +00:00
balance = walletManager . displayAmount ( currentWallet . balance ( ) ) ;
balanceU = walletManager . displayAmount ( currentWallet . unlockedBalance ( ) ) ;
2018-12-12 08:33:24 +00:00
}
2019-05-01 02:05:16 +00:00
if ( persistentSettings . fiatPriceEnabled ) {
2019-09-06 13:52:45 +00:00
appWindow . fiatApiUpdateBalance ( balance ) ;
2019-05-01 02:05:16 +00:00
}
2019-09-06 13:52:45 +00:00
leftPanel . minutesToUnlock = ( balance !== balanceU ) ? currentWallet.history.minutesToUnlock : "" ;
leftPanel . balanceString = balance
leftPanel . balanceUnlockedString = balanceU
2020-07-10 08:55:20 +00:00
if ( middlePanel . state === "Account" ) {
middlePanel . accountView . balanceAllText = walletManager . displayAmount ( appWindow . currentWallet . balanceAll ( ) ) ;
middlePanel . accountView . unlockedBalanceAllText = walletManager . displayAmount ( appWindow . currentWallet . unlockedBalanceAll ( ) ) ;
}
2017-12-11 11:15:16 +00:00
}
2019-03-22 20:02:08 +00:00
function onUriHandler ( uri ) {
if ( uri . startsWith ( "monero://" ) ) {
var address = uri . substring ( "monero://" . length ) ;
var params = { }
if ( address . length === 0 ) return ;
var spl = address . split ( "?" ) ;
if ( spl . length > 2 ) return ;
if ( spl . length >= 1 ) {
// parse additional params
address = spl [ 0 ] ;
if ( spl . length === 2 ) {
spl . shift ( ) ;
var item = spl [ 0 ] ;
var _spl = item . split ( "&" ) ;
for ( var param in _spl ) {
var _item = _spl [ param ] ;
if ( ! _item . indexOf ( "=" ) > 0 ) continue ;
var __spl = _item . split ( "=" ) ;
if ( __spl . length !== 2 ) continue ;
params [ __spl [ 0 ] ] = __spl [ 1 ] ;
}
}
}
// Fill fields
middlePanel . transferView . sendTo ( address , params [ "tx_payment_id" ] , params [ "tx_description" ] , params [ "tx_amount" ] ) ;
// Raise window
appWindow . raise ( ) ;
appWindow . show ( ) ;
}
}
2017-01-31 09:34:18 +00:00
function onWalletConnectionStatusChanged ( status ) {
2017-02-05 12:49:25 +00:00
console . log ( "Wallet connection status changed " + status )
2016-11-26 14:50:04 +00:00
middlePanel . updateStatus ( ) ;
2017-01-31 09:34:18 +00:00
leftPanel . networkStatus . connected = status
2020-05-02 14:34:54 +00:00
if ( status == Wallet . ConnectionStatus_Disconnected ) {
firstBlockSeen = 0 ;
}
2017-02-05 12:49:25 +00:00
2019-01-14 00:02:44 +00:00
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
2020-01-28 04:43:31 +00:00
if ( appWindow . walletMode >= 2 && ! persistentSettings . useRemoteNode && ! walletInitialized && disconnected ) {
2019-08-13 12:21:47 +00:00
daemonManager . runningAsync ( persistentSettings . nettype , function ( running ) {
if ( ! running ) {
daemonManagerDialog . open ( ) ;
}
} ) ;
2017-02-05 12:49:25 +00:00
}
// initialize transaction history once wallet is initialized first time;
if ( ! walletInitialized ) {
2017-07-04 03:34:09 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount )
2017-02-05 12:49:25 +00:00
walletInitialized = true
2018-12-28 04:42:37 +00:00
// check if daemon was already mining and add mining logo if true
2021-03-20 09:12:15 +00:00
middlePanel . advancedView . miningView . update ( ) ;
2017-02-05 12:49:25 +00:00
}
2019-01-14 00:02:44 +00:00
}
2016-11-26 14:50:04 +00:00
2019-03-27 08:28:42 +00:00
function onDeviceButtonRequest ( code ) {
2020-10-17 09:57:37 +00:00
if ( txConfirmationPopup . visible ) {
txConfirmationPopup . bottomTextAnimation . running = true
if ( ! txConfirmationPopup . errorText . visible ) {
txConfirmationPopup . bottomText . text = qsTr ( "Please confirm transaction on the device..." ) + translationManager . emptyString ;
} else {
txConfirmationPopup . bottomText . text = qsTr ( "Please proceed to the device..." ) + translationManager . emptyString ;
}
} else {
prevSplashText = splash . messageText ;
splashDisplayedBeforeButtonRequest = splash . visible ;
appWindow . showProcessingSplash ( qsTr ( "Please proceed to the device..." ) ) ;
}
2019-03-27 08:28:42 +00:00
}
function onDeviceButtonPressed ( ) {
2020-10-17 09:57:37 +00:00
if ( txConfirmationPopup . visible ) {
txConfirmationPopup . bottomTextAnimation . running = false ;
txConfirmationPopup . bottomText . text = qsTr ( "Signing transaction in the device..." ) + translationManager . emptyString ;
2019-03-27 08:28:42 +00:00
} else {
2020-10-17 09:57:37 +00:00
if ( splashDisplayedBeforeButtonRequest ) {
appWindow . showProcessingSplash ( prevSplashText ) ;
} else {
hideProcessingSplash ( ) ;
}
2019-03-27 08:28:42 +00:00
}
}
function onWalletOpening ( ) {
appWindow . showProcessingSplash ( qsTr ( "Opening wallet ..." ) ) ;
}
2016-08-18 18:55:34 +00:00
function onWalletOpened ( wallet ) {
2019-03-27 08:28:42 +00:00
hideProcessingSplash ( ) ;
2017-01-03 20:54:40 +00:00
walletName = usefulName ( wallet . path )
2016-08-18 18:55:34 +00:00
console . log ( ">>> wallet opened: " + wallet )
if ( wallet . status !== Wallet . Status_Ok ) {
2019-03-12 07:25:46 +00:00
// try to resolve common wallet cache errors automatically
switch ( wallet . errorString ) {
case "basic_string::_M_replace_aux" :
case "std::bad_alloc" :
walletManager . clearWalletCache ( wallet . path ) ;
walletPassword = passwordDialog . password ;
appWindow . initialize ( ) ;
console . error ( "Repairing wallet cache with error: " , wallet . errorString ) ;
appWindow . showStatusMessage ( qsTr ( "Repairing incompatible wallet cache. Resyncing wallet." ) , 6 ) ;
return ;
default:
// opening with password but password doesn't match
console . error ( "Error opening wallet with password: " , wallet . errorString ) ;
passwordDialog . showError ( qsTr ( "Couldn't open wallet: " ) + wallet . errorString ) ;
console . log ( "closing wallet async : " + wallet . address )
closeWallet ( ) ;
return ;
}
2016-08-18 18:55:34 +00:00
}
// wallet opened successfully, subscribing for wallet updates
2016-08-19 11:44:44 +00:00
connectWallet ( wallet )
2019-01-14 00:02:44 +00:00
// Force switch normal view
rootItem . state = "normal" ;
2019-03-22 20:02:08 +00:00
// Process queued IPC command
if ( typeof IPC !== "undefined" && IPC . queuedCmd ( ) . length > 0 ) {
var queuedCmd = IPC . queuedCmd ( ) ;
if ( /^\w+:\/\/(.*)$/ . test ( queuedCmd ) ) appWindow . onUriHandler ( queuedCmd ) ; // uri
}
2016-08-18 18:55:34 +00:00
}
2020-04-11 10:43:21 +00:00
function onWalletPassphraseNeededManager ( on_device ) {
onWalletPassphraseNeeded ( walletManager , on_device )
}
function onWalletPassphraseNeededWallet ( on_device ) {
onWalletPassphraseNeeded ( currentWallet , on_device )
}
function onWalletPassphraseNeeded ( handler , on_device ) {
2019-03-27 08:28:42 +00:00
hideProcessingSplash ( ) ;
console . log ( ">>> wallet passphrase needed: " )
2020-04-11 10:43:21 +00:00
devicePassphraseDialog . onAcceptedCallback = function ( passphrase ) {
handler . onPassphraseEntered ( passphrase , false , false ) ;
2020-02-27 17:39:35 +00:00
appWindow . onWalletOpening ( ) ;
2019-03-27 08:28:42 +00:00
}
2020-04-11 10:43:21 +00:00
devicePassphraseDialog . onWalletEntryCallback = function ( ) {
handler . onPassphraseEntered ( "" , true , false ) ;
2020-02-27 17:39:35 +00:00
appWindow . onWalletOpening ( ) ;
2019-03-27 08:28:42 +00:00
}
2020-04-11 10:43:21 +00:00
devicePassphraseDialog . onRejectedCallback = function ( ) {
handler . onPassphraseEntered ( "" , false , true ) ;
appWindow . onWalletOpening ( ) ;
}
devicePassphraseDialog . open ( on_device )
2019-03-27 08:28:42 +00:00
}
2016-06-17 13:35:07 +00:00
function onWalletUpdate ( ) {
2016-07-13 12:24:40 +00:00
console . log ( ">>> wallet updated" )
2017-12-11 11:15:16 +00:00
updateBalance ( ) ;
2017-03-04 23:05:31 +00:00
// Update history if new block found since last update
if ( foundNewBlock ) {
2017-01-13 22:21:58 +00:00
foundNewBlock = false ;
console . log ( "New block found - updating history" )
2017-07-04 03:34:09 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount )
2019-03-17 23:12:51 +00:00
if ( middlePanel . state == "History" )
middlePanel . historyView . update ( ) ;
2017-01-13 22:21:58 +00:00
}
2016-07-13 12:24:40 +00:00
}
2017-08-07 15:03:34 +00:00
function connectRemoteNode ( ) {
console . log ( "connecting remote node" ) ;
2019-11-24 10:04:42 +00:00
const callback = function ( ) {
persistentSettings . useRemoteNode = true ;
2021-04-03 10:45:02 +00:00
const remoteNode = remoteNodesModel . currentRemoteNode ( ) ;
currentDaemonAddress = remoteNode . address ;
currentWallet . setDaemonLogin ( remoteNode . username , remoteNode . password ) ;
2020-07-30 21:26:40 +00:00
currentWallet . initAsync (
currentDaemonAddress ,
isTrustedDaemon ( ) ,
0 ,
false ,
false ,
0 ,
persistentSettings . getWalletProxyAddress ( ) ) ;
2019-11-24 10:04:42 +00:00
walletManager . setDaemonAddressAsync ( currentDaemonAddress ) ;
} ;
if ( typeof daemonManager != "undefined" && daemonRunning ) {
showDaemonIsRunningDialog ( callback ) ;
} else {
callback ( ) ;
}
2017-08-07 15:03:34 +00:00
}
function disconnectRemoteNode ( ) {
2019-05-02 12:57:44 +00:00
if ( typeof currentWallet === "undefined" || currentWallet === null )
return ;
2017-08-07 15:03:34 +00:00
console . log ( "disconnecting remote node" ) ;
persistentSettings . useRemoteNode = false ;
currentDaemonAddress = localDaemonAddress
2021-04-03 10:45:02 +00:00
currentWallet . setDaemonLogin ( "" , "" ) ;
2020-07-30 21:26:40 +00:00
currentWallet . initAsync (
currentDaemonAddress ,
isTrustedDaemon ( ) ,
0 ,
false ,
false ,
0 ,
persistentSettings . getWalletProxyAddress ( ) ) ;
2019-05-27 22:13:53 +00:00
walletManager . setDaemonAddressAsync ( currentDaemonAddress ) ;
2020-05-02 14:34:54 +00:00
firstBlockSeen = 0 ;
2017-08-07 15:03:34 +00:00
}
2019-06-13 12:19:52 +00:00
function onHeightRefreshed ( bcHeight , dCurrentBlock , dTargetBlock ) {
2016-11-01 23:17:58 +00: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 17:07:46 +00:00
// targetBlock = currentBlock = 1 before network connection is established.
2020-05-02 14:34:54 +00:00
if ( firstBlockSeen == 0 && dTargetBlock != 1 ) {
firstBlockSeen = dCurrentBlock ;
}
2017-02-24 17:07:46 +00:00
daemonSynced = dCurrentBlock >= dTargetBlock && dTargetBlock != 1
2018-03-20 18:19:30 +00:00
walletSynced = bcHeight >= dTargetBlock
// Update progress bars
if ( ! daemonSynced ) {
2020-05-02 14:34:54 +00:00
leftPanel . daemonProgressBar . updateProgress ( dCurrentBlock , dTargetBlock , dTargetBlock - firstBlockSeen ) ;
2018-03-15 15:35:47 +00:00
leftPanel . progressBar . updateProgress ( 0 , dTargetBlock , dTargetBlock , qsTr ( "Waiting for daemon to sync" ) ) ;
2018-03-20 18:19:30 +00:00
} else {
leftPanel . daemonProgressBar . updateProgress ( dCurrentBlock , dTargetBlock , 0 , qsTr ( "Daemon is synchronized (%1)" ) . arg ( dCurrentBlock . toFixed ( 0 ) ) ) ;
if ( walletSynced )
leftPanel . progressBar . updateProgress ( bcHeight , dTargetBlock , dTargetBlock - bcHeight , qsTr ( "Wallet is synchronized" ) )
}
2017-01-31 09:34:18 +00:00
// Update wallet sync progress
2020-01-28 04:43:31 +00:00
leftPanel . isSyncing = ! disconnected && ! daemonSynced ;
2017-01-31 09:34:18 +00:00
// Update transfer page status
2016-11-27 12:35:27 +00:00
middlePanel . updateStatus ( ) ;
2016-11-01 23:17:58 +00:00
2016-11-10 11:11:25 +00:00
// Refresh is succesfull if blockchain height > 1
2018-03-20 18:19:30 +00:00
if ( bcHeight > 1 ) {
2016-10-27 22:24:02 +00:00
// recovering from seed is finished after first refresh
if ( persistentSettings . is_recovering ) {
persistentSettings . is_recovering = false
}
2019-04-20 05:38:55 +00:00
if ( persistentSettings . is_recovering_from_device ) {
persistentSettings . is_recovering_from_device = false ;
}
2016-10-27 22:24:02 +00:00
}
2017-08-08 10:23:01 +00:00
// Update history on every refresh if it's empty
if ( currentWallet . history . count == 0 )
2017-07-04 03:34:09 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount )
2017-08-08 10:23:01 +00:00
2016-07-14 10:09:39 +00:00
onWalletUpdate ( ) ;
2016-06-15 13:34:55 +00:00
}
2019-06-13 12:19:52 +00:00
function onWalletRefresh ( ) {
console . log ( ">>> wallet refreshed" )
// Daemon connected
2019-12-14 02:37:44 +00:00
leftPanel . networkStatus . connected = currentWallet ? currentWallet . connected ( ) : Wallet . ConnectionStatus_Disconnected
2019-06-13 12:19:52 +00:00
currentWallet . refreshHeightAsync ( ) ;
}
2016-12-21 13:30:15 +00:00
function startDaemon ( flags ) {
2020-10-14 02:24:22 +00:00
daemonStartStopInProgress = 1 ;
2020-05-07 13:40:43 +00:00
2017-02-25 19:25:16 +00:00
// Pause refresh while starting daemon
currentWallet . pauseRefresh ( ) ;
2019-09-02 21:32:36 +00:00
const noSync = appWindow . walletMode === 0 ;
2020-02-16 13:54:57 +00:00
const bootstrapNodeAddress = persistentSettings . walletMode < 2 ? "auto" : persistentSettings . bootstrapNodeAddress
2021-04-05 23:56:19 +00:00
daemonManager . start ( flags , persistentSettings . nettype , persistentSettings . blockchainDataDir , bootstrapNodeAddress , noSync , persistentSettings . pruneBlockchain ) ;
2016-11-26 10:31:27 +00:00
}
2016-11-26 16:01:29 +00:00
2020-10-14 02:24:22 +00:00
function stopDaemon ( callback , splash ) {
daemonStartStopInProgress = 2 ;
if ( splash ) {
appWindow . showProcessingSplash ( qsTr ( "Waiting for daemon to stop..." ) ) ;
}
2020-02-16 15:01:17 +00:00
daemonManager . stopAsync ( persistentSettings . nettype , function ( result ) {
2020-10-14 02:24:22 +00:00
daemonStartStopInProgress = 0 ;
if ( splash ) {
hideProcessingSplash ( ) ;
}
2020-02-16 15:01:17 +00:00
callback ( result ) ;
} ) ;
2016-11-26 10:31:27 +00:00
}
2016-11-25 20:09:32 +00:00
function onDaemonStarted ( ) {
console . log ( "daemon started" ) ;
2020-10-14 02:24:22 +00:00
daemonStartStopInProgress = 0 ;
2017-02-25 13:57:39 +00:00
currentWallet . connected ( true ) ;
2017-02-25 19:25:16 +00:00
// resume refresh
currentWallet . startRefresh ( ) ;
2019-01-14 00:02:44 +00:00
// resume simplemode connection timer
2019-10-09 02:02:58 +00:00
appWindow . disconnectedEpoch = Utils . epoch ( ) ;
2016-11-25 20:09:32 +00:00
}
function onDaemonStopped ( ) {
2017-02-23 18:47:58 +00:00
currentWallet . connected ( true ) ;
2016-11-25 20:09:32 +00:00
}
2020-02-04 23:27:48 +00:00
function onDaemonStartFailure ( error ) {
2017-02-25 19:25:16 +00:00
console . log ( "daemon start failed" ) ;
2020-10-14 02:24:22 +00:00
daemonStartStopInProgress = 0 ;
2017-02-25 19:25:16 +00:00
// resume refresh
currentWallet . startRefresh ( ) ;
informationPopup . title = qsTr ( "Daemon failed to start" ) + translationManager . emptyString ;
2020-02-04 23:27:48 +00:00
informationPopup . text = error + ".\n\n" + qsTr ( "Please check your wallet and daemon log for errors. You can also try to start %1 manually." ) . arg ( ( isWindows ) ? "monerod.exe" : "monerod" )
2017-02-25 19:25:16 +00:00
informationPopup . icon = StandardIcon . Critical
informationPopup . onCloseCallback = null
informationPopup . open ( ) ;
}
2017-01-31 09:34:18 +00:00
function onWalletNewBlock ( blockHeight , targetHeight ) {
// Update progress bar
2017-02-24 20:51:37 +00:00
var remaining = targetHeight - blockHeight ;
if ( blocksToSync < remaining ) {
blocksToSync = remaining ;
}
leftPanel . progressBar . updateProgress ( blockHeight , targetHeight , blocksToSync ) ;
2018-03-20 18:19:30 +00:00
// If wallet is syncing, daemon is already synced
leftPanel . daemonProgressBar . updateProgress ( 1 , 1 , 0 , qsTr ( "Daemon is synchronized" ) ) ;
2017-01-31 09:34:18 +00:00
foundNewBlock = true ;
2016-09-26 19:55:25 +00:00
}
2016-10-06 21:47:28 +00:00
function onWalletMoneyReceived ( txId , amount ) {
// refresh transaction history here
2017-08-08 10:23:01 +00:00
console . log ( "Confirmed money found" )
// history refresh is handled by walletUpdated
2017-07-04 03:34:09 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount ) // this will refresh model
currentWallet . subaddress . refresh ( currentWallet . currentSubaddressAccount )
2019-03-17 23:12:51 +00:00
if ( middlePanel . state == "History" )
middlePanel . historyView . update ( ) ;
2016-10-06 21:47:28 +00:00
}
2017-01-12 18:57:30 +00:00
function onWalletUnconfirmedMoneyReceived ( txId , amount ) {
// refresh history
2017-01-13 22:21:58 +00:00
console . log ( "unconfirmed money found" )
2019-03-17 23:12:51 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount ) ;
if ( middlePanel . state == "History" )
middlePanel . historyView . update ( ) ;
2017-01-12 18:57:30 +00:00
}
2016-10-06 21:47:28 +00:00
function onWalletMoneySent ( txId , amount ) {
// refresh transaction history here
2018-03-23 22:53:29 +00:00
console . log ( "monero sent found" )
2019-03-17 23:12:51 +00:00
currentWallet . history . refresh ( currentWallet . currentSubaddressAccount ) ; // this will refresh model
if ( middlePanel . state == "History" )
middlePanel . historyView . update ( ) ;
2016-10-06 21:47:28 +00:00
}
2016-06-07 13:26:25 +00:00
function walletsFound ( ) {
2016-10-30 16:58:12 +00:00
if ( persistentSettings . wallet_path . length > 0 ) {
2017-04-03 16:51:55 +00:00
if ( isIOS )
2020-07-28 17:42:59 +00:00
return walletManager . walletExists ( appWindow . accountsDir + persistentSettings . wallet_path ) ;
2017-04-03 16:51:55 +00:00
else
return walletManager . walletExists ( persistentSettings . wallet_path ) ;
2016-06-07 13:26:25 +00:00
}
2016-11-13 13:14:26 +00:00
return false ;
2016-06-07 13:26:25 +00:00
}
2021-01-25 11:57:49 +00:00
function onTransactionCreated ( pendingTransaction , addresses , paymentId , mixinCount ) {
2016-11-08 17:05:33 +00:00
console . log ( "Transaction created" ) ;
2020-10-17 09:57:37 +00:00
txConfirmationPopup . bottomText . text = "" ;
2016-11-08 17:05:33 +00:00
transaction = pendingTransaction ;
// validate address;
if ( transaction . status !== PendingTransaction . Status_Ok ) {
console . error ( "Can't create transaction: " , transaction . errorString ) ;
2020-10-17 09:57:37 +00:00
if ( currentWallet . connected ( ) == Wallet . ConnectionStatus_WrongVersion ) {
txConfirmationPopup . errorText . text = qsTr ( "Can't create transaction: Wrong daemon version: " ) + transaction . errorString
} else {
txConfirmationPopup . errorText . text = qsTr ( "Can't create transaction: " ) + transaction . errorString
}
2016-11-08 17:05:33 +00:00
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
2016-11-11 21:54:17 +00:00
} else if ( transaction . txCount == 0 ) {
2020-10-17 09:57:37 +00:00
console . error ( "Can't create transaction: " , transaction . errorString ) ;
txConfirmationPopup . errorText . text = qsTr ( "No unmixable outputs to sweep" ) + translationManager . emptyString
2016-11-11 21:54:17 +00:00
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
2016-11-08 17:05:33 +00:00
} else {
console . log ( "Transaction created, amount: " + walletManager . displayAmount ( transaction . amount )
+ ", fee: " + walletManager . displayAmount ( transaction . fee ) ) ;
2020-10-17 09:57:37 +00:00
// here we update txConfirmationPopup
txConfirmationPopup . transactionAmount = Utils . removeTrailingZeros ( walletManager . displayAmount ( transaction . amount ) ) ;
txConfirmationPopup . transactionFee = Utils . removeTrailingZeros ( walletManager . displayAmount ( transaction . fee ) ) ;
txConfirmationPopup . confirmButton . text = viewOnly ? qsTr ( "Save as file" ) : qsTr ( "Confirm" ) + translationManager . emptyString ;
txConfirmationPopup . confirmButton . rightIcon = viewOnly ? "" : "qrc:///images/rightArrow.png"
2016-11-08 17:05:33 +00:00
}
}
2016-08-17 12:14:43 +00:00
2021-02-02 16:00:46 +00:00
function getDisplayAmountTotal ( recipients ) {
const amounts = recipients . map ( function ( recipient ) {
return recipient . amount ;
} ) ;
const total = walletManager . amountsSumFromStrings ( amounts ) ;
return Utils . removeTrailingZeros ( walletManager . displayAmount ( total ) ) ;
}
2016-08-17 12:14:43 +00:00
2016-06-28 19:37:14 +00:00
// called on "transfer"
2021-02-02 16:00:46 +00:00
function handlePayment ( recipients , paymentId , mixinCount , priority , description , createFile ) {
2016-06-27 12:45:48 +00:00
console . log ( "Creating transaction: " )
2021-02-02 16:00:46 +00:00
console . log ( "\trecipients: " , recipients ,
2016-06-27 12:45:48 +00:00
", payment_id: " , paymentId ,
", mixins: " , mixinCount ,
2016-11-05 23:19:28 +00:00
", priority: " , priority ,
", description: " , description ) ;
2016-11-12 13:28:13 +00:00
2021-02-02 16:00:46 +00:00
const recipientAll = recipients . find ( function ( recipient ) {
return recipient . amount == "(all)" ;
} ) ;
if ( recipientAll && recipients . length > 1 ) {
throw "Sending all requires one destination address" ;
2016-08-23 13:07:52 +00:00
}
2021-02-02 16:00:46 +00:00
txConfirmationPopup . bottomTextAnimation . running = false ;
txConfirmationPopup . bottomText . text = qsTr ( "Creating transaction..." ) + translationManager . emptyString ;
txConfirmationPopup . recipients = recipients ;
txConfirmationPopup . transactionAmount = recipientAll ? "(all)" : getDisplayAmountTotal ( recipients ) ;
txConfirmationPopup . transactionPriority = priority ;
txConfirmationPopup . transactionDescription = description ;
2020-10-17 09:57:37 +00:00
txConfirmationPopup . open ( ) ;
2021-02-02 16:00:46 +00:00
if ( recipientAll ) {
currentWallet . createTransactionAllAsync ( recipientAll . address , paymentId , mixinCount , priority ) ;
} else {
const addresses = recipients . map ( function ( recipient ) {
return recipient . address ;
} ) ;
const amountsxmr = recipients . map ( function ( recipient ) {
2021-04-13 05:27:05 +00:00
return recipient . amount ;
2021-02-02 16:00:46 +00:00
} ) ;
currentWallet . createTransactionAsync ( addresses , paymentId , amountsxmr , mixinCount , priority ) ;
}
2016-06-28 19:37:14 +00:00
}
2017-01-12 19:53:27 +00:00
//Choose where to save transaction
FileDialog {
id: saveTxDialog
title: "Please choose a location"
2020-07-28 17:42:59 +00:00
folder: "file://" + appWindow . accountsDir
2017-01-12 19:53:27 +00:00
selectExisting: false ;
onAccepted: {
handleTransactionConfirmed ( )
}
onRejected: {
// do nothing
}
}
2016-11-08 20:23:50 +00:00
function handleSweepUnmixable ( ) {
console . log ( "Creating transaction: " )
2020-10-17 09:57:37 +00:00
txConfirmationPopup . sweepUnmixable = true ;
2016-11-08 20:23:50 +00:00
transaction = currentWallet . createSweepUnmixableTransaction ( ) ;
if ( transaction . status !== PendingTransaction . Status_Ok ) {
console . error ( "Can't create transaction: " , transaction . errorString ) ;
2020-10-17 09:57:37 +00:00
txConfirmationPopup . errorText . text = qsTr ( "Can't create transaction: " ) + transaction . errorString + translationManager . emptyString
2016-11-08 20:23:50 +00:00
// deleting transaction object, we don't want memleaks
currentWallet . disposeTransaction ( transaction ) ;
} else if ( transaction . txCount == 0 ) {
2020-10-17 09:57:37 +00:00
console . error ( "No unmixable outputs to sweep" ) ;
txConfirmationPopup . errorText . text = qsTr ( "No unmixable outputs to sweep" ) + translationManager . emptyString
2016-11-08 20:23:50 +00:00
// 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 ) ) ;
2020-10-17 09:57:37 +00:00
txConfirmationPopup . transactionAmount = Utils . removeTrailingZeros ( walletManager . displayAmount ( transaction . amount ) ) ;
txConfirmationPopup . transactionFee = Utils . removeTrailingZeros ( walletManager . displayAmount ( transaction . fee ) ) ;
2016-11-08 20:23:50 +00:00
// committing transaction
}
2020-10-17 09:57:37 +00:00
txConfirmationPopup . open ( ) ;
2016-11-08 20:23:50 +00:00
}
2016-06-28 19:37:14 +00:00
// called after user confirms transaction
2017-01-12 19:53:27 +00:00
function handleTransactionConfirmed ( fileName ) {
// View only wallet - we save the tx
2021-04-26 11:17:59 +00:00
if ( viewOnly ) {
2017-01-12 19:53:27 +00:00
// No file specified - abort
if ( ! saveTxDialog . fileUrl ) {
currentWallet . disposeTransaction ( transaction )
return ;
}
var path = walletManager . urlToLocalPath ( saveTxDialog . fileUrl )
// Store to file
transaction . setFilename ( path ) ;
}
2020-12-10 23:59:12 +00:00
appWindow . showProcessingSplash ( qsTr ( "Sending transaction ..." ) ) ;
2019-05-02 08:11:43 +00:00
currentWallet . commitTransactionAsync ( transaction ) ;
}
function onTransactionCommitted ( success , transaction , txid ) {
2020-12-10 23:59:12 +00:00
hideProcessingSplash ( ) ;
2019-05-02 08:11:43 +00:00
if ( ! success ) {
2016-06-28 19:37:14 +00:00
console . log ( "Error committing transaction: " + transaction . errorString ) ;
2016-07-20 19:28:11 +00:00
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString
2016-06-28 19:37:14 +00:00
informationPopup . text = qsTr ( "Couldn't send the money: " ) + transaction . errorString
informationPopup . icon = StandardIcon . Critical
2020-10-10 14:26:20 +00:00
informationPopup . onCloseCallback = null ;
informationPopup . open ( ) ;
2016-06-28 19:37:14 +00:00
} else {
2020-10-17 09:57:37 +00:00
if ( txConfirmationPopup . transactionDescription . length > 0 ) {
2016-11-05 23:19:28 +00:00
for ( var i = 0 ; i < txid . length ; ++ i )
2020-10-17 09:57:37 +00:00
currentWallet . setUserNote ( txid [ i ] , txConfirmationPopup . transactionDescription ) ;
2016-11-05 23:19:28 +00:00
}
2017-02-04 13:44:30 +00:00
// Clear tx fields
middlePanel . transferView . clearFields ( )
2020-10-17 09:57:37 +00:00
txConfirmationPopup . clearFields ( )
2020-09-29 21:31:12 +00:00
successfulTxPopup . open ( txid )
2016-06-16 14:13:46 +00:00
}
2016-08-23 13:07:52 +00:00
currentWallet . refresh ( )
currentWallet . disposeTransaction ( transaction )
2020-04-26 02:23:51 +00:00
currentWallet . storeAsync ( function ( success ) {
if ( ! success ) {
appWindow . showStatusMessage ( qsTr ( "Failed to store the wallet" ) , 3 ) ;
}
} ) ;
2016-06-16 14:13:46 +00:00
}
2020-11-04 00:43:59 +00:00
function doSearchInHistory ( searchTerm ) {
middlePanel . searchInHistory ( searchTerm ) ;
leftPanel . selectItem ( middlePanel . state )
}
2017-11-20 07:24:29 +00:00
// called on "getProof"
function handleGetProof ( txid , address , message ) {
2017-09-12 08:42:00 +00:00
console . log ( "Getting payment proof: " )
console . log ( "\ttxid: " , txid ,
", address: " , address ,
", message: " , message ) ;
2016-11-05 14:58:49 +00:00
2019-06-18 11:15:39 +00:00
function spendProofFallback ( txid , result ) {
if ( ! result || result . indexOf ( "error|" ) === 0 ) {
currentWallet . getSpendProofAsync ( txid , message , txProofComputed ) ;
} else {
txProofComputed ( txid , result ) ;
}
}
2017-11-20 07:12:36 +00:00
if ( address . length > 0 )
2019-06-18 11:15:39 +00:00
currentWallet . getTxProofAsync ( txid , address , message , spendProofFallback ) ;
else
spendProofFallback ( txid , null ) ;
}
function txProofComputed ( txid , result ) {
2017-09-12 08:42:00 +00:00
informationPopup . title = qsTr ( "Payment proof" ) + translationManager . emptyString ;
2018-02-20 03:10:19 +00:00
if ( result . indexOf ( "error|" ) === 0 ) {
2017-09-12 08:42:00 +00:00
var errorString = result . split ( "|" ) [ 1 ] ;
informationPopup . text = qsTr ( "Couldn't generate a proof because of the following reason: \n" ) + errorString + translationManager . emptyString ;
informationPopup . icon = StandardIcon . Critical ;
} else {
informationPopup . text = result ;
informationPopup . icon = StandardIcon . Critical ;
2016-11-05 14:58:49 +00:00
}
2017-09-12 08:42:00 +00:00
informationPopup . onCloseCallback = null
informationPopup . open ( )
}
2017-11-20 07:24:29 +00:00
// called on "checkProof"
function handleCheckProof ( txid , address , message , signature ) {
2017-09-12 08:42:00 +00:00
console . log ( "Checking payment proof: " )
console . log ( "\ttxid: " , txid ,
", address: " , address ,
", message: " , message ,
", signature: " , signature ) ;
2017-11-20 07:12:36 +00:00
var result ;
if ( address . length > 0 )
result = currentWallet . checkTxProof ( txid , address , message , signature ) ;
else
result = currentWallet . checkSpendProof ( txid , message , signature ) ;
2017-09-12 08:42:00 +00:00
var results = result . split ( "|" ) ;
2017-11-20 07:12:36 +00:00
if ( address . length > 0 && results . length == 5 && results [ 0 ] === "true" ) {
var good = results [ 1 ] === "true" ;
2017-09-12 08:42:00 +00:00
var received = results [ 2 ] ;
2017-11-20 07:12:36 +00:00
var in_pool = results [ 3 ] === "true" ;
2017-09-12 08:42:00 +00:00
var confirmations = results [ 4 ] ;
informationPopup . title = qsTr ( "Payment proof check" ) + translationManager . emptyString ;
2016-11-05 14:58:49 +00:00
informationPopup . icon = StandardIcon . Information
2017-09-12 08:42:00 +00:00
if ( ! good ) {
informationPopup . text = qsTr ( "Bad signature" ) ;
informationPopup . icon = StandardIcon . Critical ;
} else if ( received > 0 ) {
if ( in_pool ) {
2019-01-08 09:07:50 +00:00
informationPopup . text = qsTr ( "This address received %1 monero, but the transaction is not yet mined" ) . arg ( walletManager . displayAmount ( received ) ) ;
2016-11-05 14:58:49 +00:00
}
else {
2019-01-08 09:07:50 +00:00
informationPopup . text = qsTr ( "This address received %1 monero, with %2 confirmation(s)." ) . arg ( walletManager . displayAmount ( received ) ) . arg ( confirmations ) ;
2016-11-05 14:58:49 +00:00
}
}
else {
informationPopup . text = qsTr ( "This address received nothing" ) ;
}
}
2017-11-20 07:12:36 +00:00
else if ( results . length == 2 && results [ 0 ] === "true" ) {
var good = results [ 1 ] === "true" ;
informationPopup . title = qsTr ( "Payment proof check" ) + translationManager . emptyString ;
informationPopup . icon = good ? StandardIcon.Information : StandardIcon . Critical ;
informationPopup . text = good ? qsTr ( "Good signature" ) : qsTr ( "Bad signature" ) ;
}
2016-11-05 14:58:49 +00:00
else {
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
2017-09-12 08:42:00 +00:00
informationPopup . text = currentWallet . errorString ;
2016-11-05 14:58:49 +00:00
informationPopup . icon = StandardIcon . Critical
}
2017-09-12 08:42:00 +00:00
informationPopup . onCloseCallback = null
2016-11-05 14:58:49 +00:00
informationPopup . open ( )
}
2016-08-23 08:55:51 +00:00
function showProcessingSplash ( message ) {
console . log ( "Displaying processing splash" )
if ( typeof message != 'undefined' ) {
2016-11-08 17:05:33 +00:00
splash . messageText = message
2016-08-23 08:55:51 +00:00
}
2019-04-11 01:17:29 +00:00
leftPanel . enabled = false ;
middlePanel . enabled = false ;
titleBar . enabled = false ;
splash . show ( ) ;
2016-08-23 08:55:51 +00:00
}
function hideProcessingSplash ( ) {
console . log ( "Hiding processing splash" )
2019-04-11 01:17:29 +00:00
splash . close ( ) ;
2019-07-15 19:56:57 +00:00
if ( ! passwordDialog . visible ) {
leftPanel . enabled = true
middlePanel . enabled = true
titleBar . enabled = true
}
2016-08-23 08:55:51 +00:00
}
2016-10-29 14:48:10 +00:00
// close wallet and show wizard
function showWizard ( ) {
2016-10-29 14:59:31 +00:00
walletInitialized = false ;
2019-07-02 10:57:37 +00:00
closeWallet ( function ( ) {
wizard . restart ( ) ;
wizard . wizardState = "wizardHome" ;
rootItem . state = "wizard"
2020-05-06 16:35:33 +00:00
// reset balance, clear spendable funds message
2019-09-06 13:52:45 +00:00
clearMoneroCardLabelText ( ) ;
2020-05-06 16:35:33 +00:00
leftPanel . minutesToUnlock = "" ;
// reset fields
2019-12-20 19:28:17 +00:00
middlePanel . addressBookView . clearFields ( ) ;
middlePanel . transferView . clearFields ( ) ;
middlePanel . receiveView . clearFields ( ) ;
2020-11-04 00:43:59 +00:00
middlePanel . historyView . clearFields ( ) ;
2019-07-02 10:57:37 +00:00
// disable timers
userInActivityTimer . running = false ;
} ) ;
2016-10-29 14:48:10 +00:00
}
2016-08-17 12:14:43 +00:00
objectName: "appWindow"
2014-07-07 17:08:30 +00:00
visible: true
2021-04-15 19:00:36 +00:00
width: screenAvailableWidth > 980
2021-01-13 03:14:57 +00:00
? 980
2021-04-15 19:00:36 +00:00
: Math . min ( screenAvailableWidth , 800 )
height: screenAvailableHeight > maxWindowHeight
2021-01-13 03:14:57 +00:00
? maxWindowHeight
2021-04-15 19:00:36 +00:00
: Math . min ( screenAvailableHeight , 700 )
2019-04-11 01:17:29 +00:00
color: MoneroComponents . Style . appWindowBackgroundColor
2018-04-21 19:58:00 +00:00
flags: persistentSettings . customDecorations ? Windows.flagsCustomDecorations : Windows . flags
2014-07-19 14:07:40 +00:00
2019-05-01 02:05:16 +00:00
Timer {
id: fiatPriceTimer
interval: 1000 * 60 ;
running: persistentSettings . fiatPriceEnabled ;
repeat: true
onTriggered: {
if ( persistentSettings . fiatPriceEnabled )
appWindow . fiatApiRefresh ( ) ;
}
triggeredOnStart: false
}
2020-04-04 13:22:25 +00:00
function fiatApiParseTicker ( url , resp , currency ) {
2019-05-01 02:05:16 +00:00
// parse & validate incoming JSON
2020-03-31 16:29:28 +00:00
if ( url . startsWith ( "https://api.kraken.com/0/" ) ) {
2019-05-01 02:05:16 +00:00
if ( resp . hasOwnProperty ( "error" ) && resp . error . length > 0 || ! resp . hasOwnProperty ( "result" ) ) {
appWindow . fiatApiError ( "Kraken API has error(s)" ) ;
return ;
}
var key = currency === "xmreur" ? "XXMRZEUR" : "XXMRZUSD" ;
2021-01-10 23:29:48 +00:00
var ticker = resp . result [ key ] [ "c" ] [ 0 ] ;
2019-05-01 02:05:16 +00:00
return ticker ;
2020-03-31 16:29:28 +00:00
} else if ( url . startsWith ( "https://api.coingecko.com/api/v3/" ) ) {
2019-05-01 02:05:16 +00:00
var key = currency === "xmreur" ? "eur" : "usd" ;
if ( ! resp . hasOwnProperty ( "monero" ) || ! resp [ "monero" ] . hasOwnProperty ( key ) ) {
appWindow . fiatApiError ( "Coingecko API has error(s)" ) ;
return ;
}
return resp [ "monero" ] [ key ] ;
2020-03-31 16:29:28 +00:00
} else if ( url . startsWith ( "https://min-api.cryptocompare.com/data/" ) ) {
2019-05-01 02:05:16 +00:00
var key = currency === "xmreur" ? "EUR" : "USD" ;
if ( ! resp . hasOwnProperty ( key ) ) {
appWindow . fiatApiError ( "cryptocompare API has error(s)" ) ;
return ;
}
return resp [ key ] ;
}
}
2020-03-31 16:29:28 +00:00
function fiatApiGetCurrency ( url ) {
2019-05-01 02:05:16 +00:00
var apis = appWindow . fiatPriceAPIs ;
for ( var api in apis ) {
if ( ! apis . hasOwnProperty ( api ) )
continue ;
for ( var cur in apis [ api ] ) {
if ( ! apis [ api ] . hasOwnProperty ( cur ) )
continue ;
2020-03-31 16:29:28 +00:00
if ( apis [ api ] [ cur ] === url ) {
2019-05-01 02:05:16 +00:00
return cur ;
}
}
}
}
2020-03-31 16:29:28 +00:00
function fiatApiJsonReceived ( url , resp , error ) {
2020-04-04 13:22:25 +00:00
if ( error ) {
2020-03-31 16:29:28 +00:00
appWindow . fiatApiError ( error ) ;
return ;
}
try {
resp = JSON . parse ( resp ) ;
} catch ( e ) {
appWindow . fiatApiError ( "bad JSON: " + e ) ;
return ;
}
2019-05-01 02:05:16 +00:00
// handle incoming JSON, set ticker
2020-03-31 16:29:28 +00:00
var currency = appWindow . fiatApiGetCurrency ( url ) ;
2019-05-01 02:05:16 +00:00
if ( typeof currency == "undefined" ) {
appWindow . fiatApiError ( "could not get currency" ) ;
return ;
}
2020-03-31 16:29:28 +00:00
var ticker = appWindow . fiatApiParseTicker ( url , resp , currency ) ;
2019-05-01 02:05:16 +00:00
if ( ticker <= 0 ) {
appWindow . fiatApiError ( "could not get ticker" ) ;
return ;
}
if ( persistentSettings . fiatPriceCurrency === "xmrusd" )
appWindow . fiatPriceXMRUSD = ticker ;
else if ( persistentSettings . fiatPriceCurrency === "xmreur" )
appWindow . fiatPriceXMREUR = ticker ;
appWindow . updateBalance ( ) ;
}
function fiatApiRefresh ( ) {
// trigger API call
if ( ! persistentSettings . fiatPriceEnabled )
return ;
var userProvider = persistentSettings . fiatPriceProvider ;
if ( ! appWindow . fiatPriceAPIs . hasOwnProperty ( userProvider ) ) {
appWindow . fiatApiError ( "provider \"" + userProvider + "\" not implemented" ) ;
return ;
}
var provider = appWindow . fiatPriceAPIs [ userProvider ] ;
var userCurrency = persistentSettings . fiatPriceCurrency ;
if ( ! provider . hasOwnProperty ( userCurrency ) ) {
appWindow . fiatApiError ( "currency \"" + userCurrency + "\" not implemented" ) ;
}
var url = provider [ userCurrency ] ;
2020-07-29 17:43:02 +00:00
network . getJSON ( url , fiatApiJsonReceived ) ;
2019-05-01 02:05:16 +00:00
}
2019-11-13 08:02:19 +00:00
function fiatApiCurrencySymbol ( ) {
switch ( persistentSettings . fiatPriceCurrency ) {
case "xmrusd" :
return "USD" ;
case "xmreur" :
return "EUR" ;
default:
console . error ( "unsupported currency" , persistentSettings . fiatPriceCurrency ) ;
return "UNSUPPORTED" ;
}
}
function fiatApiConvertToFiat ( amount ) {
2019-05-01 02:05:16 +00:00
var ticker = persistentSettings . fiatPriceCurrency === "xmrusd" ? appWindow.fiatPriceXMRUSD : appWindow . fiatPriceXMREUR ;
if ( ticker <= 0 ) {
2020-10-08 19:22:27 +00:00
fiatApiError ( "Invalid ticker value: " + ticker ) ;
2019-11-13 08:02:19 +00:00
return "?.??" ;
2019-05-01 02:05:16 +00:00
}
2019-11-13 08:02:19 +00:00
return ( amount * ticker ) . toFixed ( 2 ) ;
}
function fiatApiUpdateBalance ( balance ) {
// update balance card
2019-09-06 13:52:45 +00:00
var bFiat = "?.??"
if ( ! hideBalanceForced && ! persistentSettings . hideBalance ) {
2019-11-13 08:02:19 +00:00
bFiat = fiatApiConvertToFiat ( balance ) ;
2019-09-06 13:52:45 +00:00
}
leftPanel . balanceFiatString = bFiat ;
2019-05-01 02:05:16 +00:00
}
function fiatTimerStart ( ) {
fiatPriceTimer . start ( ) ;
}
function fiatTimerStop ( ) {
fiatPriceTimer . stop ( ) ;
}
function fiatApiError ( msg ) {
console . log ( "fiatPriceError: " + msg ) ;
}
2014-07-19 14:07:40 +00:00
Component.onCompleted: {
2021-04-15 19:00:36 +00:00
if ( screenAvailableWidth > width ) {
x = ( screenAvailableWidth - width ) / 2 ;
}
if ( screenAvailableHeight > height ) {
y = ( screenAvailableHeight - height ) / 2 ;
}
2019-10-15 18:06:36 +00:00
2020-11-12 22:47:07 +00:00
translationManager . setLanguage ( persistentSettings . locale . split ( "_" ) [ 0 ] ) ;
2019-10-15 18:06:36 +00:00
applyWalletMode ( persistentSettings . walletMode ) ;
2016-06-07 13:26:25 +00:00
//
2016-08-18 18:55:34 +00:00
walletManager . walletOpened . connect ( onWalletOpened ) ;
2019-03-27 08:28:42 +00:00
walletManager . deviceButtonRequest . connect ( onDeviceButtonRequest ) ;
walletManager . deviceButtonPressed . connect ( onDeviceButtonPressed ) ;
2017-08-05 22:10:59 +00:00
walletManager . checkUpdatesComplete . connect ( onWalletCheckUpdatesComplete ) ;
2020-04-11 10:43:21 +00:00
walletManager . walletPassphraseNeeded . connect ( onWalletPassphraseNeededManager ) ;
2019-03-22 20:02:08 +00:00
IPC . uriHandler . connect ( onUriHandler ) ;
2016-08-18 18:55:34 +00:00
2017-04-03 16:51:55 +00:00
if ( typeof daemonManager != "undefined" ) {
daemonManager . daemonStarted . connect ( onDaemonStarted ) ;
daemonManager . daemonStartFailure . connect ( onDaemonStartFailure ) ;
daemonManager . daemonStopped . connect ( onDaemonStopped ) ;
}
2017-03-01 21:03:50 +00:00
// Connect app exit to qml window exit handling
mainApp . closing . connect ( appWindow . close ) ;
2017-03-27 17:39:47 +00: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 16:58:12 +00:00
if ( ! walletsFound ( ) ) {
2019-12-20 02:49:31 +00:00
wizard . wizardState = "wizardLanguage" ;
2016-10-29 14:48:10 +00:00
rootItem . state = "wizard"
} else {
2019-12-20 02:49:31 +00:00
wizard . wizardState = "wizardHome" ;
2016-10-29 14:48:10 +00:00
rootItem . state = "normal"
2020-10-08 15:52:34 +00:00
logger . resetLogFilePath ( persistentSettings . portable ) ;
2019-12-13 14:30:25 +00:00
openWallet ( "wizard" ) ;
2016-06-15 13:34:55 +00:00
}
2016-10-29 14:48:10 +00:00
2019-05-01 02:05:16 +00:00
if ( persistentSettings . fiatPriceEnabled ) {
appWindow . fiatApiRefresh ( ) ;
appWindow . fiatTimerStart ( ) ;
}
2020-11-30 15:22:31 +00:00
if ( persistentSettings . askDesktopShortcut && ! persistentSettings . portable ) {
persistentSettings . askDesktopShortcut = false ;
2020-12-07 20:06:55 +00:00
if ( isTails ) {
oshelper . createDesktopEntry ( ) ;
} else if ( isLinux ) {
confirmationDialog . title = qsTr ( "Desktop entry" ) + translationManager . emptyString ;
confirmationDialog . text = qsTr ( "Would you like to register Monero GUI Desktop entry?" ) + translationManager . emptyString ;
confirmationDialog . icon = StandardIcon . Question ;
confirmationDialog . cancelText = qsTr ( "No" ) + translationManager . emptyString ;
confirmationDialog . okText = qsTr ( "Yes" ) + translationManager . emptyString ;
confirmationDialog . onAcceptedCallback = function ( ) {
oshelper . createDesktopEntry ( ) ;
} ;
confirmationDialog . onRejectedCallback = null ;
confirmationDialog . open ( ) ;
}
2020-11-30 15:22:31 +00:00
}
2021-04-03 10:45:02 +00:00
remoteNodesModel . initialize ( ) ;
2016-06-15 13:34:55 +00:00
}
2019-07-02 23:27:25 +00:00
MoneroSettings {
2016-06-15 13:34:55 +00:00
id: persistentSettings
2019-07-03 03:13:51 +00:00
fileName: {
if ( isTails && tailsUsePersistence )
return homePath + "/Persistent/Monero/monero-core.conf" ;
return "" ;
}
2020-12-07 20:06:55 +00:00
property bool askDesktopShortcut: isLinux
2020-11-12 22:47:07 +00:00
property string language: 'English (US)'
property string language_wallet: 'English'
property string locale: 'en_US'
2016-06-15 13:34:55 +00:00
property string account_name
property string wallet_path
2016-11-12 11:11:24 +00:00
property bool allow_background_mining : false
2017-03-02 14:44:37 +00:00
property bool miningIgnoreBattery : true
2018-03-05 16:19:45 +00:00
property var nettype: NetworkType . MAINNET
2016-10-10 19:40:58 +00:00
property int restore_height : 0
2021-04-03 10:45:02 +00:00
property bool is_trusted_daemon : false // TODO: drop after v0.17.2.0 release
2016-10-10 19:40:58 +00:00
property bool is_recovering : false
2018-06-04 08:05:29 +00:00
property bool is_recovering_from_device : false
2016-12-09 21:23:43 +00:00
property bool customDecorations : true
2016-12-21 13:30:15 +00:00
property string daemonFlags
2016-12-31 10:56:08 +00:00
property int logLevel: 0
2017-02-05 12:38:43 +00:00
property string logCategories: ""
2021-04-03 10:45:02 +00:00
property string daemonUsername: "" // TODO: drop after v0.17.2.0 release
property string daemonPassword: "" // TODO: drop after v0.17.2.0 release
2017-02-27 21:05:28 +00:00
property bool transferShowAdvanced: false
2018-12-06 19:56:23 +00:00
property bool receiveShowAdvanced: false
2019-03-17 23:12:51 +00:00
property bool historyShowAdvanced: false
property bool historyHumanDates: true
2017-05-04 12:06:29 +00:00
property string blockchainDataDir: ""
2017-08-07 15:03:34 +00:00
property bool useRemoteNode: false
2021-04-03 10:45:02 +00:00
property string remoteNodeAddress: "" // TODO: drop after v0.17.2.0 release
property string remoteNodesSerialized: JSON . stringify ( {
selected: 0 ,
nodes: remoteNodeAddress != ""
? [ {
address: remoteNodeAddress ,
username: daemonUsername ,
password: daemonPassword ,
trusted: is_trusted_daemon ,
} ]
: [ ] ,
} )
2018-01-22 09:43:39 +00:00
property string bootstrapNodeAddress: ""
2018-03-16 11:55:56 +00:00
property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true
property int segregationHeight: 0
2018-07-06 09:39:58 +00:00
property int kdfRounds: 1
2021-01-12 12:59:28 +00:00
property bool displayWalletNameInTitleBar: true
2018-12-12 08:33:24 +00:00
property bool hideBalance: false
2020-04-16 18:07:10 +00:00
property bool askPasswordBeforeSending: true
2018-12-13 18:02:02 +00:00
property bool lockOnUserInActivity: true
2019-01-14 00:02:44 +00:00
property int walletMode: 2
2018-12-13 18:02:02 +00:00
property int lockOnUserInActivityInterval: 10 // minutes
2021-04-22 21:14:32 +00:00
property bool blackTheme: MoneroComponents . Style . blackTheme
2020-04-26 01:16:27 +00:00
property bool checkForUpdates: true
2020-05-02 01:48:20 +00:00
property bool autosave: true
property int autosaveMinutes: 10
2021-04-05 23:56:19 +00:00
property bool pruneBlockchain: false
2019-04-11 01:17:29 +00:00
2019-05-01 02:05:16 +00:00
property bool fiatPriceEnabled: false
2019-06-17 20:51:18 +00:00
property bool fiatPriceToggle: false
2019-05-01 02:05:16 +00:00
property string fiatPriceProvider: "kraken"
property string fiatPriceCurrency: "xmrusd"
2020-07-30 21:26:40 +00:00
property string proxyAddress: "127.0.0.1:9050"
2020-09-20 14:22:51 +00:00
property bool proxyEnabled: isTails
2020-07-30 21:26:40 +00:00
function getProxyAddress ( ) {
2020-08-29 21:21:32 +00:00
if ( ( socksProxyFlagSet && socksProxyFlag == "" ) || ! proxyEnabled ) {
2020-07-30 21:26:40 +00:00
return "" ;
}
2020-08-29 21:21:32 +00:00
var proxyAddressSetOrForced = socksProxyFlagSet ? socksProxyFlag : proxyAddress ;
if ( proxyAddressSetOrForced == "" ) {
2020-07-30 21:26:40 +00:00
return "127.0.0.1:0" ;
}
2020-08-29 21:21:32 +00:00
return proxyAddressSetOrForced ;
2020-07-30 21:26:40 +00:00
}
function getWalletProxyAddress ( ) {
if ( ! useRemoteNode ) {
return "" ;
}
return getProxyAddress ( ) ;
}
2019-04-11 01:17:29 +00:00
Component.onCompleted: {
MoneroComponents . Style . blackTheme = persistentSettings . blackTheme
}
2014-07-19 14:07:40 +00:00
}
2014-07-07 17:08:30 +00:00
2021-04-03 10:45:02 +00:00
ListModel {
id: remoteNodesModel
property int selected: 0
signal store ( )
function initialize ( ) {
try {
const remoteNodes = JSON . parse ( persistentSettings . remoteNodesSerialized ) ;
for ( var index = 0 ; index < remoteNodes . nodes . length ; ++ index ) {
const remoteNode = remoteNodes . nodes [ index ] ;
remoteNodesModel . append ( remoteNode ) ;
}
selected = remoteNodes . selected % remoteNodesModel . count || 0 ;
} catch ( e ) {
console . error ( 'failed to parse remoteNodesSerialized' , e ) ;
}
store . connect ( function ( ) {
var remoteNodes = [ ] ;
for ( var index = 0 ; index < remoteNodesModel . count ; ++ index ) {
remoteNodes . push ( remoteNodesModel . get ( index ) ) ;
}
persistentSettings . remoteNodesSerialized = JSON . stringify ( {
selected: selected ,
nodes: remoteNodes
} ) ;
} ) ;
}
function appendIfNotExists ( newRemoteNode ) {
for ( var index = 0 ; index < remoteNodesModel . count ; ++ index ) {
const remoteNode = remoteNodesModel . get ( index ) ;
if ( remoteNode . address == newRemoteNode . address &&
remoteNode . username == newRemoteNode . username &&
remoteNode . password == newRemoteNode . password &&
remoteNode . trusted == newRemoteNode . trusted ) {
return index ;
}
}
remoteNodesModel . append ( newRemoteNode ) ;
return remoteNodesModel . count - 1 ;
}
function applyRemoteNode ( index ) {
selected = index ;
const remoteNode = currentRemoteNode ( ) ;
persistentSettings . useRemoteNode = true ;
if ( currentWallet ) {
currentWallet . setDaemonLogin ( remoteNode . username , remoteNode . password ) ;
currentWallet . setTrustedDaemon ( remoteNode . trusted ) ;
appWindow . connectRemoteNode ( ) ;
}
}
function currentRemoteNode ( ) {
if ( selected < remoteNodesModel . count ) {
return remoteNodesModel . get ( selected ) ;
}
return {
address: "" ,
username: "" ,
password: "" ,
trusted: false ,
} ;
}
function removeSelectNextIfNeeded ( index ) {
remoteNodesModel . remove ( index ) ;
if ( selected == index ) {
applyRemoteNode ( selected % remoteNodesModel . count || 0 ) ;
} else if ( selected > index ) {
selected = selected - 1 ;
}
}
onCountChanged: store ( )
onDataChanged: store ( )
onSelectedChanged: store ( )
}
2016-06-28 19:37:14 +00:00
// Information dialog
2016-11-19 14:15:11 +00:00
StandardDialog {
2016-08-17 12:14:43 +00:00
// dynamically change onclose handler
property var onCloseCallback
2016-06-28 19:37:14 +00:00
id: informationPopup
2017-08-08 11:35:24 +00:00
anchors.fill: parent
z: parent . z + 1
2016-11-19 14:15:11 +00:00
cancelVisible: false
2016-08-17 12:14:43 +00:00
onAccepted: {
if ( onCloseCallback ) {
onCloseCallback ( )
}
}
2016-06-28 19:37:14 +00:00
}
2020-10-17 09:57:37 +00:00
// Transaction confirmation popup
TxConfirmationDialog {
// dynamically change onclose handler
id: txConfirmationPopup
2017-11-02 18:51:53 +00:00
z: parent . z + 1
2016-06-28 19:37:14 +00:00
onAccepted: {
2020-04-16 18:07:10 +00:00
var handleAccepted = function ( ) {
// Save transaction to file if view only wallet
if ( viewOnly ) {
saveTxDialog . open ( ) ;
} else {
handleTransactionConfirmed ( )
}
}
2016-11-19 14:15:11 +00:00
close ( ) ;
2017-11-17 01:16:35 +00:00
passwordDialog . onAcceptedCallback = function ( ) {
if ( walletPassword === passwordDialog . password ) {
2020-04-16 18:07:10 +00:00
handleAccepted ( )
2017-09-18 22:57:06 +00:00
} else {
2019-04-16 14:35:30 +00:00
passwordDialog . showError ( qsTr ( "Wrong password" ) + translationManager . emptyString ) ;
2017-09-18 22:57:06 +00:00
}
2017-10-29 04:00:18 +00:00
}
2017-11-17 01:16:35 +00:00
passwordDialog . onRejectedCallback = null ;
2020-04-16 18:07:10 +00:00
if ( ! persistentSettings . askPasswordBeforeSending ) {
handleAccepted ( )
} else {
2020-09-24 14:08:33 +00:00
passwordDialog . open (
"" ,
"" ,
( appWindow . viewOnly ? qsTr ( "Save transaction file" ) : qsTr ( "Send transaction" ) ) + translationManager . emptyString ,
appWindow . viewOnly ? "" : FontAwesome . arrowCircleRight ) ;
2020-04-16 18:07:10 +00:00
}
2017-03-02 14:44:37 +00:00
}
2017-01-12 19:53:27 +00:00
}
2020-09-29 21:31:12 +00:00
// Transaction successfully sent popup
SuccessfulTxDialog {
id: successfulTxPopup
z: parent . z + 1
}
2017-01-12 19:53:27 +00:00
StandardDialog {
2017-11-02 18:51:53 +00:00
z: parent . z + 1
2017-01-12 19:53:27 +00:00
id: confirmationDialog
2017-11-02 18:51:53 +00:00
anchors.fill: parent
2017-01-12 19:53:27 +00:00
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if ( onAcceptedCallback )
onAcceptedCallback ( )
}
onRejected: {
if ( onRejectedCallback )
onRejectedCallback ( ) ;
2016-06-28 19:37:14 +00:00
}
}
2020-04-04 13:22:25 +00:00
MoneroComponents . UpdateDialog {
id: updateDialog
allowed: ! passwordDialog . visible && ! inputDialog . visible && ! splash . visible
x: ( parent . width - width ) / 2
y: ( parent . height - height ) / 2
}
2021-04-03 10:45:02 +00:00
MoneroComponents . RemoteNodeDialog {
id: remoteNodeDialog
}
2017-08-08 09:30:08 +00:00
// Choose blockchain folder
FileDialog {
id: blockchainFileDialog
2019-01-14 00:02:44 +00:00
property string directory: ""
signal changed ( ) ;
2017-08-08 09:30:08 +00:00
title: "Please choose a folder"
selectFolder: true
folder: "file://" + persistentSettings . blockchainDataDir
2019-01-14 00:02:44 +00:00
onRejected: console . log ( "data dir selection canceled" )
2017-08-08 09:30:08 +00:00
onAccepted: {
var dataDir = walletManager . urlToLocalPath ( blockchainFileDialog . fileUrl )
var validator = daemonManager . validateDataDir ( dataDir ) ;
2019-01-14 00:02:44 +00:00
if ( validator . valid ) {
persistentSettings . blockchainDataDir = dataDir ;
} else {
2017-08-08 09:30:08 +00:00
confirmationDialog . title = qsTr ( "Warning" ) + translationManager . emptyString ;
confirmationDialog . text = "" ;
if ( validator . readOnly )
confirmationDialog . text += qsTr ( "Error: Filesystem is read only" ) + "\n\n"
2019-01-14 00:02:44 +00:00
if ( validator . storageAvailable < estimatedBlockchainSize )
2018-04-05 07:21:43 +00:00
confirmationDialog . text += qsTr ( "Warning: There's only %1 GB available on the device. Blockchain requires ~%2 GB of data." ) . arg ( validator . storageAvailable ) . arg ( estimatedBlockchainSize ) + "\n\n"
2017-08-08 09:30:08 +00:00
else
2018-04-05 07:21:43 +00:00
confirmationDialog . text += qsTr ( "Note: There's %1 GB available on the device. Blockchain requires ~%2 GB of data." ) . arg ( validator . storageAvailable ) . arg ( estimatedBlockchainSize ) + "\n\n"
2017-08-08 09:30:08 +00:00
if ( ! validator . lmdbExists )
confirmationDialog . text += qsTr ( "Note: lmdb folder not found. A new folder will be created." ) + "\n\n"
confirmationDialog . icon = StandardIcon . Question
// Continue
confirmationDialog . onAcceptedCallback = function ( ) {
persistentSettings . blockchainDataDir = dataDir
}
// Cancel
2019-01-14 00:02:44 +00:00
confirmationDialog . onRejectedCallback = function ( ) { } ;
2017-08-08 09:30:08 +00:00
confirmationDialog . open ( )
}
2019-01-14 00:02:44 +00:00
blockchainFileDialog . directory = blockchainFileDialog . fileUrl ;
2017-08-08 09:30:08 +00:00
delete validator ;
}
}
2016-08-16 20:21:46 +00:00
PasswordDialog {
id: passwordDialog
2017-08-08 11:35:24 +00:00
visible: false
2020-06-12 19:52:22 +00:00
z: parent . z + 2
2017-08-08 11:35:24 +00:00
anchors.fill: parent
2017-09-18 22:57:06 +00:00
property var onAcceptedCallback
2017-10-29 04:00:18 +00:00
property var onRejectedCallback
2017-09-18 22:57:06 +00:00
onAccepted: {
2017-10-29 04:00:18 +00:00
if ( onAcceptedCallback )
2017-09-18 22:57:06 +00:00
onAcceptedCallback ( ) ;
}
2017-10-29 04:00:18 +00:00
onRejected: {
if ( onRejectedCallback )
onRejectedCallback ( ) ;
}
2019-07-01 09:44:33 +00:00
onAcceptedNewPassword: {
if ( currentWallet . setPassword ( passwordDialog . password ) ) {
appWindow . walletPassword = passwordDialog . password ;
2017-09-22 14:25:25 +00:00
informationPopup . title = qsTr ( "Information" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Password changed successfully" ) + translationManager . emptyString ;
informationPopup . icon = StandardIcon . Information ;
} else {
informationPopup . title = qsTr ( "Error" ) + translationManager . emptyString ;
informationPopup . text = qsTr ( "Error: " ) + currentWallet . errorString ;
informationPopup . icon = StandardIcon . Critical ;
}
informationPopup . onCloseCallback = null ;
informationPopup . open ( ) ;
}
2019-07-01 09:44:33 +00:00
onRejectedNewPassword: { }
2020-04-11 10:43:21 +00:00
}
DevicePassphraseDialog {
id: devicePassphraseDialog
visible: false
z: parent . z + 1
anchors.fill: parent
2017-09-22 14:25:25 +00:00
}
2017-07-04 03:34:09 +00:00
InputDialog {
id: inputDialog
visible: false
z: parent . z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if ( onAcceptedCallback )
onAcceptedCallback ( )
}
onRejected: {
if ( onRejectedCallback )
onRejectedCallback ( )
}
}
2016-11-05 09:54:11 +00:00
DaemonManagerDialog {
id: daemonManagerDialog
2017-02-23 18:47:58 +00:00
onRejected: {
2018-12-21 00:36:37 +00:00
middlePanel . settingsView . settingsStateViewState = "Node" ;
2017-02-23 18:47:58 +00:00
loadPage ( "Settings" ) ;
}
2016-11-05 09:54:11 +00:00
}
2016-08-23 08:55:51 +00:00
ProcessingSplash {
id: splash
2020-04-29 23:12:15 +00:00
width: appWindow . width / 2
height: appWindow . height / 2.66
2017-08-20 20:23:22 +00:00
x: ( appWindow . width - width ) / 2
y: ( appWindow . height - height ) / 2
2019-04-16 14:35:30 +00:00
messageText: qsTr ( "Please wait..." ) + translationManager . emptyString
2016-07-13 12:24:40 +00:00
}
2014-07-07 17:08:30 +00:00
Item {
id: rootItem
anchors.fill: parent
2014-07-19 14:07:40 +00:00
clip: true
2014-07-07 17:08:30 +00:00
2014-08-19 12:58:02 +00:00
state: "wizard"
states: [
State {
name: "wizard"
PropertyChanges { target: middlePanel ; visible: false }
PropertyChanges { target: wizard ; visible: true }
2017-08-08 11:35:24 +00:00
PropertyChanges { target: resizeArea ; visible: true }
2019-04-11 01:17:29 +00:00
PropertyChanges { target: titleBar ; state: "essentials" }
2014-08-22 09:03:10 +00:00
} , State {
2014-08-19 12:58:02 +00:00
name: "normal"
PropertyChanges { target: middlePanel ; visible: true }
PropertyChanges { target: wizard ; visible: false }
2014-08-21 10:09:52 +00:00
PropertyChanges { target: resizeArea ; visible: true }
2019-04-11 01:17:29 +00:00
PropertyChanges { target: titleBar ; state: "default" }
2014-08-19 12:58:02 +00:00
}
]
2019-12-13 17:26:04 +00:00
Item {
id: blurredArea
anchors.fill: parent
LeftPanel {
id: leftPanel
anchors.top: parent . top
anchors.left: parent . left
anchors.bottom: parent . bottom
visible: rootItem . state == "normal" && middlePanel . state != "Merchant"
currentAccountIndex: currentWallet ? currentWallet.currentSubaddressAccount : 0
currentAccountLabel: {
if ( currentWallet ) {
return currentWallet . getSubaddressLabel ( currentWallet . currentSubaddressAccount , 0 ) ;
}
return qsTr ( "Primary account" ) + translationManager . emptyString ;
2019-12-03 11:53:12 +00:00
}
2018-04-05 08:32:43 +00:00
2019-12-13 17:26:04 +00:00
onTransferClicked: {
middlePanel . state = "Transfer" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 08:32:43 +00:00
2019-12-13 17:26:04 +00:00
onReceiveClicked: {
middlePanel . state = "Receive" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 08:32:43 +00:00
2019-12-13 17:26:04 +00:00
onHistoryClicked: {
middlePanel . state = "History" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 08:32:43 +00:00
2019-12-13 17:26:04 +00:00
onAddressBookClicked: {
middlePanel . state = "AddressBook" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 08:32:43 +00:00
2021-03-20 09:12:15 +00:00
onAdvancedClicked: {
middlePanel . state = "Advanced" ;
2019-12-13 17:26:04 +00:00
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
onSettingsClicked: {
middlePanel . state = "Settings" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 08:32:43 +00:00
2019-12-13 17:26:04 +00:00
onAccountClicked: {
middlePanel . state = "Account" ;
middlePanel . flickable . contentY = 0 ;
updateBalance ( ) ;
}
2018-04-05 09:52:09 +00:00
}
2019-12-13 17:26:04 +00:00
MiddlePanel {
id: middlePanel
accountView.currentAccountIndex: currentWallet ? currentWallet.currentSubaddressAccount : 0
anchors.top: parent . top
anchors.bottom: parent . bottom
anchors.left: leftPanel . visible ? leftPanel.right : parent . left
anchors.right: parent . right
state: "Transfer"
2019-01-14 12:25:59 +00:00
}
2020-01-08 20:56:15 +00:00
WizardController {
id: wizard
anchors.fill: parent
onUseMoneroClicked: {
rootItem . state = "normal" ;
appWindow . openWallet ( "wizard" ) ;
}
}
2014-07-07 17:08:30 +00:00
}
2019-12-13 17:26:04 +00:00
FastBlur {
id: blur
anchors.fill: blurredArea
source: blurredArea
radius: 64
2021-04-03 10:45:02 +00:00
visible: passwordDialog . visible || inputDialog . visible || splash . visible || updateDialog . visible ||
devicePassphraseDialog . visible || txConfirmationPopup . visible || successfulTxPopup . visible ||
remoteNodeDialog . visible
2014-07-07 17:08:30 +00:00
}
2014-08-19 12:58:02 +00:00
2017-01-30 09:37:14 +00:00
property int minWidth: 326
2017-04-03 16:51:55 +00:00
property int minHeight: 400
2014-07-23 10:39:35 +00:00
MouseArea {
2014-08-21 10:09:52 +00:00
id: resizeArea
2018-12-19 21:10:54 +00:00
enabled: persistentSettings . customDecorations
2014-07-23 10:39:35 +00:00
hoverEnabled: true
2019-04-11 01:17:29 +00:00
cursorShape: persistentSettings . customDecorations ? Qt.PointingHandCursor : Qt . ArrowCursor
2014-07-23 10:39:35 +00:00
anchors.right: parent . right
anchors.bottom: parent . bottom
2019-04-11 01:17:29 +00:00
height: 34
width: 34
2014-07-23 10:39:35 +00:00
2019-04-11 01:17:29 +00:00
MoneroEffects . ImageMask {
2014-07-23 10:39:35 +00:00
anchors.centerIn: parent
2018-12-19 21:10:54 +00:00
visible: persistentSettings . customDecorations
2019-04-11 01:17:29 +00:00
image: "qrc:///images/resize.png"
color: MoneroComponents . Style . defaultFontColor
width: 12
height: 12
opacity: ( parent . containsMouse || parent . pressed ) ? 0.5 : 1.0
2014-07-23 10:39:35 +00:00
}
2016-02-03 15:37:10 +00:00
property var previousPosition
2016-06-16 14:13:46 +00:00
2014-07-23 10:39:35 +00:00
onPressed: {
2016-02-03 15:37:10 +00:00
previousPosition = globalCursor . getPosition ( )
2014-07-23 10:39:35 +00:00
}
onPositionChanged: {
if ( ! pressed ) return
2016-02-03 15:37:10 +00:00
var pos = globalCursor . getPosition ( )
//var delta = previousPosition - pos
var dx = previousPosition . x - pos . x
var dy = previousPosition . y - pos . y
2014-07-23 10:39:35 +00:00
2017-01-30 09:37:14 +00:00
if ( appWindow . width - dx > parent . minWidth )
2014-07-23 10:39:35 +00:00
appWindow . width -= dx
2017-01-30 09:37:14 +00:00
else appWindow . width = parent . minWidth
2014-07-23 10:39:35 +00:00
2016-11-23 20:17:01 +00:00
if ( appWindow . height - dy > parent . minHeight )
2014-07-23 10:39:35 +00:00
appWindow . height -= dy
2016-11-23 20:17:01 +00:00
else appWindow . height = parent . minHeight
2016-02-03 15:37:10 +00:00
previousPosition = pos
2014-07-23 10:39:35 +00:00
}
}
2014-07-22 14:55:25 +00:00
2014-07-15 14:03:39 +00:00
TitleBar {
id: titleBar
2019-04-11 01:17:29 +00:00
visible: persistentSettings . customDecorations && middlePanel . state !== "Merchant"
2021-01-12 12:59:28 +00:00
walletName: persistentSettings . displayWalletNameInTitleBar ? appWindow.walletName : ""
2018-04-21 19:59:31 +00:00
anchors.left: parent . left
anchors.right: parent . right
onCloseClicked: appWindow . close ( ) ;
2019-04-11 01:17:29 +00:00
onLanguageClicked: appWindow . toggleLanguageView ( ) ;
2019-09-16 21:59:54 +00:00
onCloseWalletClicked: appWindow . showWizard ( ) ;
2019-04-11 01:17:29 +00:00
onMaximizeClicked: appWindow . visibility = appWindow . visibility !== Window . Maximized ? Window.Maximized : Window . Windowed
2018-04-21 19:59:31 +00:00
onMinimizeClicked: appWindow . visibility = Window . Minimized
2019-04-11 01:17:29 +00:00
}
2016-12-09 21:23:43 +00:00
2019-04-11 01:17:29 +00:00
MoneroMerchant . MerchantTitlebar {
id: titleBarOrange
2019-04-30 00:34:27 +00:00
visible: persistentSettings . customDecorations && middlePanel . state === "Merchant"
2019-04-11 01:17:29 +00:00
anchors.left: parent . left
anchors.right: parent . right
onCloseClicked: appWindow . close ( ) ;
onMaximizeClicked: appWindow . visibility = appWindow . visibility !== Window . Maximized ? Window.Maximized : Window . Windowed
onMinimizeClicked: appWindow . visibility = Window . Minimized
2014-07-15 14:03:39 +00:00
}
2016-12-15 13:09:37 +00: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
2019-04-11 01:17:29 +00:00
source: "qrc:///images/tip.png"
2016-12-15 13:09:37 +00:00
}
2019-04-11 01:17:29 +00:00
MoneroComponents . TextPlain {
2016-12-15 13:09:37 +00:00
id: content
anchors.horizontalCenter: parent . horizontalCenter
y: 6
lineHeight: 0.7
font.family: "Arial"
2019-04-25 19:09:23 +00:00
font.pixelSize: 12
2016-12-15 13:09:37 +00:00
color: "#FFFFFF"
}
}
2014-07-07 17:08:30 +00:00
}
2017-03-01 21:03:50 +00:00
2019-02-23 10:44:12 +00:00
function toggleLanguageView ( ) {
2021-04-14 17:16:25 +00:00
languageSidebar . visible ? languageSidebar . close ( ) : languageSidebar . open ( ) ;
2019-03-13 01:53:56 +00:00
resetLanguageFields ( )
2019-02-23 10:44:12 +00:00
}
2020-05-02 01:48:20 +00:00
Timer {
id: autosaveTimer
interval: persistentSettings . autosaveMinutes * 60 * 1000
repeat: true
running: persistentSettings . autosave
onTriggered: {
2020-10-09 12:04:53 +00:00
if ( currentWallet && ! currentWallet . refreshing ) {
2020-05-02 01:48:20 +00:00
currentWallet . storeAsync ( function ( success ) {
if ( success ) {
appWindow . showStatusMessage ( qsTr ( "Autosaved the wallet" ) , 3 ) ;
} else {
appWindow . showStatusMessage ( qsTr ( "Failed to autosave the wallet" ) , 3 ) ;
}
} ) ;
}
}
}
2017-08-08 09:29:02 +00:00
// TODO: Make the callback dynamic
Timer {
id: statusMessageTimer
interval: 5 ;
running: false ;
repeat: false
onTriggered: resetAndroidClose ( )
triggeredOnStart: false
}
2018-12-13 18:02:02 +00:00
Timer {
id: userInActivityTimer
interval: 2000 ; running: false ; repeat: true
onTriggered: checkInUserActivity ( )
}
2019-04-11 01:17:29 +00:00
Timer {
// enables theme transition animations after 500ms
id: appThemeTransition
running: true
repeat: false
interval: 500
onTriggered: appWindow . themeTransition = true ;
}
2019-09-02 21:32:36 +00:00
function checkNoSyncFlag ( ) {
if ( ! appWindow . daemonRunning ) {
return true ;
}
if ( appWindow . walletMode == 0 && ! daemonManager . noSync ( ) ) {
return false ;
}
if ( appWindow . walletMode == 1 && daemonManager . noSync ( ) ) {
return false ;
}
return true ;
}
2019-01-14 00:02:44 +00:00
function checkSimpleModeConnection ( ) {
2019-09-02 21:32:36 +00:00
const disconnectedTimeoutSec = 30 ;
const firstCheckDelaySec = 2 ;
const firstRun = appWindow . disconnectedEpoch == 0 ;
if ( firstRun ) {
appWindow . disconnectedEpoch = Utils . epoch ( ) + firstCheckDelaySec - disconnectedTimeoutSec ;
2020-01-28 04:43:31 +00:00
} else if ( ! disconnected ) {
2019-01-14 00:02:44 +00:00
appWindow . disconnectedEpoch = Utils . epoch ( ) ;
}
2019-09-02 21:32:36 +00:00
const sinceLastConnect = Utils . epoch ( ) - appWindow . disconnectedEpoch ;
if ( sinceLastConnect < disconnectedTimeoutSec && checkNoSyncFlag ( ) ) {
return ;
}
2019-01-14 00:02:44 +00:00
2021-01-22 19:50:51 +00:00
const simpleModeFlags = "--enable-dns-blocklist --out-peers 16" ;
2019-09-02 21:32:36 +00:00
if ( appWindow . daemonRunning ) {
2020-05-07 13:40:43 +00:00
appWindow . stopDaemon ( function ( ) {
2021-01-22 19:50:51 +00:00
appWindow . startDaemon ( simpleModeFlags )
2020-05-07 13:40:43 +00:00
} ) ;
} else {
2021-01-22 19:50:51 +00:00
appWindow . startDaemon ( simpleModeFlags ) ;
2019-01-14 00:02:44 +00:00
}
}
Timer {
// Simple mode connection check timer
id: simpleModeConnectionTimer
2020-05-07 13:40:43 +00:00
interval: 2000
2020-10-14 02:24:22 +00:00
running: appWindow . walletMode < 2 && currentWallet != undefined && daemonStartStopInProgress == 0
2020-05-07 13:40:43 +00:00
repeat: true
2019-01-14 00:02:44 +00:00
onTriggered: appWindow . checkSimpleModeConnection ( )
}
2017-08-08 09:29:02 +00:00
Rectangle {
id: statusMessage
2017-11-02 06:51:15 +00:00
z: 99
2017-08-08 09:29:02 +00:00
visible: false
property alias text: statusMessageText . text
anchors.bottom: parent . bottom
2019-04-25 19:09:23 +00:00
width: statusMessageText . contentWidth + 20
2017-08-08 09:29:02 +00:00
anchors.horizontalCenter: parent . horizontalCenter
2019-04-11 01:17:29 +00:00
color: MoneroComponents . Style . blackTheme ? "black" : "white"
2019-04-25 19:09:23 +00:00
height: 40
2019-04-11 01:17:29 +00:00
MoneroComponents . TextPlain {
2017-08-08 09:29:02 +00:00
id: statusMessageText
anchors.fill: parent
2019-04-25 19:09:23 +00:00
anchors.margins: 10
font.pixelSize: 14
2019-04-11 01:17:29 +00:00
color: MoneroComponents . Style . defaultFontColor
themeTransition: false
2017-08-08 09:29:02 +00:00
}
}
function resetAndroidClose ( ) {
console . log ( "resetting android close" ) ;
androidCloseTapped = false ;
statusMessage . visible = false
}
function showStatusMessage ( msg , timeout ) {
console . log ( "showing status message" )
statusMessageTimer . interval = timeout * 1000 ;
statusMessageTimer . start ( )
statusMessageText . text = msg ;
statusMessage . visible = true
}
2019-11-24 10:04:42 +00:00
function showDaemonIsRunningDialog ( onClose ) {
// Show confirmation dialog
confirmationDialog . title = qsTr ( "Local node is running" ) + translationManager . emptyString ;
confirmationDialog . text = qsTr ( "Do you want to stop local node or keep it running in the background?" ) + translationManager . emptyString ;
confirmationDialog . icon = StandardIcon . Question ;
confirmationDialog . cancelText = qsTr ( "Force stop" ) + translationManager . emptyString ;
confirmationDialog . okText = qsTr ( "Keep it running" ) + translationManager . emptyString ;
confirmationDialog . onAcceptedCallback = function ( ) {
onClose ( ) ;
}
confirmationDialog . onRejectedCallback = function ( ) {
2020-02-16 15:01:17 +00:00
stopDaemon ( onClose ) ;
2019-11-24 10:04:42 +00:00
} ;
confirmationDialog . open ( ) ;
}
2016-10-10 19:42:25 +00:00
onClosing: {
2017-08-08 09:29:02 +00:00
close . accepted = false ;
console . log ( "blocking close event" ) ;
if ( isAndroid ) {
console . log ( "blocking android exit" ) ;
if ( qrScannerEnabled )
cameraUi . state = "Stopped"
if ( ! androidCloseTapped ) {
androidCloseTapped = true ;
appWindow . showStatusMessage ( qsTr ( "Tap again to close..." ) , 3 )
// first close
return ;
}
}
2017-03-01 21:03:50 +00:00
// If daemon is running - prompt user before exiting
2020-05-04 14:48:56 +00:00
if ( daemonManager == undefined || persistentSettings . useRemoteNode ) {
closeAccepted ( ) ;
} else if ( appWindow . walletMode == 0 ) {
2020-10-14 02:24:22 +00:00
stopDaemon ( closeAccepted , true ) ;
2020-05-04 14:48:56 +00:00
} else {
showProcessingSplash ( qsTr ( "Checking local node status..." ) ) ;
const handler = function ( running ) {
hideProcessingSplash ( ) ;
if ( running ) {
showDaemonIsRunningDialog ( closeAccepted ) ;
} else {
closeAccepted ( ) ;
}
} ;
if ( currentWallet ) {
handler ( ! currentWallet . disconnected ) ;
2019-09-02 21:32:36 +00:00
} else {
2020-05-04 14:48:56 +00:00
daemonManager . runningAsync ( persistentSettings . nettype , handler ) ;
2019-09-02 21:32:36 +00:00
}
2017-03-01 21:03:50 +00:00
}
}
function closeAccepted ( ) {
2017-08-08 09:29:02 +00:00
console . log ( "close accepted" ) ;
2016-12-15 12:18:04 +00:00
// Close wallet non async on exit
2017-02-25 13:57:39 +00:00
daemonManager . exit ( ) ;
2019-07-02 10:57:37 +00:00
closeWallet ( Qt . quit ) ;
2016-10-10 19:42:25 +00:00
}
2017-02-19 10:38:03 +00:00
2020-04-14 21:03:15 +00:00
function onWalletCheckUpdatesComplete ( version , downloadUrl , hash , firstSigner , secondSigner ) {
const alreadyAsked = updateDialog . url == downloadUrl && updateDialog . hash == hash ;
if ( ! alreadyAsked )
{
updateDialog . show ( version , isMac || isWindows || isLinux ? downloadUrl : "" , hash ) ;
2017-02-19 10:38:03 +00:00
}
}
2020-04-23 14:19:20 +00:00
function getBuildTag ( ) {
if ( isMac ) {
return "mac-x64" ;
}
if ( isWindows ) {
return oshelper . installed ? "install-win-x64" : "win-x64" ;
}
if ( isLinux ) {
return "linux-x64" ;
}
return "source" ;
}
2017-08-05 22:10:59 +00:00
function checkUpdates ( ) {
2020-04-23 14:19:20 +00:00
const version = Version . GUI_VERSION . match ( /\d+\.\d+\.\d+\.\d+/ ) ;
if ( version ) {
walletManager . checkUpdatesAsync ( "monero-gui" , "gui" , getBuildTag ( ) , version [ 0 ] ) ;
} else {
console . error ( "failed to parse version number" , Version . GUI_VERSION ) ;
}
2017-08-05 22:10:59 +00:00
}
2017-02-19 10:38:03 +00:00
Timer {
id: updatesTimer
2020-04-24 01:54:42 +00:00
interval: 3600 * 1000
repeat: true
2020-04-26 01:16:27 +00:00
running: ! disableCheckUpdatesFlag && persistentSettings . checkForUpdates
2020-04-24 01:54:42 +00:00
triggeredOnStart: true
2017-02-19 10:38:03 +00:00
onTriggered: checkUpdates ( )
}
2017-08-07 10:22:49 +00:00
function releaseFocus ( ) {
// Workaround to release focus from textfield when scrolling (https://bugreports.qt.io/browse/QTBUG-34867)
if ( isAndroid ) {
console . log ( "releasing focus" )
middlePanel . focus = true
middlePanel . focus = false
}
2018-04-21 20:21:35 +00:00
}
2017-08-07 10:22:49 +00:00
2018-12-17 04:13:07 +00:00
// reset label text. othewise potential privacy leak showing unlock time when switching wallets
function clearMoneroCardLabelText ( ) {
2019-09-06 13:52:45 +00:00
leftPanel . balanceString = "?.??"
leftPanel . balanceFiatString = "?.??"
2018-12-17 04:13:07 +00:00
}
2019-03-13 01:53:56 +00:00
// some fields need an extra nudge when changing languages
function resetLanguageFields ( ) {
clearMoneroCardLabelText ( )
2019-11-27 09:14:35 +00:00
if ( currentWallet ) {
onWalletRefresh ( ) ;
}
2019-03-13 01:53:56 +00:00
}
2018-12-13 18:02:02 +00:00
function userActivity ( ) {
// register user activity
var epoch = Math . floor ( ( new Date ) . getTime ( ) / 1000 ) ;
appWindow . userLastActive = epoch ;
}
function checkInUserActivity ( ) {
2019-01-14 00:02:44 +00:00
if ( rootItem . state !== "normal" ) return ;
2018-12-13 18:02:02 +00:00
if ( ! persistentSettings . lockOnUserInActivity ) return ;
2019-07-16 12:17:22 +00:00
if ( passwordDialog . visible ) return ;
2019-12-20 01:20:12 +00:00
var inputDialogVisible = inputDialog && inputDialog . visible
2021-05-27 20:25:35 +00:00
var successfulTxPopupVisible = successfulTxPopup && successfulTxPopup . visible
var informationPopupVisible = informationPopup && informationPopup . visible
2018-12-13 18:02:02 +00:00
// prompt password after X seconds of inactivity
var epoch = Math . floor ( ( new Date ) . getTime ( ) / 1000 ) ;
var inactivity = epoch - appWindow . userLastActive ;
if ( inactivity < ( persistentSettings . lockOnUserInActivityInterval * 60 ) ) return ;
passwordDialog . onAcceptedCallback = function ( ) {
if ( walletPassword === passwordDialog . password ) {
passwordDialog . close ( ) ;
2021-05-27 20:25:35 +00:00
if ( inputDialogVisible ) inputDialog . open ( inputDialog . inputText )
if ( successfulTxPopupVisible ) successfulTxPopup . open ( successfulTxPopup . transactionID )
if ( informationPopupVisible ) informationPopup . open ( )
2018-12-13 18:02:02 +00:00
} else {
passwordDialog . showError ( qsTr ( "Wrong password" ) ) ;
}
}
passwordDialog . onRejectedCallback = function ( ) { appWindow . showWizard ( ) ; }
2019-12-20 01:20:12 +00:00
if ( inputDialogVisible ) inputDialog . close ( )
2021-04-03 10:45:02 +00:00
remoteNodeDialog . close ( ) ;
2021-05-27 20:25:35 +00:00
informationPopup . close ( )
txConfirmationPopup . close ( )
txConfirmationPopup . clearFields ( )
txConfirmationPopup . rejected ( )
successfulTxPopup . close ( ) ;
2018-12-13 18:02:02 +00:00
passwordDialog . open ( ) ;
}
2019-02-17 14:33:12 +00:00
function getDefaultDaemonRpcPort ( networkType ) {
switch ( networkType ) {
case NetworkType.STAGENET:
return 38081 ;
case NetworkType.TESTNET:
return 28081 ;
default:
return 18081 ;
}
}
2019-01-14 00:02:44 +00:00
function changeWalletMode ( mode ) {
2019-09-02 21:32:36 +00:00
appWindow . disconnectedEpoch = 0 ;
2019-01-14 00:02:44 +00:00
appWindow . walletMode = mode ;
persistentSettings . walletMode = mode ;
2019-10-15 18:06:36 +00:00
applyWalletMode ( mode ) ;
}
function applyWalletMode ( mode ) {
2019-09-02 21:32:36 +00:00
if ( mode < 2 ) {
persistentSettings . useRemoteNode = false ;
2020-06-15 11:17:42 +00:00
if ( middlePanel . settingsView . settingsStateViewState === "Node" ) {
2019-09-02 21:32:36 +00:00
middlePanel . settingsView . settingsStateViewState = "Wallet"
}
2019-09-03 22:05:48 +00:00
}
2019-10-15 18:06:36 +00:00
console . log ( "walletMode: " + ( mode === 0 ? "simple" : mode === 1 ? "simple (bootstrap)" : "Advanced" ) ) ;
2019-01-14 00:02:44 +00:00
}
2018-04-21 20:21:35 +00:00
Rectangle {
id: inactiveOverlay
2019-12-13 17:26:04 +00:00
visible: blur . visible
2018-04-21 20:21:35 +00:00
anchors.fill: parent
2019-04-11 01:17:29 +00:00
anchors.topMargin: titleBar . height
color: MoneroComponents . Style . blackTheme ? "black" : "white"
2019-12-13 17:26:04 +00:00
opacity: isOpenGL ? 0.3 : inputDialog . visible || splash . visible ? 0.7 : 1.0
2019-04-11 01:17:29 +00:00
MoneroEffects . ColorTransition {
targetObj: parent
blackColor: "black"
whiteColor: "white"
}
2020-04-04 13:22:25 +00:00
MouseArea {
anchors.fill: parent
hoverEnabled: true
}
2019-04-11 01:17:29 +00:00
}
// borders on white theme + linux
Rectangle {
visible: isLinux && ! MoneroComponents . Style . blackTheme && middlePanel . state !== "Merchant"
z: parent . z + 1
anchors.left: parent . left
anchors.top: parent . top
anchors.bottom: parent . bottom
width: 1
color: MoneroComponents . Style . appWindowBorderColor
MoneroEffects . ColorTransition {
targetObj: parent
blackColor: MoneroComponents . Style . _b_appWindowBorderColor
whiteColor: MoneroComponents . Style . _w_appWindowBorderColor
}
}
Rectangle {
visible: isLinux && ! MoneroComponents . Style . blackTheme && middlePanel . state !== "Merchant"
z: parent . z + 1
anchors.right: parent . right
anchors.top: parent . top
anchors.bottom: parent . bottom
width: 1
color: MoneroComponents . Style . appWindowBorderColor
MoneroEffects . ColorTransition {
targetObj: parent
blackColor: MoneroComponents . Style . _b_appWindowBorderColor
whiteColor: MoneroComponents . Style . _w_appWindowBorderColor
}
}
Rectangle {
visible: isLinux && ! MoneroComponents . Style . blackTheme && middlePanel . state !== "Merchant"
z: parent . z + 1
anchors.right: parent . right
anchors.top: parent . top
anchors.left: parent . left
height: 1
color: MoneroComponents . Style . appWindowBorderColor
MoneroEffects . ColorTransition {
targetObj: parent
blackColor: MoneroComponents . Style . _b_appWindowBorderColor
whiteColor: MoneroComponents . Style . _w_appWindowBorderColor
}
}
Rectangle {
visible: isLinux && ! MoneroComponents . Style . blackTheme && middlePanel . state !== "Merchant"
z: parent . z + 1
anchors.right: parent . right
anchors.bottom: parent . bottom
anchors.left: parent . left
height: 1
color: MoneroComponents . Style . appWindowBorderColor
MoneroEffects . ColorTransition {
targetObj: parent
blackColor: MoneroComponents . Style . _b_appWindowBorderColor
whiteColor: MoneroComponents . Style . _w_appWindowBorderColor
}
2017-08-07 10:22:49 +00:00
}
2019-01-14 00:02:44 +00:00
2020-04-22 21:40:55 +00:00
MoneroComponents . LanguageSidebar {
id: languageSidebar
dragMargin: 0
}
2020-07-20 14:47:13 +00:00
2019-07-01 08:42:23 +00:00
MoneroComponents . MenuBar { }
2020-07-29 17:43:02 +00:00
Network {
id: network
2020-07-30 21:26:40 +00:00
proxyAddress: persistentSettings . getProxyAddress ( )
2020-07-29 17:43:02 +00:00
}
2020-07-20 14:47:13 +00:00
WalletManager {
id: walletManager
2020-07-30 21:26:40 +00:00
proxyAddress: persistentSettings . getProxyAddress ( )
2020-07-20 14:47:13 +00:00
}
2014-07-07 17:08:30 +00:00
}