diff --git a/components/AddressBookTable.qml b/components/AddressBookTable.qml deleted file mode 100644 index adc4aec9..00000000 --- a/components/AddressBookTable.qml +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2014-2018, 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 -import moneroComponents.Clipboard 1.0 -import "../js/TxUtils.js" as TxUtils - -ListView { - id: listView - clip: true - boundsBehavior: ListView.StopAtBounds - property bool selectAndSend: false - - footer: Rectangle { - height: 127 - width: listView.width - color: "transparent" - - Text { - anchors.centerIn: parent - font.family: "Arial" - font.pixelSize: 14 - color: "#808080" - text: qsTr("No more results") + translationManager.emptyString - } - } - - property var previousItem - delegate: Rectangle { - id: delegate - height: 64 - width: listView.width - color: "transparent" - z: listView.count - index - function collapseDropdown() { dropdown.expanded = false } - function doSend() { - console.log("Sending to: ", address +" "+ paymentId); - middlePanel.sendTo(address, paymentId, description); - leftPanel.selectItem(middlePanel.state) - } - - Text { - id: descriptionText - anchors.left: parent.left - anchors.top: parent.top - anchors.topMargin: 12 - width: text.length ? (descriptionArea.containsMouse ? 139 : 139) : 0 - font.family: "Arial" - font.bold: true - font.pixelSize: 19 - color: "#ffffff" - elide: Text.ElideRight - text: description - textFormat: Text.PlainText - - MouseArea { - id: descriptionArea - anchors.fill: parent - hoverEnabled: true - } - } - - TextEdit { - id: addressText - selectByMouse: true - anchors.bottom: descriptionText.bottom - anchors.left: descriptionText.right - anchors.right: dropdown.left - anchors.leftMargin: description.length > 0 ? 12 : 0 - anchors.rightMargin: 40 - font.family: "Arial" - font.pixelSize: 16 - color: "#ffffff" - text: { - if(isMobile){ - TxUtils.addressTruncate(address, 6); - } else { - return TxUtils.addressTruncate(address, 10); - } - } - readOnly: true - } - - Text { - id: paymentLabel - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - - width: 139 - font.family: "Arial" - font.pixelSize: 12 - color: "#ffffff" - text: qsTr("Payment ID:") + translationManager.emptyString - } - - TextEdit { - selectByMouse: true; - anchors.bottom: paymentLabel.bottom - anchors.left: paymentLabel.right - anchors.leftMargin: 12 - anchors.rightMargin: 12 - anchors.right: dropdown.left - readOnly: true - - font.family: "Arial" - font.pixelSize: 13 - color: "#545454" - text: { - if(isMobile){ - TxUtils.addressTruncate(paymentId, 6); - } else { - return TxUtils.addressTruncate(paymentId, 10); - } - } - } - - ListModel { - id: dropModel - ListElement { name: "Copy address to clipboard"; icon: "../images/dropdownCopy.png" } - ListElement { name: "Send to this address"; icon: "../images/dropdownSend.png" } -// ListElement { name: "Find similar transactions"; icon: "../images/dropdownSearch.png" } - ListElement { name: "Remove from address book"; icon: "../images/dropdownDel.png" } - } - - Clipboard { id: clipboard } - TableDropdown { - id: dropdown - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.rightMargin: 5 - dataModel: dropModel - visible: !listView.selectAndSend - z: 1 - onExpandedChanged: { - if(expanded) { - listView.previousItem = delegate - listView.currentIndex = index - } - } - onOptionClicked: { - // Ensure tooltip is closed - appWindow.toolTip.visible = false; - if(option === 0) { - clipboard.setText(address) - appWindow.showStatusMessage(qsTr("Address copied to clipboard"),3) - } - else if(option === 1){ - doSend() - } else if(option === 2){ - console.log("Delete: ", rowId); - currentWallet.addressBookModel.deleteRow(rowId); - } - } - } - - Rectangle { - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - height: 1 - color: "#404040" - } - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - visible: listView.selectAndSend - onClicked: { - doSend(); - } - } - } -} diff --git a/components/Style.qml b/components/Style.qml index cc106239..8555cb5e 100644 --- a/components/Style.qml +++ b/components/Style.qml @@ -8,6 +8,11 @@ QtObject { property QtObject fontLight: FontLoader { id: _fontLight; source: "qrc:/fonts/Roboto-Light.ttf"; } property QtObject fontRegular: FontLoader { id: _fontRegular; source: "qrc:/fonts/Roboto-Regular.ttf"; } + property QtObject fontMonoMedium: FontLoader { id: _fontMonoMedium; source: "qrc:/fonts/RobotoMono-Medium.ttf"; } + property QtObject fontMonoBold: FontLoader { id: _fontMonoBold; source: "qrc:/fonts/RobotoMono-Bold.ttf"; } + property QtObject fontMonoLight: FontLoader { id: _fontMonoLight; source: "qrc:/fonts/RobotoMono-Light.ttf"; } + property QtObject fontMonoRegular: FontLoader { id: _fontMonoRegular; source: "qrc:/fonts/RobotoMono-Regular.ttf"; } + property string grey: "#404040" property string orange: "#FF6C3C" property string white: "#FFFFFF" @@ -17,6 +22,7 @@ QtObject { property string defaultFontColor: "white" property string dimmedFontColor: "#BBBBBB" property string lightGreyFontColor: "#DFDFDF" + property string greyFontColor: "#808080" property string warningColor: "#963E00" property string errorColor: "#FA6800" property string inputBoxBackground: "black" diff --git a/fonts/RobotoMono-Bold.ttf b/fonts/RobotoMono-Bold.ttf new file mode 100755 index 00000000..61842afd Binary files /dev/null and b/fonts/RobotoMono-Bold.ttf differ diff --git a/fonts/RobotoMono-Light.ttf b/fonts/RobotoMono-Light.ttf new file mode 100755 index 00000000..81563d86 Binary files /dev/null and b/fonts/RobotoMono-Light.ttf differ diff --git a/fonts/RobotoMono-Medium.ttf b/fonts/RobotoMono-Medium.ttf new file mode 100755 index 00000000..f40bc588 Binary files /dev/null and b/fonts/RobotoMono-Medium.ttf differ diff --git a/fonts/RobotoMono-Regular.ttf b/fonts/RobotoMono-Regular.ttf new file mode 100755 index 00000000..f7b4a9b3 Binary files /dev/null and b/fonts/RobotoMono-Regular.ttf differ diff --git a/images/arrow-right-in-circle.png b/images/arrow-right-in-circle.png new file mode 100755 index 00000000..0d19f08e Binary files /dev/null and b/images/arrow-right-in-circle.png differ diff --git a/images/arrow-right-in-circle@2x.png b/images/arrow-right-in-circle@2x.png new file mode 100755 index 00000000..aa859b02 Binary files /dev/null and b/images/arrow-right-in-circle@2x.png differ diff --git a/images/clipboard.png b/images/clipboard.png new file mode 100755 index 00000000..8ab3d8de Binary files /dev/null and b/images/clipboard.png differ diff --git a/images/clipboard@2x.png b/images/clipboard@2x.png new file mode 100755 index 00000000..02e2ec6d Binary files /dev/null and b/images/clipboard@2x.png differ diff --git a/images/dropdownDel.png b/images/dropdownDel.png deleted file mode 100644 index 73af193f..00000000 Binary files a/images/dropdownDel.png and /dev/null differ diff --git a/images/rename.png b/images/rename.png new file mode 100755 index 00000000..25a9bf64 Binary files /dev/null and b/images/rename.png differ diff --git a/images/rename@2x.png b/images/rename@2x.png new file mode 100755 index 00000000..308a2809 Binary files /dev/null and b/images/rename@2x.png differ diff --git a/js/TxUtils.js b/js/TxUtils.js index e53424c6..fcd00ca3 100644 --- a/js/TxUtils.js +++ b/js/TxUtils.js @@ -17,6 +17,13 @@ function addressTruncate(address, range){ return address.substring(0, range) + "..." + address.substring(address.length-range); } +function addressTruncatePretty(address, blocks){ + if(typeof(address) === "undefined") return; + if(typeof(blocks) === "undefined") blocks = 2; + var ret = ""; + return address.substring(0, 4 * blocks).match(/.{1,4}/g).join(' ') + " .. " + address.substring(address.length - 4 * blocks).match(/.{1,4}/g).join(' '); +} + function check256(str, length) { if (str.length != length) return false; diff --git a/pages/AddressBook.qml b/pages/AddressBook.qml index b8c7967c..2103b235 100644 --- a/pages/AddressBook.qml +++ b/pages/AddressBook.qml @@ -27,6 +27,7 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import QtQuick 2.0 +import QtQuick.Controls 2.0 import QtQuick.Layouts 1.1 import QtQuick.Dialogs 1.2 import "../components" as MoneroComponents @@ -35,231 +36,442 @@ import moneroComponents.AddressBook 1.0 import moneroComponents.AddressBookModel 1.0 import moneroComponents.Clipboard 1.0 import moneroComponents.NetworkType 1.0 +import FontAwesome 1.0 -ColumnLayout { +Rectangle { id: root - property var model + color: "transparent" property bool selectAndSend: false + property bool editEntry: false + Clipboard { id: clipboard } ColumnLayout { - Layout.margins: (isMobile ? 17 : 20) * scaleRatio - Layout.topMargin: 40 * scaleRatio - Layout.fillWidth: true - spacing: 26 * scaleRatio - visible: !root.selectAndSend - - MoneroComponents.LineEditMulti { - id: addressLine + id: mainLayout + anchors.margins: (isMobile)? 17 * scaleRatio : 20 * scaleRatio + anchors.topMargin: 40 * scaleRatio + + anchors.left: parent.left + anchors.top: parent.top + anchors.right: parent.right + + spacing: 20 * scaleRatio + + ColumnLayout { + id: addressBookEmptyLayout + visible: addressBookListView.count == 0 + spacing: 0 Layout.fillWidth: true - fontBold: true - labelText: qsTr("Address") + translationManager.emptyString - placeholderText: { - switch (persistentSettings.nettype) { - case NetworkType.MAINNET: - return "4.. / 8.. / OpenAlias"; - case NetworkType.STAGENET: - return "5.. / 7.."; - case NetworkType.TESTNET: - return "9.. / B.."; - default: - break; + + TextArea { + id: titleLabel + Layout.fillWidth: true + color: MoneroComponents.Style.defaultFontColor + font.family: MoneroComponents.Style.fontRegular.name + font.pixelSize: 32 * scaleRatio + horizontalAlignment: TextInput.AlignLeft + selectByMouse: false + wrapMode: Text.WordWrap; + textMargin: 0 + leftPadding: 0 + topPadding: 0 + text: qsTr("Save your most used addresses here") + translationManager.emptyString + width: parent.width + readOnly: true + + // @TODO: Legacy. Remove after Qt 5.8. + // https://stackoverflow.com/questions/41990013 + MouseArea { + anchors.fill: parent + enabled: false } } - wrapMode: Text.WrapAnywhere - addressValidation: true - pasteButton: true - onPaste: function(clipboardText) { - const parsed = walletManager.parse_uri_to_object(clipboardText); - if (!parsed.error) { - addressLine.text = parsed.address; - setPaymentId(parsed.payment_id); - setDescription(parsed.tx_description); - } else { - addressLine.text = clipboardText; + + TextArea { + Layout.fillWidth: true + color: MoneroComponents.Style.greyFontColor + font.family: MoneroComponents.Style.fontRegular.name + font.pixelSize: 16 * scaleRatio + horizontalAlignment: TextInput.AlignLeft + selectByMouse: false + wrapMode: Text.WordWrap; + textMargin: 0 + leftPadding: 0 + topPadding: 0 + text: qsTr("This makes it easier to send or receive Monero and reduces errors when typing in addresses manually.") + translationManager.emptyString + width: parent.width + readOnly: true + + // @TODO: Legacy. Remove after Qt 5.8. + // https://stackoverflow.com/questions/41990013 + MouseArea { + anchors.fill: parent + enabled: false } } - inlineButton.icon: "../images/qr.png" - inlineButton.buttonColor: MoneroComponents.Style.orange - inlineButton.onClicked: { - cameraUi.state = "Capture" - cameraUi.qrcode_decoded.connect(updateFromQrCode) + + MoneroComponents.StandardButton { + id: addFirstEntryButton + Layout.topMargin: 20 + text: qsTr("Add an address") + translationManager.emptyString + onClicked: { + root.showAddAddress(); + } } - inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text } - MoneroComponents.StandardButton { - id: resolveButton - text: qsTr("Resolve") + translationManager.emptyString - visible: TxUtils.isValidOpenAliasAddress(addressLine.text) - enabled : visible - onClicked: { - var result = walletManager.resolveOpenAlias(addressLine.text) - if (result) { - var parts = result.split("|") - if (parts.length === 2) { - var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype) - if (parts[0] === "true") { - if (address_ok) { - // prepend openalias to description - descriptionLine.text = descriptionLine.text ? addressLine.text + " " + descriptionLine.text : addressLine.text - addressLine.text = parts[1] + ColumnLayout { + id: addressBookLayout + visible: addressBookListView.count >= 1 + spacing: 0 + + MoneroComponents.Label { + Layout.bottomMargin: 20 + fontSize: 32 * scaleRatio + text: qsTr("Address book") + translationManager.emptyString + } + + ColumnLayout { + id: addressBookListRow + property int addressBookListItemHeight: 50 * scaleRatio + Layout.fillWidth: true + Layout.minimumWidth: 240 + Layout.preferredHeight: addressBookListItemHeight * addressBookListView.count + + ListView { + id: addressBookListView + Layout.fillWidth: true + anchors.fill: parent + clip: true + boundsBehavior: ListView.StopAtBounds + interactive: false + delegate: Rectangle { + id: tableItem2 + height: addressBookListRow.addressBookListItemHeight + width: parent.width + Layout.fillWidth: true + color: "transparent" + + function doSend() { + console.log("Sending to: ", address +" "+ paymentId); + middlePanel.sendTo(address, paymentId, description); + leftPanel.selectItem(middlePanel.state) + } + + Rectangle { + anchors.right: parent.right + anchors.left: parent.left + anchors.top: parent.top + height: 1 + color: MoneroComponents.Style.grey + } + + Rectangle { + anchors.fill: parent + anchors.topMargin: 5 * scaleRatio + anchors.rightMargin: 110 * scaleRatio + color: "transparent" + + MoneroComponents.Label { + id: descriptionLabel + color: MoneroComponents.Style.defaultFontColor + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 6 * scaleRatio + fontSize: 16 * scaleRatio + text: description + elide: Text.ElideRight + textWidth: addressLabel.x - descriptionLabel.x - 1 + } + + MoneroComponents.Label { + id: addressLabel + color: MoneroComponents.Style.defaultFontColor + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.right + anchors.leftMargin: -addressLabel.width - 5 * scaleRatio + + fontSize: 16 * scaleRatio + fontFamily: MoneroComponents.Style.fontMonoRegular.name; + text: TxUtils.addressTruncatePretty(address, mainLayout.width < 540 ? 1 : (mainLayout.width < 700 ? 2 : 3)); + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + visible: root.selectAndSend + onClicked: { + doSend(); + } } - else - oa_message(qsTr("No valid address found at this OpenAlias address")) } - else if (parts[0] === "false") { - if (address_ok) { - addressLine.text = parts[1] - oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed")) - } - else - { - oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed")) - } + + MoneroComponents.IconButton { + id: sendToButton + imageSource: "../images/arrow-right-in-circle.png" + image.opacity: 0.5 + anchors.right: parent.right + anchors.rightMargin: 63 * scaleRatio + onClicked: { + doSend(); + } + } + + MoneroComponents.IconButton { + id: renameButton + imageSource: "../images/rename.png" + image.opacity: 0.5 + anchors.right: parent.right + anchors.rightMargin: 30 * scaleRatio + anchors.topMargin: 1 * scaleRatio + + onClicked: { + addressBookListView.currentIndex = index; + root.showEditAddress(address, description); + } } - else { - oa_message(qsTr("Internal error")) + + MoneroComponents.IconButton { + id: copyButton + imageSource: "../images/clipboard.png" + image.opacity: 0.5 + anchors.right: parent.right + + onClicked: { + console.log("Address copied to clipboard"); + clipboard.setText(address); + appWindow.showStatusMessage(qsTr("Address copied to clipboard"),3); + } } } - else { - oa_message(qsTr("Internal error")) - } } - else { - oa_message(qsTr("No address found")) + } + + Rectangle { + color: MoneroComponents.Style.grey + Layout.fillWidth: true + height: 1 + } + + MoneroComponents.CheckBox { + id: addNewEntryCheckbox + border: false + checkedIcon: "qrc:///images/plus-in-circle-medium-white.png" + uncheckedIcon: "qrc:///images/plus-in-circle-medium-white.png" + fontSize: 16 * scaleRatio + iconOnTheLeft: true + Layout.fillWidth: true + Layout.topMargin: 10 * scaleRatio + text: qsTr("Add address") + translationManager.emptyString; + onClicked: { + root.showAddAddress(); } } - } - MoneroComponents.LineEditMulti { - id: paymentIdLine - visible: appWindow.persistentSettings.showPid - Layout.fillWidth: true - labelText: qsTr("Payment ID (Optional)") + translationManager.emptyString - placeholderText: qsTr("Paste 64 hexadecimal characters") + translationManager.emptyString - wrapMode: Text.WrapAnywhere -// tipText: qsTr("Payment ID

A unique user name used in
the address book. It is not a
transfer of information sent
during the transfer") -// + translationManager.emptyString } + ColumnLayout { + id: addContactLayout + visible: false + spacing: 0 - MoneroComponents.LineEditMulti { - id: descriptionLine - Layout.fillWidth: true - labelText: qsTr("Description (Optional)") + translationManager.emptyString - placeholderText: qsTr("Give this entry a name or description") + translationManager.emptyString - wrapMode: Text.WrapAnywhere - } + MoneroComponents.Label { + fontSize: 32 * scaleRatio + wrapMode: Text.WordWrap + text: (root.editEntry ? qsTr("Edit an address") : qsTr("Add an address")) + translationManager.emptyString + } - RowLayout { - id: addButton - Layout.bottomMargin: 17 * scaleRatio - MoneroComponents.StandardButton { - text: qsTr("Add") + translationManager.emptyString - enabled: checkInformation(addressLine.text, paymentIdLine.text, appWindow.persistentSettings.nettype) + MoneroComponents.LineEditMulti { + id: addressLine + Layout.topMargin: 20 + labelText: qsTr("\ + Address") + translationManager.emptyString + placeholderText: { + if(persistentSettings.nettype == NetworkType.MAINNET){ + return "4.. / 8.. / OpenAlias"; + } else if (persistentSettings.nettype == NetworkType.STAGENET){ + return "5.. / 7.."; + } else if(persistentSettings.nettype == NetworkType.TESTNET){ + return "9.. / B.."; + } + } + wrapMode: Text.WrapAnywhere + addressValidation: true + pasteButton: true + onPaste: function(clipboardText) { + const parsed = walletManager.parse_uri_to_object(clipboardText); + if (!parsed.error) { + addressLine.text = parsed.address; + descriptionLine.text = parsed.tx_description; + } else { + addressLine.text = clipboardText; + } + } + inlineButton.icon: "../images/qr.png" + inlineButton.buttonColor: MoneroComponents.Style.orange + inlineButton.onClicked: { + cameraUi.state = "Capture" + cameraUi.qrcode_decoded.connect(root.updateFromQrCode) + } + inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text + } + MoneroComponents.StandardButton { + id: resolveButton + Layout.topMargin: 10 + text: qsTr("Resolve") + translationManager.emptyString + visible: TxUtils.isValidOpenAliasAddress(addressLine.text) + enabled : visible onClicked: { - if (!currentWallet.addressBook.addRow(addressLine.text.trim(), paymentIdLine.text.trim(), descriptionLine.text)) { - informationPopup.title = qsTr("Error") + translationManager.emptyString; - // TODO: check currentWallet.addressBook.errorString() instead. - if(currentWallet.addressBook.errorCode() === AddressBook.Invalid_Address) - informationPopup.text = qsTr("Invalid address") + translationManager.emptyString - else if(currentWallet.addressBook.errorCode() === AddressBook.Invalid_Payment_Id) - informationPopup.text = currentWallet.addressBook.errorString() - else - informationPopup.text = qsTr("Can't create entry") + translationManager.emptyString - - informationPopup.onCloseCallback = null - informationPopup.open(); + var result = walletManager.resolveOpenAlias(addressLine.text) + if (result) { + var parts = result.split("|") + if (parts.length === 2) { + var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype) + if (parts[0] === "true") { + if (address_ok) { + // prepend openalias to description + descriptionLine.text = descriptionLine.text ? addressLine.text + " " + descriptionLine.text : addressLine.text + addressLine.text = parts[1] + } else { + root.oa_message(qsTr("No valid address found at this OpenAlias address")) + } + } else if (parts[0] === "false") { + if (address_ok) { + addressLine.text = parts[1] + root.oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed")) + } else { + root.oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed")) + } + } else { + root.oa_message(qsTr("Internal error")) + } + } else { + root.oa_message(qsTr("Internal error")) + } } else { - clearFields(); + root.oa_message(qsTr("No address found")) } } } - } - } - Rectangle { - id: tableRect - Layout.leftMargin: (isMobile ? 17 : 40) * scaleRatio - Layout.rightMargin: (isMobile ? 17 : 40) * scaleRatio - Layout.topMargin: (root.selectAndSend ? 40 : 0) * scaleRatio - Layout.fillHeight: true - Layout.fillWidth: true - color: "transparent" - - Behavior on height { - NumberAnimation { duration: 200; easing.type: Easing.InQuad } - } + MoneroComponents.LineEditMulti { + id: descriptionLine + Layout.topMargin: 20 + labelText: qsTr("\ + Description") + translationManager.emptyString + placeholderText: qsTr("Add a name...") + translationManager.emptyString + } + RowLayout { + Layout.topMargin: 20 + MoneroComponents.StandardButton { + id: addButton + text: (root.editEntry ? qsTr("Save") : qsTr("Add")) + translationManager.emptyString + enabled: root.checkInformation(addressLine.text, appWindow.persistentSettings.nettype) + onClicked: { + console.log("Add") + if (!currentWallet.addressBook.addRow(addressLine.text.trim(),"", descriptionLine.text)) { + informationPopup.title = qsTr("Error") + translationManager.emptyString; + // TODO: check currentWallet.addressBook.errorString() instead. + if(currentWallet.addressBook.errorCode() === AddressBook.Invalid_Address) + informationPopup.text = qsTr("Invalid address") + translationManager.emptyString + else if(currentWallet.addressBook.errorCode() === AddressBook.Invalid_Payment_Id) + informationPopup.text = currentWallet.addressBook.errorString() + else + informationPopup.text = qsTr("Can't create entry") + translationManager.emptyString - MoneroComponents.Scroll { - id: flickableScroll - anchors.right: table.right - anchors.rightMargin: -14 * scaleRatio - anchors.top: table.top - anchors.bottom: table.bottom - flickable: table - } + informationPopup.onCloseCallback = null + informationPopup.open(); + } else { + if (root.editEntry) { + currentWallet.addressBook.deleteRow(addressBookListView.currentIndex); + } + root.showAddressBook(); + } + } + } + + Text { + id: cancelButton + Layout.leftMargin: 20 + font.pixelSize: 16 * scaleRatio + font.bold: false + color: MoneroComponents.Style.defaultFontColor + text: qsTr("Cancel") - MoneroComponents.AddressBookTable { - id: table - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - onContentYChanged: flickableScroll.flickableContentYChanged() - model: root.model - selectAndSend: root.selectAndSend + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: root.showAddressBook(); + } + } + + Text { + id: deleteButton + visible: root.editEntry + Layout.leftMargin: 20 + font.pixelSize: 16 * scaleRatio + font.bold: false + color: MoneroComponents.Style.defaultFontColor + text: qsTr("Delete") + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + currentWallet.addressBook.deleteRow(addressBookListView.currentIndex); + root.showAddressBook(); + } + } + } + } } } - function checkInformation(address, payment_id, nettype) { - address = address.trim() - payment_id = payment_id.trim() - - var address_ok = walletManager.addressValid(address, nettype) - var payment_id_ok = payment_id.length === 0 || walletManager.paymentIdValid(payment_id) - var ipid = walletManager.paymentIdFromAddress(address, nettype) - if (ipid.length > 0 && payment_id.length > 0) - payment_id_ok = false + function checkInformation(address, nettype) { + address = address.trim() + var address_ok = walletManager.addressValid(address, nettype) + addressLine.error = !address_ok + return address_ok + } - addressLine.error = !address_ok - paymentIdLine.error = !payment_id_ok + function clearFields() { + addressLine.text = ""; + descriptionLine.text = ""; + } - return address_ok && payment_id_ok + function showAddressBook() { + addressBookEmptyLayout.visible = addressBookListView.count == 0 + addressBookLayout.visible = addressBookListView.count >= 1; + addContactLayout.visible = false; + clearFields(); } - function onPageClosed() { - root.selectAndSend = false; + function showAddAddress() { + root.editEntry = false; + addressBookEmptyLayout.visible = false + addressBookLayout.visible = false; + addContactLayout.visible = true; } - function onPageCompleted() { - console.log("adress book"); - root.model = currentWallet.addressBookModel; + function showEditAddress(address, description) { + //TODO: real contact editing, requires API change + root.editEntry = true; + addressBookEmptyLayout.visible = false + addressBookLayout.visible = false; + addContactLayout.visible = true; + addressLine.text = address; + descriptionLine.text = description; } function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) { console.log("updateFromQrCode") addressLine.text = address - paymentIdLine.text = payment_id descriptionLine.text = recipient_name + " " + tx_description cameraUi.qrcode_decoded.disconnect(updateFromQrCode) } - function setDescription(value) { - descriptionLine.text = value; - } - - function setPaymentId(value) { - paymentIdLine.text = value; - } - - function clearFields() { - addressLine.text = ""; - paymentIdLine.text = ""; - descriptionLine.text = ""; - } - function oa_message(text) { oaPopup.title = qsTr("OpenAlias error") + translationManager.emptyString oaPopup.text = text @@ -273,10 +485,21 @@ ColumnLayout { property var onCloseCallback id: oaPopup cancelVisible: false - onAccepted: { + onAccepted: { if (onCloseCallback) { onCloseCallback() } } } + function onPageCompleted() { + console.log("adress book"); + addressBookListView.model = currentWallet.addressBookModel; + showAddressBook(); + } + + function onPageClosed() { + root.selectAndSend = false; + root.editEntry = false; + clearFields(); + } } diff --git a/qml.qrc b/qml.qrc index 6f5088cb..acefb890 100644 --- a/qml.qrc +++ b/qml.qrc @@ -37,7 +37,6 @@ components/TipItem.qml images/tip.png components/Scroll.qml - components/AddressBookTable.qml images/moneroIcon.png components/StandardDropdown.qml images/whiteDropIndicator.png @@ -53,7 +52,6 @@ images/expandRightPanel.png images/dropdownCopy.png images/dropdownCopy@2x.png - images/dropdownDel.png components/HistoryTable.qml components/HistoryTableMobile.qml images/moneroLogo2.png @@ -158,6 +156,10 @@ fonts/Roboto-Regular.ttf fonts/Roboto-Light.ttf fonts/Roboto-Bold.ttf + fonts/RobotoMono-Medium.ttf + fonts/RobotoMono-Regular.ttf + fonts/RobotoMono-Light.ttf + fonts/RobotoMono-Bold.ttf components/Style.qml components/qmldir components/InlineButton.qml @@ -275,5 +277,11 @@ images/local-node-full@2x.png wizard/WizardNavProgressDot.qml wizard/WizardOpenWallet1.qml + images/arrow-right-in-circle.png + images/arrow-right-in-circle@2x.png + images/rename.png + images/rename@2x.png + images/clipboard.png + images/clipboard@2x.png