monero-gui/main.qml

1042 lines
40 KiB
QML
Raw Normal View History

2015-04-01 11:56:05 +03:00
// Copyright (c) 2014-2015, The Monero Project
//
2015-04-01 11:56:05 +03:00
// All rights reserved.
//
2015-04-01 11:56:05 +03: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 11:56:05 +03:00
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
2015-04-01 11:56:05 +03: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 11:56:05 +03: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 11:56:05 +03: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 20:08:30 +03:00
import QtQuick 2.2
import QtQuick.Window 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
2016-06-28 22:37:14 +03:00
import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0
2016-07-13 15:24:40 +03:00
2014-07-07 20:08:30 +03:00
import "components"
2014-08-19 15:58:02 +03:00
import "wizard"
2014-07-07 20:08:30 +03:00
ApplicationWindow {
id: appWindow
property var currentItem
2014-07-07 20:08:30 +03: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 22:37:14 +03:00
property var transaction;
property var transactionDescription;
property alias password : passwordDialog.password
2016-09-30 13:12:26 +03:00
property int splashCounter: 0
property bool isNewWallet: false
property int restoreHeight:0
property bool daemonSynced: false
property int maxWindowHeight: (Screen.height < 900)? 720 : 800;
// true if wallet ever synchronized
property bool walletInitialized : false
2016-07-13 15:24:40 +03:00
function altKeyReleased() { ctrlPressed = false; }
function showPageRequest(page) {
middlePanel.state = page
leftPanel.selectItem(page)
}
function sequencePressed(obj, seq) {
if(seq === undefined)
return
if(seq === "Ctrl") {
ctrlPressed = true
return
}
if(seq === "Ctrl+D") middlePanel.state = "Dashboard"
else if(seq === "Ctrl+H") middlePanel.state = "History"
else if(seq === "Ctrl+T") middlePanel.state = "Transfer"
else if(seq === "Ctrl+B") middlePanel.state = "AddressBook"
else if(seq === "Ctrl+M") middlePanel.state = "Mining"
else if(seq === "Ctrl+S") middlePanel.state = "Settings"
else if(seq === "Ctrl+Tab" || seq === "Alt+Tab") {
if(middlePanel.state === "Dashboard") middlePanel.state = "Transfer"
else if(middlePanel.state === "Transfer") 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 = "Settings"
else if(middlePanel.state === "Settings") middlePanel.state = "Dashboard"
} else if(seq === "Ctrl+Shift+Backtab" || seq === "Alt+Shift+Backtab") {
if(middlePanel.state === "Dashboard") middlePanel.state = "Settings"
else if(middlePanel.state === "Settings") 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 = "Transfer"
else if(middlePanel.state === "Transfer") middlePanel.state = "Dashboard"
}
2014-07-09 19:03:37 +03:00
leftPanel.selectItem(middlePanel.state)
}
function sequenceReleased(obj, seq) {
if(seq === "Ctrl")
ctrlPressed = false
}
function mousePressed(obj, mouseX, mouseY) {
// if(obj.objectName === "appWindow")
// obj = rootItem
// var tmp = rootItem.mapFromItem(obj, mouseX, mouseY)
// if(tmp !== undefined) {
// mouseX = tmp.x
// mouseY = tmp.y
// }
// if(currentItem !== undefined) {
// var tmp_x = rootItem.mapToItem(currentItem, mouseX, mouseY).x
// var tmp_y = rootItem.mapToItem(currentItem, mouseX, mouseY).y
// if(!currentItem.containsPoint(tmp_x, tmp_y)) {
// currentItem.hide()
// currentItem = undefined
// }
// }
}
function mouseReleased(obj, mouseX, mouseY) {
}
2014-07-07 20:08:30 +03:00
function openWalletFromFile(){
persistentSettings.restore_height = 0
restoreHeight = 0;
persistentSettings.is_recovering = false
appWindow.password = ""
fileDialog.open();
}
function initialize() {
2016-07-13 15:24:40 +03:00
console.log("initializing..")
2016-07-19 23:45:12 +03:00
2016-11-07 12:27:53 +02:00
walletInitialized = false;
2016-07-19 23:45:12 +03:00
// setup language
var locale = persistentSettings.locale
if (locale !== "") {
translationManager.setLanguage(locale.split("_")[0]);
}
2016-11-07 00:40:26 +02:00
// disconnect handlers before connecting
middlePanel.paymentClicked.disconnect(handlePayment);
2016-11-08 14:28:05 +02:00
// TODO: remove if statement when PR #111 is merged
if(typeof(handleCheckPayment) !== "undefined") {
middlePanel.checkPaymentClicked.disconnect(handleCheckPayment);
}
middlePanel.paymentClicked.connect(handlePayment);
middlePanel.sweepUnmixableClicked.connect(handleSweepUnmixable);
2016-08-23 16:07:52 +03:00
// basicPanel.paymentClicked.connect(handlePayment);
middlePanel.checkPaymentClicked.connect(handleCheckPayment);
2016-10-05 01:18:50 +03:00
// currentWallet is defined on daemon address change - close/reopen
2016-10-11 00:23:17 +03:00
// TODO: strict comparison here (!==) causes crash after passwordDialog on previously crashed unsynced wallets
if (currentWallet != undefined) {
2016-10-05 01:18:50 +03:00
console.log("closing currentWallet")
walletManager.closeWallet(currentWallet);
} else {
// set page to transfer if not changing daemon
middlePanel.state = "Transfer";
leftPanel.selectItem(middlePanel.state)
2016-10-05 01:18:50 +03:00
}
2016-07-19 23:45:12 +03:00
// wallet already opened with wizard, we just need to initialize it
if (typeof wizard.settings['wallet'] !== 'undefined') {
2016-10-05 01:18:50 +03:00
console.log("using wizard wallet")
//Set restoreHeight
2016-10-10 17:37:03 +03:00
if(persistentSettings.restore_height > 0){
// We store restore height in own variable for performance reasons.
2016-10-10 17:37:03 +03:00
restoreHeight = persistentSettings.restore_height
}
connectWallet(wizard.settings['wallet'])
isNewWallet = true
2016-10-05 01:18:50 +03:00
// We don't need the wizard wallet any more - delete to avoid conflict with daemon adress change
delete wizard.settings['wallet']
} else {
var wallet_path = walletPath();
2016-09-23 00:07:12 +03:00
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.password);
console.log("opening wallet at: ", wallet_path, ", testnet: ", persistentSettings.testnet);
walletManager.openWalletAsync(wallet_path, appWindow.password,
persistentSettings.testnet);
}
2016-06-17 16:35:07 +03:00
}
function connectWallet(wallet) {
showProcessingSplash("Please wait...")
currentWallet = wallet
2016-11-07 00:40:26 +02:00
// Disconnect before connecting
currentWallet.refreshed.disconnect(onWalletRefresh)
currentWallet.updated.disconnect(onWalletUpdate)
currentWallet.newBlock.disconnect(onWalletNewBlock)
currentWallet.moneySpent.disconnect(onWalletMoneySent)
currentWallet.moneyReceived.disconnect(onWalletMoneyReceived)
2016-11-08 19:05:33 +02:00
currentWallet.transactionCreated.disconnect(onTransactionCreated)
2016-11-07 00:40:26 +02:00
currentWallet.refreshed.connect(onWalletRefresh)
currentWallet.updated.connect(onWalletUpdate)
currentWallet.newBlock.connect(onWalletNewBlock)
currentWallet.moneySpent.connect(onWalletMoneySent)
currentWallet.moneyReceived.connect(onWalletMoneyReceived)
2016-11-08 19:05:33 +02:00
currentWallet.transactionCreated.connect(onTransactionCreated)
2016-11-07 00:40:26 +02:00
console.log("initializing with daemon address: ", persistentSettings.daemon_address)
console.log("Recovering from seed: ", persistentSettings.is_recovering)
console.log("restore Height", persistentSettings.restore_height)
currentWallet.initAsync(persistentSettings.daemon_address, 0, persistentSettings.is_recovering, persistentSettings.restore_height);
}
function walletPath() {
var wallet_path = persistentSettings.wallet_path
return wallet_path;
}
function onWalletOpened(wallet) {
console.log(">>> wallet opened: " + wallet)
if (wallet.status !== Wallet.Status_Ok) {
if (appWindow.password === '') {
console.error("Error opening wallet with empty password: ", wallet.errorString);
console.log("closing wallet async : " + wallet.address)
walletManager.closeWalletAsync(wallet)
// try to open wallet with password;
passwordDialog.open();
} else {
// opening with password but password doesn't match
console.error("Error opening wallet with password: ", wallet.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Couldn't open wallet: ") + wallet.errorString;
informationPopup.icon = StandardIcon.Critical
console.log("closing wallet async : " + wallet.address)
walletManager.closeWalletAsync(wallet);
informationPopup.open()
informationPopup.onCloseCallback = function() {
passwordDialog.open()
}
}
return;
}
// wallet opened successfully, subscribing for wallet updates
connectWallet(wallet)
}
function onWalletClosed(walletAddress) {
console.log(">>> wallet closed: " + walletAddress)
}
2016-06-17 16:35:07 +03:00
function onWalletUpdate() {
2016-07-13 15:24:40 +03:00
console.log(">>> wallet updated")
2016-10-09 01:32:03 +03:00
middlePanel.unlockedBalanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(currentWallet.unlockedBalance);
middlePanel.balanceText = leftPanel.balanceText = walletManager.displayAmount(currentWallet.balance);
2016-07-13 15:24:40 +03:00
}
function onWalletRefresh() {
console.log(">>> wallet refreshed")
if (splash.visible) {
hideProcessingSplash()
}
// Check daemon status
var dCurrentBlock = currentWallet.daemonBlockChainHeight();
var dTargetBlock = currentWallet.daemonBlockChainTargetHeight();
leftPanel.daemonProgress.updateProgress(dCurrentBlock,dTargetBlock);
// Daemon connected
leftPanel.networkStatus.connected = currentWallet.connected
// Daemon fully synced
// TODO: implement onDaemonSynced or similar in wallet API and don't start refresh thread before daemon is synced
daemonSynced = (currentWallet.connected != Wallet.ConnectionStatus_Disconnected && dCurrentBlock >= dTargetBlock)
2016-11-10 13:11:25 +02:00
// Refresh is succesfull if blockchain height > 1
if (currentWallet.blockChainHeight() > 1){
2016-11-10 13:11:25 +02: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 13:23:43 +02:00
currentWallet.store()
2016-11-10 13:11:25 +02:00
isNewWallet = false
}
// recovering from seed is finished after first refresh
if(persistentSettings.is_recovering) {
persistentSettings.is_recovering = false
}
}
// initialize transaction history once wallet is initializef first time;
if (!walletInitialized) {
currentWallet.history.refresh()
walletInitialized = true
}
2016-07-14 13:09:39 +03:00
onWalletUpdate();
}
function onWalletNewBlock(blockHeight) {
if (splash.visible) {
var currHeight = blockHeight
//fast refresh until restoreHeight is reached
var increment = ((restoreHeight == 0) || currHeight < restoreHeight)? 1000 : 10
if(currHeight > splashCounter + increment){
2016-09-30 13:12:26 +03:00
splashCounter = currHeight
var locale = Qt.locale()
var currHeightString = currHeight.toLocaleString(locale,"f",0)
var targetHeightString = currentWallet.daemonBlockChainTargetHeight().toLocaleString(locale,"f",0)
2016-10-09 21:49:56 +03:00
var progressText = qsTr("Synchronizing blocks %1 / %2").arg(currHeightString).arg(targetHeightString);
2016-09-30 13:12:26 +03:00
console.log("Progress text: " + progressText);
splash.heightProgressText = progressText
}
}
}
function onWalletMoneyReceived(txId, amount) {
// refresh transaction history here
currentWallet.refresh()
currentWallet.history.refresh() // this will refresh model
}
function onWalletMoneySent(txId, amount) {
// refresh transaction history here
currentWallet.refresh()
currentWallet.history.refresh() // this will refresh model
}
function walletsFound() {
2016-10-30 18:58:12 +02:00
if (persistentSettings.wallet_path.length > 0) {
return walletManager.walletExists(persistentSettings.wallet_path);
}
return false;
}
2016-11-08 19:05:33 +02: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)
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) {
informationPopup.title = qsTr("No unmixable outputs to sweep") + 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 19:05:33 +02:00
} else {
console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount)
+ ", fee: " + walletManager.displayAmount(transaction.fee));
// here we show confirmation popup;
transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString
transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n")
+ (address === "" ? "" : (qsTr("\nAddress: ") + address))
+ (paymentId === "" ? "" : (qsTr("\nPayment ID: ") + paymentId))
2016-11-08 19:05:33 +02:00
+ qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount)
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee)
+ qsTr("\n\nMixin: ") + mixinCount
+ qsTr("\n\Number of transactions: ") + transaction.txCount
+ (transactionDescription === "" ? "" : (qsTr("\n\nDescription: ") + transactionDescription))
2016-11-08 19:05:33 +02:00
+ translationManager.emptyString
transactionConfirmationPopup.icon = StandardIcon.Question
transactionConfirmationPopup.open()
}
}
2016-06-28 22:37:14 +03:00
// called on "transfer"
function handlePayment(address, paymentId, amount, mixinCount, priority, description) {
2016-06-27 15:45:48 +03:00
console.log("Creating transaction: ")
console.log("\taddress: ", address,
", payment_id: ", paymentId,
", amount: ", amount,
", mixins: ", mixinCount,
", priority: ", priority,
", description: ", description);
2016-06-27 15:45:48 +03:00
2016-11-08 19:05:33 +02:00
showProcessingSplash("Creating transaction");
2016-11-08 19:05:33 +02:00
transactionDescription = description;
2016-08-23 16:07:52 +03:00
// validate amount;
2016-11-09 15:00:43 +02:00
if (amount !== "(all)") {
var amountxmr = walletManager.amountFromString(amount);
console.log("integer amount: ", amountxmr);
console.log("integer unlocked",currentWallet.unlockedBalance)
if (amountxmr <= 0) {
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 16:07:52 +03:00
2016-11-09 15:00:43 +02:00
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open()
return;
} else if (amountxmr > currentWallet.unlockedBalance) {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("insufficient funds. Unlocked balance: %1")
.arg(walletManager.displayAmount(currentWallet.unlockedBalance))
+ translationManager.emptyString
2016-10-12 00:02:21 +03:00
2016-11-09 15:00:43 +02:00
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open()
return;
}
2016-08-23 16:07:52 +03:00
}
2016-11-09 15:00:43 +02:00
if (amount === "(all)")
currentWallet.createTransactionAllAsync(address, paymentId, mixinCount, priority);
2016-11-09 15:00:43 +02:00
else
currentWallet.createTransactionAsync(address, paymentId, amountxmr, mixinCount, priority);
2016-06-28 22:37:14 +03:00
}
function handleSweepUnmixable() {
console.log("Creating transaction: ")
transaction = currentWallet.createSweepUnmixableTransaction();
if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't create transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
// deleting transaction object, we don't want memleaks
currentWallet.disposeTransaction(transaction);
} else if (transaction.txCount == 0) {
informationPopup.title = qsTr("No unmixable outputs to sweep") + 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 22:37:14 +03:00
// called after user confirms transaction
function handleTransactionConfirmed() {
// 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]
2016-06-28 22:37:14 +03:00
if (!transaction.commit()) {
console.log("Error committing transaction: " + transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString
2016-06-28 22:37:14 +03: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]
}
informationPopup.text = qsTr("Money sent successfully: %1 transaction(s) ").arg(txid.length) + txid_text + translationManager.emptyString
2016-06-28 22:37:14 +03:00
informationPopup.icon = StandardIcon.Information
if (transactionDescription.length > 0) {
for (var i = 0; i < txid.length; ++i)
currentWallet.setUserNote(txid[i], transactionDescription);
}
}
informationPopup.onCloseCallback = null
2016-06-28 22:37:14 +03:00
informationPopup.open()
2016-08-23 16:07:52 +03:00
currentWallet.refresh()
currentWallet.disposeTransaction(transaction)
2016-11-19 18:33:30 +02:00
currentWallet.store();
}
// called on "checkPayment"
function handleCheckPayment(address, txid, txkey) {
console.log("Checking payment: ")
console.log("\taddress: ", address,
", txid: ", txid,
", txkey: ", txkey);
var result = walletManager.checkPayment(address, txid, txkey, persistentSettings.daemon_address);
var results = result.split("|");
if (results.length < 4) {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = "internal error";
informationPopup.icon = StandardIcon.Critical
informationPopup.open()
return
}
var success = results[0] == "true";
var received = results[1]
var height = results[2]
var error = results[3]
if (success) {
informationPopup.title = qsTr("Payment check") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information
if (received > 0) {
received = received / 1e12
if (height == 0) {
informationPopup.text = qsTr("This address received %1 monero, but the transaction is not yet mined").arg(received);
}
else {
var dCurrentBlock = currentWallet.daemonBlockChainHeight();
var confirmations = dCurrentBlock - height
informationPopup.text = qsTr("This address received %1 monero, with %2 confirmations").arg(received).arg(confirmations);
}
}
else {
informationPopup.text = qsTr("This address received nothing");
}
}
else {
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = error;
informationPopup.icon = StandardIcon.Critical
}
informationPopup.open()
}
// blocks UI if wallet can't be opened or no connection to the daemon
function enableUI(enable) {
middlePanel.enabled = enable;
leftPanel.enabled = enable;
rightPanel.enabled = enable;
2016-10-09 00:50:35 +03:00
// basicPanel.enabled = enable;
}
function showProcessingSplash(message) {
console.log("Displaying processing splash")
if (typeof message != 'undefined') {
2016-11-08 19:05:33 +02:00
splash.messageText = message
splash.heightProgressText = ""
}
splash.show()
}
function hideProcessingSplash() {
console.log("Hiding processing splash")
splash.close()
}
// close wallet and show wizard
function showWizard(){
walletInitialized = false;
splashCounter = 0;
2016-10-30 18:58:12 +02:00
// we can't close async here. Gui crashes if wallet is open
if (currentWallet != undefined) {
walletManager.closeWallet(currentWallet);
currentWallet = undefined
}
wizard.restart();
rootItem.state = "wizard"
}
2016-06-28 22:37:14 +03:00
objectName: "appWindow"
2014-07-07 20:08:30 +03:00
visible: true
width: rightPanelExpanded ? 1269 : 1269 - 300
height: maxWindowHeight;
2014-07-07 20:08:30 +03:00
color: "#FFFFFF"
flags: Qt.FramelessWindowHint | Qt.WindowSystemMenuHint | Qt.Window | Qt.WindowMinimizeButtonHint
2014-07-19 17:07:40 +03:00
onWidthChanged: x -= 0
2014-07-19 17:07:40 +03:00
Component.onCompleted: {
x = (Screen.width - width) / 2
y = (Screen.height - maxWindowHeight) / 2
//
walletManager.walletOpened.connect(onWalletOpened);
walletManager.walletClosed.connect(onWalletClosed);
2016-10-30 18:58:12 +02:00
if(!walletsFound()) {
rootItem.state = "wizard"
} else {
rootItem.state = "normal"
initialize(persistentSettings);
}
}
2016-06-21 11:58:06 +03:00
onRightPanelExpandedChanged: {
if (rightPanelExpanded) {
rightPanel.updateTweets()
}
}
Settings {
id: persistentSettings
property string language
2016-07-19 23:45:12 +03:00
property string locale
property string account_name
property string wallet_path
2016-11-12 13:11:24 +02:00
property bool auto_donations_enabled : false
property int auto_donations_amount : 50
2016-11-12 13:11:24 +02:00
property bool allow_background_mining : false
property bool testnet: false
property string daemon_address: "localhost:18081"
property string payment_id
property int restore_height : 0
property bool is_recovering : false
2014-07-19 17:07:40 +03:00
}
2014-07-07 20:08:30 +03:00
2016-06-28 22:37:14 +03:00
// TODO: replace with customized popups
// Information dialog
MessageDialog {
// dynamically change onclose handler
property var onCloseCallback
2016-06-28 22:37:14 +03:00
id: informationPopup
standardButtons: StandardButton.Ok
onAccepted: {
if (onCloseCallback) {
onCloseCallback()
}
}
2016-06-28 22:37:14 +03:00
}
// Confrirmation aka question dialog
MessageDialog {
id: transactionConfirmationPopup
standardButtons: StandardButton.Ok + StandardButton.Cancel
onAccepted: {
handleTransactionConfirmed()
}
}
//Open Wallet from file
FileDialog {
id: fileDialog
title: "Please choose a file"
folder: "file://" +moneroAccountsDir
2016-10-30 18:58:12 +02:00
nameFilters: [ "Wallet files (*.keys)"]
onAccepted: {
persistentSettings.wallet_path = walletManager.urlToLocalPath(fileDialog.fileUrl)
initialize();
}
onRejected: {
console.log("Canceled")
rootItem.state = "wizard";
}
}
PasswordDialog {
id: passwordDialog
onAccepted: {
appWindow.currentWallet = null
appWindow.initialize();
}
onRejected: {
//appWindow.enableUI(false)
rootItem.state = "wizard"
}
}
ProcessingSplash {
id: splash
2016-10-09 21:49:56 +03:00
width: appWindow.width / 1.5
height: appWindow.height / 2
x: (appWindow.width - width) / 2 + appWindow.x
y: (appWindow.height - height) / 2 + appWindow.y
messageText: qsTr("Please wait...")
2016-07-13 15:24:40 +03:00
}
2016-06-28 22:37:14 +03:00
2014-07-07 20:08:30 +03:00
Item {
id: rootItem
anchors.fill: parent
2014-07-19 17:07:40 +03:00
clip: true
2014-07-07 20:08:30 +03:00
2014-08-19 15:58:02 +03:00
state: "wizard"
states: [
State {
name: "wizard"
PropertyChanges { target: leftPanel; visible: false }
PropertyChanges { target: rightPanel; visible: false }
PropertyChanges { target: middlePanel; visible: false }
PropertyChanges { target: titleBar; basicButtonVisible: false }
PropertyChanges { target: wizard; visible: true }
2014-08-21 13:09:52 +03:00
PropertyChanges { target: appWindow; width: 930; }
PropertyChanges { target: appWindow; height: 595; }
PropertyChanges { target: resizeArea; visible: false }
2014-08-22 12:03:10 +03:00
PropertyChanges { target: titleBar; maximizeButtonVisible: false }
PropertyChanges { target: frameArea; blocked: true }
PropertyChanges { target: titleBar; y: 0 }
PropertyChanges { target: titleBar; title: qsTr("Program setup wizard") + translationManager.emptyString }
2014-08-22 12:03:10 +03:00
}, State {
2014-08-19 15:58:02 +03:00
name: "normal"
PropertyChanges { target: leftPanel; visible: true }
PropertyChanges { target: rightPanel; visible: true }
PropertyChanges { target: middlePanel; visible: true }
PropertyChanges { target: titleBar; basicButtonVisible: true }
PropertyChanges { target: wizard; visible: false }
2014-08-21 13:09:52 +03:00
PropertyChanges { target: appWindow; width: rightPanelExpanded ? 1269 : 1269 - 300; }
PropertyChanges { target: appWindow; height: maxWindowHeight; }
2014-08-21 13:09:52 +03:00
PropertyChanges { target: resizeArea; visible: true }
2014-08-22 12:03:10 +03:00
PropertyChanges { target: titleBar; maximizeButtonVisible: true }
PropertyChanges { target: frameArea; blocked: false }
2016-11-16 01:02:09 +02:00
PropertyChanges { target: titleBar; y: 0 }
PropertyChanges { target: titleBar; title: qsTr("Monero") + translationManager.emptyString }
2014-08-19 15:58:02 +03:00
}
]
2014-07-07 20:08:30 +03:00
LeftPanel {
id: leftPanel
anchors.left: parent.left
anchors.bottom: parent.bottom
2014-07-19 17:07:40 +03:00
height: parent.height
2014-07-07 20:08:30 +03:00
onDashboardClicked: middlePanel.state = "Dashboard"
onHistoryClicked: middlePanel.state = "History"
onTransferClicked: middlePanel.state = "Transfer"
onReceiveClicked: middlePanel.state = "Receive"
onTxkeyClicked: middlePanel.state = "TxKey"
2014-07-07 20:08:30 +03:00
onAddressBookClicked: middlePanel.state = "AddressBook"
onMiningClicked: middlePanel.state = "Minning"
2016-11-08 12:06:34 +02:00
onSignClicked: middlePanel.state = "Sign"
2014-07-07 20:08:30 +03:00
onSettingsClicked: middlePanel.state = "Settings"
}
RightPanel {
id: rightPanel
anchors.right: parent.right
anchors.bottom: parent.bottom
2014-07-19 17:07:40 +03:00
height: parent.height
width: appWindow.rightPanelExpanded ? 300 : 0
visible: appWindow.rightPanelExpanded
2014-07-07 20:08:30 +03:00
}
2014-07-07 20:08:30 +03:00
MiddlePanel {
id: middlePanel
anchors.bottom: parent.bottom
2016-10-09 00:50:35 +03:00
anchors.left: leftPanel.visible ? leftPanel.right : parent.left
2014-07-07 20:08:30 +03:00
anchors.right: rightPanel.left
2014-07-19 17:07:40 +03:00
height: parent.height
state: "Transfer"
2014-07-07 20:08:30 +03:00
}
TipItem {
id: tipItem
text: qsTr("send to the same destination") + translationManager.emptyString
2014-07-07 20:08:30 +03:00
visible: false
}
MouseArea {
id: frameArea
2014-07-19 17:07:40 +03:00
property bool blocked: false
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 30
z: 1
hoverEnabled: true
2016-11-16 01:02:09 +02:00
// Uncomment to enable 'auto-hidden' titlebar
/*
2014-07-19 17:07:40 +03:00
onEntered: if(!blocked) titleBar.y = 0
onExited: if(!blocked) titleBar.y = -titleBar.height
2016-11-16 01:02:09 +02:00
*/
propagateComposedEvents: true
onPressed: mouse.accepted = false
onReleased: mouse.accepted = false
onMouseXChanged: titleBar.mouseX = mouseX
onContainsMouseChanged: titleBar.containsMouse = containsMouse
}
2014-07-19 17:07:40 +03:00
SequentialAnimation {
id: goToBasicAnimation
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 12:03:10 +03:00
PropertyAction {
target: resizeArea
properties: "visible"
value: false
}
2014-07-19 17:07:40 +03:00
NumberAnimation {
target: appWindow
properties: "height"
to: 30
easing.type: Easing.InCubic
duration: 200
}
NumberAnimation {
target: appWindow
properties: "width"
to: 470
easing.type: Easing.InCubic
duration: 200
}
PropertyAction {
2016-10-09 00:50:35 +03:00
targets: [leftPanel, rightPanel]
2014-07-19 17:07:40 +03:00
properties: "visible"
value: false
}
PropertyAction {
2016-10-09 00:50:35 +03:00
target: middlePanel
properties: "basicMode"
2014-07-19 17:07:40 +03:00
value: true
}
2016-10-09 00:50:35 +03:00
2014-07-19 17:07:40 +03:00
NumberAnimation {
target: appWindow
properties: "height"
2016-10-09 00:50:35 +03:00
to: middlePanel.height
2014-07-19 17:07:40 +03:00
easing.type: Easing.InCubic
duration: 200
}
onStopped: {
2016-10-09 00:50:35 +03:00
// middlePanel.visible = false
2014-07-19 17:07:40 +03:00
rightPanel.visible = false
leftPanel.visible = false
}
}
SequentialAnimation {
id: goToProAnimation
NumberAnimation {
target: appWindow
properties: "height"
to: 30
easing.type: Easing.InCubic
duration: 200
}
PropertyAction {
2016-10-09 00:50:35 +03:00
target: middlePanel
properties: "basicMode"
2014-07-19 17:07:40 +03:00
value: false
}
PropertyAction {
2014-08-22 12:03:10 +03:00
targets: [leftPanel, middlePanel, rightPanel, resizeArea]
2014-07-19 17:07:40 +03:00
properties: "visible"
value: true
}
NumberAnimation {
target: appWindow
properties: "width"
to: rightPanelExpanded ? 1269 : 1269 - 300
easing.type: Easing.InCubic
duration: 200
}
NumberAnimation {
target: appWindow
properties: "height"
2016-11-21 23:22:26 +02:00
to: maxWindowHeight
2014-07-19 17:07:40 +03:00
easing.type: Easing.InCubic
duration: 200
}
PropertyAction {
target: frameArea
properties: "blocked"
value: false
}
PropertyAction {
target: titleBar
properties: "maximizeButtonVisible"
value: true
}
}
2014-08-19 15:58:02 +03:00
WizardMain {
id: wizard
anchors.fill: parent
onUseMoneroClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow;
appWindow.initialize();
}
onOpenWalletFromFileClicked: {
rootItem.state = "normal" // TODO: listen for this state change in appWindow;
appWindow.openWalletFromFile();
}
2014-08-19 15:58:02 +03:00
}
property int maxWidth: leftPanel.width + 655 + rightPanel.width
property int minHeight: 720
MouseArea {
2014-08-21 13:09:52 +03:00
id: resizeArea
hoverEnabled: true
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 30
width: 30
Rectangle {
anchors.fill: parent
2014-07-23 14:59:26 +03:00
color: parent.containsMouse || parent.pressed ? "#111111" : "transparent"
}
Image {
anchors.centerIn: parent
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
if(appWindow.width - dx > parent.maxWidth)
appWindow.width -= dx
else appWindow.width = parent.maxWidth
if(appWindow.height - dy > parent.minHeight)
appWindow.height -= dy
else appWindow.height = parent.minHeight
previousPosition = pos
}
}
TitleBar {
id: titleBar
anchors.left: parent.left
anchors.right: parent.right
2014-07-19 17:07:40 +03:00
onGoToBasicVersion: {
2016-10-09 00:50:35 +03:00
if (yes) {
// basicPanel.currentView = middlePanel.currentView
goToBasicAnimation.start()
} else {
// middlePanel.currentView = basicPanel.currentView
goToProAnimation.start()
}
2014-07-19 17:07:40 +03:00
}
MouseArea {
property var previousPosition
anchors.fill: parent
propagateComposedEvents: true
onPressed: previousPosition = globalCursor.getPosition()
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
var pos = globalCursor.getPosition()
var dx = pos.x - previousPosition.x
var dy = pos.y - previousPosition.y
appWindow.x += dx
appWindow.y += dy
previousPosition = pos
}
}
}
}
2014-07-07 20:08:30 +03:00
}
onClosing: {
2016-11-10 13:11:25 +02:00
// Close and save to disk on app close
if (currentWallet != undefined) {
walletManager.closeWallet(currentWallet);
currentWallet = undefined
}
}
2014-07-07 20:08:30 +03:00
}