monero-gui/main.qml

2022 lines
77 KiB
QML
Raw Normal View History

2018-01-07 05:20:45 +00:00
// Copyright (c) 2014-2018, The Monero Project
//
2015-04-01 08:56:05 +00:00
// All rights reserved.
//
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:
//
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.
//
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.
//
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.
//
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.
2014-07-07 17:08:30 +00:00
import QtQuick 2.2
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
import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
2018-03-05 16:19:45 +00:00
import moneroComponents.NetworkType 1.0
2014-07-07 17:08:30 +00:00
import "components"
2019-01-14 00:02:44 +00:00
import "components" as MoneroComponents
2014-08-19 12:58:02 +00:00
import "wizard"
2018-12-07 07:48:20 +00:00
import "js/Utils.js" as Utils
import "js/Windows.js" as Windows
2014-07-07 17:08:30 +00:00
ApplicationWindow {
id: appWindow
title: "Monero"
property var currentItem
property bool hideBalanceForced: false
2014-07-07 17:08:30 +00:00
property bool whatIsEnable: false
property bool ctrlPressed: false
property bool rightPanelExpanded: false
property bool osx: false
property alias persistentSettings : persistentSettings
property var currentWallet;
2016-06-28 19:37:14 +00:00
property var transaction;
property var transactionDescription;
2017-11-17 01:16:35 +00:00
property var walletPassword
property bool isNewWallet: false
property int restoreHeight:0
property bool daemonSynced: false
2018-03-20 18:19:30 +00:00
property bool walletSynced: false
2017-08-07 14:20:37 +00:00
property int maxWindowHeight: (isAndroid || isIOS)? screenHeight : (screenHeight < 900)? 720 : 800;
2016-11-25 20:09:32 +00:00
property bool daemonRunning: false
property alias toolTip: toolTip
property string walletName
property bool viewOnly: false
property bool foundNewBlock: false
property int timeToUnlock: 0
2017-03-27 17:39:47 +00:00
property bool qrScannerEnabled: (typeof builtWithScanner != "undefined") && builtWithScanner
property int blocksToSync: 1
2017-08-07 14:20:37 +00:00
property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true
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
property bool remoteNodeConnected: false
property bool androidCloseTapped: false;
2018-12-13 18:02:02 +00:00
property int userLastActive; // epoch
// Default daemon addresses
readonly property string localDaemonAddress : "localhost:" + getDefaultDaemonRpcPort(persistentSettings.nettype)
property string currentDaemonAddress;
property bool startLocalNodeCancelled: false
2019-01-14 00:02:44 +00:00
property int disconnectedEpoch: 0
property int estimatedBlockchainSize: 75 // GB
property alias viewState: rootItem.state
property string remoteNodeService: {
// support user-defined remote node aggregators
if(persistentSettings.remoteNodeService){
var service = persistentSettings.remoteNodeService;
if(service.charAt(service.length-1) !== "/")
service += "/";
return service;
}
2019-02-28 08:41:44 +00:00
// monero-gui workgroup maintained
if(isWindows)
return "http://autonode.xmr.pm/";
else
return "https://autonode.xmr.pm/"
2019-01-14 00:02:44 +00:00
}
// true if wallet ever synchronized
property bool walletInitialized : false
2016-07-13 12:24:40 +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
property int current_subaddress_account_table_index: 0
2018-12-08 15:55:29 +00:00
function altKeyReleased() { ctrlPressed = false; }
function showPageRequest(page) {
middlePanel.state = page
leftPanel.selectItem(page)
}
function sequencePressed(obj, seq) {
if(seq === undefined || !leftPanel.enabled)
return
if(seq === "Ctrl") {
ctrlPressed = true
return
}
2017-01-17 21:59:40 +00:00
if(seq === "Ctrl+S") middlePanel.state = "Transfer"
else if(seq === "Ctrl+R") middlePanel.state = "Receive"
else if(seq === "Ctrl+K") middlePanel.state = "TxKey"
else if(seq === "Ctrl+H") middlePanel.state = "History"
else if(seq === "Ctrl+B") middlePanel.state = "AddressBook"
else if(seq === "Ctrl+M") middlePanel.state = "Mining"
else if(seq === "Ctrl+I") middlePanel.state = "Sign"
else if(seq === "Ctrl+G") middlePanel.state = "SharedRingDB"
else if(seq === "Ctrl+E") middlePanel.state = "Settings"
2018-09-27 14:01:14 +00:00
else if(seq === "Ctrl+Y") leftPanel.keysClicked()
2017-01-17 21:59:40 +00:00
else if(seq === "Ctrl+D") middlePanel.state = "Advanced"
else if(seq === "Ctrl+T") middlePanel.state = "Account"
else if(seq === "Ctrl+Tab" || seq === "Alt+Tab") {
/*
if(middlePanel.state === "Transfer") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "Settings"
*/
if(middlePanel.state === "Settings") middlePanel.state = "Account"
else if(middlePanel.state === "Account") middlePanel.state = "Transfer"
else if(middlePanel.state === "Transfer") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "Settings"
} else if(seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab") {
/*
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "Transfer"
*/
if(middlePanel.state === "Settings") middlePanel.state = "Sign"
else if(middlePanel.state === "Sign") middlePanel.state = "SharedRingDB"
else if(middlePanel.state === "SharedRingDB") middlePanel.state = "TxKey"
else if(middlePanel.state === "TxKey") middlePanel.state = "Mining"
else if(middlePanel.state === "Mining") middlePanel.state = "History"
else if(middlePanel.state === "History") middlePanel.state = "Receive"
else if(middlePanel.state === "Receive") middlePanel.state = "AddressBook"
else if(middlePanel.state === "AddressBook") middlePanel.state = "Transfer"
else if(middlePanel.state === "Transfer") middlePanel.state = "Account"
else if(middlePanel.state === "Account") middlePanel.state = "Settings"
}
if (middlePanel.state !== "Advanced") updateBalance();
2014-07-09 16:03:37 +00:00
leftPanel.selectItem(middlePanel.state)
}
function sequenceReleased(obj, seq) {
if(seq === "Ctrl")
ctrlPressed = false
}
function mousePressed(obj, mouseX, mouseY) {}
function mouseReleased(obj, mouseX, mouseY) {}
2014-07-07 17:08:30 +00:00
function loadPage(page) {
middlePanel.state = page;
leftPanel.selectItem(page);
}
function openWalletFromFile(){
persistentSettings.restore_height = 0
restoreHeight = 0;
persistentSettings.is_recovering = false
2017-11-17 01:16:35 +00:00
walletPassword = ""
2019-01-14 00:02:44 +00:00
fileDialog.folder = "file://" + moneroAccountsDir
fileDialog.open();
}
function initialize() {
2019-01-14 00:02:44 +00:00
appWindow.viewState = "normal";
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
if (persistentSettings.logLevel == 5)
walletManager.setLogCategories(persistentSettings.logCategories)
else
walletManager.setLogLevel(persistentSettings.logLevel)
2016-12-31 10:56:08 +00:00
2016-07-19 20:45:12 +00:00
// setup language
var locale = persistentSettings.locale
if (locale !== "") {
translationManager.setLanguage(locale.split("_")[0]);
}
2017-03-09 15:46:03 +00:00
// Reload transfer page with translations enabled
middlePanel.transferView.onPageCompleted();
// 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();
currentWallet = undefined
} else if (!walletInitialized) {
// 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
// Local daemon settings
walletManager.setDaemonAddress(localDaemonAddress)
2019-01-14 00:02:44 +00:00
// enable timers
2018-12-13 18:02:02 +00:00
userInActivityTimer.running = true;
2019-01-14 00:02:44 +00:00
simpleModeConnectionTimer.running = true;
// wallet already opened with wizard, we just need to initialize it
if (typeof wizard.m_wallet !== 'undefined') {
2016-10-04 22:18:50 +00:00
console.log("using wizard wallet")
//Set restoreHeight
2016-10-10 14:37:03 +00:00
if(persistentSettings.restore_height > 0){
// We store restore height in own variable for performance reasons.
2016-10-10 14:37:03 +00:00
restoreHeight = persistentSettings.restore_height
}
connectWallet(wizard.m_wallet)
isNewWallet = true
2016-10-04 22:18:50 +00:00
// We don't need the wizard wallet any more - delete to avoid conflict with daemon adress change
delete wizard.m_wallet
} else {
var wallet_path = walletPath();
2017-04-03 16:51:55 +00:00
if(isIOS)
wallet_path = moneroAccountsDir + wallet_path;
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.walletPassword);
2018-03-27 18:41:15 +00:00
console.log("opening wallet at: ", wallet_path, ", network type: ", persistentSettings.nettype == NetworkType.MAINNET ? "mainnet" : persistentSettings.nettype == NetworkType.TESTNET ? "testnet" : "stagenet");
2017-11-17 01:16:35 +00:00
walletManager.openWalletAsync(wallet_path, walletPassword,
persistentSettings.nettype, persistentSettings.kdfRounds);
}
// Hide titlebar based on persistentSettings.customDecorations
titleBar.visible = persistentSettings.customDecorations;
2016-06-17 13:35:07 +00:00
}
2016-12-15 12:18:04 +00:00
function closeWallet() {
2016-06-17 13:35:07 +00:00
2016-12-15 12:18:04 +00:00
// Disconnect all listeners
2016-12-15 23:12:27 +00:00
if (typeof currentWallet !== "undefined" && currentWallet !== null) {
currentWallet.refreshed.disconnect(onWalletRefresh)
currentWallet.updated.disconnect(onWalletUpdate)
currentWallet.newBlock.disconnect(onWalletNewBlock)
currentWallet.moneySpent.disconnect(onWalletMoneySent)
currentWallet.moneyReceived.disconnect(onWalletMoneyReceived)
currentWallet.unconfirmedMoneyReceived.disconnect(onWalletUnconfirmedMoneyReceived)
2016-12-15 23:12:27 +00:00
currentWallet.transactionCreated.disconnect(onTransactionCreated)
currentWallet.connectionStatusChanged.disconnect(onWalletConnectionStatusChanged)
middlePanel.paymentClicked.disconnect(handlePayment);
middlePanel.sweepUnmixableClicked.disconnect(handleSweepUnmixable);
2017-11-20 07:24:29 +00:00
middlePanel.getProofClicked.disconnect(handleGetProof);
middlePanel.checkProofClicked.disconnect(handleCheckProof);
2016-12-15 23:12:27 +00:00
}
2017-08-08 09:40:54 +00:00
2016-12-15 12:18:04 +00:00
currentWallet = undefined;
2017-08-08 09:40:54 +00:00
walletManager.closeWallet();
2016-12-15 12:18:04 +00:00
}
function connectWallet(wallet) {
currentWallet = wallet
// 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)
updateSyncing(false)
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
}
// connect handlers
currentWallet.refreshed.connect(onWalletRefresh)
currentWallet.updated.connect(onWalletUpdate)
currentWallet.newBlock.connect(onWalletNewBlock)
currentWallet.moneySpent.connect(onWalletMoneySent)
currentWallet.moneyReceived.connect(onWalletMoneyReceived)
currentWallet.unconfirmedMoneyReceived.connect(onWalletUnconfirmedMoneyReceived)
2016-11-08 17:05:33 +00:00
currentWallet.transactionCreated.connect(onTransactionCreated)
currentWallet.connectionStatusChanged.connect(onWalletConnectionStatusChanged)
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
console.log("Recovering from seed: ", persistentSettings.is_recovering)
console.log("restore Height", persistentSettings.restore_height)
// Use saved daemon rpc login settings
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword)
if(persistentSettings.useRemoteNode)
currentDaemonAddress = persistentSettings.remoteNodeAddress
else
currentDaemonAddress = localDaemonAddress
console.log("initializing with daemon address: ", currentDaemonAddress)
currentWallet.initAsync(currentDaemonAddress, 0, persistentSettings.is_recovering, persistentSettings.is_recovering_from_device, persistentSettings.restore_height);
// save wallet keys in case wallet settings have been changed in the init
currentWallet.setPassword(walletPassword);
}
function walletPath() {
var wallet_path = persistentSettings.wallet_path
return wallet_path;
}
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$/, '')
}
function updateBalance() {
if (!currentWallet)
return;
var balance_unlocked = qsTr("HIDDEN");
var balance = qsTr("HIDDEN");
if(!hideBalanceForced && !persistentSettings.hideBalance){
balance_unlocked = walletManager.displayAmount(currentWallet.unlockedBalance(currentWallet.currentSubaddressAccount));
balance = walletManager.displayAmount(currentWallet.balance(currentWallet.currentSubaddressAccount));
}
middlePanel.unlockedBalanceText = balance_unlocked;
leftPanel.unlockedBalanceText = balance_unlocked;
middlePanel.balanceText = balance;
leftPanel.balanceText = balance;
var accountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
leftPanel.balanceLabelText = qsTr("Balance (#%1%2)").arg(currentWallet.currentSubaddressAccount).arg(accountLabel === "" ? "" : (" " + accountLabel));
}
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)
middlePanel.updateStatus();
2017-01-31 09:34:18 +00:00
leftPanel.networkStatus.connected = status
2017-02-05 12:49:25 +00:00
// update local daemon status.
if(!isMobile && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address))
daemonRunning = status;
// Update fee multiplier dropdown on transfer page
middlePanel.transferView.updatePriorityDropdown();
2019-01-14 00:02:44 +00:00
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
if(!isMobile && appWindow.walletMode >= 2 && walletManager.isDaemonLocal(appWindow.persistentSettings.daemon_address) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
2017-02-05 12:49:25 +00:00
daemonManagerDialog.open();
}
// initialize transaction history once wallet is initialized first time;
if (!walletInitialized) {
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
2017-02-05 12:49:25 +00:00
walletInitialized = true
// check if daemon was already mining and add mining logo if true
middlePanel.miningView.update();
2017-02-05 12:49:25 +00:00
}
2019-01-14 00:02:44 +00:00
}
function onWalletOpened(wallet) {
2017-01-03 20:54:40 +00:00
walletName = usefulName(wallet.path)
console.log(">>> wallet opened: " + wallet)
if (wallet.status !== Wallet.Status_Ok) {
2017-11-17 01:16:35 +00:00
passwordDialog.onAcceptedCallback = function() {
walletPassword = passwordDialog.password;
appWindow.initialize();
}
passwordDialog.onRejectedCallback = function() {
walletPassword = "";
//appWindow.enableUI(false)
2019-01-14 00:02:44 +00:00
wizard.wizardState = "wizardHome";
2017-11-17 01:16:35 +00:00
rootItem.state = "wizard";
}
// opening with password but password doesn't match
console.error("Error opening wallet with password: ", wallet.errorString);
2018-10-24 03:50:56 +00:00
passwordDialog.showError(qsTr("Couldn't open wallet: ") + wallet.errorString);
2017-11-17 01:16:35 +00:00
console.log("closing wallet async : " + wallet.address)
closeWallet();
return;
}
// wallet opened successfully, subscribing for wallet updates
connectWallet(wallet)
2019-01-14 00:02:44 +00:00
// Force switch normal view
rootItem.state = "normal";
}
function onWalletClosed(walletAddress) {
console.log(">>> wallet closed: " + walletAddress)
}
2016-06-17 13:35:07 +00:00
function onWalletUpdate() {
2016-07-13 12:24:40 +00:00
console.log(">>> wallet updated")
updateBalance();
2017-03-04 23:05:31 +00:00
// Update history if new block found since last update
if(foundNewBlock) {
foundNewBlock = false;
console.log("New block found - updating history")
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
timeToUnlock = currentWallet.history.minutesToUnlock
leftPanel.minutesToUnlockTxt = (timeToUnlock > 0)? (timeToUnlock == 20)? qsTr("Unlocked balance (waiting for block)") : qsTr("Unlocked balance (~%1 min)").arg(timeToUnlock) : qsTr("Unlocked balance");
}
2016-07-13 12:24:40 +00:00
}
function connectRemoteNode() {
console.log("connecting remote node");
persistentSettings.useRemoteNode = true;
currentDaemonAddress = persistentSettings.remoteNodeAddress;
currentWallet.initAsync(currentDaemonAddress);
walletManager.setDaemonAddress(currentDaemonAddress);
remoteNodeConnected = true;
}
function disconnectRemoteNode() {
console.log("disconnecting remote node");
persistentSettings.useRemoteNode = false;
currentDaemonAddress = localDaemonAddress
currentWallet.initAsync(currentDaemonAddress);
walletManager.setDaemonAddress(currentDaemonAddress);
remoteNodeConnected = false;
}
2016-07-13 12:24:40 +00:00
function onWalletRefresh() {
console.log(">>> wallet refreshed")
// Daemon connected
leftPanel.networkStatus.connected = currentWallet.connected()
2018-03-20 18:19:30 +00:00
// Wallet height
var bcHeight = currentWallet.blockChainHeight();
// Check daemon status
var dCurrentBlock = currentWallet.daemonBlockChainHeight();
var dTargetBlock = currentWallet.daemonBlockChainTargetHeight();
// 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.
daemonSynced = dCurrentBlock >= dTargetBlock && dTargetBlock != 1
2018-03-20 18:19:30 +00:00
walletSynced = bcHeight >= dTargetBlock
// Update progress bars
if(!daemonSynced) {
leftPanel.daemonProgressBar.updateProgress(dCurrentBlock,dTargetBlock, dTargetBlock-dCurrentBlock);
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
updateSyncing((currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced)
2017-01-31 09:34:18 +00:00
// Update transfer page status
middlePanel.updateStatus();
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-11-10 11:11:25 +00:00
// Save new wallet after first refresh
// Wallet is nomrmally saved to disk on app exit. This prevents rescan from block 0 after app crash
if(isNewWallet){
console.log("Saving wallet after first refresh");
2016-11-10 11:23:43 +00:00
currentWallet.store()
2016-11-10 11:11:25 +00:00
isNewWallet = false
// Update History
currentWallet.history.refresh(currentWallet.currentSubaddressAccount);
2016-11-10 11:11:25 +00:00
}
// recovering from seed is finished after first refresh
if(persistentSettings.is_recovering) {
persistentSettings.is_recovering = false
}
}
2017-08-08 10:23:01 +00:00
// Update history on every refresh if it's empty
if(currentWallet.history.count == 0)
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
2017-08-08 10:23:01 +00:00
2016-07-14 10:09:39 +00:00
onWalletUpdate();
}
2016-12-21 13:30:15 +00:00
function startDaemon(flags){
// Pause refresh while starting daemon
currentWallet.pauseRefresh();
2019-01-14 00:02:44 +00:00
// Pause simplemode connection timer
simpleModeConnectionTimer.stop();
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
2018-03-05 16:19:45 +00:00
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress);
2016-12-21 13:30:15 +00:00
persistentSettings.daemonFlags = flags
}
function stopDaemon(){
appWindow.showProcessingSplash(qsTr("Waiting for daemon to stop..."))
2018-03-05 16:19:45 +00:00
daemonManager.stop(persistentSettings.nettype);
}
2016-11-25 20:09:32 +00:00
function onDaemonStarted(){
console.log("daemon started");
daemonRunning = true;
hideProcessingSplash();
2017-02-25 13:57:39 +00:00
currentWallet.connected(true);
// resume refresh
currentWallet.startRefresh();
2019-01-14 00:02:44 +00:00
// resume simplemode connection timer
simpleModeConnectionTimer.start();
2016-11-25 20:09:32 +00:00
}
function onDaemonStopped(){
console.log("daemon stopped");
2016-12-14 12:48:12 +00:00
hideProcessingSplash();
2016-11-25 20:09:32 +00:00
daemonRunning = false;
currentWallet.connected(true);
2016-11-25 20:09:32 +00:00
}
function onDaemonStartFailure(){
console.log("daemon start failed");
hideProcessingSplash();
// resume refresh
currentWallet.startRefresh();
daemonRunning = false;
informationPopup.title = qsTr("Daemon failed to start") + translationManager.emptyString;
informationPopup.text = qsTr("Please check your wallet and daemon log for errors. You can also try to start %1 manually.").arg((isWindows)? "monerod.exe" : "monerod")
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
}
2017-01-31 09:34:18 +00:00
function onWalletNewBlock(blockHeight, targetHeight) {
// Update progress bar
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;
}
function onWalletMoneyReceived(txId, amount) {
// refresh transaction history here
currentWallet.refresh()
2017-08-08 10:23:01 +00:00
console.log("Confirmed money found")
// history refresh is handled by walletUpdated
currentWallet.history.refresh(currentWallet.currentSubaddressAccount) // this will refresh model
currentWallet.subaddress.refresh(currentWallet.currentSubaddressAccount)
}
function onWalletUnconfirmedMoneyReceived(txId, amount) {
// refresh history
console.log("unconfirmed money found")
currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
}
function onWalletMoneySent(txId, amount) {
// refresh transaction history here
2018-03-23 22:53:29 +00:00
console.log("monero sent found")
currentWallet.refresh()
currentWallet.history.refresh(currentWallet.currentSubaddressAccount) // this will refresh model
}
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)
return walletManager.walletExists(moneroAccountsDir + persistentSettings.wallet_path);
else
return walletManager.walletExists(persistentSettings.wallet_path);
}
return false;
}
2016-11-08 17:05:33 +00:00
function onTransactionCreated(pendingTransaction,address,paymentId,mixinCount){
console.log("Transaction created");
hideProcessingSplash();
transaction = pendingTransaction;
// validate address;
if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't create transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion)
2016-11-08 17:05:33 +00:00
informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString
else
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else if (transaction.txCount == 0) {
2017-05-03 13:29:23 +00:00
informationPopup.title = qsTr("Error") + translationManager.emptyString
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open()
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
2016-11-08 17:05:33 +00:00
} else {
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
+ ", fee: " + walletManager.displayAmount(transaction.fee));
// here we show confirmation popup;
2018-03-19 23:58:49 +00:00
transactionConfirmationPopup.title = qsTr("Please confirm transaction:\n") + translationManager.emptyString;
transactionConfirmationPopup.text = "";
transactionConfirmationPopup.text += (address === "" ? "" : (qsTr("Address: ") + address));
transactionConfirmationPopup.text += (paymentId === "" ? "" : (qsTr("\nPayment ID: ") + paymentId));
transactionConfirmationPopup.text += qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount);
transactionConfirmationPopup.text += qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee);
transactionConfirmationPopup.text += qsTr("\nRingsize: ") + (mixinCount + 1);
transactionConfirmationPopup.text += qsTr("\n\nNumber of transactions: ") + transaction.txCount
transactionConfirmationPopup.text += (transactionDescription === "" ? "" : (qsTr("\nDescription: ") + transactionDescription))
2018-03-19 23:58:49 +00:00
for (var i = 0; i < transaction.subaddrIndices.length; ++i){
transactionConfirmationPopup.text += qsTr("\nSpending address index: ") + transaction.subaddrIndices[i];
}
transactionConfirmationPopup.text += translationManager.emptyString;
2016-11-08 17:05:33 +00:00
transactionConfirmationPopup.icon = StandardIcon.Question
transactionConfirmationPopup.open()
}
}
2016-06-28 19:37:14 +00:00
// called on "transfer"
2017-01-12 19:53:27 +00:00
function handlePayment(address, paymentId, amount, mixinCount, priority, description, createFile) {
2016-06-27 12:45:48 +00:00
console.log("Creating transaction: ")
console.log("\taddress: ", address,
", payment_id: ", paymentId,
", amount: ", amount,
", mixins: ", mixinCount,
", priority: ", priority,
", description: ", description);
2016-06-27 12:45:48 +00:00
2016-11-08 17:05:33 +00:00
showProcessingSplash("Creating transaction");
2016-11-08 17:05:33 +00:00
transactionDescription = description;
2016-08-23 13:07:52 +00:00
// validate amount;
2016-11-09 13:00:43 +00:00
if (amount !== "(all)") {
var amountxmr = walletManager.amountFromString(amount);
console.log("integer amount: ", amountxmr);
console.log("integer unlocked",currentWallet.unlockedBalance)
if (amountxmr <= 0) {
hideProcessingSplash()
2016-11-09 13:00:43 +00:00
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Amount is wrong: expected number from %1 to %2")
.arg(walletManager.displayAmount(0))
.arg(walletManager.maximumAllowedAmountAsSting())
+ translationManager.emptyString
2016-08-23 13:07:52 +00:00
2016-11-09 13:00:43 +00:00
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open()
return;
} else if (amountxmr > currentWallet.unlockedBalance) {
hideProcessingSplash()
2016-11-09 13:00:43 +00:00
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Insufficient funds. Unlocked balance: %1")
2016-11-09 13:00:43 +00:00
.arg(walletManager.displayAmount(currentWallet.unlockedBalance))
+ translationManager.emptyString
2016-10-11 21:02:21 +00:00
2016-11-09 13:00:43 +00:00
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open()
return;
}
2016-08-23 13:07:52 +00:00
}
2016-11-09 13:00:43 +00:00
if (amount === "(all)")
currentWallet.createTransactionAllAsync(address, paymentId, mixinCount, priority);
2016-11-09 13:00:43 +00:00
else
currentWallet.createTransactionAsync(address, paymentId, amountxmr, 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"
folder: "file://" +moneroAccountsDir
selectExisting: false;
onAccepted: {
handleTransactionConfirmed()
}
onRejected: {
// do nothing
}
}
function handleSweepUnmixable() {
console.log("Creating transaction: ")
transaction = currentWallet.createSweepUnmixableTransaction();
if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't create transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else if (transaction.txCount == 0) {
2017-05-03 13:29:23 +00:00
informationPopup.title = qsTr("Error") + translationManager.emptyString
informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open()
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else {
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
+ ", fee: " + walletManager.displayAmount(transaction.fee));
// here we show confirmation popup;
transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString
transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n")
+ qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount)
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee)
+ translationManager.emptyString
transactionConfirmationPopup.icon = StandardIcon.Question
transactionConfirmationPopup.open()
// committing transaction
}
}
2016-06-28 19:37:14 +00:00
// called after user confirms transaction
2017-01-12 19:53:27 +00:00
function handleTransactionConfirmed(fileName) {
// grab transaction.txid before commit, since it clears it.
// we actually need to copy it, because QML will incredibly
// call the function multiple times when the variable is used
// after commit, where it returns another result...
// Of course, this loop is also calling the function multiple
// times, but at least with the same result.
var txid = [], txid_org = transaction.txid, txid_text = ""
for (var i = 0; i < txid_org.length; ++i)
txid[i] = txid_org[i]
2017-01-12 19:53:27 +00:00
// View only wallet - we save the tx
if(viewOnly && saveTxDialog.fileUrl){
// No file specified - abort
if(!saveTxDialog.fileUrl) {
currentWallet.disposeTransaction(transaction)
return;
}
var path = walletManager.urlToLocalPath(saveTxDialog.fileUrl)
// Store to file
transaction.setFilename(path);
}
2016-06-28 19:37:14 +00:00
if (!transaction.commit()) {
console.log("Error committing transaction: " + transaction.errorString);
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
} else {
informationPopup.title = qsTr("Information") + translationManager.emptyString
for (var i = 0; i < txid.length; ++i) {
if (txid_text.length > 0)
txid_text += ", "
txid_text += txid[i]
}
2018-03-23 22:53:29 +00:00
informationPopup.text = (viewOnly)? qsTr("Transaction saved to file: %1").arg(path) : qsTr("Monero sent successfully: %1 transaction(s) ").arg(txid.length) + txid_text + translationManager.emptyString
2016-06-28 19:37:14 +00:00
informationPopup.icon = StandardIcon.Information
if (transactionDescription.length > 0) {
for (var i = 0; i < txid.length; ++i)
currentWallet.setUserNote(txid[i], transactionDescription);
}
2017-02-04 13:44:30 +00:00
// Clear tx fields
middlePanel.transferView.clearFields()
}
informationPopup.onCloseCallback = null
2016-06-28 19:37:14 +00:00
informationPopup.open()
2016-08-23 13:07:52 +00:00
currentWallet.refresh()
currentWallet.disposeTransaction(transaction)
2016-11-19 16:33:30 +00:00
currentWallet.store();
}
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);
2017-11-20 07:12:36 +00:00
var result;
if (address.length > 0)
result = currentWallet.getTxProof(txid, address, message);
if (!result || result.indexOf("error|") === 0)
2017-11-20 07:12:36 +00:00
result = currentWallet.getSpendProof(txid, message);
2017-09-12 08:42:00 +00:00
informationPopup.title = qsTr("Payment proof") + translationManager.emptyString;
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;
}
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;
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));
}
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);
}
}
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");
}
else {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
2017-09-12 08:42:00 +00:00
informationPopup.text = currentWallet.errorString;
informationPopup.icon = StandardIcon.Critical
}
2017-09-12 08:42:00 +00:00
informationPopup.onCloseCallback = null
informationPopup.open()
}
function updateSyncing(syncing) {
var text = (syncing ? qsTr("Balance (syncing)") : qsTr("Balance")) + translationManager.emptyString
leftPanel.balanceLabelText = text
middlePanel.balanceLabelText = text
}
// blocks UI if wallet can't be opened or no connection to the daemon
function enableUI(enable) {
middlePanel.enabled = enable;
leftPanel.enabled = enable;
rightPanel.enabled = enable;
}
function showProcessingSplash(message) {
console.log("Displaying processing splash")
if (typeof message != 'undefined') {
2016-11-08 17:05:33 +00:00
splash.messageText = message
splash.heightProgressText = ""
}
splash.show()
}
function hideProcessingSplash() {
console.log("Hiding processing splash")
splash.close()
}
// close wallet and show wizard
function showWizard(){
clearMoneroCardLabelText();
walletInitialized = false;
2016-12-15 12:18:04 +00:00
closeWallet();
2016-12-15 23:12:27 +00:00
currentWallet = undefined;
wizard.restart();
2019-01-14 00:02:44 +00:00
wizard.wizardState = "wizardHome";
rootItem.state = "wizard"
2017-03-03 23:11:26 +00:00
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
2019-01-14 00:02:44 +00:00
// disable timers
2018-12-13 18:02:02 +00:00
userInActivityTimer.running = false;
2019-01-14 00:02:44 +00:00
simpleModeConnectionTimer.running = false;
}
2017-04-03 16:51:55 +00:00
function hideMenu() {
goToBasicAnimation.start();
console.log(appWindow.width)
}
function showMenu() {
goToProAnimation.start();
console.log(appWindow.width)
}
objectName: "appWindow"
2014-07-07 17:08:30 +00:00
visible: true
2017-08-07 14:20:37 +00:00
// width: screenWidth //rightPanelExpanded ? 1269 : 1269 - 300
2017-04-03 16:51:55 +00:00
// height: 900 //300//maxWindowHeight;
2014-07-07 17:08:30 +00:00
color: "#FFFFFF"
flags: persistentSettings.customDecorations ? Windows.flagsCustomDecorations : Windows.flags
2014-07-19 14:07:40 +00:00
onWidthChanged: x -= 0
Component.onCompleted: {
x = (Screen.width - width) / 2
y = (Screen.height - maxWindowHeight) / 2
//
walletManager.walletOpened.connect(onWalletOpened);
walletManager.walletClosed.connect(onWalletClosed);
2017-08-05 22:10:59 +00:00
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
2017-04-03 16:51:55 +00:00
if(typeof daemonManager != "undefined") {
daemonManager.daemonStarted.connect(onDaemonStarted);
daemonManager.daemonStartFailure.connect(onDaemonStartFailure);
daemonManager.daemonStopped.connect(onDaemonStopped);
}
2016-11-25 20:09:32 +00:00
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()) {
rootItem.state = "wizard"
} else {
rootItem.state = "normal"
2017-11-17 01:16:35 +00:00
passwordDialog.onAcceptedCallback = function() {
walletPassword = passwordDialog.password;
initialize(persistentSettings);
2017-11-17 01:16:35 +00:00
}
passwordDialog.onRejectedCallback = function() {
2019-01-14 00:02:44 +00:00
wizard.wizardState = "wizardHome";
2017-11-17 01:16:35 +00:00
rootItem.state = "wizard"
}
passwordDialog.open(usefulName(walletPath()))
}
2017-02-19 10:38:03 +00:00
checkUpdates();
}
2016-06-21 08:58:06 +00:00
onRightPanelExpandedChanged: {
if (rightPanelExpanded) {
rightPanel.updateTweets()
}
}
Settings {
id: persistentSettings
property string language
2016-07-19 20:45:12 +00:00
property string locale
property string account_name
property string wallet_path
2016-11-12 11:11:24 +00:00
property bool auto_donations_enabled : false
property int auto_donations_amount : 50
2016-11-12 11:11:24 +00:00
property bool allow_background_mining : false
property bool miningIgnoreBattery : true
2018-03-05 16:19:45 +00:00
property var nettype: NetworkType.MAINNET
property string daemon_address: "localhost:" + getDefaultDaemonRpcPort(nettype)
property string payment_id
property int restore_height : 0
property bool is_trusted_daemon : false
property bool is_recovering : false
property bool is_recovering_from_device : false
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
property string logCategories: ""
property string daemonUsername: ""
property string daemonPassword: ""
2017-02-27 21:05:28 +00:00
property bool transferShowAdvanced: false
property bool receiveShowAdvanced: false
2017-05-04 12:06:29 +00:00
property string blockchainDataDir: ""
property bool useRemoteNode: false
property string remoteNodeAddress: ""
2018-01-22 09:43:39 +00:00
property string bootstrapNodeAddress: ""
2019-01-14 00:02:44 +00:00
property string remoteNodeRegion: ""
property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true
property int segregationHeight: 0
property int kdfRounds: 1
property bool hideBalance: false
2018-12-13 18:02:02 +00:00
property bool lockOnUserInActivity: true
2019-01-14 00:02:44 +00:00
property int walletMode: 2
property string remoteNodeService: ""
2018-12-13 18:02:02 +00:00
property int lockOnUserInActivityInterval: 10 // minutes
property bool showPid: false
2014-07-19 14:07:40 +00:00
}
2014-07-07 17:08:30 +00:00
2016-06-28 19:37:14 +00:00
// Information dialog
StandardDialog {
// 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
cancelVisible: false
onAccepted: {
if (onCloseCallback) {
onCloseCallback()
}
}
2016-06-28 19:37:14 +00:00
}
// Confrirmation aka question dialog
StandardDialog {
2017-11-02 18:51:53 +00:00
z: parent.z + 1
2016-06-28 19:37:14 +00:00
id: transactionConfirmationPopup
onAccepted: {
close();
2017-11-17 01:16:35 +00:00
passwordDialog.onAcceptedCallback = function() {
if(walletPassword === passwordDialog.password){
// Save transaction to file if view only wallet
if(viewOnly) {
saveTxDialog.open();
} else {
handleTransactionConfirmed()
}
} else {
2018-10-24 03:50:56 +00:00
passwordDialog.showError(qsTr("Wrong password"));
}
}
2017-11-17 01:16:35 +00:00
passwordDialog.onRejectedCallback = null;
passwordDialog.open()
}
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
}
}
2017-01-12 19:53:27 +00:00
//Open Wallet from file
FileDialog {
id: fileDialog
2019-01-14 00:02:44 +00:00
title: qsTr("Please choose a file")
folder: "file://" + moneroAccountsDir
2016-10-30 16:58:12 +00:00
nameFilters: [ "Wallet files (*.keys)"]
2017-11-02 06:52:38 +00:00
sidebarVisible: false
2019-01-14 00:02:44 +00:00
visible: false
onAccepted: {
persistentSettings.wallet_path = walletManager.urlToLocalPath(fileDialog.fileUrl)
2017-11-02 06:52:38 +00:00
if(isIOS)
persistentSettings.wallet_path = persistentSettings.wallet_path.replace(moneroAccountsDir,"")
console.log("ÖPPPPNA")
console.log(moneroAccountsDir)
console.log(fileDialog.fileUrl)
console.log(persistentSettings.wallet_path)
2017-11-17 01:16:35 +00:00
passwordDialog.onAcceptedCallback = function() {
walletPassword = passwordDialog.password;
initialize();
}
passwordDialog.onRejectedCallback = function() {
2019-01-14 00:02:44 +00:00
console.log("Canceled");
wizard.wizardState = "wizardHome";
2017-11-17 01:16:35 +00:00
rootItem.state = "wizard";
}
passwordDialog.open(usefulName(walletPath()));
}
onRejected: {
console.log("Canceled")
rootItem.state = "wizard";
}
}
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
confirmationDialog.cancelText = qsTr("Cancel")
// 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;
}
}
PasswordDialog {
id: passwordDialog
2017-08-08 11:35:24 +00:00
visible: false
z: parent.z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
}
onRejected: {
if (onRejectedCallback)
onRejectedCallback();
}
}
2017-09-22 14:25:25 +00:00
NewPasswordDialog {
id: newPasswordDialog
z: parent.z + 1
visible:false
anchors.fill: parent
onAccepted: {
if (currentWallet.setPassword(newPasswordDialog.password)) {
appWindow.walletPassword = newPasswordDialog.password;
informationPopup.title = qsTr("Information") + translationManager.emptyString;
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information;
} else {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Error: ") + currentWallet.errorString;
informationPopup.icon = StandardIcon.Critical;
}
informationPopup.onCloseCallback = null;
informationPopup.open();
}
onRejected: {
}
}
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()
}
}
DaemonManagerDialog {
id: daemonManagerDialog
onRejected: {
middlePanel.settingsView.settingsStateViewState = "Node";
loadPage("Settings");
startLocalNodeCancelled = true
}
}
ProcessingSplash {
id: splash
2016-10-09 18:49:56 +00:00
width: appWindow.width / 1.5
height: appWindow.height / 2
2017-08-20 20:23:22 +00:00
x: (appWindow.width - width) / 2
y: (appWindow.height - height) / 2
messageText: qsTr("Please wait...")
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: leftPanel; visible: false }
PropertyChanges { target: rightPanel; visible: false }
PropertyChanges { target: middlePanel; visible: false }
PropertyChanges { target: wizard; visible: true }
2019-01-14 00:02:44 +00:00
PropertyChanges { target: appWindow; width: (screenWidth < 969 || isAndroid || isIOS)? screenWidth : 969 } //rightPanelExpanded ? 1269 : 1269 - 300;
2017-05-06 15:49:43 +00:00
PropertyChanges { target: appWindow; height: maxWindowHeight; }
2017-08-08 11:35:24 +00:00
PropertyChanges { target: resizeArea; visible: true }
2017-04-03 16:51:55 +00:00
// PropertyChanges { target: frameArea; blocked: true }
2017-08-08 11:35:24 +00:00
PropertyChanges { target: mobileHeader; visible: false }
2019-01-14 00:02:44 +00:00
PropertyChanges { target: titleBar; basicButtonVisible: false }
PropertyChanges { target: titleBar; showMaximizeButton: true }
PropertyChanges { target: titleBar; visible: true }
PropertyChanges { target: titleBar; title: qsTr("Monero") + translationManager.emptyString }
2014-08-22 09:03:10 +00:00
}, State {
2014-08-19 12:58:02 +00:00
name: "normal"
2017-04-03 16:51:55 +00:00
PropertyChanges { target: leftPanel; visible: (isMobile)? false : true }
2014-08-19 12:58:02 +00:00
PropertyChanges { target: rightPanel; visible: true }
PropertyChanges { target: middlePanel; visible: true }
2017-05-06 15:49:43 +00:00
PropertyChanges { target: titleBar; basicButtonVisible: true }
2014-08-19 12:58:02 +00:00
PropertyChanges { target: wizard; visible: false }
2017-08-07 14:20:37 +00:00
PropertyChanges { target: appWindow; width: (screenWidth < 969 || isAndroid || isIOS)? screenWidth : 969 } //rightPanelExpanded ? 1269 : 1269 - 300;
2017-05-06 15:49:43 +00:00
PropertyChanges { target: appWindow; height: maxWindowHeight; }
2014-08-21 10:09:52 +00:00
PropertyChanges { target: resizeArea; visible: true }
2018-04-21 19:59:31 +00:00
PropertyChanges { target: titleBar; showMaximizeButton: true }
2017-05-06 15:49:43 +00:00
// PropertyChanges { target: frameArea; blocked: true }
PropertyChanges { target: titleBar; visible: true }
2017-04-03 16:51:55 +00:00
// PropertyChanges { target: titleBar; y: 0 }
PropertyChanges { target: titleBar; title: qsTr("Monero") + translationManager.emptyString }
2017-08-07 14:20:37 +00:00
PropertyChanges { target: mobileHeader; visible: isMobile ? true : false }
2014-08-19 12:58:02 +00:00
}
]
2017-04-03 16:51:55 +00:00
MobileHeader {
id: mobileHeader
visible: isMobile
anchors.left: parent.left
anchors.right: parent.right
2017-08-07 14:20:37 +00:00
height: visible? 65 * scaleRatio : 0
2018-07-03 16:56:23 +00:00
MouseArea {
enabled: persistentSettings.customDecorations
property var previousPosition
anchors.fill: parent
propagateComposedEvents: true
onPressed: previousPosition = globalCursor.getPosition()
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
var pos = globalCursor.getPosition()
var dx = pos.x - previousPosition.x
var dy = pos.y - previousPosition.y
appWindow.x += dx
appWindow.y += dy
previousPosition = pos
}
}
}
2017-04-03 16:51:55 +00:00
}
2014-07-07 17:08:30 +00:00
LeftPanel {
id: leftPanel
2017-04-03 16:51:55 +00:00
anchors.top: mobileHeader.bottom
2014-07-07 17:08:30 +00:00
anchors.left: parent.left
anchors.bottom: parent.bottom
2018-04-05 08:32:43 +00:00
onTransferClicked: {
middlePanel.state = "Transfer";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onReceiveClicked: {
middlePanel.state = "Receive";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
2018-12-08 15:55:29 +00:00
onMerchantClicked: {
middlePanel.state = "Merchant";
middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance();
}
2018-04-05 08:32:43 +00:00
onTxkeyClicked: {
middlePanel.state = "TxKey";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onSharedringdbClicked: {
middlePanel.state = "SharedRingDB";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onHistoryClicked: {
middlePanel.state = "History";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onAddressBookClicked: {
middlePanel.state = "AddressBook";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onMiningClicked: {
middlePanel.state = "Mining";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onSignClicked: {
middlePanel.state = "Sign";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
onSettingsClicked: {
middlePanel.state = "Settings";
middlePanel.flickable.contentY = 0;
2018-04-05 08:32:43 +00:00
if(isMobile) {
hideMenu();
}
updateBalance();
}
2018-04-05 08:32:43 +00:00
onKeysClicked: Utils.showSeedPage();
onAccountClicked: {
middlePanel.state = "Account";
middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance();
}
2014-07-07 17:08:30 +00:00
}
RightPanel {
id: rightPanel
anchors.right: parent.right
anchors.bottom: parent.bottom
width: appWindow.rightPanelExpanded ? 300 : 0
visible: appWindow.rightPanelExpanded
2014-07-07 17:08:30 +00:00
}
2014-07-07 17:08:30 +00:00
MiddlePanel {
id: middlePanel
2017-04-03 16:51:55 +00:00
anchors.top: mobileHeader.bottom
2014-07-07 17:08:30 +00:00
anchors.bottom: parent.bottom
2016-10-08 21:50:35 +00:00
anchors.left: leftPanel.visible ? leftPanel.right : parent.left
2017-04-03 16:51:55 +00:00
anchors.right: parent.right
state: "Transfer"
2014-07-07 17:08:30 +00:00
}
TipItem {
id: tipItem
text: qsTr("send to the same destination") + translationManager.emptyString
2014-07-07 17:08:30 +00:00
visible: false
}
2014-07-19 14:07:40 +00:00
SequentialAnimation {
id: goToBasicAnimation
2017-04-03 16:51:55 +00:00
// PropertyAction {
// target: appWindow
// properties: "visibility"
// value: Window.Windowed
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: false
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: true
// }
2014-08-22 09:03:10 +00:00
PropertyAction {
target: resizeArea
properties: "visible"
2017-04-03 16:51:55 +00:00
value: true
2014-07-19 14:07:40 +00:00
}
2017-04-03 16:51:55 +00:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
// PropertyAction {
// target: appWindow
// properties: "width"
// value: 326
// }
2014-07-19 14:07:40 +00:00
PropertyAction {
2016-10-08 21:50:35 +00:00
targets: [leftPanel, rightPanel]
2014-07-19 14:07:40 +00:00
properties: "visible"
value: false
}
PropertyAction {
2016-10-08 21:50:35 +00:00
target: middlePanel
properties: "basicMode"
2014-07-19 14:07:40 +00:00
value: true
}
2016-10-08 21:50:35 +00:00
2017-04-03 16:51:55 +00:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: middlePanel.height
// }
2014-07-19 14:07:40 +00:00
onStopped: {
2016-10-08 21:50:35 +00:00
// middlePanel.visible = false
2014-07-19 14:07:40 +00:00
rightPanel.visible = false
leftPanel.visible = false
}
}
SequentialAnimation {
id: goToProAnimation
2017-04-03 16:51:55 +00:00
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
2014-07-19 14:07:40 +00:00
PropertyAction {
2016-10-08 21:50:35 +00:00
target: middlePanel
properties: "basicMode"
2014-07-19 14:07:40 +00:00
value: false
}
PropertyAction {
2014-08-22 09:03:10 +00:00
targets: [leftPanel, middlePanel, rightPanel, resizeArea]
2014-07-19 14:07:40 +00:00
properties: "visible"
value: true
}
2017-04-03 16:51:55 +00:00
// PropertyAction {
// target: appWindow
// properties: "width"
// value: rightPanelExpanded ? 1269 : 1269 - 300
// }
// PropertyAction {
// target: appWindow
// properties: "height"
// value: maxWindowHeight
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: false
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: true
// }
2014-07-19 14:07:40 +00:00
}
2019-01-14 00:02:44 +00:00
WizardController {
2014-08-19 12:58:02 +00:00
id: wizard
anchors.fill: parent
onUseMoneroClicked: {
2019-01-14 00:02:44 +00:00
rootItem.state = "normal";
appWindow.initialize();
}
2014-08-19 12:58:02 +00:00
}
WizardLang {
id: languageView
visible: false
anchors.fill: parent
}
2017-01-30 09:37:14 +00:00
property int minWidth: 326
2017-04-03 16:51:55 +00:00
property int minHeight: 400
MouseArea {
2014-08-21 10:09:52 +00:00
id: resizeArea
enabled: persistentSettings.customDecorations
hoverEnabled: true
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 30
width: 30
Rectangle {
anchors.fill: parent
2014-07-23 11:59:26 +00:00
color: parent.containsMouse || parent.pressed ? "#111111" : "transparent"
}
Image {
anchors.centerIn: parent
visible: persistentSettings.customDecorations
source: parent.containsMouse || parent.pressed ? "images/resizeHovered.png" :
"images/resize.png"
}
property var previousPosition
onPressed: {
previousPosition = globalCursor.getPosition()
}
onPositionChanged: {
if(!pressed) return
var pos = globalCursor.getPosition()
//var delta = previousPosition - pos
var dx = previousPosition.x - pos.x
var dy = previousPosition.y - pos.y
2017-01-30 09:37:14 +00:00
if(appWindow.width - dx > parent.minWidth)
appWindow.width -= dx
2017-01-30 09:37:14 +00:00
else appWindow.width = parent.minWidth
if(appWindow.height - dy > parent.minHeight)
appWindow.height -= dy
else appWindow.height = parent.minHeight
previousPosition = pos
}
}
TitleBar {
id: titleBar
x: 0
y: 0
2018-04-21 19:59:31 +00:00
anchors.left: parent.left
anchors.right: parent.right
showMinimizeButton: true
showMaximizeButton: true
showWhatIsButton: false
showMoneroLogo: true
onCloseClicked: appWindow.close();
onMaximizeClicked: {
2018-07-28 12:06:05 +00:00
appWindow.visibility = appWindow.visibility !== Window.Maximized ? Window.Maximized :
2018-04-21 19:59:31 +00:00
Window.Windowed
}
onMinimizeClicked: appWindow.visibility = Window.Minimized
2014-07-19 14:07:40 +00:00
onGoToBasicVersion: {
2016-10-08 21:50:35 +00:00
if (yes) {
// basicPanel.currentView = middlePanel.currentView
goToBasicAnimation.start()
} else {
// middlePanel.currentView = basicPanel.currentView
goToProAnimation.start()
}
2014-07-19 14:07:40 +00:00
}
2017-05-06 15:49:43 +00:00
MouseArea {
enabled: persistentSettings.customDecorations
property var previousPosition
anchors.fill: parent
propagateComposedEvents: true
onPressed: previousPosition = globalCursor.getPosition()
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
var pos = globalCursor.getPosition()
var dx = pos.x - previousPosition.x
var dy = pos.y - previousPosition.y
appWindow.x += dx
appWindow.y += dy
previousPosition = pos
}
}
}
}
// new ToolTip
Rectangle {
id: toolTip
property alias text: content.text
width: content.width + 12
height: content.height + 17
color: "#FF6C3C"
//radius: 3
visible:false;
Image {
id: tip
anchors.top: parent.bottom
anchors.right: parent.right
anchors.rightMargin: 5
source: "../images/tip.png"
}
Text {
id: content
anchors.horizontalCenter: parent.horizontalCenter
y: 6
lineHeight: 0.7
font.family: "Arial"
2017-08-07 14:20:37 +00:00
font.pixelSize: 12 * scaleRatio
color: "#FFFFFF"
}
}
2017-02-19 10:38:03 +00:00
Notifier {
2017-04-03 16:51:55 +00:00
visible:false
2017-02-19 10:38:03 +00:00
id: notifier
}
2014-07-07 17:08:30 +00:00
}
2017-03-01 21:03:50 +00:00
function toggleLanguageView(){
middlePanel.visible = !middlePanel.visible;
languageView.visible = !languageView.visible
// update after changing language from settings page
if (persistentSettings.language != wizard.language_language) {
persistentSettings.language = wizard.language_language
persistentSettings.locale = wizard.language_locale
}
}
// 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-01-14 00:02:44 +00:00
function checkSimpleModeConnection(){
// auto-connection mechanism for simple mode
if(persistentSettings.nettype != NetworkType.MAINNET) return;
if(appWindow.walletMode >= 2) return;
var disconnected = leftPanel.networkStatus.connected === Wallet.ConnectionStatus_Disconnected;
var disconnectedEpoch = appWindow.disconnectedEpoch;
if(disconnectedEpoch === 0){
appWindow.disconnectedEpoch = Utils.epoch();
}
// disconnected longer than 5 seconds?
if(disconnected && disconnectedEpoch > 0 && (Utils.epoch() - disconnectedEpoch) >= 5){
// for bootstrap mode, first wait until daemon is killed
if(appWindow.walletMode === 1 && appWindow.daemonRunning) {
appWindow.stopDaemon();
return;
}
// fetch new node list
wizard.fetchRemoteNodes(function() {
// fetched node, connect
if(appWindow.walletMode === 0){
appWindow.connectRemoteNode();
} else if(appWindow.walletMode === 1){
appWindow.startDaemon(persistentSettings.daemonFlags);
}
// reset state
appWindow.disconnectedEpoch = 0;
return;
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), simpleModeConnectionTimer.interval / 1000);
2019-01-14 00:02:44 +00:00
});
}
}
Timer {
// Simple mode connection check timer
id: simpleModeConnectionTimer
interval: 2000; running: false; repeat: true
onTriggered: appWindow.checkSimpleModeConnection()
}
Rectangle {
id: statusMessage
2017-11-02 06:51:15 +00:00
z: 99
visible: false
property alias text: statusMessageText.text
anchors.bottom: parent.bottom
2017-11-02 06:51:15 +00:00
width: statusMessageText.contentWidth + 20 * scaleRatio
anchors.horizontalCenter: parent.horizontalCenter
color: "black"
height: 40 * scaleRatio
Text {
id: statusMessageText
anchors.fill: parent
anchors.margins: 10 * scaleRatio
font.pixelSize: 14 * scaleRatio
color: "white"
}
}
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
}
onClosing: {
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
2018-03-05 16:19:45 +00:00
if(typeof daemonManager != "undefined" && daemonManager.running(persistentSettings.nettype)) {
2017-03-01 21:03:50 +00:00
// Show confirmation dialog
confirmationDialog.title = qsTr("Daemon is running") + translationManager.emptyString;
confirmationDialog.text = qsTr("Daemon will still be running in background when GUI is closed.");
confirmationDialog.icon = StandardIcon.Question
confirmationDialog.cancelText = qsTr("Stop daemon")
confirmationDialog.onAcceptedCallback = function() {
closeAccepted();
}
confirmationDialog.onRejectedCallback = function() {
2018-03-05 16:19:45 +00:00
daemonManager.stop(persistentSettings.nettype);
2017-03-01 21:03:50 +00:00
closeAccepted();
};
confirmationDialog.open()
} else {
closeAccepted();
}
}
function closeAccepted(){
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();
walletManager.closeWallet();
2017-03-01 21:03:50 +00:00
Qt.quit();
}
2017-02-19 10:38:03 +00:00
2017-08-05 22:10:59 +00:00
function onWalletCheckUpdatesComplete(update) {
2017-02-19 10:38:03 +00:00
if (update === "")
return
print("Update found: " + update)
var parts = update.split("|")
if (parts.length == 4) {
var version = parts[0]
var hash = parts[1]
var user_url = parts[2]
var auto_url = parts[3]
var msg = qsTr("New version of monero-wallet-gui is available: %1<br>%2").arg(version).arg(user_url) + translationManager.emptyString
notifier.show(msg)
}
else {
print("Failed to parse update spec")
}
}
2017-08-05 22:10:59 +00:00
function checkUpdates() {
walletManager.checkUpdatesAsync("monero-gui", "gui")
}
2017-02-19 10:38:03 +00:00
Timer {
id: updatesTimer
interval: 3600*1000; running: true; repeat: true
onTriggered: checkUpdates()
}
2018-12-08 15:55:29 +00:00
function titlebarToggleOrange(flag){
// toggle titlebar orange style
if(flag !== undefined){
titleBar.orange = flag;
} else {
titleBar.orange = !titleBar.orange;
}
}
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
}
}
// reset label text. othewise potential privacy leak showing unlock time when switching wallets
function clearMoneroCardLabelText(){
leftPanel.minutesToUnlockTxt = qsTr("Unlocked balance")
leftPanel.balanceLabelText = qsTr("Balance")
}
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;
// 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();
} else {
passwordDialog.showError(qsTr("Wrong password"));
}
}
passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
passwordDialog.open();
}
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){
appWindow.walletMode = mode;
persistentSettings.walletMode = mode;
persistentSettings.useRemoteNode = mode === 0 ? true : false;
console.log("walletMode changed: " + (mode === 0 ? "simple": mode === 1 ? "simple (bootstrap)" : "Advanced"));
}
// Daemon console
DaemonConsole {
id: daemonConsolePopup
height:500
width:800
title: qsTr("Daemon log") + translationManager.emptyString
onAccepted: {
close();
}
}
// background gradient
Rectangle {
id: inactiveOverlay
visible: false
anchors.fill: parent
color: "black"
opacity: 0.8
}
2019-01-14 00:02:44 +00:00
// @TODO: QML type 'Drawer' has issues with buildbot; debug after Qt 5.9 migration
// MoneroComponents.LanguageSidebar {
// id: languageSidebar
// }
2014-07-07 17:08:30 +00:00
}