mirror of
https://github.com/monero-project/monero-gui.git
synced 2025-01-14 14:54:39 +00:00
Merge pull request #41
b1454c6
removed duplicated-by-mistake code (Ilya Kitaev)be135e3
Processing splash formatting improved (Ilya Kitaev)54b22d2
Wizard: finish page: restore height hidden if not set (Ilya Kitaev)d67071a
Settings page: layout items vertically (Ilya Kitaev)4f4cc9c
Settings page: small renaming and formatting (Ilya Kitaev)da552a0
History: Fixed filter collapse (Ilya Kitaev)7ed623e
Basic mode: updating balance properly (Ilya Kitaev)eafcf71
Minimized aka basic mode (Ilya Kitaev)a032c84
History: fee color (Ilya Kitaev)60b2d90
History: display "fee" for sent transactions (Ilya Kitaev)0ac27e1
History: filter by amount (Ilya Kitaev)10c2786
added restore height to wizardFinish (Jacob Brydolf)883762c
removed daemon-blockchain-progress rests (Jacob Brydolf)38d9034
Wizard: added restore-height (Jacob Brydolf)7f0d6c4
persistentSettings: added restoreHeight (Jacob Brydolf)9f336a5
libwalletqt: added restore-height parameter to recoveryWallet(); (Jacob Brydolf)0e0b0be
removed moneroComponets dependency (Jacob Brydolf)38db5a4
Integrate splash counter with restore-height (Jacob Brydolf)868610c
fix conflict (Jacob Brydolf)4901839
added comma/locale separation to sync counter (Jacob Brydolf)8b748bf
History: filter by amount (Ilya Kitaev)9b09e83
History: filtering by paymentId and date (Ilya Kitaev)e3cea85
TransactionHistory: firstDateTime and lastDateTime properties (Ilya Kitaev)9927182
Fix: unused dummy property removed (Ilya Kitaev)fd9ed56
Fix: DatePicker component doesn't update the date (Ilya Kitaev)612c497
TransactionHistory sorting (Ilya Kitaev)e7e6c58
Adding sort-filter-proxy model (Ilya Kitaev)0498c3b
Transaction history is not crashing and refreshing properly (Ilya Kitaev)defc2a4
build: get_libwallet_api.sh accepts build type ("Debug" or "Release", release is default); extra build script that skips cmake invocations (Ilya Kitaev)2966b0d
settings page: daemon change + password prompt on seed view (Jacob Brydolf)9700944
close wallet before reopen (Jacob Brydolf)522b067
Simple transaction history (Ilya Kitaev)9cc92bf
added onPageCompleted (Jacob Brydolf)53d3bc4
Receive page: display long address from the beginning in TextField (Ilya Kitaev)5814c19
Fixed overlapping clipboard icons on recieve page (Jacob Brydolf)cd1247c
Added option to show seed on settings-page (Jacob Brydolf)af70c81
Added daemon BC sync progress bar depends on https://github.com/monero-project/monero/pull/1173 (Jacob Brydolf)6a50951
Removed hardcoded height from PasswordDialog (Ilya Kitaev)819be91
Integrating TransactionHistoryModel (Ilya Kitaev)56c3579
Replaced Loader with StackView; Fixed payment id generation (Ilya Kitaev)0ff3fd3
added TransactionHistoryModel; renamings (Ilya Kitaev)bd8646d
UX improvements in wizard - password page styling - tab navigation / focus on load - click language loads next page (Jacob Brydolf)
This commit is contained in:
commit
053e7c7cda
42 changed files with 1705 additions and 262 deletions
BasicPanel.qmlLeftPanel.qmlMiddlePanel.qmlbuild_libwallet_api.sh
components
AddressBookTable.qmlDaemonProgress.qmlDashboardTable.qmlDatePicker.qmlHistoryTable.qmlLineEdit.qmlPasswordDialog.qmlProcessingSplash.qml
get_libwallet_api.shmain.cppmain.qmlmonero-core.propages
qml.qrcsrc
libwalletqt
TransactionHistory.cppTransactionHistory.hTransactionInfo.cppTransactionInfo.hWallet.cppWallet.hWalletManager.cppWalletManager.h
model
wizard
|
@ -31,6 +31,8 @@ import QtGraphicalEffects 1.0
|
|||
import "components"
|
||||
import "pages"
|
||||
|
||||
// mbg033 @ 2016-10-08: Not used anymore, to be deleted
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 470
|
||||
|
|
|
@ -36,6 +36,7 @@ Rectangle {
|
|||
property alias unlockedBalanceText: unlockedBalanceText.text
|
||||
property alias balanceText: balanceText.text
|
||||
property alias networkStatus : networkStatus
|
||||
property alias daemonProgress : daemonProgress
|
||||
|
||||
signal dashboardClicked()
|
||||
signal historyClicked()
|
||||
|
@ -252,17 +253,17 @@ Rectangle {
|
|||
panel.receiveClicked()
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
color: transferButton.checked || historyButton.checked ? "#1C1C1C" : "#505050"
|
||||
height: 1
|
||||
}*/
|
||||
}
|
||||
|
||||
// ------------- History tab ---------------
|
||||
/*
|
||||
|
||||
MenuButton {
|
||||
id: historyButton
|
||||
anchors.left: parent.left
|
||||
|
@ -276,7 +277,7 @@ Rectangle {
|
|||
panel.historyClicked()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
@ -330,7 +331,7 @@ Rectangle {
|
|||
color: miningButton.checked || settingsButton.checked ? "#1C1C1C" : "#505050"
|
||||
height: 1
|
||||
}
|
||||
|
||||
*/
|
||||
// ------------- Settings tab ---------------
|
||||
MenuButton {
|
||||
id: settingsButton
|
||||
|
@ -345,16 +346,23 @@ Rectangle {
|
|||
panel.settingsClicked()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
NetworkStatusItem {
|
||||
id: networkStatus
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottom: (daemonProgress.visible)? daemonProgress.top : parent.bottom;
|
||||
connected: false
|
||||
}
|
||||
|
||||
DaemonProgress {
|
||||
id: daemonProgress
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
// indicate disabled state
|
||||
Desaturate {
|
||||
|
|
261
MiddlePanel.qml
261
MiddlePanel.qml
|
@ -27,44 +27,103 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQml 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import "pages"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "#F0EEEE"
|
||||
|
||||
property Item currentView
|
||||
property bool basicMode : false
|
||||
property string balanceText
|
||||
property string unlockedBalanceText
|
||||
|
||||
property Transfer transferView: Transfer { }
|
||||
property Receive receiveView: Receive { }
|
||||
property History historyView: History { }
|
||||
property Settings settingsView: Settings { }
|
||||
|
||||
|
||||
signal paymentClicked(string address, string paymentId, double amount, int mixinCount, int priority)
|
||||
signal generatePaymentIdInvoked()
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Dashboard"
|
||||
PropertyChanges { target: loader; source: "pages/Dashboard.qml" }
|
||||
}, State {
|
||||
name: "History"
|
||||
PropertyChanges { target: loader; source: "pages/History.qml" }
|
||||
}, State {
|
||||
name: "Transfer"
|
||||
PropertyChanges { target: loader; source: "pages/Transfer.qml" }
|
||||
}, State {
|
||||
name: "Receive"
|
||||
PropertyChanges { target: loader; source: "pages/Receive.qml" }
|
||||
}, State {
|
||||
name: "AddressBook"
|
||||
PropertyChanges { target: loader; source: "pages/AddressBook.qml" }
|
||||
}, State {
|
||||
name: "Settings"
|
||||
PropertyChanges { target: loader; source: "pages/Settings.qml" }
|
||||
}, State {
|
||||
name: "Mining"
|
||||
PropertyChanges { target: loader; source: "pages/Mining.qml" }
|
||||
}
|
||||
]
|
||||
color: "#F0EEEE"
|
||||
|
||||
onCurrentViewChanged: {
|
||||
if (currentView) {
|
||||
stackView.replace(currentView)
|
||||
|
||||
// Component.onCompleted is called before wallet is initilized
|
||||
if (typeof currentView.onPageCompleted === "function") {
|
||||
currentView.onPageCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// XXX: just for memo, to be removed
|
||||
// states: [
|
||||
// State {
|
||||
// name: "Dashboard"
|
||||
// PropertyChanges { target: loader; source: "pages/Dashboard.qml" }
|
||||
// }, State {
|
||||
// name: "History"
|
||||
// PropertyChanges { target: loader; source: "pages/History.qml" }
|
||||
// }, State {
|
||||
// name: "Transfer"
|
||||
// PropertyChanges { target: loader; source: "pages/Transfer.qml" }
|
||||
// }, State {
|
||||
// name: "Receive"
|
||||
// PropertyChanges { target: loader; source: "pages/Receive.qml" }
|
||||
// }, State {
|
||||
// name: "AddressBook"
|
||||
// PropertyChanges { target: loader; source: "pages/AddressBook.qml" }
|
||||
// }, State {
|
||||
// name: "Settings"
|
||||
// PropertyChanges { target: loader; source: "pages/Settings.qml" }
|
||||
// }, State {
|
||||
// name: "Mining"
|
||||
// PropertyChanges { target: loader; source: "pages/Mining.qml" }
|
||||
// }
|
||||
// ]
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Dashboard"
|
||||
PropertyChanges { }
|
||||
}, State {
|
||||
name: "History"
|
||||
PropertyChanges { target: root; currentView: historyView }
|
||||
PropertyChanges { target: historyView; model: appWindow.currentWallet.historyModel }
|
||||
}, State {
|
||||
name: "Transfer"
|
||||
PropertyChanges { target: root; currentView: transferView }
|
||||
}, State {
|
||||
name: "Receive"
|
||||
PropertyChanges { target: root; currentView: receiveView }
|
||||
}, State {
|
||||
name: "AddressBook"
|
||||
PropertyChanges { /*TODO*/ }
|
||||
}, State {
|
||||
name: "Settings"
|
||||
PropertyChanges { target: root; currentView: settingsView }
|
||||
}, State {
|
||||
name: "Mining"
|
||||
PropertyChanges { /*TODO*/ }
|
||||
}
|
||||
]
|
||||
|
||||
// color stripe at the top
|
||||
Row {
|
||||
id: styledRow
|
||||
height: 4
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
|
||||
|
||||
Rectangle { height: 4; width: parent.width / 5; color: "#FFE00A" }
|
||||
Rectangle { height: 4; width: parent.width / 5; color: "#6B0072" }
|
||||
|
@ -73,28 +132,127 @@ Rectangle {
|
|||
Rectangle { height: 4; width: parent.width / 5; color: "#FF4F41" }
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: styledRow.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
onLoaded: {
|
||||
console.log("Loaded " + item);
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
anchors.topMargin: 30
|
||||
spacing: 0
|
||||
|
||||
|
||||
// BasicPanel header
|
||||
Rectangle {
|
||||
id: header
|
||||
anchors.leftMargin: 1
|
||||
anchors.rightMargin: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 64
|
||||
color: "#FFFFFF"
|
||||
visible: basicMode
|
||||
|
||||
Image {
|
||||
id: logo
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: -5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
source: "images/moneroLogo2.png"
|
||||
}
|
||||
|
||||
Grid {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
width: 256
|
||||
columns: 3
|
||||
|
||||
Text {
|
||||
|
||||
width: 116
|
||||
height: 20
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 12
|
||||
font.letterSpacing: -1
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignBottom
|
||||
color: "#535353"
|
||||
text: qsTr("Balance:")
|
||||
}
|
||||
|
||||
Text {
|
||||
id: balanceText
|
||||
width: 110
|
||||
height: 20
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
font.letterSpacing: -1
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignBottom
|
||||
color: "#000000"
|
||||
text: root.balanceText
|
||||
}
|
||||
|
||||
Item {
|
||||
height: 20
|
||||
width: 20
|
||||
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
source: "images/lockIcon.png"
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
width: 116
|
||||
height: 20
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 12
|
||||
font.letterSpacing: -1
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignBottom
|
||||
color: "#535353"
|
||||
text: qsTr("Unlocked Balance:")
|
||||
}
|
||||
|
||||
Text {
|
||||
id: availableBalanceText
|
||||
width: 110
|
||||
height: 20
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 14
|
||||
font.letterSpacing: -1
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignBottom
|
||||
color: "#000000"
|
||||
text: root.unlockedBalanceText
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: 1
|
||||
color: "#DBDBDB"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* connect "payment" click */
|
||||
Connections {
|
||||
ignoreUnknownSignals: false
|
||||
target: loader.item
|
||||
onPaymentClicked : {
|
||||
console.log("MiddlePanel: paymentClicked")
|
||||
paymentClicked(address, paymentId, amount, mixinCount, priority)
|
||||
// Views container
|
||||
StackView {
|
||||
id: stackView
|
||||
initialItem: transferView
|
||||
anchors.topMargin: 30
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
anchors.top: styledRow.bottom
|
||||
anchors.margins: 4
|
||||
clip: true // otherwise animation will affect left panel
|
||||
}
|
||||
}
|
||||
|
||||
// border
|
||||
Rectangle {
|
||||
anchors.top: styledRow.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
|
@ -117,12 +275,25 @@ Rectangle {
|
|||
anchors.bottom: parent.bottom
|
||||
height: 1
|
||||
color: "#DBDBDB"
|
||||
|
||||
}
|
||||
|
||||
// indicate disabled state
|
||||
|
||||
// indicates disabled state
|
||||
Desaturate {
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
desaturation: root.enabled ? 0.0 : 1.0
|
||||
}
|
||||
|
||||
|
||||
/* connect "payment" click */
|
||||
Connections {
|
||||
ignoreUnknownSignals: false
|
||||
target: transferView
|
||||
onPaymentClicked : {
|
||||
console.log("MiddlePanel: paymentClicked")
|
||||
paymentClicked(address, paymentId, amount, mixinCount, priority)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
52
build_libwallet_api.sh
Executable file
52
build_libwallet_api.sh
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# MONERO_URL=https://github.com/monero-project/monero.git
|
||||
# MONERO_BRANCH=master
|
||||
CPU_CORE_COUNT=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu)
|
||||
pushd $(pwd)
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
source $ROOT_DIR/utils.sh
|
||||
|
||||
|
||||
INSTALL_DIR=$ROOT_DIR/wallet
|
||||
MONERO_DIR=$ROOT_DIR/monero
|
||||
|
||||
|
||||
mkdir -p $MONERO_DIR/build/release
|
||||
pushd $MONERO_DIR/build/release
|
||||
|
||||
# reusing function from "utils.sh"
|
||||
platform=$(get_platform)
|
||||
|
||||
pushd $MONERO_DIR/build/release/src/wallet
|
||||
make -j$CPU_CORE_COUNT
|
||||
make install -j$CPU_CORE_COUNT
|
||||
popd
|
||||
|
||||
# unbound is one more dependency. can't be merged to the wallet_merged
|
||||
# since filename conflict (random.c.obj)
|
||||
# for Linux, we use libunbound shipped with the system, so we don't need to build it
|
||||
|
||||
if [ "$platform" != "linux" ]; then
|
||||
echo "Building libunbound..."
|
||||
pushd $MONERO_DIR/build/release/external/unbound
|
||||
# no need to make, it was already built as dependency for libwallet
|
||||
# make -j$CPU_CORE_COUNT
|
||||
make install -j$CPU_CORE_COUNT
|
||||
popd
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
|
90
components/DaemonProgress.qml
Normal file
90
components/DaemonProgress.qml
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2014-2015, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: item
|
||||
property int fillLevel: 0
|
||||
height: 44
|
||||
anchors.margins: 10
|
||||
visible: false
|
||||
//clip: true
|
||||
|
||||
function updateProgress(currentBlock,targetBlock){
|
||||
if(targetBlock > 0) {
|
||||
var progressLevel = ((currentBlock/targetBlock) * 100).toFixed(0);
|
||||
fillLevel = progressLevel
|
||||
console.log("target block: ",progressLevel)
|
||||
progressText.text = qsTr("Synchronizing blocks %1/%2").arg(currentBlock.toFixed(0)).arg(targetBlock.toFixed(0));
|
||||
console.log("Progress text: " + progressText.text);
|
||||
|
||||
// TODO: lower daemon block height cache, ttl and refresh interval?
|
||||
|
||||
item.visible = (currentBlock < targetBlock)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: bar
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
height: 18
|
||||
//radius: 4
|
||||
color: "#FFFFFF"
|
||||
|
||||
Rectangle {
|
||||
id: fillRect
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 2
|
||||
property int maxWidth: parent.width - 4
|
||||
width: (maxWidth * fillLevel) / 100
|
||||
|
||||
color: {
|
||||
if(item.fillLevel < 99) return "#FF6C3C"
|
||||
//if(item.fillLevel < 99) return "#FFE00A"
|
||||
return "#36B25C"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id:progressText
|
||||
anchors.bottom: parent.bottom
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 12
|
||||
color: "#545454"
|
||||
text: qsTr("Synchronizing blocks")
|
||||
}
|
||||
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
|
|
@ -33,12 +33,13 @@ import QtQuick.Controls.Styles 1.2
|
|||
Item {
|
||||
id: datePicker
|
||||
property bool expanded: false
|
||||
property var currentDate: new Date()
|
||||
property date currentDate
|
||||
property bool showCurrentDate: true
|
||||
height: 37
|
||||
width: 156
|
||||
|
||||
onExpandedChanged: if(expanded) appWindow.currentItem = datePicker
|
||||
|
||||
function hide() { datePicker.expanded = false }
|
||||
function containsPoint(px, py) {
|
||||
if(px < 0)
|
||||
|
@ -121,12 +122,29 @@ Item {
|
|||
}
|
||||
|
||||
Row {
|
||||
id: dateInput
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
|
||||
function setDate(date) {
|
||||
var day = date.getDate()
|
||||
var month = date.getMonth() + 1
|
||||
dayInput.text = day < 10 ? "0" + day : day
|
||||
monthInput.text = month < 10 ? "0" + month : month
|
||||
yearInput.text = date.getFullYear()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: datePicker
|
||||
onCurrentDateChanged: {
|
||||
dateInput.setDate(datePicker.currentDate)
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: dayInput
|
||||
readOnly: true
|
||||
width: 22
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
|
@ -135,6 +153,7 @@ Item {
|
|||
horizontalAlignment: TextInput.AlignHCenter
|
||||
validator: IntValidator{bottom: 01; top: 31;}
|
||||
KeyNavigation.tab: monthInput
|
||||
|
||||
text: {
|
||||
if(datePicker.showCurrentDate) {
|
||||
var day = datePicker.currentDate.getDate()
|
||||
|
@ -158,6 +177,7 @@ Item {
|
|||
|
||||
TextInput {
|
||||
id: monthInput
|
||||
readOnly: true
|
||||
width: 22
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
|
@ -277,12 +297,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if(styleData.visibleMonth) {
|
||||
var date = styleData.date
|
||||
var day = date.getDate()
|
||||
var month = date.getMonth() + 1
|
||||
dayInput.text = day < 10 ? "0" + day : day
|
||||
monthInput.text = month < 10 ? "0" + month : month
|
||||
yearInput.text = date.getFullYear()
|
||||
currentDate = styleData.date
|
||||
datePicker.expanded = false
|
||||
} else {
|
||||
var date = styleData.date
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
clip: true
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
property var previousItem
|
||||
|
||||
footer: Rectangle {
|
||||
height: 127
|
||||
|
@ -48,7 +50,7 @@ ListView {
|
|||
}
|
||||
}
|
||||
|
||||
property var previousItem
|
||||
|
||||
delegate: Rectangle {
|
||||
id: delegate
|
||||
height: 114
|
||||
|
@ -63,13 +65,13 @@ ListView {
|
|||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 14
|
||||
|
||||
// -- direction indicator
|
||||
Rectangle {
|
||||
id: dot
|
||||
width: 14
|
||||
height: width
|
||||
radius: width / 2
|
||||
color: out ? "#FF4F41" : "#36B05B"
|
||||
color: isOut ? "#FF4F41" : "#36B05B"
|
||||
}
|
||||
|
||||
Item { //separator
|
||||
|
@ -77,6 +79,8 @@ ListView {
|
|||
height: 14
|
||||
}
|
||||
|
||||
// -- description aka recepient name from address book (TODO)
|
||||
/*
|
||||
Text {
|
||||
id: descriptionText
|
||||
width: text.length ? (descriptionArea.containsMouse ? parent.width - x - 12 : 120) : 0
|
||||
|
@ -94,13 +98,15 @@ ListView {
|
|||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
/*
|
||||
Item { //separator
|
||||
width: descriptionText.width ? 12 : 0
|
||||
height: 14
|
||||
visible: !descriptionArea.containsMouse
|
||||
}
|
||||
|
||||
*/
|
||||
// -- address (in case outgoing transaction) - N/A in case of incoming
|
||||
Text {
|
||||
id: addressText
|
||||
anchors.verticalCenter: dot.verticalCenter
|
||||
|
@ -109,11 +115,11 @@ ListView {
|
|||
font.family: "Arial"
|
||||
font.pixelSize: 14
|
||||
color: "#545454"
|
||||
text: address
|
||||
visible: !descriptionArea.containsMouse
|
||||
text: hash
|
||||
// visible: !descriptionArea.containsMouse
|
||||
}
|
||||
}
|
||||
|
||||
// -- "PaymentID" title
|
||||
Text {
|
||||
id: paymentLabel
|
||||
anchors.left: parent.left
|
||||
|
@ -128,7 +134,7 @@ ListView {
|
|||
color: "#535353"
|
||||
text: paymentId !== "" ? qsTr("Payment ID:") + translationManager.emptyString : ""
|
||||
}
|
||||
|
||||
// -- "PaymentID" value
|
||||
Text {
|
||||
anchors.bottom: paymentLabel.bottom
|
||||
anchors.left: paymentLabel.right
|
||||
|
@ -143,7 +149,7 @@ ListView {
|
|||
color: "#545454"
|
||||
text: paymentId
|
||||
}
|
||||
|
||||
// -- "Date", "Balance" and "Amound" section
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
@ -155,6 +161,7 @@ ListView {
|
|||
height: 14
|
||||
}
|
||||
|
||||
// -- "Date" column
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
width: 215
|
||||
|
@ -189,10 +196,13 @@ ListView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- "Balance" column
|
||||
// XXX: we don't have a balance
|
||||
/*
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
width: 148
|
||||
visible: false
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
|
@ -210,7 +220,9 @@ ListView {
|
|||
text: balance
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// -- "Amount column
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
width: 148
|
||||
|
@ -230,8 +242,8 @@ ListView {
|
|||
anchors.bottomMargin: 3
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
color: out ? "#FF4F41" : "#36B05B"
|
||||
text: out ? "↓" : "↑"
|
||||
color: isOut ? "#FF4F41" : "#36B05B"
|
||||
text: isOut ? "↓" : "↑"
|
||||
}
|
||||
|
||||
Text {
|
||||
|
@ -239,22 +251,44 @@ ListView {
|
|||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
font.letterSpacing: -1
|
||||
color: out ? "#FF4F41" : "#36B05B"
|
||||
text: amount
|
||||
color: isOut ? "#FF4F41" : "#36B05B"
|
||||
text: displayAmount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- "Fee column
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
width: 148
|
||||
visible: isOut
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 12
|
||||
color: "#545454"
|
||||
text: qsTr("Fee") + translationManager.emptyString
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 2
|
||||
Text {
|
||||
anchors.bottom: parent.bottom
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
font.letterSpacing: -1
|
||||
color: "#FF4F41"
|
||||
text: fee
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: dropModel
|
||||
ListElement { name: "<b>Copy address to clipboard</b>"; icon: "../images/dropdownCopy.png" }
|
||||
ListElement { name: "<b>Add to address book</b>"; icon: "../images/dropdownAdd.png" }
|
||||
ListElement { name: "<b>Send to same destination</b>"; icon: "../images/dropdownSend.png" }
|
||||
ListElement { name: "<b>Find similar transactions</b>"; icon: "../images/dropdownSearch.png" }
|
||||
}
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
||||
/*
|
||||
// Transaction dropdown menu.
|
||||
// Disable for now until AddressBook implemented
|
||||
TableDropdown {
|
||||
id: dropdown
|
||||
anchors.right: parent.right
|
||||
|
@ -282,5 +316,16 @@ ListView {
|
|||
height: 1
|
||||
color: "#DBDBDB"
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: dropModel
|
||||
ListElement { name: "<b>Copy address to clipboard</b>"; icon: "../images/dropdownCopy.png" }
|
||||
ListElement { name: "<b>Add to address book</b>"; icon: "../images/dropdownAdd.png" }
|
||||
ListElement { name: "<b>Send to same destination</b>"; icon: "../images/dropdownSend.png" }
|
||||
ListElement { name: "<b>Find similar transactions</b>"; icon: "../images/dropdownSearch.png" }
|
||||
}
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ Item {
|
|||
property alias text: input.text
|
||||
property alias validator: input.validator
|
||||
property alias readOnly : input.readOnly
|
||||
property alias cursorPosition: input.cursorPosition
|
||||
property int fontSize: 18
|
||||
|
||||
|
||||
|
@ -56,7 +57,7 @@ Item {
|
|||
id: input
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 4
|
||||
anchors.rightMargin: 4
|
||||
anchors.rightMargin: 30
|
||||
font.pixelSize: parent.fontSize
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ Dialog {
|
|||
standardButtons: StandardButton.Ok + StandardButton.Cancel
|
||||
ColumnLayout {
|
||||
id: column
|
||||
height: 40
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
|
|
|
@ -43,8 +43,13 @@ Window {
|
|||
opacity: 0.7
|
||||
|
||||
ColumnLayout {
|
||||
id: rootLayout
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 30
|
||||
anchors.rightMargin: 30
|
||||
|
||||
BusyIndicator {
|
||||
running: parent.visible
|
||||
|
@ -59,6 +64,7 @@ Window {
|
|||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,6 +75,7 @@ Window {
|
|||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@ MONERO_URL=https://github.com/monero-project/monero.git
|
|||
MONERO_BRANCH=master
|
||||
# MONERO_URL=https://github.com/mbg033/monero.git
|
||||
# MONERO_BRANCH=develop
|
||||
# Buidling "debug" build optionally
|
||||
BUILD_TYPE=$1
|
||||
if [ -z $BUILD_TYPE ]; then
|
||||
BUILD_TYPE=Release
|
||||
fi
|
||||
# thanks to SO: http://stackoverflow.com/a/20283965/4118915
|
||||
CPU_CORE_COUNT=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu)
|
||||
pushd $(pwd)
|
||||
|
@ -39,19 +44,19 @@ platform=$(get_platform)
|
|||
if [ "$platform" == "darwin" ]; then
|
||||
# Do something under Mac OS X platform
|
||||
echo "Configuring build for MacOS.."
|
||||
cmake -D CMAKE_BUILD_TYPE=Release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
cmake -D CMAKE_BUILD_TYPE=$BUILD_TYPE -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
elif [ "$platform" == "linux" ]; then
|
||||
# Do something under GNU/Linux platform
|
||||
echo "Configuring build for Linux.."
|
||||
cmake -D CMAKE_BUILD_TYPE=Release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
cmake -D CMAKE_BUILD_TYPE=$BUILD_TYPE -D STATIC=ON -D BUILD_GUI_DEPS=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" ../..
|
||||
elif [ "$platform" == "mingw64" ]; then
|
||||
# Do something under Windows NT platform
|
||||
echo "Configuring build for MINGW64.."
|
||||
cmake -D CMAKE_BUILD_TYPE=Release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" ../..
|
||||
cmake -D CMAKE_BUILD_TYPE=$BUILD_TYPE -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" ../..
|
||||
elif [ "$platform" == "mingw32" ]; then
|
||||
# Do something under Windows NT platform
|
||||
echo "Configuring build for MINGW32.."
|
||||
cmake -D CMAKE_BUILD_TYPE=Release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" ../..
|
||||
cmake -D CMAKE_BUILD_TYPE=$BUILD_TYPE -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="$MONERO_DIR" -G "MSYS Makefiles" ../..
|
||||
else
|
||||
echo "Unsupported platform: $platform"
|
||||
popd
|
||||
|
|
37
main.cpp
37
main.cpp
|
@ -39,8 +39,10 @@
|
|||
#include "Wallet.h"
|
||||
#include "PendingTransaction.h"
|
||||
#include "TranslationManager.h"
|
||||
|
||||
|
||||
#include "TransactionInfo.h"
|
||||
#include "TransactionHistory.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "model/TransactionHistorySortFilterModel.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -56,23 +58,38 @@ int main(int argc, char *argv[])
|
|||
filter *eventFilter = new filter;
|
||||
app.installEventFilter(eventFilter);
|
||||
|
||||
qmlRegisterType<clipboardAdapter>("moneroComponents", 1, 0, "Clipboard");
|
||||
// registering types for QML
|
||||
qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard");
|
||||
|
||||
qmlRegisterUncreatableType<Wallet>("Bitmonero.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
|
||||
qmlRegisterUncreatableType<Wallet>("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<PendingTransaction>("Bitmonero.PendingTransaction", 1, 0, "PendingTransaction",
|
||||
|
||||
qmlRegisterUncreatableType<PendingTransaction>("moneroComponents.PendingTransaction", 1, 0, "PendingTransaction",
|
||||
"PendingTransaction can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<WalletManager>("Bitmonero.WalletManager", 1, 0, "WalletManager",
|
||||
qmlRegisterUncreatableType<WalletManager>("moneroComponents.WalletManager", 1, 0, "WalletManager",
|
||||
"WalletManager can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<TranslationManager>("moneroComponents", 1, 0, "TranslationManager",
|
||||
qmlRegisterUncreatableType<TranslationManager>("moneroComponents.TranslationManager", 1, 0, "TranslationManager",
|
||||
"TranslationManager can't be instantiated directly");
|
||||
|
||||
|
||||
|
||||
qmlRegisterUncreatableType<TransactionHistoryModel>("moneroComponents.TransactionHistoryModel", 1, 0, "TransactionHistoryModel",
|
||||
"TransactionHistoryModel can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<TransactionHistorySortFilterModel>("moneroComponents.TransactionHistorySortFilterModel", 1, 0, "TransactionHistorySortFilterModel",
|
||||
"TransactionHistorySortFilterModel can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<TransactionHistory>("moneroComponents.TransactionHistory", 1, 0, "TransactionHistory",
|
||||
"TransactionHistory can't be instantiated directly");
|
||||
|
||||
qmlRegisterUncreatableType<TransactionInfo>("moneroComponents.TransactionInfo", 1, 0, "TransactionInfo",
|
||||
"TransactionHistory can't be instantiated directly");
|
||||
|
||||
qRegisterMetaType<PendingTransaction::Priority>();
|
||||
|
||||
|
||||
|
||||
qRegisterMetaType<TransactionInfo::Direction>();
|
||||
qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>();
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
|
|
114
main.qml
114
main.qml
|
@ -32,8 +32,9 @@ import QtQuick.Controls 1.1
|
|||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import Qt.labs.settings 1.0
|
||||
import Bitmonero.Wallet 1.0
|
||||
import Bitmonero.PendingTransaction 1.0
|
||||
|
||||
import moneroComponents.Wallet 1.0
|
||||
import moneroComponents.PendingTransaction 1.0
|
||||
|
||||
|
||||
import "components"
|
||||
|
@ -54,6 +55,10 @@ ApplicationWindow {
|
|||
property alias password : passwordDialog.password
|
||||
property int splashCounter: 0
|
||||
property bool isNewWallet: false
|
||||
property int restoreHeight:0
|
||||
|
||||
// true if wallet ever synchronized
|
||||
property bool walletInitialized : false
|
||||
|
||||
function altKeyReleased() { ctrlPressed = false; }
|
||||
|
||||
|
@ -138,15 +143,31 @@ ApplicationWindow {
|
|||
middlePanel.paymentClicked.connect(handlePayment);
|
||||
// basicPanel.paymentClicked.connect(handlePayment);
|
||||
|
||||
// currentWallet is defined on daemon address change - close/reopen
|
||||
if (currentWallet !== undefined) {
|
||||
console.log("closing currentWallet")
|
||||
walletManager.closeWallet(currentWallet);
|
||||
}
|
||||
|
||||
// wallet already opened with wizard, we just need to initialize it
|
||||
if (typeof wizard.settings['wallet'] !== 'undefined') {
|
||||
console.log("using wizard wallet")
|
||||
//Set restoreHeight
|
||||
if(persistentSettings.restoreHeight > 0){
|
||||
restoreHeight = persistentSettings.restoreHeight
|
||||
}
|
||||
|
||||
console.log("using wizard wallet")
|
||||
|
||||
connectWallet(wizard.settings['wallet'])
|
||||
|
||||
isNewWallet = true
|
||||
// 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();
|
||||
// console.log("opening wallet at: ", wallet_path, "with password: ", appWindow.password);
|
||||
console.log("opening wallet at: ", wallet_path);
|
||||
console.log("opening wallet at: ", wallet_path, ", testnet: ", persistentSettings.testnet);
|
||||
walletManager.openWalletAsync(wallet_path, appWindow.password,
|
||||
persistentSettings.testnet);
|
||||
}
|
||||
|
@ -159,11 +180,10 @@ ApplicationWindow {
|
|||
currentWallet.refreshed.connect(onWalletRefresh)
|
||||
currentWallet.updated.connect(onWalletUpdate)
|
||||
currentWallet.newBlock.connect(onWalletNewBlock)
|
||||
|
||||
currentWallet.moneySpent.connect(onWalletMoneySent)
|
||||
currentWallet.moneyReceived.connect(onWalletMoneyReceived)
|
||||
console.log("initializing with daemon address: ", persistentSettings.daemon_address)
|
||||
|
||||
currentWallet.initAsync(persistentSettings.daemon_address, 0);
|
||||
|
||||
}
|
||||
|
||||
function walletPath() {
|
||||
|
@ -210,9 +230,8 @@ ApplicationWindow {
|
|||
|
||||
function onWalletUpdate() {
|
||||
console.log(">>> wallet updated")
|
||||
basicPanel.unlockedBalanceText = leftPanel.unlockedBalanceText =
|
||||
walletManager.displayAmount(currentWallet.unlockedBalance);
|
||||
basicPanel.balanceText = leftPanel.balanceText = walletManager.displayAmount(currentWallet.balance);
|
||||
middlePanel.unlockedBalanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(currentWallet.unlockedBalance);
|
||||
middlePanel.balanceText = leftPanel.balanceText = walletManager.displayAmount(currentWallet.balance);
|
||||
}
|
||||
|
||||
function onWalletRefresh() {
|
||||
|
@ -220,6 +239,9 @@ ApplicationWindow {
|
|||
if (splash.visible) {
|
||||
hideProcessingSplash()
|
||||
}
|
||||
var dCurrentBlock = currentWallet.daemonBlockChainHeight();
|
||||
var dTargetBlock = currentWallet.daemonBlockChainTargetHeight();
|
||||
leftPanel.daemonProgress.updateProgress(dCurrentBlock,dTargetBlock);
|
||||
|
||||
// Store wallet after first refresh. To prevent broken wallet after a crash
|
||||
// TODO: Move this to libwallet?
|
||||
|
@ -229,22 +251,49 @@ ApplicationWindow {
|
|||
console.log("wallet stored after first successfull refresh")
|
||||
}
|
||||
|
||||
// initialize transaction history once wallet is initializef first time;
|
||||
if (!walletInitialized) {
|
||||
currentWallet.history.refresh()
|
||||
walletInitialized = true
|
||||
}
|
||||
|
||||
leftPanel.networkStatus.connected = currentWallet.connected
|
||||
|
||||
onWalletUpdate();
|
||||
}
|
||||
|
||||
function onWalletNewBlock(blockHeight) {
|
||||
if (splash.visible) {
|
||||
var currHeight = blockHeight.toFixed(0)
|
||||
if(currHeight > splashCounter + 1000){
|
||||
var currHeight = blockHeight
|
||||
|
||||
//fast refresh until restoreHeight is reached
|
||||
var increment = ((restoreHeight == 0) || currHeight < restoreHeight)? 1000 : 10
|
||||
|
||||
if(currHeight > splashCounter + increment){
|
||||
splashCounter = currHeight
|
||||
var progressText = qsTr("Synchronizing blocks %1/%2").arg(currHeight).arg(currentWallet.daemonBlockChainHeight().toFixed(0));
|
||||
var locale = Qt.locale()
|
||||
var currHeightString = currHeight.toLocaleString(locale,"f",0)
|
||||
var targetHeightString = currentWallet.daemonBlockChainHeight().toLocaleString(locale,"f",0)
|
||||
var progressText = qsTr("Synchronizing blocks %1 / %2").arg(currHeightString).arg(targetHeightString);
|
||||
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() {
|
||||
var wallets = walletManager.findWallets(moneroAccountsDir);
|
||||
|
@ -338,7 +387,7 @@ ApplicationWindow {
|
|||
middlePanel.enabled = enable;
|
||||
leftPanel.enabled = enable;
|
||||
rightPanel.enabled = enable;
|
||||
basicPanel.enabled = enable;
|
||||
// basicPanel.enabled = enable;
|
||||
}
|
||||
|
||||
function showProcessingSplash(message) {
|
||||
|
@ -396,6 +445,7 @@ ApplicationWindow {
|
|||
property bool testnet: true
|
||||
property string daemon_address: "localhost:38081"
|
||||
property string payment_id
|
||||
property int restoreHeight:0
|
||||
}
|
||||
|
||||
// TODO: replace with customized popups
|
||||
|
@ -440,7 +490,7 @@ ApplicationWindow {
|
|||
|
||||
ProcessingSplash {
|
||||
id: splash
|
||||
width: appWindow.width / 2
|
||||
width: appWindow.width / 1.5
|
||||
height: appWindow.height / 2
|
||||
x: (appWindow.width - width) / 2 + appWindow.x
|
||||
y: (appWindow.height - height) / 2 + appWindow.y
|
||||
|
@ -514,7 +564,7 @@ ApplicationWindow {
|
|||
MiddlePanel {
|
||||
id: middlePanel
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: leftPanel.right
|
||||
anchors.left: leftPanel.visible ? leftPanel.right : parent.left
|
||||
anchors.right: rightPanel.left
|
||||
height: parent.height
|
||||
state: "Transfer"
|
||||
|
@ -526,16 +576,6 @@ ApplicationWindow {
|
|||
visible: false
|
||||
}
|
||||
|
||||
BasicPanel {
|
||||
id: basicPanel
|
||||
x: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
visible: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: frameArea
|
||||
property bool blocked: false
|
||||
|
@ -591,25 +631,26 @@ ApplicationWindow {
|
|||
duration: 200
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [leftPanel, middlePanel, rightPanel]
|
||||
targets: [leftPanel, rightPanel]
|
||||
properties: "visible"
|
||||
value: false
|
||||
}
|
||||
PropertyAction {
|
||||
target: basicPanel
|
||||
properties: "visible"
|
||||
target: middlePanel
|
||||
properties: "basicMode"
|
||||
value: true
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: appWindow
|
||||
properties: "height"
|
||||
to: basicPanel.height
|
||||
to: middlePanel.height
|
||||
easing.type: Easing.InCubic
|
||||
duration: 200
|
||||
}
|
||||
|
||||
onStopped: {
|
||||
middlePanel.visible = false
|
||||
// middlePanel.visible = false
|
||||
rightPanel.visible = false
|
||||
leftPanel.visible = false
|
||||
}
|
||||
|
@ -625,8 +666,8 @@ ApplicationWindow {
|
|||
duration: 200
|
||||
}
|
||||
PropertyAction {
|
||||
target: basicPanel
|
||||
properties: "visible"
|
||||
target: middlePanel
|
||||
properties: "basicMode"
|
||||
value: false
|
||||
}
|
||||
PropertyAction {
|
||||
|
@ -719,8 +760,13 @@ ApplicationWindow {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
onGoToBasicVersion: {
|
||||
if(yes) goToBasicAnimation.start()
|
||||
else goToProAnimation.start()
|
||||
if (yes) {
|
||||
// basicPanel.currentView = middlePanel.currentView
|
||||
goToBasicAnimation.start()
|
||||
} else {
|
||||
// middlePanel.currentView = basicPanel.currentView
|
||||
goToProAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
|
|
@ -10,7 +10,8 @@ CONFIG += c++11
|
|||
QMAKE_DISTCLEAN += -r $$WALLET_ROOT
|
||||
|
||||
INCLUDEPATH += $$WALLET_ROOT/include \
|
||||
$$PWD/src/libwalletqt
|
||||
$$PWD/src/libwalletqt \
|
||||
$$PWD/src
|
||||
|
||||
HEADERS += \
|
||||
filter.h \
|
||||
|
@ -22,7 +23,9 @@ HEADERS += \
|
|||
src/libwalletqt/TransactionHistory.h \
|
||||
src/libwalletqt/TransactionInfo.h \
|
||||
oshelper.h \
|
||||
TranslationManager.h
|
||||
TranslationManager.h \
|
||||
src/model/TransactionHistoryModel.h \
|
||||
src/model/TransactionHistorySortFilterModel.h
|
||||
|
||||
|
||||
SOURCES += main.cpp \
|
||||
|
@ -35,7 +38,9 @@ SOURCES += main.cpp \
|
|||
src/libwalletqt/TransactionHistory.cpp \
|
||||
src/libwalletqt/TransactionInfo.cpp \
|
||||
oshelper.cpp \
|
||||
TranslationManager.cpp
|
||||
TranslationManager.cpp \
|
||||
src/model/TransactionHistoryModel.cpp \
|
||||
src/model/TransactionHistorySortFilterModel.cpp
|
||||
|
||||
lupdate_only {
|
||||
SOURCES = *.qml \
|
||||
|
|
|
@ -27,10 +27,28 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
import moneroComponents.Wallet 1.0
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import moneroComponents.TransactionHistory 1.0
|
||||
import moneroComponents.TransactionInfo 1.0
|
||||
import moneroComponents.TransactionHistoryModel 1.0
|
||||
|
||||
import "../components"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property var model
|
||||
|
||||
color: "#F0EEEE"
|
||||
onModelChanged: {
|
||||
if (typeof model !== 'undefined') {
|
||||
// setup date filter scope according to real transactions
|
||||
fromDatePicker.currentDate = model.transactionHistory.firstDateTime
|
||||
toDatePicker.currentDate = model.transactionHistory.lastDateTime
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
id: filterHeaderText
|
||||
|
@ -47,6 +65,8 @@ Rectangle {
|
|||
text: qsTr("Filter transactions history") + translationManager.emptyString
|
||||
}
|
||||
|
||||
// Filter by Address input (senseless, removing)
|
||||
/*
|
||||
Label {
|
||||
id: addressLabel
|
||||
anchors.left: parent.left
|
||||
|
@ -67,11 +87,14 @@ Rectangle {
|
|||
anchors.rightMargin: 17
|
||||
anchors.topMargin: 5
|
||||
}
|
||||
*/
|
||||
|
||||
// Filter by Payment ID input
|
||||
|
||||
Label {
|
||||
id: paymentIdLabel
|
||||
anchors.left: parent.left
|
||||
anchors.top: addressLine.bottom
|
||||
anchors.top: filterHeaderText.bottom // addressLine.bottom
|
||||
anchors.leftMargin: 17
|
||||
anchors.topMargin: 17
|
||||
text: qsTr("Payment ID <font size='2'>(Optional)</font>") + translationManager.emptyString
|
||||
|
@ -84,12 +107,16 @@ Rectangle {
|
|||
id: paymentIdLine
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: paymentIdLabel.bottom
|
||||
anchors.top: paymentIdLabel.bottom // addressLabel.bottom
|
||||
anchors.leftMargin: 17
|
||||
anchors.rightMargin: 17
|
||||
anchors.topMargin: 5
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Filter by description input (not implemented yet)
|
||||
/*
|
||||
Label {
|
||||
id: descriptionLabel
|
||||
anchors.left: parent.left
|
||||
|
@ -110,11 +137,14 @@ Rectangle {
|
|||
anchors.rightMargin: 17
|
||||
anchors.topMargin: 5
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// DateFrom picker
|
||||
Label {
|
||||
id: dateFromText
|
||||
anchors.left: parent.left
|
||||
anchors.top: descriptionLine.bottom
|
||||
anchors.top: paymentIdLine.bottom // descriptionLine.bottom
|
||||
anchors.leftMargin: 17
|
||||
anchors.topMargin: 17
|
||||
width: 156
|
||||
|
@ -132,10 +162,11 @@ Rectangle {
|
|||
z: 2
|
||||
}
|
||||
|
||||
// DateTo picker
|
||||
Label {
|
||||
id: dateToText
|
||||
anchors.left: dateFromText.right
|
||||
anchors.top: descriptionLine.bottom
|
||||
anchors.top: paymentIdLine.bottom //descriptionLine.bottom
|
||||
anchors.leftMargin: 17
|
||||
anchors.topMargin: 17
|
||||
text: qsTr("To")
|
||||
|
@ -163,10 +194,30 @@ Rectangle {
|
|||
shadowPressedColor: "#2D002F"
|
||||
releasedColor: "#6B0072"
|
||||
pressedColor: "#4D0051"
|
||||
onClicked: {
|
||||
// Apply filter here;
|
||||
model.paymentIdFilter = paymentIdLine.text
|
||||
model.dateFromFilter = fromDatePicker.currentDate
|
||||
model.dateToFilter = toDatePicker.currentDate
|
||||
if (advancedFilteringCheckBox.checked) {
|
||||
if (amountFromLine.text.length) {
|
||||
model.amountFromFilter = parseFloat(amountFromLine.text)
|
||||
}
|
||||
if (amountToLine.text.length) {
|
||||
model.amountToFilter = parseFloat(amountToLine.text)
|
||||
}
|
||||
|
||||
var directionFilter = transactionsModel.get(transactionTypeDropdown.currentIndex).value
|
||||
console.log("Direction filter: " + directionFilter)
|
||||
model.directionFilter = directionFilter
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: checkBox
|
||||
id: advancedFilteringCheckBox
|
||||
text: qsTr("Advance filtering")
|
||||
anchors.left: filterButton.right
|
||||
anchors.bottom: filterButton.bottom
|
||||
|
@ -193,9 +244,10 @@ Rectangle {
|
|||
|
||||
ListModel {
|
||||
id: transactionsModel
|
||||
ListElement { column1: "SENT"; column2: "" }
|
||||
ListElement { column1: "RECIVE"; column2: "" }
|
||||
ListElement { column1: "ON HOLD"; column2: "" }
|
||||
ListElement { column1: "ALL"; column2: ""; value: TransactionInfo.Direction_Both }
|
||||
ListElement { column1: "SENT"; column2: ""; value: TransactionInfo.Direction_Out }
|
||||
ListElement { column1: "RECEIVED"; column2: ""; value: TransactionInfo.Direction_In }
|
||||
|
||||
}
|
||||
|
||||
StandardDropdown {
|
||||
|
@ -274,8 +326,11 @@ Rectangle {
|
|||
anchors.fill: parent
|
||||
onClicked: {
|
||||
parent.expanded = !parent.expanded
|
||||
if(checkBox.checked) tableRect.height = Qt.binding(function(){ return parent.expanded ? tableRect.expandedHeight : tableRect.collapsedHeight })
|
||||
else tableRect.height = Qt.binding(function(){ return parent.expanded ? tableRect.expandedHeight : tableRect.middleHeight })
|
||||
if (advancedFilteringCheckBox.checked) {
|
||||
tableRect.height = Qt.binding(function() { return parent.expanded ? tableRect.expandedHeight : tableRect.collapsedHeight })
|
||||
} else {
|
||||
tableRect.height = Qt.binding(function() { return parent.expanded ? tableRect.expandedHeight : tableRect.middleHeight })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,10 +367,11 @@ Rectangle {
|
|||
|
||||
ListModel {
|
||||
id: columnsModel
|
||||
ListElement { columnName: "Address"; columnWidth: 127 }
|
||||
|
||||
ListElement { columnName: "Payment ID"; columnWidth: 127 }
|
||||
ListElement { columnName: "Date"; columnWidth: 100 }
|
||||
ListElement { columnName: "Amount"; columnWidth: 148 }
|
||||
ListElement { columnName: "Description"; columnWidth: 148 }
|
||||
// ListElement { columnName: "Description"; columnWidth: 148 }
|
||||
}
|
||||
|
||||
TableHeader {
|
||||
|
@ -328,21 +384,24 @@ Rectangle {
|
|||
anchors.rightMargin: 14
|
||||
dataModel: columnsModel
|
||||
offset: 20
|
||||
onSortRequest: console.log("column: " + column + " desc: " + desc)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: testModel
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: "Client from Australia"; out: false }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: true }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: true }
|
||||
ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: false }
|
||||
ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: "Client from Australia"; out: false }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: false }
|
||||
ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: false }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: false }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: "Client from Australia"; out: false }
|
||||
ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 <font size='2'>AM</font>"; amount: "0.<font size='2'>000709159241</font>"; balance: "19301.<font size='2'>870709159241</font>"; description: ""; out: false }
|
||||
onSortRequest: {
|
||||
console.log("column: " + column + " desc: " + desc)
|
||||
switch (column) {
|
||||
case 0:
|
||||
// Payment ID
|
||||
model.sortRole = TransactionHistoryModel.TransactionPaymentIdRole
|
||||
break;
|
||||
case 1:
|
||||
// Date;
|
||||
model.sortRole = TransactionHistoryModel.TransactionDateRole
|
||||
break;
|
||||
case 2:
|
||||
// Amount;
|
||||
model.sortRole = TransactionHistoryModel.TransactionAmountRole
|
||||
break;
|
||||
}
|
||||
model.sort(0, desc ? Qt.DescendingOrder : Qt.AscendingOrder)
|
||||
}
|
||||
}
|
||||
|
||||
Scroll {
|
||||
|
@ -363,7 +422,7 @@ Rectangle {
|
|||
anchors.leftMargin: 14
|
||||
anchors.rightMargin: 14
|
||||
onContentYChanged: flickableScroll.flickableContentYChanged()
|
||||
model: testModel
|
||||
model: root.model
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
// Copyright (c) 2014-2015, The Monero Project
|
||||
//
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
|
@ -32,7 +32,7 @@ import QtQuick.Controls.Styles 1.4
|
|||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components"
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
Rectangle {
|
||||
|
||||
|
@ -43,14 +43,14 @@ Rectangle {
|
|||
|
||||
function updatePaymentId() {
|
||||
var payment_id = appWindow.persistentSettings.payment_id
|
||||
if (payment_id.length === 0) {
|
||||
payment_id = appWindow.wallet.generatePaymentId()
|
||||
if (typeof appWindow.currentWallet !== 'undefined') {
|
||||
payment_id = appWindow.currentWallet.generatePaymentId()
|
||||
appWindow.persistentSettings.payment_id = payment_id
|
||||
appWindow.currentWallet.payment_id = payment_id
|
||||
addressLine.text = appWindow.currentWallet.address
|
||||
integratedAddressLine.text = appWindow.currentWallet.integratedAddress(payment_id)
|
||||
}
|
||||
|
||||
paymentIdLine.text = payment_id
|
||||
addressLine.text = appWindow.currentWallet.address
|
||||
integratedAddressLine.text = appWindow.currentWallet.integratedAddress(payment_id)
|
||||
}
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
@ -87,6 +87,8 @@ Rectangle {
|
|||
readOnly: true
|
||||
width: mainLayout.editWidth
|
||||
Layout.fillWidth: true
|
||||
onTextChanged: cursorPosition = 0
|
||||
|
||||
IconButton {
|
||||
imageSource: "../images/copyToClipboard.png"
|
||||
onClicked: {
|
||||
|
@ -116,6 +118,9 @@ Rectangle {
|
|||
readOnly: true
|
||||
width: mainLayout.editWidth
|
||||
Layout.fillWidth: true
|
||||
|
||||
onTextChanged: cursorPosition = 0
|
||||
|
||||
IconButton {
|
||||
imageSource: "../images/copyToClipboard.png"
|
||||
onClicked: {
|
||||
|
@ -176,9 +181,13 @@ Rectangle {
|
|||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
function onPageCompleted() {
|
||||
console.log("Receive page loaded");
|
||||
updatePaymentId()
|
||||
|
||||
if(addressLine.text.length == 0) {
|
||||
updatePaymentId()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,8 +27,264 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
|
||||
|
||||
import "../components"
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 62
|
||||
|
||||
property var daemonAddress
|
||||
|
||||
color: "#F0EEEE"
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
||||
function initSettings() {
|
||||
|
||||
|
||||
// Mnemonic seed settings
|
||||
memoTextInput.text = qsTr("Click button to show seed") + translationManager.emptyString
|
||||
showSeedButton.visible = true
|
||||
|
||||
// Daemon settings
|
||||
|
||||
daemonAddress = persistentSettings.daemon_address.split(":");
|
||||
console.log("address: " + persistentSettings.daemon_address)
|
||||
// try connecting to daemon
|
||||
var connectedToDaemon = currentWallet.connectToDaemon();
|
||||
|
||||
if(!connectedToDaemon){
|
||||
console.log("not connected");
|
||||
//TODO: Print error?
|
||||
//daemonStatusText.text = qsTr("Unable to connect to Daemon.")
|
||||
//daemonStatusText.visible = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PasswordDialog {
|
||||
id: settingsPasswordDialog
|
||||
standardButtons: StandardButton.Ok + StandardButton.Cancel
|
||||
onAccepted: {
|
||||
if(appWindow.password == settingsPasswordDialog.password){
|
||||
memoTextInput.text = currentWallet.seed
|
||||
showSeedButton.visible = false
|
||||
}
|
||||
|
||||
}
|
||||
onRejected: {
|
||||
|
||||
}
|
||||
onDiscard: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: 40
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
spacing: 10
|
||||
|
||||
|
||||
Label {
|
||||
id: seedLabel
|
||||
color: "#4A4949"
|
||||
fontSize: 16
|
||||
text: qsTr("Mnemonic seed: ") + translationManager.emptyString
|
||||
Layout.preferredWidth: 100
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: memoTextInput
|
||||
textMargin: 6
|
||||
font.family: "Arial"
|
||||
font.pointSize: 14
|
||||
wrapMode: TextEdit.WordWrap
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 100
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
text: qsTr("Click button to show seed") + translationManager.emptyString
|
||||
|
||||
Image {
|
||||
id : clipboardButton
|
||||
anchors.right: memoTextInput.right
|
||||
anchors.bottom: memoTextInput.bottom
|
||||
source: "qrc:///images/greyTriangle.png"
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///images/copyToClipboard.png"
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: clipboard.setText(memoTextInput.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
id: wordsTipText
|
||||
font.family: "Arial"
|
||||
font.pointSize: 12
|
||||
color: "#4A4646"
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("It is very important to write it down as this is the only backup you will need for your wallet.")
|
||||
+ translationManager.emptyString
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
|
||||
id: showSeedButton
|
||||
|
||||
fontSize: 14
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
releasedColor: "#FF6C3C"
|
||||
pressedColor: "#FF4304"
|
||||
text: qsTr("Show seed")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.preferredWidth: 100
|
||||
onClicked: {
|
||||
settingsPasswordDialog.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: "#DEDEDE"
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: daemonAddrRow
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
Layout.topMargin: 40
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
id: daemonAddrLabel
|
||||
|
||||
Layout.fillWidth: true
|
||||
color: "#4A4949"
|
||||
text: qsTr("Daemon adress") + translationManager.emptyString
|
||||
fontSize: 16
|
||||
}
|
||||
|
||||
LineEdit {
|
||||
id: daemonAddr
|
||||
Layout.preferredWidth: 200
|
||||
Layout.fillWidth: true
|
||||
text: (daemonAddress !== undefined) ? daemonAddress[0] : ""
|
||||
placeholderText: qsTr("Hostname / IP")
|
||||
}
|
||||
|
||||
|
||||
LineEdit {
|
||||
id: daemonPort
|
||||
Layout.preferredWidth: 100
|
||||
Layout.fillWidth: true
|
||||
text: (daemonAddress !== undefined) ? daemonAddress[1] : ""
|
||||
placeholderText: qsTr("Port")
|
||||
}
|
||||
|
||||
|
||||
StandardButton {
|
||||
id: daemonAddrSave
|
||||
|
||||
Layout.fillWidth: false
|
||||
|
||||
Layout.leftMargin: 30
|
||||
Layout.minimumWidth: 100
|
||||
width: 60
|
||||
text: qsTr("Save") + translationManager.emptyString
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
releasedColor: "#FF6C3C"
|
||||
pressedColor: "#FF4304"
|
||||
visible: true
|
||||
onClicked: {
|
||||
console.log("saving daemon adress settings")
|
||||
var newDaemon = daemonAddr.text + ":" + daemonPort.text
|
||||
if(persistentSettings.daemon_address != newDaemon) {
|
||||
persistentSettings.daemon_address = newDaemon
|
||||
//reconnect wallet
|
||||
appWindow.initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
id: daemonStatusRow
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
id: daemonStatusText
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
wrapMode: Text.Wrap
|
||||
textFormat: Text.RichText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: "#FF0000"
|
||||
visible: true //!currentWallet.connected
|
||||
}
|
||||
|
||||
// StandardButton {
|
||||
// id: checkConnectionButton
|
||||
// anchors.left: daemonStatusText.right
|
||||
// anchors.leftMargin: 30
|
||||
// width: 90
|
||||
// text: qsTr("Check again") + translationManager.emptyString
|
||||
// shadowReleasedColor: "#FF4304"
|
||||
// shadowPressedColor: "#B32D00"
|
||||
// releasedColor: "#FF6C3C"
|
||||
// pressedColor: "#FF4304"
|
||||
// visible: true
|
||||
// onClicked: {
|
||||
// checkDaemonConnection();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onPageCompleted() {
|
||||
console.log("Settings page loaded");
|
||||
initSettings();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import Bitmonero.PendingTransaction 1.0
|
||||
import moneroComponents.PendingTransaction 1.0
|
||||
import "../components"
|
||||
|
||||
|
||||
|
|
1
qml.qrc
1
qml.qrc
|
@ -116,5 +116,6 @@
|
|||
<file>lang/flags/italy.png</file>
|
||||
<file>components/PasswordDialog.qml</file>
|
||||
<file>components/ProcessingSplash.qml</file>
|
||||
<file>components/DaemonProgress.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -2,49 +2,89 @@
|
|||
#include "TransactionInfo.h"
|
||||
#include <wallet/wallet2_api.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
int TransactionHistory::count() const
|
||||
{
|
||||
return m_pimpl->count();
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistory::transaction(int index)
|
||||
{
|
||||
// box up Bitmonero::TransactionInfo
|
||||
Bitmonero::TransactionInfo * impl = m_pimpl->transaction(index);
|
||||
TransactionInfo * result = new TransactionInfo(impl, this);
|
||||
return result;
|
||||
|
||||
if (index < 0 || index >= m_tinfo.size()) {
|
||||
qCritical("%s: no transaction info for index %d", __FUNCTION__, index);
|
||||
qCritical("%s: there's %d transactions in backend", __FUNCTION__, m_pimpl->count());
|
||||
return nullptr;
|
||||
}
|
||||
return m_tinfo.at(index);
|
||||
}
|
||||
|
||||
TransactionInfo *TransactionHistory::transaction(const QString &id)
|
||||
{
|
||||
// box up Bitmonero::TransactionInfo
|
||||
Bitmonero::TransactionInfo * impl = m_pimpl->transaction(id.toStdString());
|
||||
TransactionInfo * result = new TransactionInfo(impl, this);
|
||||
return result;
|
||||
}
|
||||
//// XXX: not sure if this method really needed;
|
||||
//TransactionInfo *TransactionHistory::transaction(const QString &id)
|
||||
//{
|
||||
// return nullptr;
|
||||
//}
|
||||
|
||||
QList<TransactionInfo *> TransactionHistory::getAll() const
|
||||
{
|
||||
// XXX this invalidates previously saved history that might be used by model
|
||||
emit refreshStarted();
|
||||
qDeleteAll(m_tinfo);
|
||||
m_tinfo.clear();
|
||||
|
||||
QDateTime firstDateTime = QDateTime::currentDateTime();
|
||||
QDateTime lastDateTime = QDateTime(QDate(1970, 1, 1));
|
||||
|
||||
TransactionHistory * parent = const_cast<TransactionHistory*>(this);
|
||||
for (const auto i : m_pimpl->getAll()) {
|
||||
TransactionInfo * ti = new TransactionInfo(i, parent);
|
||||
m_tinfo.append(ti);
|
||||
// looking for transactions timestamp scope
|
||||
if (ti->timestamp() >= lastDateTime) {
|
||||
lastDateTime = ti->timestamp();
|
||||
}
|
||||
if (ti->timestamp() <= firstDateTime) {
|
||||
firstDateTime = ti->timestamp();
|
||||
}
|
||||
}
|
||||
emit refreshFinished();
|
||||
|
||||
if (m_firstDateTime != firstDateTime) {
|
||||
m_firstDateTime = firstDateTime;
|
||||
emit firstDateTimeChanged();
|
||||
}
|
||||
if (m_lastDateTime != lastDateTime) {
|
||||
m_lastDateTime = lastDateTime;
|
||||
emit lastDateTimeChanged();
|
||||
}
|
||||
|
||||
return m_tinfo;
|
||||
}
|
||||
|
||||
void TransactionHistory::refresh()
|
||||
{
|
||||
// XXX this invalidates previously saved history that might be used by clients
|
||||
// rebuilding transaction list in wallet_api;
|
||||
m_pimpl->refresh();
|
||||
emit invalidated();
|
||||
// copying list here and keep track on every item to avoid memleaks
|
||||
getAll();
|
||||
}
|
||||
|
||||
quint64 TransactionHistory::count() const
|
||||
{
|
||||
return m_tinfo.count();
|
||||
}
|
||||
|
||||
QDateTime TransactionHistory::firstDateTime() const
|
||||
{
|
||||
return m_firstDateTime;
|
||||
}
|
||||
|
||||
QDateTime TransactionHistory::lastDateTime() const
|
||||
{
|
||||
return m_lastDateTime;
|
||||
}
|
||||
|
||||
|
||||
TransactionHistory::TransactionHistory(Bitmonero::TransactionHistory *pimpl, QObject *parent)
|
||||
: QObject(parent), m_pimpl(pimpl)
|
||||
{
|
||||
|
||||
m_firstDateTime = QDateTime(QDate(1970, 1, 1));
|
||||
m_lastDateTime = QDateTime::currentDateTime();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace Bitmonero {
|
||||
class TransactionHistory;
|
||||
|
@ -14,16 +15,23 @@ class TransactionHistory : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ count)
|
||||
Q_PROPERTY(QDateTime firstDateTime READ firstDateTime NOTIFY firstDateTimeChanged)
|
||||
Q_PROPERTY(QDateTime lastDateTime READ lastDateTime NOTIFY lastDateTimeChanged)
|
||||
|
||||
public:
|
||||
int count() const;
|
||||
Q_INVOKABLE TransactionInfo *transaction(int index);
|
||||
Q_INVOKABLE TransactionInfo * transaction(const QString &id);
|
||||
// Q_INVOKABLE TransactionInfo * transaction(const QString &id);
|
||||
Q_INVOKABLE QList<TransactionInfo*> getAll() const;
|
||||
Q_INVOKABLE void refresh();
|
||||
quint64 count() const;
|
||||
QDateTime firstDateTime() const;
|
||||
QDateTime lastDateTime() const;
|
||||
|
||||
signals:
|
||||
void invalidated();
|
||||
void refreshStarted() const;
|
||||
void refreshFinished() const;
|
||||
void firstDateTimeChanged() const;
|
||||
void lastDateTimeChanged() const;
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -36,6 +44,8 @@ private:
|
|||
|
||||
Bitmonero::TransactionHistory * m_pimpl;
|
||||
mutable QList<TransactionInfo*> m_tinfo;
|
||||
mutable QDateTime m_firstDateTime;
|
||||
mutable QDateTime m_lastDateTime;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "TransactionInfo.h"
|
||||
#include "WalletManager.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
TransactionInfo::Direction TransactionInfo::direction() const
|
||||
|
@ -16,15 +18,21 @@ bool TransactionInfo::isFailed() const
|
|||
return m_pimpl->isFailed();
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::amount() const
|
||||
|
||||
double TransactionInfo::amount() const
|
||||
{
|
||||
return m_pimpl->amount();
|
||||
// there's no unsigned uint64 for JS, so better use double
|
||||
return WalletManager::instance()->displayAmount(m_pimpl->amount()).toDouble();
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::fee() const
|
||||
QString TransactionInfo::displayAmount() const
|
||||
{
|
||||
return m_pimpl->fee();
|
||||
return WalletManager::instance()->displayAmount(m_pimpl->amount());
|
||||
}
|
||||
|
||||
QString TransactionInfo::fee() const
|
||||
{
|
||||
return WalletManager::instance()->displayAmount(m_pimpl->fee());
|
||||
}
|
||||
|
||||
quint64 TransactionInfo::blockHeight() const
|
||||
|
@ -37,13 +45,23 @@ QString TransactionInfo::hash() const
|
|||
return QString::fromStdString(m_pimpl->hash());
|
||||
}
|
||||
|
||||
QString TransactionInfo::timestamp()
|
||||
QDateTime TransactionInfo::timestamp() const
|
||||
{
|
||||
QString result = QDateTime::fromTime_t(m_pimpl->timestamp()).toString(Qt::ISODate);
|
||||
QDateTime result = QDateTime::fromTime_t(m_pimpl->timestamp());
|
||||
return result;
|
||||
}
|
||||
|
||||
QString TransactionInfo::paymentId()
|
||||
QString TransactionInfo::date() const
|
||||
{
|
||||
return timestamp().date().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionInfo::time() const
|
||||
{
|
||||
return timestamp().time().toString(Qt::ISODate);
|
||||
}
|
||||
|
||||
QString TransactionInfo::paymentId() const
|
||||
{
|
||||
return QString::fromStdString(m_pimpl->paymentId());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#ifndef TRANSACTIONINFO_H
|
||||
#define TRANSACTIONINFO_H
|
||||
|
||||
#include <QObject>
|
||||
#include <wallet/wallet2_api.h>
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
|
||||
class TransactionInfo : public QObject
|
||||
{
|
||||
|
@ -10,19 +11,25 @@ class TransactionInfo : public QObject
|
|||
Q_PROPERTY(Direction direction READ direction)
|
||||
Q_PROPERTY(bool isPending READ isPending)
|
||||
Q_PROPERTY(bool isFailed READ isFailed)
|
||||
Q_PROPERTY(quint64 amount READ amount)
|
||||
Q_PROPERTY(quint64 fee READ fee)
|
||||
Q_PROPERTY(double amount READ amount)
|
||||
Q_PROPERTY(QString displayAmount READ displayAmount)
|
||||
Q_PROPERTY(QString fee READ fee)
|
||||
Q_PROPERTY(quint64 blockHeight READ blockHeight)
|
||||
Q_PROPERTY(QString hash READ hash)
|
||||
Q_PROPERTY(QString timestamp READ timestamp)
|
||||
Q_PROPERTY(QDateTime timestamp READ timestamp)
|
||||
Q_PROPERTY(QString date READ date)
|
||||
Q_PROPERTY(QString time READ time)
|
||||
Q_PROPERTY(QString paymentId READ paymentId)
|
||||
|
||||
public:
|
||||
enum Direction {
|
||||
Direction_In = Bitmonero::TransactionInfo::Direction_In,
|
||||
Direction_Out = Bitmonero::TransactionInfo::Direction_Out
|
||||
Direction_Out = Bitmonero::TransactionInfo::Direction_Out,
|
||||
Direction_Both // invalid direction value, used for filtering
|
||||
};
|
||||
|
||||
Q_ENUM(Direction)
|
||||
|
||||
// TODO: implement as separate class;
|
||||
|
||||
// struct Transfer {
|
||||
|
@ -30,16 +37,21 @@ public:
|
|||
// const uint64_t amount;
|
||||
// const std::string address;
|
||||
// };
|
||||
|
||||
Direction direction() const;
|
||||
bool isPending() const;
|
||||
bool isFailed() const;
|
||||
quint64 amount() const;
|
||||
quint64 fee() const;
|
||||
double amount() const;
|
||||
QString displayAmount() const;
|
||||
QString fee() const;
|
||||
quint64 blockHeight() const;
|
||||
//! transaction_id
|
||||
QString hash() const;
|
||||
QString timestamp();
|
||||
QString paymentId();
|
||||
QDateTime timestamp() const;
|
||||
QString date() const;
|
||||
QString time() const;
|
||||
QString paymentId() const;
|
||||
|
||||
|
||||
// TODO: implement it
|
||||
//! only applicable for output transactions
|
||||
|
@ -51,4 +63,8 @@ private:
|
|||
Bitmonero::TransactionInfo * m_pimpl;
|
||||
};
|
||||
|
||||
// in order to wrap it to QVariant
|
||||
Q_DECLARE_METATYPE(TransactionInfo*)
|
||||
|
||||
|
||||
#endif // TRANSACTIONINFO_H
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "Wallet.h"
|
||||
#include "PendingTransaction.h"
|
||||
#include "TransactionHistory.h"
|
||||
#include "model/TransactionHistoryModel.h"
|
||||
#include "model/TransactionHistorySortFilterModel.h"
|
||||
#include "wallet/wallet2_api.h"
|
||||
|
||||
#include <QFile>
|
||||
|
@ -31,7 +33,6 @@ public:
|
|||
|
||||
virtual void moneyReceived(const std::string &txId, uint64_t amount)
|
||||
{
|
||||
|
||||
qDebug() << __FUNCTION__;
|
||||
emit m_wallet->moneyReceived(QString::fromStdString(txId), amount);
|
||||
}
|
||||
|
@ -59,7 +60,10 @@ private:
|
|||
Wallet * m_wallet;
|
||||
};
|
||||
|
||||
|
||||
Wallet::Wallet(QObject * parent)
|
||||
: Wallet(nullptr, parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString Wallet::getSeed() const
|
||||
{
|
||||
|
@ -86,6 +90,11 @@ bool Wallet::connected() const
|
|||
return m_walletImpl->connected();
|
||||
}
|
||||
|
||||
bool Wallet::synchronized() const
|
||||
{
|
||||
return m_walletImpl->synchronized();
|
||||
}
|
||||
|
||||
QString Wallet::errorString() const
|
||||
{
|
||||
return QString::fromStdString(m_walletImpl->errorString());
|
||||
|
@ -153,9 +162,16 @@ quint64 Wallet::daemonBlockChainHeight() const
|
|||
return m_daemonBlockChainHeight;
|
||||
}
|
||||
|
||||
quint64 Wallet::daemonBlockChainTargetHeight() const
|
||||
{
|
||||
m_daemonBlockChainTargetHeight = m_walletImpl->daemonBlockChainTargetHeight();
|
||||
return m_daemonBlockChainTargetHeight;
|
||||
}
|
||||
|
||||
bool Wallet::refresh()
|
||||
{
|
||||
bool result = m_walletImpl->refresh();
|
||||
m_history->refresh();
|
||||
if (result)
|
||||
emit updated();
|
||||
return result;
|
||||
|
@ -193,15 +209,24 @@ void Wallet::disposeTransaction(PendingTransaction *t)
|
|||
delete t;
|
||||
}
|
||||
|
||||
TransactionHistory *Wallet::history()
|
||||
TransactionHistory *Wallet::history() const
|
||||
{
|
||||
if (!m_history) {
|
||||
Bitmonero::TransactionHistory * impl = m_walletImpl->history();
|
||||
m_history = new TransactionHistory(impl, this);
|
||||
}
|
||||
return m_history;
|
||||
}
|
||||
|
||||
TransactionHistorySortFilterModel *Wallet::historyModel() const
|
||||
{
|
||||
if (!m_historyModel) {
|
||||
Wallet * w = const_cast<Wallet*>(this);
|
||||
m_historyModel = new TransactionHistoryModel(w);
|
||||
m_historyModel->setTransactionHistory(this->history());
|
||||
m_historySortFilterModel = new TransactionHistorySortFilterModel(w);
|
||||
m_historySortFilterModel->setSourceModel(m_historyModel);
|
||||
}
|
||||
|
||||
return m_historySortFilterModel;
|
||||
}
|
||||
|
||||
|
||||
QString Wallet::generatePaymentId() const
|
||||
{
|
||||
|
@ -228,13 +253,16 @@ Wallet::Wallet(Bitmonero::Wallet *w, QObject *parent)
|
|||
: QObject(parent)
|
||||
, m_walletImpl(w)
|
||||
, m_history(nullptr)
|
||||
, m_historyModel(nullptr)
|
||||
, m_daemonBlockChainHeight(0)
|
||||
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
|
||||
{
|
||||
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
||||
m_walletImpl->setListener(new WalletListenerImpl(this));
|
||||
}
|
||||
|
||||
Wallet::~Wallet()
|
||||
{
|
||||
|
||||
Bitmonero::WalletManagerFactory::getWalletManager()->closeWallet(m_walletImpl);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace Bitmonero {
|
|||
|
||||
|
||||
class TransactionHistory;
|
||||
class TransactionHistoryModel;
|
||||
class TransactionHistorySortFilterModel;
|
||||
|
||||
class Wallet : public QObject
|
||||
{
|
||||
|
@ -21,14 +23,18 @@ class Wallet : public QObject
|
|||
Q_PROPERTY(QString seedLanguage READ getSeedLanguage)
|
||||
Q_PROPERTY(Status status READ status)
|
||||
Q_PROPERTY(bool connected READ connected)
|
||||
Q_PROPERTY(bool synchronized READ synchronized)
|
||||
Q_PROPERTY(QString errorString READ errorString)
|
||||
Q_PROPERTY(QString address READ address)
|
||||
Q_PROPERTY(quint64 balance READ balance)
|
||||
Q_PROPERTY(quint64 unlockedBalance READ unlockedBalance)
|
||||
Q_PROPERTY(TransactionHistory * history READ history)
|
||||
Q_PROPERTY(QString paymentId READ paymentId WRITE setPaymentId)
|
||||
Q_PROPERTY(TransactionHistorySortFilterModel * historyModel READ historyModel NOTIFY historyModelChanged)
|
||||
|
||||
public:
|
||||
|
||||
|
||||
enum Status {
|
||||
Status_Ok = Bitmonero::Wallet::Status_Ok,
|
||||
Status_Error = Bitmonero::Wallet::Status_Error
|
||||
|
@ -48,9 +54,13 @@ public:
|
|||
//! returns last operation's status
|
||||
Status status() const;
|
||||
|
||||
//! returns of wallet connected
|
||||
//! returns true if wallet connected
|
||||
bool connected() const;
|
||||
|
||||
//! returns true if wallet was ever synchronized
|
||||
bool synchronized() const;
|
||||
|
||||
|
||||
//! returns last operation's error message
|
||||
QString errorString() const;
|
||||
|
||||
|
@ -88,10 +98,12 @@ public:
|
|||
//! returns daemon's blockchain height
|
||||
Q_INVOKABLE quint64 daemonBlockChainHeight() const;
|
||||
|
||||
//! returns daemon's blockchain target height
|
||||
Q_INVOKABLE quint64 daemonBlockChainTargetHeight() const;
|
||||
|
||||
//! refreshes the wallet
|
||||
Q_INVOKABLE bool refresh();
|
||||
|
||||
|
||||
//! refreshes the wallet asynchronously
|
||||
Q_INVOKABLE void refreshAsync();
|
||||
|
||||
|
@ -109,7 +121,10 @@ public:
|
|||
Q_INVOKABLE void disposeTransaction(PendingTransaction * t);
|
||||
|
||||
//! returns transaction history
|
||||
TransactionHistory * history();
|
||||
TransactionHistory * history() const;
|
||||
|
||||
//! returns transaction history model
|
||||
TransactionHistorySortFilterModel *historyModel() const;
|
||||
|
||||
//! generate payment id
|
||||
Q_INVOKABLE QString generatePaymentId() const;
|
||||
|
@ -136,12 +151,13 @@ signals:
|
|||
void moneySpent(const QString &txId, quint64 amount);
|
||||
void moneyReceived(const QString &txId, quint64 amount);
|
||||
void newBlock(quint64 height);
|
||||
void historyModelChanged() const;
|
||||
|
||||
|
||||
private:
|
||||
Wallet(QObject * parent = nullptr);
|
||||
Wallet(Bitmonero::Wallet *w, QObject * parent = 0);
|
||||
~Wallet();
|
||||
|
||||
private:
|
||||
friend class WalletManager;
|
||||
friend class WalletListenerImpl;
|
||||
|
@ -149,11 +165,16 @@ private:
|
|||
Bitmonero::Wallet * m_walletImpl;
|
||||
// history lifetime managed by wallet;
|
||||
TransactionHistory * m_history;
|
||||
// Used for UI history view
|
||||
mutable TransactionHistoryModel * m_historyModel;
|
||||
mutable TransactionHistorySortFilterModel * m_historySortFilterModel;
|
||||
QString m_paymentId;
|
||||
mutable QTime m_daemonBlockChainHeightTime;
|
||||
mutable quint64 m_daemonBlockChainHeight;
|
||||
int m_daemonBlockChainHeightTtl;
|
||||
|
||||
mutable quint64 m_daemonBlockChainTargetHeight;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // WALLET_H
|
||||
|
|
|
@ -61,9 +61,9 @@ void WalletManager::openWalletAsync(const QString &path, const QString &password
|
|||
}
|
||||
|
||||
|
||||
Wallet *WalletManager::recoveryWallet(const QString &path, const QString &memo, bool testnet)
|
||||
Wallet *WalletManager::recoveryWallet(const QString &path, const QString &memo, bool testnet, quint64 restoreHeight)
|
||||
{
|
||||
Bitmonero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), memo.toStdString(), testnet);
|
||||
Bitmonero::Wallet * w = m_pimpl->recoveryWallet(path.toStdString(), memo.toStdString(), testnet, restoreHeight);
|
||||
Wallet * wallet = new Wallet(w);
|
||||
return wallet;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
|
||||
// wizard: recoveryWallet path; hint: internally it recorvers wallet and set password = ""
|
||||
Q_INVOKABLE Wallet * recoveryWallet(const QString &path, const QString &memo,
|
||||
bool testnet = false);
|
||||
bool testnet = false, quint64 restoreHeight = 0);
|
||||
|
||||
/*!
|
||||
* \brief closeWallet - closes wallet and frees memory
|
||||
|
|
126
src/model/TransactionHistoryModel.cpp
Normal file
126
src/model/TransactionHistoryModel.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "TransactionHistoryModel.h"
|
||||
#include "TransactionHistory.h"
|
||||
#include "TransactionInfo.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
|
||||
TransactionHistoryModel::TransactionHistoryModel(QObject *parent)
|
||||
: QAbstractListModel(parent), m_transactionHistory(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TransactionHistoryModel::setTransactionHistory(TransactionHistory *th)
|
||||
{
|
||||
beginResetModel();
|
||||
m_transactionHistory = th;
|
||||
endResetModel();
|
||||
|
||||
connect(m_transactionHistory, &TransactionHistory::refreshStarted,
|
||||
this, &TransactionHistoryModel::beginResetModel);
|
||||
connect(m_transactionHistory, &TransactionHistory::refreshFinished,
|
||||
this, &TransactionHistoryModel::endResetModel);
|
||||
|
||||
emit transactionHistoryChanged();
|
||||
}
|
||||
|
||||
TransactionHistory *TransactionHistoryModel::transactionHistory() const
|
||||
{
|
||||
return m_transactionHistory;
|
||||
}
|
||||
|
||||
QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!m_transactionHistory) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (index.row() < 0 || (unsigned)index.row() >= m_transactionHistory->count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
TransactionInfo * tInfo = m_transactionHistory->transaction(index.row());
|
||||
|
||||
|
||||
Q_ASSERT(tInfo);
|
||||
if (!tInfo) {
|
||||
qCritical("%s: internal error: no transaction info for index %d", __FUNCTION__, index.row());
|
||||
return QVariant();
|
||||
}
|
||||
QVariant result;
|
||||
switch (role) {
|
||||
case TransactionRole:
|
||||
result = QVariant::fromValue(tInfo);
|
||||
break;
|
||||
case TransactionDirectionRole:
|
||||
result = QVariant::fromValue(tInfo->direction());
|
||||
break;
|
||||
case TransactionPendingRole:
|
||||
result = tInfo->isPending();
|
||||
break;
|
||||
case TransactionFailedRole:
|
||||
result = tInfo->isFailed();
|
||||
break;
|
||||
case TransactionAmountRole:
|
||||
result = tInfo->amount();
|
||||
break;
|
||||
case TransactionDisplayAmountRole:
|
||||
result = tInfo->displayAmount();
|
||||
break;
|
||||
case TransactionFeeRole:
|
||||
result = tInfo->fee();
|
||||
break;
|
||||
case TransactionBlockHeightRole:
|
||||
result = tInfo->blockHeight();
|
||||
break;
|
||||
case TransactionHashRole:
|
||||
result = tInfo->hash();
|
||||
break;
|
||||
case TransactionTimeStampRole:
|
||||
result = tInfo->timestamp();
|
||||
break;
|
||||
case TransactionPaymentIdRole:
|
||||
result = tInfo->paymentId();
|
||||
break;
|
||||
case TransactionIsOutRole:
|
||||
result = tInfo->direction() == TransactionInfo::Direction_Out;
|
||||
break;
|
||||
case TransactionDateRole:
|
||||
result = tInfo->date();
|
||||
break;
|
||||
case TransactionTimeRole:
|
||||
result = tInfo->time();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int TransactionHistoryModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_transactionHistory ? m_transactionHistory->count() : 0;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> TransactionHistoryModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
|
||||
roleNames.insert(TransactionRole, "transaction");
|
||||
roleNames.insert(TransactionDirectionRole, "direction");
|
||||
roleNames.insert(TransactionPendingRole, "isPending");
|
||||
roleNames.insert(TransactionFailedRole, "isFailed");
|
||||
roleNames.insert(TransactionAmountRole, "amount");
|
||||
roleNames.insert(TransactionDisplayAmountRole, "displayAmount");
|
||||
roleNames.insert(TransactionFeeRole, "fee");
|
||||
roleNames.insert(TransactionBlockHeightRole, "blockHeight");
|
||||
roleNames.insert(TransactionHashRole, "hash");
|
||||
roleNames.insert(TransactionTimeStampRole, "timeStamp");
|
||||
roleNames.insert(TransactionPaymentIdRole, "paymentId");
|
||||
roleNames.insert(TransactionIsOutRole, "isOut");
|
||||
roleNames.insert(TransactionDateRole, "date");
|
||||
roleNames.insert(TransactionTimeRole, "time");
|
||||
return roleNames;
|
||||
}
|
||||
|
||||
|
68
src/model/TransactionHistoryModel.h
Normal file
68
src/model/TransactionHistoryModel.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef TRANSACTIONHISTORYMODEL_H
|
||||
#define TRANSACTIONHISTORYMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class TransactionHistory;
|
||||
class TransactionInfo;
|
||||
|
||||
/**
|
||||
* @brief The TransactionHistoryModel class - read-only list model for Transaction History
|
||||
*/
|
||||
|
||||
class TransactionHistoryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(TransactionHistory * transactionHistory READ transactionHistory WRITE setTransactionHistory NOTIFY transactionHistoryChanged)
|
||||
|
||||
public:
|
||||
enum TransactionInfoRole {
|
||||
TransactionRole = Qt::UserRole + 1, // for the TransactionInfo object;
|
||||
TransactionDirectionRole,
|
||||
TransactionPendingRole,
|
||||
TransactionFailedRole,
|
||||
TransactionAmountRole,
|
||||
TransactionDisplayAmountRole,
|
||||
TransactionFeeRole,
|
||||
TransactionBlockHeightRole,
|
||||
TransactionHashRole,
|
||||
TransactionTimeStampRole,
|
||||
TransactionPaymentIdRole,
|
||||
// extra role (alias) for TransactionDirectionRole (as UI currently wants just boolean "out")
|
||||
TransactionIsOutRole,
|
||||
// extra roles for date and time (as UI wants date and time separately)
|
||||
TransactionDateRole,
|
||||
TransactionTimeRole
|
||||
};
|
||||
Q_ENUM(TransactionInfoRole)
|
||||
|
||||
TransactionHistoryModel(QObject * parent = 0);
|
||||
void setTransactionHistory(TransactionHistory * th);
|
||||
TransactionHistory * transactionHistory() const;
|
||||
/**
|
||||
* @brief dateFrom - returns firstmost transaction datetime
|
||||
* @return
|
||||
*/
|
||||
QDateTime firstDateTime() const;
|
||||
|
||||
/**
|
||||
* @brief dateTo - returns lastmost transaction datetime
|
||||
* @return
|
||||
*/
|
||||
QDateTime lastDateTime() const;
|
||||
|
||||
|
||||
|
||||
/// QAbstractListModel
|
||||
virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
|
||||
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const override;
|
||||
virtual QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
signals:
|
||||
void transactionHistoryChanged();
|
||||
|
||||
private:
|
||||
TransactionHistory * m_transactionHistory;
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONHISTORYMODEL_H
|
209
src/model/TransactionHistorySortFilterModel.cpp
Normal file
209
src/model/TransactionHistorySortFilterModel.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
#include "TransactionHistorySortFilterModel.h"
|
||||
#include "TransactionHistoryModel.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* helper to extract scope value from filter
|
||||
*/
|
||||
template <typename T>
|
||||
T scopeFilterValue(const QMap<int, QVariant> &filters, int role, int scopeIndex)
|
||||
{
|
||||
if (!filters.contains(role)) {
|
||||
return T();
|
||||
}
|
||||
return filters.value(role).toList().at(scopeIndex).value<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* helper to setup scope value to filter
|
||||
*/
|
||||
template <typename T>
|
||||
void setScopeFilterValue(QMap<int, QVariant> &filters, int role, int scopeIndex, const T &value)
|
||||
{
|
||||
QVariantList scopeFilter;
|
||||
|
||||
if (filters.contains(role)) {
|
||||
scopeFilter = filters.value(role).toList();
|
||||
}
|
||||
while (scopeFilter.size() < 2) {
|
||||
scopeFilter.append(T());
|
||||
}
|
||||
scopeFilter[scopeIndex] = QVariant::fromValue(value);
|
||||
filters[role] = scopeFilter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TransactionHistorySortFilterModel::TransactionHistorySortFilterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
QString TransactionHistorySortFilterModel::paymentIdFilter() const
|
||||
{
|
||||
return m_filterValues.value(TransactionHistoryModel::TransactionPaymentIdRole).toString();
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setPaymentIdFilter(const QString &arg)
|
||||
{
|
||||
if (paymentIdFilter() != arg) {
|
||||
m_filterValues[TransactionHistoryModel::TransactionPaymentIdRole] = arg;
|
||||
emit paymentIdFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
QDate TransactionHistorySortFilterModel::dateFromFilter() const
|
||||
{
|
||||
return scopeFilterValue<QDate>(m_filterValues, TransactionHistoryModel::TransactionTimeStampRole, ScopeIndex::From);
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setDateFromFilter(const QDate &date)
|
||||
{
|
||||
if (date != dateFromFilter()) {
|
||||
setScopeFilterValue(m_filterValues, TransactionHistoryModel::TransactionTimeStampRole, ScopeIndex::From, date);
|
||||
emit dateFromFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
QDate TransactionHistorySortFilterModel::dateToFilter() const
|
||||
{
|
||||
return scopeFilterValue<QDate>(m_filterValues, TransactionHistoryModel::TransactionTimeStampRole, ScopeIndex::To);
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setDateToFilter(const QDate &date)
|
||||
{
|
||||
if (date != dateToFilter()) {
|
||||
setScopeFilterValue(m_filterValues, TransactionHistoryModel::TransactionTimeStampRole, ScopeIndex::To, date);
|
||||
emit dateToFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
double TransactionHistorySortFilterModel::amountFromFilter() const
|
||||
{
|
||||
return scopeFilterValue<double>(m_filterValues, TransactionHistoryModel::TransactionAmountRole, ScopeIndex::From);
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setAmountFromFilter(double value)
|
||||
{
|
||||
if (value != amountFromFilter()) {
|
||||
setScopeFilterValue(m_filterValues, TransactionHistoryModel::TransactionAmountRole, ScopeIndex::From, value);
|
||||
emit amountFromFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
double TransactionHistorySortFilterModel::amountToFilter() const
|
||||
{
|
||||
return scopeFilterValue<double>(m_filterValues, TransactionHistoryModel::TransactionAmountRole, ScopeIndex::To);
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setAmountToFilter(double value)
|
||||
{
|
||||
if (value != amountToFilter()) {
|
||||
setScopeFilterValue(m_filterValues, TransactionHistoryModel::TransactionAmountRole, ScopeIndex::To, value);
|
||||
emit amountToFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
int TransactionHistorySortFilterModel::directionFilter() const
|
||||
{
|
||||
return m_filterValues.value(TransactionHistoryModel::TransactionDirectionRole).value<TransactionInfo::Direction>();
|
||||
}
|
||||
|
||||
void TransactionHistorySortFilterModel::setDirectionFilter(int value)
|
||||
{
|
||||
if (value != directionFilter()) {
|
||||
m_filterValues[TransactionHistoryModel::TransactionDirectionRole] = QVariant::fromValue(value);
|
||||
emit directionFilterChanged();
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TransactionHistorySortFilterModel::sort(int column, Qt::SortOrder order)
|
||||
{
|
||||
QSortFilterProxyModel::sort(column, order);
|
||||
}
|
||||
|
||||
TransactionHistory *TransactionHistorySortFilterModel::transactionHistory() const
|
||||
{
|
||||
const TransactionHistoryModel * model = static_cast<const TransactionHistoryModel*> (sourceModel());
|
||||
return model->transactionHistory();
|
||||
}
|
||||
|
||||
bool TransactionHistorySortFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
|
||||
if (source_row < 0 || source_row >= sourceModel()->rowCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
|
||||
if (!index.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
// iterating through filters
|
||||
for (int role : m_filterValues.keys()) {
|
||||
if (m_filterValues.contains(role)) {
|
||||
QVariant data = sourceModel()->data(index, role);
|
||||
switch (role) {
|
||||
case TransactionHistoryModel::TransactionPaymentIdRole:
|
||||
result = data.toString().contains(paymentIdFilter());
|
||||
break;
|
||||
case TransactionHistoryModel::TransactionTimeStampRole:
|
||||
{
|
||||
QDateTime from = QDateTime(dateFromFilter());
|
||||
QDateTime to = QDateTime(dateToFilter());
|
||||
to = to.addDays(1); // including upperbound
|
||||
QDateTime timestamp = data.toDateTime();
|
||||
bool matchFrom = from.isNull() || timestamp.isNull() || timestamp >= from;
|
||||
bool matchTo = to.isNull() || timestamp.isNull() || timestamp <= to;
|
||||
result = matchFrom && matchTo;
|
||||
}
|
||||
break;
|
||||
case TransactionHistoryModel::TransactionAmountRole:
|
||||
{
|
||||
double from = amountFromFilter();
|
||||
double to = amountToFilter();
|
||||
double amount = data.toDouble();
|
||||
|
||||
bool matchFrom = from <= 0 || amount >= from;
|
||||
bool matchTo = to <= 0 || amount <= to;
|
||||
result = matchFrom && matchTo;
|
||||
}
|
||||
break;
|
||||
case TransactionHistoryModel::TransactionDirectionRole:
|
||||
result = directionFilter() == TransactionInfo::Direction_Both ? true
|
||||
: data.toInt() == directionFilter();
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!result) { // stop the loop once filter doesn't match
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TransactionHistorySortFilterModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
79
src/model/TransactionHistorySortFilterModel.h
Normal file
79
src/model/TransactionHistorySortFilterModel.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#ifndef TRANSACTIONHISTORYSORTFILTERMODEL_H
|
||||
#define TRANSACTIONHISTORYSORTFILTERMODEL_H
|
||||
|
||||
#include "TransactionInfo.h"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QDate>
|
||||
|
||||
|
||||
class TransactionHistory;
|
||||
|
||||
class TransactionHistorySortFilterModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString paymentIdFilter READ paymentIdFilter WRITE setPaymentIdFilter NOTIFY paymentIdFilterChanged)
|
||||
Q_PROPERTY(QDate dateFromFilter READ dateFromFilter WRITE setDateFromFilter NOTIFY dateFromFilterChanged)
|
||||
Q_PROPERTY(QDate dateToFilter READ dateToFilter WRITE setDateToFilter NOTIFY dateToFilterChanged)
|
||||
Q_PROPERTY(double amountFromFilter READ amountFromFilter WRITE setAmountFromFilter NOTIFY amountFromFilterChanged)
|
||||
Q_PROPERTY(double amountToFilter READ amountToFilter WRITE setAmountToFilter NOTIFY amountToFilterChanged)
|
||||
Q_PROPERTY(int directionFilter READ directionFilter WRITE setDirectionFilter NOTIFY directionFilterChanged)
|
||||
|
||||
Q_PROPERTY(TransactionHistory * transactionHistory READ transactionHistory)
|
||||
|
||||
public:
|
||||
TransactionHistorySortFilterModel(QObject * parent = nullptr);
|
||||
//! filtering by payment id
|
||||
QString paymentIdFilter() const;
|
||||
void setPaymentIdFilter(const QString &arg);
|
||||
|
||||
//! filtering by date (lower bound)
|
||||
QDate dateFromFilter() const;
|
||||
void setDateFromFilter(const QDate &date);
|
||||
|
||||
//! filtering by to date (upper bound)
|
||||
QDate dateToFilter() const;
|
||||
void setDateToFilter(const QDate &date);
|
||||
|
||||
//! filtering by amount (lower bound)
|
||||
double amountFromFilter() const;
|
||||
void setAmountFromFilter(double value);
|
||||
|
||||
//! filtering by amount (upper bound)
|
||||
double amountToFilter() const;
|
||||
void setAmountToFilter(double value);
|
||||
|
||||
//! filtering by direction
|
||||
int directionFilter() const;
|
||||
void setDirectionFilter(int value);
|
||||
|
||||
Q_INVOKABLE void sort(int column, Qt::SortOrder order);
|
||||
TransactionHistory * transactionHistory() const;
|
||||
|
||||
signals:
|
||||
void paymentIdFilterChanged();
|
||||
void dateFromFilterChanged();
|
||||
void dateToFilterChanged();
|
||||
void amountFromFilterChanged();
|
||||
void amountToFilterChanged();
|
||||
void directionFilterChanged();
|
||||
|
||||
protected:
|
||||
// QSortFilterProxyModel overrides
|
||||
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
|
||||
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
|
||||
|
||||
|
||||
private:
|
||||
enum ScopeIndex {
|
||||
From = 0,
|
||||
To = 1
|
||||
};
|
||||
|
||||
private:
|
||||
QMap<int, QVariant> m_filterValues;
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONHISTORYSORTFILTERMODEL_H
|
|
@ -27,7 +27,9 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.2
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
|
||||
import QtQuick.Dialogs 1.2
|
||||
import 'utils.js' as Utils
|
||||
|
||||
|
@ -94,5 +96,6 @@ Item {
|
|||
wordsTextItem.clipboardButtonVisible: true
|
||||
wordsTextItem.tipTextVisible: true
|
||||
wordsTextItem.memoTextReadOnly: true
|
||||
restoreHeightVisible:false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ Item {
|
|||
+ qsTr("<b>Allow background mining: </b>") + wizard.settings['allow_background_mining'] + "<br>"
|
||||
+ qsTr("<b>Daemon address: </b>") + wizard.settings['daemon_address'] + "<br>"
|
||||
+ qsTr("<b>testnet: </b>") + wizard.settings['testnet'] + "<br>"
|
||||
+ (wizard.settings['restore_height'] === undefined ? "" : qsTr("<b>Restore height: </b>") + wizard.settings['restore_height']) + "<br>"
|
||||
+ translationManager.emptyString
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ Rectangle {
|
|||
appWindow.persistentSettings.auto_donations_amount = settings.auto_donations_amount
|
||||
appWindow.persistentSettings.daemon_address = settings.daemon_address
|
||||
appWindow.persistentSettings.testnet = settings.testnet
|
||||
appWindow.persistentSettings.restore_height = parseInt(settings.restore_height)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.2
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.TranslationManager 1.0
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import "../components"
|
||||
|
||||
// Reusable component for managing wallet (account name, path, private key)
|
||||
|
||||
|
@ -39,6 +41,8 @@ Item {
|
|||
property alias wordsTextTitle: frameHeader.text
|
||||
property alias walletPath: fileUrlInput.text
|
||||
property alias wordsTextItem : memoTextItem
|
||||
property alias restoreHeight : restoreHeightItem.text
|
||||
property alias restoreHeightVisible: restoreHeightItem.visible
|
||||
|
||||
|
||||
// TODO extend properties if needed
|
||||
|
@ -112,7 +116,7 @@ Item {
|
|||
width: 300
|
||||
height: 62
|
||||
|
||||
TextInput {
|
||||
TextEdit {
|
||||
id: accountName
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
|
@ -159,10 +163,22 @@ Item {
|
|||
anchors.topMargin: 16
|
||||
}
|
||||
|
||||
// Restore Height
|
||||
LineEdit {
|
||||
id: restoreHeightItem
|
||||
anchors.top: memoTextItem.bottom
|
||||
width: 250
|
||||
anchors.topMargin: 20
|
||||
placeholderText: qsTr("Restore height")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
validator: IntValidator {
|
||||
bottom:0
|
||||
}
|
||||
}
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: memoTextItem.bottom
|
||||
anchors.top: (restoreHeightItem.visible)? restoreHeightItem.bottom : memoTextItem.bottom
|
||||
anchors.topMargin: 24
|
||||
spacing: 16
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import QtQuick 2.0
|
||||
import moneroComponents 1.0
|
||||
import moneroComponents.Clipboard 1.0
|
||||
|
||||
Column {
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ Item {
|
|||
} else {
|
||||
passwordPage.titleText = qsTr("Now that your wallet has been restored, please set a password for the wallet") + translationManager.emptyString
|
||||
}
|
||||
|
||||
passwordItem.focus = true;
|
||||
}
|
||||
|
||||
function onPageClosed(settingsObject) {
|
||||
|
@ -146,30 +148,34 @@ Item {
|
|||
anchors.topMargin: 24
|
||||
width: 300
|
||||
height: 62
|
||||
placeholderText : qsTr("Password") + translationManager.emptyString;
|
||||
KeyNavigation.tab: retypePasswordItem
|
||||
onChanged: handlePassword()
|
||||
|
||||
}
|
||||
|
||||
WizardPasswordInput {
|
||||
id: retypePasswordItem
|
||||
anchors.top: passwordItem.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 24
|
||||
width: 300
|
||||
height: 62
|
||||
placeholderText : qsTr("Confirm password") + translationManager.emptyString;
|
||||
KeyNavigation.tab: passwordItem
|
||||
onChanged: handlePassword()
|
||||
}
|
||||
|
||||
PrivacyLevelSmall {
|
||||
id: privacyLevel
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: passwordItem.bottom
|
||||
anchors.topMargin: 24
|
||||
anchors.top: retypePasswordItem.bottom
|
||||
anchors.topMargin: 60
|
||||
background: "#F0EEEE"
|
||||
interactive: false
|
||||
}
|
||||
|
||||
WizardPasswordInput {
|
||||
id: retypePasswordItem
|
||||
anchors.top: privacyLevel.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 24
|
||||
width: 300
|
||||
height: 62
|
||||
onChanged: handlePassword()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log
|
||||
}
|
||||
|
|
|
@ -27,24 +27,34 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Item {
|
||||
FocusScope {
|
||||
property alias password: password.text
|
||||
property alias placeholderText: password.placeholderText
|
||||
signal changed(string password)
|
||||
|
||||
|
||||
TextInput {
|
||||
TextField {
|
||||
id : password
|
||||
focus:true
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 32
|
||||
renderType: Text.NativeRendering
|
||||
color: "#35B05A"
|
||||
passwordCharacter: "•"
|
||||
echoMode: TextInput.Password
|
||||
focus: true
|
||||
style: TextFieldStyle {
|
||||
renderType: Text.NativeRendering
|
||||
textColor: "#35B05A"
|
||||
passwordCharacter: "•"
|
||||
background: Rectangle {
|
||||
radius: 0
|
||||
border.width: 0
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReleased: {
|
||||
changed(text)
|
||||
}
|
||||
|
|
|
@ -27,9 +27,8 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.2
|
||||
import moneroComponents 1.0
|
||||
import QtQuick.Dialogs 1.2
|
||||
import Bitmonero.Wallet 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
import 'utils.js' as Utils
|
||||
|
||||
Item {
|
||||
|
@ -55,12 +54,14 @@ Item {
|
|||
settingsObject['account_name'] = uiItem.accountNameText
|
||||
settingsObject['words'] = Utils.lineBreaksToSpaces(uiItem.wordsTextItem.memoText)
|
||||
settingsObject['wallet_path'] = uiItem.walletPath
|
||||
settingsObject['restoreHeight'] = parseInt(uiItem.restoreHeight)
|
||||
return recoveryWallet(settingsObject)
|
||||
}
|
||||
|
||||
function recoveryWallet(settingsObject) {
|
||||
var testnet = appWindow.persistentSettings.testnet;
|
||||
var wallet = walletManager.recoveryWallet(oshelper.temporaryFilename(), settingsObject.words, testnet);
|
||||
var restoreHeight = settingsObject.restoreHeight;
|
||||
var wallet = walletManager.recoveryWallet(oshelper.temporaryFilename(), settingsObject.words, testnet, restoreHeight);
|
||||
var success = wallet.status === Wallet.Status_Ok;
|
||||
if (success) {
|
||||
settingsObject['wallet'] = wallet;
|
||||
|
@ -81,6 +82,7 @@ Item {
|
|||
wordsTextItem.tipTextVisible: false
|
||||
wordsTextItem.memoTextReadOnly: false
|
||||
wordsTextItem.memoText: ""
|
||||
restoreHeightVisible: true
|
||||
wordsTextItem.onMemoTextChanged: {
|
||||
checkNextButton();
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ Item {
|
|||
if (data !== null || data !== undefined) {
|
||||
var locale = data.locale
|
||||
translationManager.setLanguage(locale.split("_")[0]);
|
||||
wizard.switchPage(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue