diff --git a/src/app/profile/core.nim b/src/app/profile/core.nim
index 72cd10deec..74ea6b4c0e 100644
--- a/src/app/profile/core.nim
+++ b/src/app/profile/core.nim
@@ -1,4 +1,4 @@
-import NimQml, json, eventemitter, strutils
+import NimQml, json, eventemitter, strutils, sugar, sequtils
import json_serialization
import ../../status/libstatus/mailservers as status_mailservers
import ../../signals/types
@@ -62,6 +62,14 @@ proc init*(self: ProfileController, account: Account) =
let contacts = self.status.contacts.getContacts()
self.view.setContactList(contacts)
+ self.status.events.on("contactBlocked") do(e: Args):
+ let contacts = self.status.contacts.getContacts()
+ self.view.setContactList(contacts)
+
+ self.status.events.on("contactUnblocked") do(e: Args):
+ let contacts = self.status.contacts.getContacts()
+ self.view.setContactList(contacts)
+
self.status.events.on("contactRemoved") do(e: Args):
let contacts = self.status.contacts.getContacts()
self.view.setContactList(contacts)
diff --git a/src/app/profile/view.nim b/src/app/profile/view.nim
index 68e1ccf07e..063bbe2177 100644
--- a/src/app/profile/view.nim
+++ b/src/app/profile/view.nim
@@ -1,4 +1,4 @@
-import NimQml, sequtils
+import NimQml, sequtils, strutils, sugar
import views/[mailservers_list, contact_list, profile_info, device_list]
import ../../status/profile/[mailserver, profile, devices]
import ../../status/profile as status_profile
@@ -6,6 +6,7 @@ import ../../status/contacts as status_contacts
import ../../status/accounts as status_accounts
import ../../status/status
import ../../status/devices as status_devices
+import ../../status/ens as status_ens
import ../../status/chat/chat
import ../../status/libstatus/types
import qrcode/qrcode
@@ -15,12 +16,15 @@ QtObject:
profile*: ProfileInfoView
mailserversList*: MailServersList
contactList*: ContactList
+ addedContacts*: ContactList
+ blockedContacts*: ContactList
deviceList*: DeviceList
mnemonic: string
network: string
status*: Status
isDeviceSetup: bool
changeLanguage*: proc(locale: string)
+ contactToAdd*: Profile
proc setup(self: ProfileView) =
self.QObject.setup
@@ -28,6 +32,8 @@ QtObject:
proc delete*(self: ProfileView) =
if not self.mailserversList.isNil: self.mailserversList.delete
if not self.contactList.isNil: self.contactList.delete
+ if not self.addedContacts.isNil: self.addedContacts.delete
+ if not self.blockedContacts.isNil: self.blockedContacts.delete
if not self.deviceList.isNil: self.deviceList.delete
if not self.profile.isNil: self.profile.delete
self.QObject.delete
@@ -38,12 +44,19 @@ QtObject:
result.profile = newProfileInfoView()
result.mailserversList = newMailServersList()
result.contactList = newContactList()
+ result.addedContacts = newContactList()
+ result.blockedContacts = newContactList()
result.deviceList = newDeviceList()
result.mnemonic = ""
result.network = ""
result.status = status
result.isDeviceSetup = false
result.changeLanguage = changeLanguage
+ result.contactToAdd = Profile(
+ username: "",
+ alias: "",
+ ensName: ""
+ )
result.setup
proc addMailServerToList*(self: ProfileView, mailserver: MailServer) =
@@ -58,6 +71,10 @@ QtObject:
proc updateContactList*(self: ProfileView, contacts: seq[Profile]) =
for contact in contacts:
self.contactList.updateContact(contact)
+ if contact.systemTags.contains(":contact/added"):
+ self.addedContacts.updateContact(contact)
+ if contact.systemTags.contains(":contact/blocked"):
+ self.blockedContacts.updateContact(contact)
proc contactListChanged*(self: ProfileView) {.signal.}
@@ -66,6 +83,8 @@ QtObject:
proc setContactList*(self: ProfileView, contactList: seq[Profile]) =
self.contactList.setNewData(contactList)
+ self.addedContacts.setNewData(contactList.filter(c => c.systemTags.contains(":contact/added")))
+ self.blockedContacts.setNewData(contactList.filter(c => c.systemTags.contains(":contact/blocked")))
self.contactListChanged()
QtProperty[QVariant] contactList:
@@ -73,6 +92,20 @@ QtObject:
write = setContactList
notify = contactListChanged
+ proc getAddedContacts(self: ProfileView): QVariant {.slot.} =
+ return newQVariant(self.addedContacts)
+
+ QtProperty[QVariant] addedContacts:
+ read = getAddedContacts
+ notify = contactListChanged
+
+ proc getBlockedContacts(self: ProfileView): QVariant {.slot.} =
+ return newQVariant(self.blockedContacts)
+
+ QtProperty[QVariant] blockedContacts:
+ read = getBlockedContacts
+ notify = contactListChanged
+
proc mnemonicChanged*(self: ProfileView) {.signal.}
proc getMnemonic*(self: ProfileView): QVariant {.slot.} =
@@ -116,6 +149,27 @@ QtObject:
QtProperty[QVariant] profile:
read = getProfile
+ proc contactToAddChanged*(self: ProfileView) {.signal.}
+
+ proc getContactToAddUsername(self: ProfileView): QVariant {.slot.} =
+ var username = self.contactToAdd.alias;
+
+ if self.contactToAdd.ensVerified and self.contactToAdd.ensName != "":
+ username = self.contactToAdd.ensName
+
+ return newQVariant(username)
+
+ QtProperty[QVariant] contactToAddUsername:
+ read = getContactToAddUsername
+ notify = contactToAddChanged
+
+ proc getContactToAddPubKey(self: ProfileView): QVariant {.slot.} =
+ return newQVariant(self.contactToAdd.address)
+
+ QtProperty[QVariant] contactToAddPubKey:
+ read = getContactToAddPubKey
+ notify = contactToAddChanged
+
proc logout*(self: ProfileView) {.slot.} =
self.status.profile.logout()
@@ -173,4 +227,38 @@ QtObject:
if enable:
status_devices.enable(installationId)
else:
- status_devices.disable(installationId)
\ No newline at end of file
+ status_devices.disable(installationId)
+
+ proc lookupContact*(self: ProfileView, value: string) {.slot.} =
+ if value == "":
+ return
+
+ var id = value
+
+ if not id.startsWith("0x"):
+ id = status_ens.pubkey(id)
+
+ let contact = self.status.contacts.getContactByID(id)
+
+ if contact != nil:
+ self.contactToAdd = contact
+ else:
+ self.contactToAdd = Profile(
+ username: "",
+ alias: "",
+ ensName: "",
+ ensVerified: false
+ )
+ self.contactToAddChanged()
+
+ proc addContact*(self: ProfileView, pk: string) {.slot.} =
+ discard self.status.contacts.addContact(pk)
+
+ proc unblockContact*(self: ProfileView, id: string) {.slot.} =
+ discard self.status.contacts.unblockContact(id)
+
+ proc blockContact*(self: ProfileView, id: string) {.slot.} =
+ discard self.status.contacts.blockContact(id)
+
+ proc removeContact*(self: ProfileView, id: string) {.slot.} =
+ self.status.contacts.removeContact(id)
diff --git a/src/app/profile/views/contact_list.nim b/src/app/profile/views/contact_list.nim
index 914767c153..d6bc04ffad 100644
--- a/src/app/profile/views/contact_list.nim
+++ b/src/app/profile/views/contact_list.nim
@@ -10,6 +10,7 @@ type
Address = UserRole + 3
Identicon = UserRole + 4
IsContact = UserRole + 5
+ IsBlocked = UserRole + 6
QtObject:
type ContactList* = ref object of QAbstractListModel
@@ -46,6 +47,7 @@ QtObject:
of "identicon": result = contact.identicon
of "pubKey": result = contact.id
of "isContact": result = $contact.isContact()
+ of "isBlocked": result = $contact.isBlocked()
method data(self: ContactList, index: QModelIndex, role: int): QVariant =
if not index.isValid:
@@ -59,6 +61,7 @@ QtObject:
of ContactRoles.Identicon: result = newQVariant(contact.identicon)
of ContactRoles.PubKey: result = newQVariant(contact.id)
of ContactRoles.IsContact: result = newQVariant(contact.isContact())
+ of ContactRoles.IsBlocked: result = newQVariant(contact.isBlocked())
method roleNames(self: ContactList): Table[int, string] =
{
@@ -66,7 +69,8 @@ QtObject:
ContactRoles.Address.int:"address",
ContactRoles.Identicon.int:"identicon",
ContactRoles.PubKey.int:"pubKey",
- ContactRoles.IsContact.int:"isContact"
+ ContactRoles.IsContact.int:"isContact",
+ ContactRoles.IsBlocked.int:"isBlocked"
}.toTable
proc addContactToList*(self: ContactList, contact: Profile) =
diff --git a/src/status/contacts.nim b/src/status/contacts.nim
index 9dc6dd56da..6382f8560e 100644
--- a/src/status/contacts.nim
+++ b/src/status/contacts.nim
@@ -26,7 +26,14 @@ proc getContactByID*(self: ContactModel, id: string): Profile =
proc blockContact*(self: ContactModel, id: string): string =
var contact = self.getContactByID(id)
contact.systemTags.add(":contact/blocked")
- status_contacts.blockContact(contact)
+ discard status_contacts.blockContact(contact)
+ self.events.emit("contactBlocked", Args())
+
+proc unblockContact*(self: ContactModel, id: string): string =
+ var contact = self.getContactByID(id)
+ contact.systemTags.delete(contact.systemTags.find(":contact/blocked"))
+ discard status_contacts.saveContact(contact.id, contact.ensVerified, contact.ensName, contact.ensVerifiedAt, contact.ensVerificationRetries, contact.alias, contact.identicon, contact.systemTags)
+ self.events.emit("contactUnblocked", Args())
proc getContacts*(self: ContactModel): seq[Profile] =
result = map(status_contacts.getContacts().getElems(), proc(x: JsonNode): Profile = x.toProfileModel())
diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml
index 8b9846a981..a59901fff9 100644
--- a/ui/app/AppLayouts/Profile/ProfileLayout.qml
+++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml
@@ -32,9 +32,9 @@ SplitView {
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
anchors.right: parent.right
- anchors.rightMargin: 0
+ anchors.rightMargin: 113
anchors.left: leftTab.right
- anchors.leftMargin: 0
+ anchors.leftMargin: 113
currentIndex: leftTab.currentTab
// This list needs to match LeftTab/constants.js
diff --git a/ui/app/AppLayouts/Profile/Sections/Contacts/Contact.qml b/ui/app/AppLayouts/Profile/Sections/Contacts/Contact.qml
index d4deb7e7af..73fe5d6d9b 100644
--- a/ui/app/AppLayouts/Profile/Sections/Contacts/Contact.qml
+++ b/ui/app/AppLayouts/Profile/Sections/Contacts/Contact.qml
@@ -11,8 +11,11 @@ Rectangle {
property bool selectable: false
property var profileClick: function() {}
property bool isContact: true
+ property bool isBlocked: false
+ property string searchStr: ""
+ id: container
- visible: isContact
+ visible: isContact && (searchStr == "" || name.includes(searchStr))
height: visible ? 64 : 0
anchors.right: parent.right
anchors.left: parent.left
@@ -26,6 +29,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
source: identicon
}
+
StyledText {
id: usernameText
text: name
@@ -34,22 +38,106 @@ Rectangle {
anchors.rightMargin: Style.current.padding
font.pixelSize: 17
anchors.top: accountImage.top
+ anchors.topMargin: Style.current.smallPadding
anchors.left: accountImage.right
anchors.leftMargin: Style.current.padding
}
- StyledText {
- id: addressText
- width: 108
- font.family: Style.current.fontHexRegular.name
- text: address
- elide: Text.ElideMiddle
- anchors.bottom: accountImage.bottom
- anchors.bottomMargin: 0
- anchors.left: usernameText.left
- anchors.leftMargin: 0
- font.pixelSize: 15
- color: Style.current.darkGrey
+
+ Rectangle {
+ property int iconSize: 14
+ id: menuButton
+ height: 32
+ width: 32
+ anchors.top: usernameText.top
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ radius: 8
+
+ SVGImage {
+ source: "../../../../img/dots-icon.svg"
+ width: 18
+ height: 4
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ property bool menuOpened: false
+ cursorShape: Qt.PointingHandCursor
+ anchors.fill: parent
+ hoverEnabled: true
+ onExited: {
+ menuButton.color = Style.current.white
+ }
+ onEntered: {
+ menuButton.color = Style.current.grey
+ }
+ onClicked: {
+ menuOpened = true
+ contactContextMenu.popup()
+ }
+
+ PopupMenu {
+ id: contactContextMenu
+ hasArrow: false
+ onClosed: {
+ mouseArea.menuOpened = false
+ }
+ Action {
+ icon.source: "../../../../img/profileActive.svg"
+ icon.width: menuButton.iconSize
+ icon.height: menuButton.iconSize
+ text: qsTrId("view-profile")
+ onTriggered: profileClick(name, address, identicon)
+ enabled: true
+ }
+ Action {
+ icon.source: "../../../../img/message.svg"
+ icon.width: menuButton.iconSize
+ icon.height: menuButton.iconSize
+ text: qsTrId("send-message")
+ onTriggered: {
+ tabBar.currentIndex = 0
+ chatsModel.joinChat(address, Constants.chatTypeOneToOne)
+ }
+ enabled: !container.isBlocked
+ }
+ Action {
+ icon.source: "../../../../img/block-icon.svg"
+ icon.width: menuButton.iconSize
+ icon.height: menuButton.iconSize
+ text: qsTrId("block-user")
+ enabled: !container.isBlocked
+ onTriggered: {
+ profileModel.blockContact(address)
+ }
+ }
+ Action {
+ icon.source: "../../../../img/remove-contact.svg"
+ icon.width: menuButton.iconSize
+ icon.height: menuButton.iconSize
+ icon.color: Style.current.red
+ text: qsTrId("remove-contact")
+ enabled: container.isContact
+ onTriggered: profileModel.removeContact(address)
+ }
+ Action {
+ icon.source: "../../../../img/block-icon.svg"
+ icon.width: menuButton.iconSize
+ icon.height: menuButton.iconSize
+ icon.color: Style.current.red
+ text: qsTrId("unblock-user")
+ enabled: container.isBlocked
+ onTriggered: {
+ profileModel.unblockContact(address)
+ contactContextMenu.close()
+ }
+ }
+ }
+ }
}
+
RadioButton {
visible: selectable
anchors.top: parent.top
@@ -57,12 +145,4 @@ Rectangle {
anchors.right: parent.right
ButtonGroup.group: contactGroup
}
- MouseArea {
- enabled: !selectable
- cursorShape: Qt.PointingHandCursor
- anchors.fill: parent
- onClicked: {
- profileClick(name, address, identicon)
- }
- }
}
diff --git a/ui/app/AppLayouts/Profile/Sections/Contacts/ContactList.qml b/ui/app/AppLayouts/Profile/Sections/Contacts/ContactList.qml
index 6576475e23..d7714fc1d8 100644
--- a/ui/app/AppLayouts/Profile/Sections/Contacts/ContactList.qml
+++ b/ui/app/AppLayouts/Profile/Sections/Contacts/ContactList.qml
@@ -11,6 +11,7 @@ ListView {
id: contactList
property var contacts: ContactsData {}
property var selectable: true
+ property string searchStr: ""
property alias selectedContact: contactGroup.checkedButton
property string searchString: ""
property string lowerCaseSearchString: searchString.toLowerCase()
@@ -23,6 +24,7 @@ ListView {
address: model.address
identicon: model.identicon
isContact: model.isContact
+ isBlocked: model.isBlocked
selectable: contactList.selectable
profileClick: profilePopup.openPopup.bind(profilePopup)
visible: searchString === "" ||
@@ -37,6 +39,7 @@ ListView {
ButtonGroup {
id: contactGroup
}
+
}
/*##^##
Designer {
diff --git a/ui/app/AppLayouts/Profile/Sections/ContactsContainer.qml b/ui/app/AppLayouts/Profile/Sections/ContactsContainer.qml
index 5242842093..1f1030c131 100644
--- a/ui/app/AppLayouts/Profile/Sections/ContactsContainer.qml
+++ b/ui/app/AppLayouts/Profile/Sections/ContactsContainer.qml
@@ -9,93 +9,193 @@ import "./Contacts"
Item {
id: contactsContainer
Layout.fillHeight: true
- Layout.fillWidth: true
+ property alias searchStr: searchBox.text
- Item {
+ SearchBox {
+ id: searchBox
anchors.top: parent.top
anchors.topMargin: 32
- anchors.right: parent.right
- anchors.rightMargin: contentMargin
- anchors.left: parent.left
- anchors.leftMargin: contentMargin
- anchors.bottom: parent.bottom
+ fontPixelSize: 15
+ }
- SearchBox {
- id: searchBox
+ Item {
+ id: addNewContact
+ anchors.top: searchBox.bottom
+ anchors.topMargin: Style.current.bigPadding
+ width: addButton.width + usernameText.width + Style.current.padding
+ height: addButton.height
+
+ AddButton {
+ id: addButton
+ clickable: false
+ anchors.verticalCenter: parent.verticalCenter
+ width: 40
+ height: 40
}
- Item {
- id: addNewContact
- anchors.top: searchBox.bottom
- anchors.topMargin: Style.current.bigPadding
- width: parent.width
- height: addButton.height
+ StyledText {
+ id: usernameText
+ text: qsTr("Add new contact")
+ color: Style.current.blue
+ anchors.left: addButton.right
+ anchors.leftMargin: Style.current.padding
+ anchors.verticalCenter: addButton.verticalCenter
+ font.pixelSize: 15
+ }
- AddButton {
- id: addButton
- clickable: false
- anchors.verticalCenter: parent.verticalCenter
- }
- StyledText {
- id: usernameText
- text: qsTr("Add new contact")
- color: Style.current.blue
- anchors.left: addButton.right
- anchors.leftMargin: Style.current.padding
- anchors.verticalCenter: addButton.verticalCenter
- font.pixelSize: 15
- }
-
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- onClicked: {
- // TODO implement adding a contact
- console.log('Add a contact')
- }
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ addContactModal.open()
}
}
+ }
+
+ Item {
+ id: blockedContactsButton
+ anchors.top: addNewContact.bottom
+ anchors.topMargin: Style.current.bigPadding
+ width: blockButton.width + blockButtonLabel.width + Style.current.padding
+ height: addButton.height
+
+ IconButton {
+ id: blockButton
+ clickable: false
+ anchors.verticalCenter: parent.verticalCenter
+ width: 40
+ height: 40
+ iconName: "block-icon"
+ color: Style.current.lightBlue
+ }
+
+ StyledText {
+ id: blockButtonLabel
+ text: qsTr("Blocked contacts")
+ color: Style.current.blue
+ anchors.left: blockButton.right
+ anchors.leftMargin: Style.current.padding
+ anchors.verticalCenter: blockButton.verticalCenter
+ font.pixelSize: 15
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ blockedContactsModal.open()
+ }
+ }
+ }
+
+ ModalPopup {
+ id: blockedContactsModal
+ title: qsTr("Blocked contacts")
ContactList {
- id: contactListView
- anchors.top: addNewContact.bottom
- anchors.topMargin: Style.current.bigPadding
+ anchors.top: parent.top
anchors.bottom: parent.bottom
- contacts: profileModel.contactList
+ contacts: profileModel.blockedContacts
selectable: false
- searchString: searchBox.text
+ }
+ }
+
+ ModalPopup {
+ id: addContactModal
+ title: qsTr("Add contact")
+
+ Input {
+ id: addContactSearchInput
+ placeholderText: qsTrId("Enter ENS username or chat key")
+ customHeight: 44
+ fontPixelSize: 15
+ onEditingFinished: {
+ profileModel.lookupContact(inputValue)
+ }
}
Item {
- id: element
- visible: profileModel.contactList.rowCount() === 0
- anchors.fill: parent
+ id: contactToAddInfo
+ anchors.top: addContactSearchInput.bottom
+ anchors.topMargin: Style.current.padding
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: contactUsername.height
+ width: contactUsername.width + contactPubKey.width
+ visible: profileModel.contactToAddPubKey !== ""
- StyledText {
- id: noFriendsText
- text: qsTr("You don’t have any contacts yet")
- anchors.verticalCenterOffset: -Style.current.bigPadding
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.verticalCenter: parent.verticalCenter
- font.pixelSize: 15
- color: Style.current.darkGrey
- }
+ StyledText {
+ id: contactUsername
+ text: profileModel.contactToAddUsername + " • "
+ anchors.top: addContactSearchInput.bottom
+ anchors.topMargin: Style.current.padding
+ font.pixelSize: 12
+ color: Style.current.darkGrey
+ }
- StyledButton {
- anchors.horizontalCenter: noFriendsText.horizontalCenter
- anchors.top: noFriendsText.bottom
- anchors.topMargin: Style.current.bigPadding
- label: qsTr("Invite firends")
- onClicked: function () {
- inviteFriendsPopup.open()
- }
- }
+ StyledText {
+ id: contactPubKey
+ text: profileModel.contactToAddPubKey
+ anchors.left: contactUsername.right
+ width: 100
+ font.pixelSize: 12
+ elide: Text.ElideMiddle
+ color: Style.current.darkGrey
+ }
- InviteFriendsPopup {
- id: inviteFriendsPopup
+ }
+ footer: StyledButton {
+ anchors.right: parent.right
+ anchors.leftMargin: Style.current.padding
+ //% "Send Message"
+ label: qsTr("Add contact")
+ disabled: !contactToAddInfo.visible
+ anchors.bottom: parent.bottom
+ onClicked: {
+ profileModel.addContact(profileModel.contactToAddPubKey);
+ addContactModal.close()
}
}
}
+
+ ContactList {
+ id: contactListView
+ anchors.top: blockedContactsButton.bottom
+ anchors.topMargin: Style.current.bigPadding
+ anchors.bottom: parent.bottom
+ contacts: profileModel.addedContacts
+ selectable: false
+ searchString: searchBox.text
+ }
+
+ Item {
+ id: element
+ visible: profileModel.contactList.rowCount() === 0
+ anchors.fill: parent
+
+ StyledText {
+ id: noFriendsText
+ text: qsTr("You don’t have any contacts yet")
+ anchors.verticalCenterOffset: -Style.current.bigPadding
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: 15
+ color: Style.current.darkGrey
+ }
+
+ StyledButton {
+ anchors.horizontalCenter: noFriendsText.horizontalCenter
+ anchors.top: noFriendsText.bottom
+ anchors.topMargin: Style.current.bigPadding
+ label: qsTr("Invite firends")
+ onClicked: function () {
+ inviteFriendsPopup.open()
+ }
+ }
+
+ InviteFriendsPopup {
+ id: inviteFriendsPopup
+ }
+ }
}
/*##^##
diff --git a/ui/app/img/block-icon.svg b/ui/app/img/block-icon.svg
new file mode 100644
index 0000000000..c1ce6b4901
--- /dev/null
+++ b/ui/app/img/block-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/app/img/dots-icon.svg b/ui/app/img/dots-icon.svg
new file mode 100644
index 0000000000..b3f89c55b9
--- /dev/null
+++ b/ui/app/img/dots-icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/app/img/remove-contact.svg b/ui/app/img/remove-contact.svg
new file mode 100644
index 0000000000..4aaaca41b4
--- /dev/null
+++ b/ui/app/img/remove-contact.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/nim-status-client.pro b/ui/nim-status-client.pro
index 0c00b30530..39c55ad804 100644
--- a/ui/nim-status-client.pro
+++ b/ui/nim-status-client.pro
@@ -308,6 +308,7 @@ DISTFILES += \
onboarding/img/wallet@3x.jpg \
onboarding/qmldir \
shared/AddButton.qml \
+ shared/IconButton.qml \
shared/Input.qml \
shared/ModalPopup.qml \
shared/NotificationWindow.qml \
diff --git a/ui/shared/AddButton.qml b/ui/shared/AddButton.qml
index f0c2849a93..c86ea186dc 100644
--- a/ui/shared/AddButton.qml
+++ b/ui/shared/AddButton.qml
@@ -3,80 +3,9 @@ import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import Qt.labs.platform 1.1
import "../imports"
+import "./"
-Rectangle {
- signal clicked
- property int iconWidth: 14
- property int iconHeight: 14
- property alias icon: imgIcon
- property bool clickable: true
-
- id: btnAddContainer
- width: 36
- height: 36
- color: Style.current.blue
- radius: width / 2
-
-
- Image {
- id: imgIcon
- fillMode: Image.PreserveAspectFit
- source: "../app/img/plusSign.svg"
- width: iconWidth
- height: iconHeight
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.verticalCenter: parent.verticalCenter
-
- state: "default"
- rotation: 0
- states: [
- State {
- name: "default"
- PropertyChanges {
- target: imgIcon
- rotation: 0
- }
- },
- State {
- name: "rotated"
- PropertyChanges {
- target: imgIcon
- rotation: 45
- }
- }
- ]
-
- transitions: [
- Transition {
- from: "default"
- to: "rotated"
- RotationAnimation {
- duration: 150
- direction: RotationAnimation.Clockwise
- easing.type: Easing.InCubic
- }
- },
- Transition {
- from: "rotated"
- to: "default"
- RotationAnimation {
- duration: 150
- direction: RotationAnimation.Counterclockwise
- easing.type: Easing.OutCubic
- }
- }
- ]
- }
-
- MouseArea {
- id: mouseArea
- visible: btnAddContainer.clickable
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton | Qt.RightButton
- cursorShape: Qt.PointingHandCursor
- onClicked: {
- imgIcon.state = "rotated"
- btnAddContainer.clicked()
- }
- }
+IconButton {
+ id: iconButton
+ iconName: "plusSign"
}
diff --git a/ui/shared/IconButton.qml b/ui/shared/IconButton.qml
new file mode 100644
index 0000000000..e1e0293247
--- /dev/null
+++ b/ui/shared/IconButton.qml
@@ -0,0 +1,83 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.3
+import QtQuick.Layouts 1.3
+import Qt.labs.platform 1.1
+import "../imports"
+
+Rectangle {
+ signal clicked
+ property int iconWidth: 14
+ property int iconHeight: 14
+ property alias icon: imgIcon
+ property bool clickable: true
+ property string iconName: "plusSign"
+
+ id: btnAddContainer
+ width: 36
+ height: 36
+ color: Style.current.blue
+ radius: width / 2
+
+ Image {
+ id: imgIcon
+ fillMode: Image.PreserveAspectFit
+ source: "../app/img/" + parent.iconName + ".svg"
+ width: iconWidth
+ height: iconHeight
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+
+ state: "default"
+ rotation: 0
+ states: [
+ State {
+ name: "default"
+ PropertyChanges {
+ target: imgIcon
+ rotation: 0
+ }
+ },
+ State {
+ name: "rotated"
+ PropertyChanges {
+ target: imgIcon
+ rotation: 45
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "default"
+ to: "rotated"
+ RotationAnimation {
+ duration: 150
+ direction: RotationAnimation.Clockwise
+ easing.type: Easing.InCubic
+ }
+ },
+ Transition {
+ from: "rotated"
+ to: "default"
+ RotationAnimation {
+ duration: 150
+ direction: RotationAnimation.Counterclockwise
+ easing.type: Easing.OutCubic
+ }
+ }
+ ]
+ }
+
+ MouseArea {
+ id: mouseArea
+ visible: btnAddContainer.clickable
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ imgIcon.state = "rotated"
+ btnAddContainer.clicked()
+ }
+ }
+}
+
diff --git a/ui/shared/Input.qml b/ui/shared/Input.qml
index 64cfc799bf..ca0e7de0ca 100644
--- a/ui/shared/Input.qml
+++ b/ui/shared/Input.qml
@@ -21,6 +21,7 @@ Item {
readonly property int labelMargin: 7
property int customHeight: 44
property int fontPixelSize: 15
+ signal editingFinished(string inputValue)
id: inputBox
height: inputRectangle.height + (hasLabel ? inputLabel.height + labelMargin : 0) + (!!validationError ? validationErrorText.height : 0)
@@ -70,6 +71,7 @@ Item {
background: Rectangle {
color: Style.current.transparent
}
+ onEditingFinished: inputBox.editingFinished(inputBox.text)
}
SVGImage {
diff --git a/ui/shared/PopupMenu.qml b/ui/shared/PopupMenu.qml
index f2e3faa3e9..197c4f6c1c 100644
--- a/ui/shared/PopupMenu.qml
+++ b/ui/shared/PopupMenu.qml
@@ -7,6 +7,7 @@ import "../shared"
Menu {
property alias arrowX: bgPopupMenuTopArrow.x
property int paddingSize: 8
+ property bool hasArrow: true
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnReleaseOutside | Popup.CloseOnEscape
id: popupMenu
topPadding: bgPopupMenuTopArrow.height + paddingSize
@@ -18,6 +19,8 @@ Menu {
implicitHeight: 34
font.pixelSize: 13
icon.color: popupMenuItem.action.icon.color != "#00000000" ? popupMenuItem.action.icon.color : Style.current.blue
+ visible: popupMenuItem.action.enabled
+ height: popupMenuItem.action.enabled ? popupMenuItem.implicitHeight : 0
contentItem: Item {
id: menuItemContent
@@ -66,6 +69,7 @@ Menu {
color: "transparent"
Rectangle {
id: bgPopupMenuTopArrow
+ visible: popupMenu.hasArrow
color: Style.current.modalBackground
height: 14
width: 14