diff --git a/BasicPanel.qml b/BasicPanel.qml
index 07aeb080..12a257bf 100644
--- a/BasicPanel.qml
+++ b/BasicPanel.qml
@@ -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
diff --git a/LeftPanel.qml b/LeftPanel.qml
index 851db047..7209a6dc 100644
--- a/LeftPanel.qml
+++ b/LeftPanel.qml
@@ -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 {
diff --git a/MiddlePanel.qml b/MiddlePanel.qml
index a2cabc1c..9160a359 100644
--- a/MiddlePanel.qml
+++ b/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)
+ }
+ }
}
diff --git a/build_libwallet_api.sh b/build_libwallet_api.sh
new file mode 100755
index 00000000..832b48d2
--- /dev/null
+++ b/build_libwallet_api.sh
@@ -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
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/AddressBookTable.qml b/components/AddressBookTable.qml
index 756445f7..2ad9d2ff 100644
--- a/components/AddressBookTable.qml
+++ b/components/AddressBookTable.qml
@@ -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
diff --git a/components/DaemonProgress.qml b/components/DaemonProgress.qml
new file mode 100644
index 00000000..1ed533e3
--- /dev/null
+++ b/components/DaemonProgress.qml
@@ -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")
+ }
+
+}
diff --git a/components/DashboardTable.qml b/components/DashboardTable.qml
index 05b23c6e..1dc0d3b4 100644
--- a/components/DashboardTable.qml
+++ b/components/DashboardTable.qml
@@ -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
diff --git a/components/DatePicker.qml b/components/DatePicker.qml
index 442ecdb0..9d0cbf20 100644
--- a/components/DatePicker.qml
+++ b/components/DatePicker.qml
@@ -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
diff --git a/components/HistoryTable.qml b/components/HistoryTable.qml
index db92aa69..867fdedf 100644
--- a/components/HistoryTable.qml
+++ b/components/HistoryTable.qml
@@ -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: "Copy address to clipboard"; icon: "../images/dropdownCopy.png" }
- ListElement { name: "Add to address book"; icon: "../images/dropdownAdd.png" }
- ListElement { name: "Send to same destination"; icon: "../images/dropdownSend.png" }
- ListElement { name: "Find similar transactions"; 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: "Copy address to clipboard"; icon: "../images/dropdownCopy.png" }
+ ListElement { name: "Add to address book"; icon: "../images/dropdownAdd.png" }
+ ListElement { name: "Send to same destination"; icon: "../images/dropdownSend.png" }
+ ListElement { name: "Find similar transactions"; icon: "../images/dropdownSearch.png" }
+ }
+
+ Clipboard { id: clipboard }
}
diff --git a/components/LineEdit.qml b/components/LineEdit.qml
index 81786881..2ebc6e0c 100644
--- a/components/LineEdit.qml
+++ b/components/LineEdit.qml
@@ -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
}
}
diff --git a/components/PasswordDialog.qml b/components/PasswordDialog.qml
index a8ff294a..9edf87fc 100644
--- a/components/PasswordDialog.qml
+++ b/components/PasswordDialog.qml
@@ -40,7 +40,6 @@ Dialog {
standardButtons: StandardButton.Ok + StandardButton.Cancel
ColumnLayout {
id: column
- height: 40
anchors.fill: parent
Label {
diff --git a/components/ProcessingSplash.qml b/components/ProcessingSplash.qml
index 297631ec..84218f88 100644
--- a/components/ProcessingSplash.qml
+++ b/components/ProcessingSplash.qml
@@ -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
}
}
}
diff --git a/get_libwallet_api.sh b/get_libwallet_api.sh
index 875ca2e9..fbba689a 100755
--- a/get_libwallet_api.sh
+++ b/get_libwallet_api.sh
@@ -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
diff --git a/main.cpp b/main.cpp
index 129d38c2..0e0d58e3 100644
--- a/main.cpp
+++ b/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("moneroComponents", 1, 0, "Clipboard");
+ // registering types for QML
+ qmlRegisterType("moneroComponents.Clipboard", 1, 0, "Clipboard");
- qmlRegisterUncreatableType("Bitmonero.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
+ qmlRegisterUncreatableType("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
- qmlRegisterUncreatableType("Bitmonero.PendingTransaction", 1, 0, "PendingTransaction",
+
+ qmlRegisterUncreatableType("moneroComponents.PendingTransaction", 1, 0, "PendingTransaction",
"PendingTransaction can't be instantiated directly");
- qmlRegisterUncreatableType("Bitmonero.WalletManager", 1, 0, "WalletManager",
+ qmlRegisterUncreatableType("moneroComponents.WalletManager", 1, 0, "WalletManager",
"WalletManager can't be instantiated directly");
- qmlRegisterUncreatableType("moneroComponents", 1, 0, "TranslationManager",
+ qmlRegisterUncreatableType("moneroComponents.TranslationManager", 1, 0, "TranslationManager",
"TranslationManager can't be instantiated directly");
+
+
+ qmlRegisterUncreatableType("moneroComponents.TransactionHistoryModel", 1, 0, "TransactionHistoryModel",
+ "TransactionHistoryModel can't be instantiated directly");
+
+ qmlRegisterUncreatableType("moneroComponents.TransactionHistorySortFilterModel", 1, 0, "TransactionHistorySortFilterModel",
+ "TransactionHistorySortFilterModel can't be instantiated directly");
+
+ qmlRegisterUncreatableType("moneroComponents.TransactionHistory", 1, 0, "TransactionHistory",
+ "TransactionHistory can't be instantiated directly");
+
+ qmlRegisterUncreatableType("moneroComponents.TransactionInfo", 1, 0, "TransactionInfo",
+ "TransactionHistory can't be instantiated directly");
+
qRegisterMetaType();
-
-
-
+ qRegisterMetaType();
+ qRegisterMetaType();
QQmlApplicationEngine engine;
diff --git a/main.qml b/main.qml
index d6706d5d..ac45ed20 100644
--- a/main.qml
+++ b/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 {
diff --git a/monero-core.pro b/monero-core.pro
index 4c1a5158..daa1378d 100644
--- a/monero-core.pro
+++ b/monero-core.pro
@@ -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 \
diff --git a/pages/History.qml b/pages/History.qml
index 15161a5d..4c2a0dec 100644
--- a/pages/History.qml
+++ b/pages/History.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 (Optional)") + 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 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: "Client from Australia"; out: false }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: true }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: true }
- ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: false }
- ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: "Client from Australia"; out: false }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: false }
- ListElement { paymentId: ""; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: false }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: ""; out: false }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; description: "Client from Australia"; out: false }
- ListElement { paymentId: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; address: "faef56b9acf67a7dba75ec01f403497049d7cff111628edfe7b57278554dc798"; date: "Jan 12, 2014"; time: "12:23 AM"; amount: "0.000709159241"; balance: "19301.870709159241"; 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
}
}
}
diff --git a/pages/Receive.qml b/pages/Receive.qml
index e2c1cb7f..4ea32a2f 100644
--- a/pages/Receive.qml
+++ b/pages/Receive.qml
@@ -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()
+ }
+
}
}
diff --git a/pages/Settings.qml b/pages/Settings.qml
index e9a50476..d46186af 100644
--- a/pages/Settings.qml
+++ b/pages/Settings.qml
@@ -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();
+ }
+
+
}
+
+
+
+
diff --git a/pages/Transfer.qml b/pages/Transfer.qml
index 2d011c18..3921b1ef 100644
--- a/pages/Transfer.qml
+++ b/pages/Transfer.qml
@@ -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"
diff --git a/qml.qrc b/qml.qrc
index a44266b9..ad47ba44 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -116,5 +116,6 @@
lang/flags/italy.png
components/PasswordDialog.qml
components/ProcessingSplash.qml
+ components/DaemonProgress.qml
diff --git a/src/libwalletqt/TransactionHistory.cpp b/src/libwalletqt/TransactionHistory.cpp
index 2c2c9f73..7fd7c7bc 100644
--- a/src/libwalletqt/TransactionHistory.cpp
+++ b/src/libwalletqt/TransactionHistory.cpp
@@ -2,49 +2,89 @@
#include "TransactionInfo.h"
#include
+#include
-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 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(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();
}
diff --git a/src/libwalletqt/TransactionHistory.h b/src/libwalletqt/TransactionHistory.h
index a6287506..ee05787a 100644
--- a/src/libwalletqt/TransactionHistory.h
+++ b/src/libwalletqt/TransactionHistory.h
@@ -3,6 +3,7 @@
#include
#include
+#include
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 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 m_tinfo;
+ mutable QDateTime m_firstDateTime;
+ mutable QDateTime m_lastDateTime;
};
diff --git a/src/libwalletqt/TransactionInfo.cpp b/src/libwalletqt/TransactionInfo.cpp
index 192e85e5..248fd73e 100644
--- a/src/libwalletqt/TransactionInfo.cpp
+++ b/src/libwalletqt/TransactionInfo.cpp
@@ -1,4 +1,6 @@
#include "TransactionInfo.h"
+#include "WalletManager.h"
+
#include
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());
}
diff --git a/src/libwalletqt/TransactionInfo.h b/src/libwalletqt/TransactionInfo.h
index 62c26e2f..f30f42fa 100644
--- a/src/libwalletqt/TransactionInfo.h
+++ b/src/libwalletqt/TransactionInfo.h
@@ -1,8 +1,9 @@
#ifndef TRANSACTIONINFO_H
#define TRANSACTIONINFO_H
-#include
#include
+#include
+#include
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
diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp
index 987f4640..b52963bc 100644
--- a/src/libwalletqt/Wallet.cpp
+++ b/src/libwalletqt/Wallet.cpp
@@ -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
@@ -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(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);
}
diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h
index 703bd186..d794550a 100644
--- a/src/libwalletqt/Wallet.h
+++ b/src/libwalletqt/Wallet.h
@@ -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
diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp
index ea299cdc..2e1fe57b 100644
--- a/src/libwalletqt/WalletManager.cpp
+++ b/src/libwalletqt/WalletManager.cpp
@@ -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;
}
diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h
index 23c56925..24fb60fc 100644
--- a/src/libwalletqt/WalletManager.h
+++ b/src/libwalletqt/WalletManager.h
@@ -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
diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp
new file mode 100644
index 00000000..1ad17944
--- /dev/null
+++ b/src/model/TransactionHistoryModel.cpp
@@ -0,0 +1,126 @@
+#include "TransactionHistoryModel.h"
+#include "TransactionHistory.h"
+#include "TransactionInfo.h"
+
+#include
+
+
+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 TransactionHistoryModel::roleNames() const
+{
+ QHash 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;
+}
+
+
diff --git a/src/model/TransactionHistoryModel.h b/src/model/TransactionHistoryModel.h
new file mode 100644
index 00000000..0960ceae
--- /dev/null
+++ b/src/model/TransactionHistoryModel.h
@@ -0,0 +1,68 @@
+#ifndef TRANSACTIONHISTORYMODEL_H
+#define TRANSACTIONHISTORYMODEL_H
+
+#include
+
+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 roleNames() const override;
+
+signals:
+ void transactionHistoryChanged();
+
+private:
+ TransactionHistory * m_transactionHistory;
+};
+
+#endif // TRANSACTIONHISTORYMODEL_H
diff --git a/src/model/TransactionHistorySortFilterModel.cpp b/src/model/TransactionHistorySortFilterModel.cpp
new file mode 100644
index 00000000..6d6a2b44
--- /dev/null
+++ b/src/model/TransactionHistorySortFilterModel.cpp
@@ -0,0 +1,209 @@
+#include "TransactionHistorySortFilterModel.h"
+#include "TransactionHistoryModel.h"
+
+#include
+
+namespace {
+ /**
+ * helper to extract scope value from filter
+ */
+ template
+ T scopeFilterValue(const QMap &filters, int role, int scopeIndex)
+ {
+ if (!filters.contains(role)) {
+ return T();
+ }
+ return filters.value(role).toList().at(scopeIndex).value();
+ }
+
+ /**
+ * helper to setup scope value to filter
+ */
+ template
+ void setScopeFilterValue(QMap &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(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(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(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(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();
+}
+
+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 (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);
+}
diff --git a/src/model/TransactionHistorySortFilterModel.h b/src/model/TransactionHistorySortFilterModel.h
new file mode 100644
index 00000000..1b5c2fce
--- /dev/null
+++ b/src/model/TransactionHistorySortFilterModel.h
@@ -0,0 +1,79 @@
+#ifndef TRANSACTIONHISTORYSORTFILTERMODEL_H
+#define TRANSACTIONHISTORYSORTFILTERMODEL_H
+
+#include "TransactionInfo.h"
+
+#include
+#include
+#include
+#include
+
+
+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 m_filterValues;
+};
+
+#endif // TRANSACTIONHISTORYSORTFILTERMODEL_H
diff --git a/wizard/WizardCreateWallet.qml b/wizard/WizardCreateWallet.qml
index f0344a94..6d632cbe 100644
--- a/wizard/WizardCreateWallet.qml
+++ b/wizard/WizardCreateWallet.qml
@@ -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
}
}
diff --git a/wizard/WizardFinish.qml b/wizard/WizardFinish.qml
index 48b4ae61..7c44b7bc 100644
--- a/wizard/WizardFinish.qml
+++ b/wizard/WizardFinish.qml
@@ -47,6 +47,7 @@ Item {
+ qsTr("Allow background mining: ") + wizard.settings['allow_background_mining'] + "
"
+ qsTr("Daemon address: ") + wizard.settings['daemon_address'] + "
"
+ qsTr("testnet: ") + wizard.settings['testnet'] + "
"
+ + (wizard.settings['restore_height'] === undefined ? "" : qsTr("Restore height: ") + wizard.settings['restore_height']) + "
"
+ translationManager.emptyString
return str;
}
diff --git a/wizard/WizardMain.qml b/wizard/WizardMain.qml
index 7466cdf8..3168733b 100644
--- a/wizard/WizardMain.qml
+++ b/wizard/WizardMain.qml
@@ -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)
}
diff --git a/wizard/WizardManageWalletUI.qml b/wizard/WizardManageWalletUI.qml
index cc8a5be3..7104dc9f 100644
--- a/wizard/WizardManageWalletUI.qml
+++ b/wizard/WizardManageWalletUI.qml
@@ -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
diff --git a/wizard/WizardMemoTextInput.qml b/wizard/WizardMemoTextInput.qml
index 9497d9e5..37dbcb39 100644
--- a/wizard/WizardMemoTextInput.qml
+++ b/wizard/WizardMemoTextInput.qml
@@ -1,5 +1,5 @@
import QtQuick 2.0
-import moneroComponents 1.0
+import moneroComponents.Clipboard 1.0
Column {
diff --git a/wizard/WizardPassword.qml b/wizard/WizardPassword.qml
index 8318a785..476c5742 100644
--- a/wizard/WizardPassword.qml
+++ b/wizard/WizardPassword.qml
@@ -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
}
diff --git a/wizard/WizardPasswordInput.qml b/wizard/WizardPasswordInput.qml
index 82597421..00201ecf 100644
--- a/wizard/WizardPasswordInput.qml
+++ b/wizard/WizardPasswordInput.qml
@@ -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)
}
diff --git a/wizard/WizardRecoveryWallet.qml b/wizard/WizardRecoveryWallet.qml
index 505bc239..7f6d87f4 100644
--- a/wizard/WizardRecoveryWallet.qml
+++ b/wizard/WizardRecoveryWallet.qml
@@ -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();
}
diff --git a/wizard/WizardWelcome.qml b/wizard/WizardWelcome.qml
index 46448e2c..ef97f984 100644
--- a/wizard/WizardWelcome.qml
+++ b/wizard/WizardWelcome.qml
@@ -163,6 +163,7 @@ Item {
if (data !== null || data !== undefined) {
var locale = data.locale
translationManager.setLanguage(locale.split("_")[0]);
+ wizard.switchPage(true)
}
}
}