diff --git a/ui/StatusQ/sandbox/demoapp/ChatChannelView.qml b/ui/StatusQ/sandbox/demoapp/ChatChannelView.qml
new file mode 100644
index 0000000000..25f41203cd
--- /dev/null
+++ b/ui/StatusQ/sandbox/demoapp/ChatChannelView.qml
@@ -0,0 +1,103 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import QtQml.Models 2.2
+
+import StatusQ.Controls 0.1
+import StatusQ.Popups 0.1
+import StatusQ.Components 0.1
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+
+ListView {
+ id: messageList
+ anchors.fill: parent
+ anchors.margins: 15
+ clip: true
+ delegate: StatusMessage {
+ id: delegate
+ width: parent.width
+
+ audioMessageInfoText: "Audio Message"
+ cancelButtonText: "Cancel"
+ saveButtonText: "Save"
+ loadingImageText: "Loading image..."
+ errorLoadingImageText: "Error loading the image"
+ resendText: "Resend"
+ pinnedMsgInfoText: "Pinned by"
+
+ messageDetails: StatusMessageDetails {
+ contentType: model.contentType
+ messageContent: model.messageContent
+ amISender: model.amIsender
+ displayName: model.userName
+ secondaryName: model.localName !== "" && model.ensName.startsWith("@") ? model.ensName: ""
+ chatID: model.chatKey
+ profileImage: StatusImageSettings {
+ width: 40
+ height: 40
+ source: model.profileImage
+ isIdenticon: model.isIdenticon
+ }
+ messageText: model.message
+ hasMention: model.hasMention
+ contactType: model.contactType
+ isPinned: model.isPinned
+ pinnedBy: model.pinnedBy
+ hasExpired: model.hasExpired
+ }
+ timestamp.text: "10:00 am"
+ timestamp.tooltip.text: "10:01 am"
+ // reply related data
+ isAReply: model.isReply
+ replyDetails: StatusMessageDetails {
+ amISender: model.isReply ? model.replyAmISender : ""
+ displayName: model.isReply ? model.replySenderName: ""
+ profileImage: StatusImageSettings {
+ width: 20
+ height: 20
+ source: model.isReply ? model.replyProfileImage: ""
+ isIdenticon: model.isReply ? model.replyIsIdenticon: ""
+ }
+ messageText: model.isReply ? model.replyMessageText: ""
+ contentType: model.replyContentType
+ messageContent: model.replyMessageContent
+ }
+ quickActions: [
+ StatusFlatRoundButton {
+ id: emojiBtn
+ width: 32
+ height: 32
+ icon.name: "reaction-b"
+ type: StatusFlatRoundButton.Type.Tertiary
+ tooltip.text: "Add reaction"
+ },
+ StatusFlatRoundButton {
+ id: replyBtn
+ width: 32
+ height: 32
+ icon.name: "reply"
+ type: StatusFlatRoundButton.Type.Tertiary
+ tooltip.text: "Reply"
+ },
+ StatusFlatRoundButton {
+ width: 32
+ height: 32
+ icon.name: "tiny/edit"
+ type: StatusFlatRoundButton.Type.Tertiary
+ tooltip.text: "Edit"
+ onClicked: {
+ delegate.editMode = !delegate.editMode
+ }
+ },
+ StatusFlatRoundButton {
+ id: otherBtn
+ width: 32
+ height: 32
+ icon.name: "more"
+ type: StatusFlatRoundButton.Type.Tertiary
+ tooltip.text: "More"
+ }
+ ]
+ }
+}
diff --git a/ui/StatusQ/sandbox/demoapp/CreateChatView.qml b/ui/StatusQ/sandbox/demoapp/CreateChatView.qml
new file mode 100644
index 0000000000..b8de5912e5
--- /dev/null
+++ b/ui/StatusQ/sandbox/demoapp/CreateChatView.qml
@@ -0,0 +1,232 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import QtQml.Models 2.2
+import QtGraphicalEffects 1.0
+
+import StatusQ.Controls 0.1
+import StatusQ.Components 0.1
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+
+Page {
+ id: root
+ anchors.fill: parent
+ anchors.margins: 16
+ property ListModel contactsModel: null
+ background: null
+
+ header: RowLayout {
+ id: headerRow
+ width: parent.width
+ height: tagSelector.height
+ anchors.right: parent.right
+ anchors.rightMargin: 8
+
+ StatusTagSelector {
+ id: tagSelector
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
+ Layout.leftMargin: 17
+ implicitHeight: 44
+ toLabelText: qsTr("To: ")
+ warningText: qsTr("5 USER LIMIT REACHED")
+ //simulate model filtering, TODO this
+ //makes more sense to be provided by the backend
+ //figure how real implementation should look like
+ property ListModel sortedList: ListModel { }
+ onTextChanged: {
+ sortedList.clear();
+ if (text !== "") {
+ for (var i = 0; i < contactsModel.count; i++ ) {
+ var entry = contactsModel.get(i);
+ if (entry.name.toLowerCase().includes(text.toLowerCase())) {
+ sortedList.insert(sortedList.count, {"publicId": entry.publicId, "name": entry.name,
+ "icon": entry.icon, "isIdenticon": entry.isIdenticon,
+ "onlineStatus": entry.onlineStatus});
+ userListView.model = sortedList;
+ }
+ }
+ } else {
+ userListView.model = contactsModel;
+ }
+ }
+ }
+
+ StatusButton {
+ implicitHeight: 44
+ enabled: (tagSelector.namesModel.count > 0)
+ text: "Confirm"
+ }
+ }
+
+ contentItem: Item {
+ anchors.fill: parent
+ anchors.topMargin: headerRow.height + 16
+
+ Item {
+ anchors.fill: parent
+ visible: (contactsModel.count > 0)
+
+ StatusBaseText {
+ id: contactsLabel
+ font.pixelSize: 15
+ color: Theme.palette.baseColor1
+ text: "Contacts"
+ }
+ Control {
+ width: 360
+ anchors {
+ top: contactsLabel.bottom
+ topMargin: 8//Style.current.padding
+ bottom: parent.bottom
+ bottomMargin: 20//Style.current.bigPadding
+ }
+ background: Rectangle {
+ id: statusPopupMenuBackgroundContent
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: (userListView.height + 8)
+ visible: (tagSelector.sortedList.count > 0)
+ color: Theme.palette.statusPopupMenu.backgroundColor
+ radius: 8
+ layer.enabled: true
+ layer.effect: DropShadow {
+ width: statusPopupMenuBackgroundContent.width
+ height: statusPopupMenuBackgroundContent.height
+ x: statusPopupMenuBackgroundContent.x
+ visible: statusPopupMenuBackgroundContent.visible
+ source: statusPopupMenuBackgroundContent
+ horizontalOffset: 0
+ verticalOffset: 4
+ radius: 12
+ samples: 25
+ spread: 0.2
+ color: Theme.palette.dropShadow
+ }
+ }
+ contentItem: ListView {
+ id: userListView
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: (count * 64) > parent.height ? parent.height : (count * 64)
+ clip: true
+ model: contactsModel
+ ScrollBar.vertical: ScrollBar {
+ policy: ScrollBar.AsNeeded
+ }
+ boundsBehavior: Flickable.StopAtBounds
+ delegate: Item {
+ id: wrapper
+ anchors.right: parent.right
+ anchors.left: parent.left
+ height: 64
+ property bool hovered: false
+ Rectangle {
+ id: rectangle
+ anchors.fill: parent
+ anchors.topMargin: 8
+ anchors.rightMargin: 8
+ anchors.leftMargin: 8
+ radius: 8
+ visible: (tagSelector.sortedList.count > 0)
+ color: (wrapper.hovered) ? Theme.palette.baseColor2 : "transparent"
+ }
+
+ StatusSmartIdenticon {
+ id: contactImage
+ anchors.left: parent.left
+ anchors.leftMargin: 16//Style.current.padding
+ anchors.verticalCenter: parent.verticalCenter
+ name: model.name
+ icon: StatusIconSettings {
+ width: 28
+ height: 28
+ letterSize: 15
+ }
+ image: StatusImageSettings {
+ width: 28
+ height: 28
+ source: model.icon
+ isIdenticon: model.isIdenticon
+ }
+ }
+
+ StatusBaseText {
+ id: contactInfo
+ text: model.name
+ anchors.right: parent.right
+ anchors.rightMargin: 8
+ anchors.left: contactImage.right
+ anchors.leftMargin: 16
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ color: Theme.palette.directColor1
+ font.weight: Font.Medium
+ font.pixelSize: 15
+ }
+
+ StatusBadge {
+ id: statusBadge
+ width: 15
+ height: 15
+ anchors.left: contactImage.right
+ anchors.leftMargin: -8
+ anchors.bottom: contactImage.bottom
+ border.width: 3
+ border.color: Theme.palette.statusAppNavBar.backgroundColor
+ color: {
+ if (model.onlineStatus === 1)
+ return Theme.palette.successColor1;
+ else if (model.onlineStatus === 2)
+ return Theme.palette.pinColor1;
+ else if (model.onlineStatus === 3)
+ return Theme.palette.dangerColor1;
+
+ return "transparent"
+ }
+ }
+
+ MouseArea {
+ cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: {
+ wrapper.hovered = true;
+ }
+ onExited: {
+ wrapper.hovered = false;
+ }
+ onClicked: {
+ tagSelector.insertTag(model.name, model.publicId);
+ }
+ }
+ }
+ }
+ }
+ Component.onCompleted: {
+ if (visible) {
+ tagSelector.textEdit.forceActiveFocus();
+ }
+ }
+ }
+
+ StatusBaseText {
+ visible: (contactsModel.count === 0)
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 15
+ color: Theme.palette.baseColor1
+ text: qsTr("You can only send direct messages to your Contacts. \n\n
+Send a contact request to the person you would like to chat with, you will be\n able to
+chat with them once they have accepted your contact request.")
+ Component.onCompleted: {
+ if (visible) {
+ tagSelector.enabled = false;
+ }
+ }
+ }
+ }
+}
diff --git a/ui/StatusQ/sandbox/demoapp/StatusAppChatView.qml b/ui/StatusQ/sandbox/demoapp/StatusAppChatView.qml
index 19cf4a06c6..a59a2c46d7 100644
--- a/ui/StatusQ/sandbox/demoapp/StatusAppChatView.qml
+++ b/ui/StatusQ/sandbox/demoapp/StatusAppChatView.qml
@@ -1,4 +1,5 @@
import QtQuick 2.12
+import QtQuick.Layouts 1.12
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
@@ -11,6 +12,7 @@ import "data" 1.0
StatusAppThreePanelLayout {
id: root
+ property bool createChat: false
leftPanel: Item {
anchors.fill: parent
@@ -23,113 +25,35 @@ StatusAppThreePanelLayout {
text: "Chat"
}
- Item {
+ RowLayout {
id: searchInputWrapper
- anchors.top: headline.bottom
- anchors.topMargin: 16
width: parent.width
height: searchInput.height
+ anchors.top: headline.bottom
+ anchors.topMargin: 16
+ anchors.right: parent.right
+ anchors.rightMargin: 8
StatusBaseInput {
id: searchInput
-
- anchors.verticalCenter: parent.verticalCenter
- anchors.left: parent.left
- anchors.right: actionButton.left
- anchors.leftMargin: 16
- anchors.rightMargin: 16
-
- height: 36
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
+ Layout.leftMargin: 17
+ implicitHeight: 36
topPadding: 8
bottomPadding: 0
placeholderText: "Search"
icon.name: "search"
}
- StatusRoundButton {
- id: actionButton
- anchors.verticalCenter: parent.verticalCenter
- anchors.right: parent.right
- anchors.rightMargin: 8
- width: 32
- height: 32
+ StatusIconTabButton {
+ icon.name: "public-chat"
+ }
- type: StatusRoundButton.Type.Secondary
- icon.name: "add"
- state: "default"
-
- onClicked: chatContextMenu.popup(actionButton.width-chatContextMenu.width, actionButton.height + 4)
- states: [
- State {
- name: "default"
- PropertyChanges {
- target: actionButton
- icon.rotation: 0
- highlighted: false
- }
- },
- State {
- name: "pressed"
- PropertyChanges {
- target: actionButton
- icon.rotation: 45
- highlighted: true
- }
- }
- ]
-
- transitions: [
- Transition {
- from: "default"
- to: "pressed"
-
- RotationAnimation {
- duration: 150
- direction: RotationAnimation.Clockwise
- easing.type: Easing.InCubic
- }
- },
- Transition {
- from: "pressed"
- to: "default"
- RotationAnimation {
- duration: 150
- direction: RotationAnimation.Counterclockwise
- easing.type: Easing.OutCubic
- }
- }
- ]
-
- StatusPopupMenu {
- id: chatContextMenu
-
- onOpened: {
- actionButton.state = "pressed"
- }
-
- onClosed: {
- actionButton.state = "default"
- }
-
- StatusMenuItem {
- text: "Start new chat"
- icon.name: "private-chat"
- }
-
- StatusMenuItem {
- text: "Start group chat"
- icon.name: "group-chat"
- }
-
- StatusMenuItem {
- text: "Join public chat"
- icon.name: "public-chat"
- }
-
- StatusMenuItem {
- text: "Communities"
- icon.name: "communities"
- }
+ StatusIconTabButton {
+ icon.name: "edit"
+ onClicked: {
+ root.createChat = !root.createChat;
}
}
}
@@ -201,6 +125,25 @@ StatusAppThreePanelLayout {
}
}
+ centerPanel: Loader {
+ anchors.fill: parent
+ sourceComponent: root.createChat ? createChatView : chatChannelView
+ }
+
+ Component {
+ id: createChatView
+ CreateChatView {
+ contactsModel: Models.dummyContactsModel
+ }
+ }
+
+ Component {
+ id: chatChannelView
+ ChatChannelView {
+ model: Models.chatMessagesModel
+ }
+ }
+
rightPanel: Item {
anchors.fill: parent
@@ -248,98 +191,4 @@ StatusAppThreePanelLayout {
}
}
}
-
- centerPanel: ListView {
- id: messageList
- anchors.fill: parent
- anchors.margins: 15
- clip: true
- model: Models.chatMessagesModel
- delegate: StatusMessage {
- id: delegate
- width: parent.width
-
- audioMessageInfoText: "Audio Message"
- cancelButtonText: "Cancel"
- saveButtonText: "Save"
- loadingImageText: "Loading image..."
- errorLoadingImageText: "Error loading the image"
- resendText: "Resend"
- pinnedMsgInfoText: "Pinned by"
-
- messageDetails: StatusMessageDetails {
- contentType: model.contentType
- messageContent: model.messageContent
- amISender: model.amIsender
- displayName: model.userName
- secondaryName: model.localName !== "" && model.ensName.startsWith("@") ? model.ensName: ""
- chatID: model.chatKey
- profileImage: StatusImageSettings {
- width: 40
- height: 40
- source: model.profileImage
- isIdenticon: model.isIdenticon
- }
- messageText: model.message
- hasMention: model.hasMention
- contactType: model.contactType
- isPinned: model.isPinned
- pinnedBy: model.pinnedBy
- hasExpired: model.hasExpired
- }
- timestamp.text: "10:00 am"
- timestamp.tooltip.text: "10:01 am"
- // reply related data
- isAReply: model.isReply
- replyDetails: StatusMessageDetails {
- amISender: model.isReply ? model.replyAmISender : ""
- displayName: model.isReply ? model.replySenderName: ""
- profileImage: StatusImageSettings {
- width: 20
- height: 20
- source: model.isReply ? model.replyProfileImage: ""
- isIdenticon: model.isReply ? model.replyIsIdenticon: ""
- }
- messageText: model.isReply ? model.replyMessageText: ""
- contentType: model.replyContentType
- messageContent: model.replyMessageContent
- }
- quickActions: [
- StatusFlatRoundButton {
- id: emojiBtn
- width: 32
- height: 32
- icon.name: "reaction-b"
- type: StatusFlatRoundButton.Type.Tertiary
- tooltip.text: "Add reaction"
- },
- StatusFlatRoundButton {
- id: replyBtn
- width: 32
- height: 32
- icon.name: "reply"
- type: StatusFlatRoundButton.Type.Tertiary
- tooltip.text: "Reply"
- },
- StatusFlatRoundButton {
- width: 32
- height: 32
- icon.name: "tiny/edit"
- type: StatusFlatRoundButton.Type.Tertiary
- tooltip.text: "Edit"
- onClicked: {
- delegate.editMode = !delegate.editMode
- }
- },
- StatusFlatRoundButton {
- id: otherBtn
- width: 32
- height: 32
- icon.name: "more"
- type: StatusFlatRoundButton.Type.Tertiary
- tooltip.text: "More"
- }
- ]
- }
- }
}
diff --git a/ui/StatusQ/sandbox/demoapp/data/Models.qml b/ui/StatusQ/sandbox/demoapp/data/Models.qml
index 91695fd602..2ee36abae5 100644
--- a/ui/StatusQ/sandbox/demoapp/data/Models.qml
+++ b/ui/StatusQ/sandbox/demoapp/data/Models.qml
@@ -4,6 +4,58 @@ import StatusQ.Components 0.1
QtObject {
+ property ListModel dummyContactsModel: ListModel {
+ ListElement {
+ publicId: "0x0"
+ name: "Maria"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 3
+ }
+ ListElement {
+ publicId: "0x1"
+ name: "James"
+ icon: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
+ isIdenticon: false
+ onlineStatus: 1
+ }
+ ListElement {
+ publicId: "0x2"
+ name: "Paul"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 2
+ }
+ ListElement {
+ publicId: "0x3"
+ name: "Tracy"
+ icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
+ isIdenticon: true
+ onlineStatus: 3
+ }
+ ListElement {
+ publicId: "0x4"
+ name: "Nick"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 3
+ }
+ ListElement {
+ publicId: "0x5"
+ name: "Steven"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 2
+ }
+ ListElement {
+ publicId: "0x6"
+ name: "Helen"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 3
+ }
+ }
+
property var demoChatListItems: ListModel {
id: demoChatListItems
ListElement {
diff --git a/ui/StatusQ/sandbox/main.qml b/ui/StatusQ/sandbox/main.qml
index f9c5ce7b08..15acad15ca 100644
--- a/ui/StatusQ/sandbox/main.qml
+++ b/ui/StatusQ/sandbox/main.qml
@@ -255,6 +255,11 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page("StatusExpandableSettingsItem");
}
+ StatusNavigationListItem {
+ title: "StatusTagSelector"
+ selected: viewLoader.source.toString().includes(title)
+ onClicked: mainPageView.page(title);
+ }
StatusListSectionHeadline { text: "StatusQ.Popup" }
StatusNavigationListItem {
title: "StatusPopupMenu"
diff --git a/ui/StatusQ/sandbox/pages/StatusTagSelectorPage.qml b/ui/StatusQ/sandbox/pages/StatusTagSelectorPage.qml
new file mode 100644
index 0000000000..3de2c69e1d
--- /dev/null
+++ b/ui/StatusQ/sandbox/pages/StatusTagSelectorPage.qml
@@ -0,0 +1,56 @@
+import QtQuick 2.14
+
+import StatusQ.Components 0.1
+
+Item {
+ id: root
+ anchors.fill: parent
+
+ property ListModel asortedContacts: ListModel {
+ ListElement {
+ publicId: "0x0"
+ name: "Maria"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 3
+ }
+ ListElement {
+ publicId: "0x1"
+ name: "James"
+ icon: "https://pbs.twimg.com/profile_images/1369221718338895873/T_5fny6o_400x400.jpg"
+ isIdenticon: false
+ onlineStatus: 1
+ }
+ ListElement {
+ publicId: "0x2"
+ name: "Paul"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 2
+ }
+ ListElement {
+ publicId: "0x3"
+ name: "Tracy"
+ icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
+ isIdenticon: true
+ onlineStatus: 3
+ }
+ ListElement {
+ publicId: "0x4"
+ name: "Nick"
+ icon: ""
+ isIdenticon: false
+ onlineStatus: 3
+ }
+ }
+
+ StatusTagSelector {
+ id: tagSelector
+ width: 650
+ height: 44
+ anchors.centerIn: parent
+ namesModel: root.asortedContacts
+ toLabelText: qsTr("To: ")
+ warningText: qsTr("5 USER LIMIT REACHED")
+ }
+}
diff --git a/ui/StatusQ/src/StatusQ/Components/StatusTagSelector.qml b/ui/StatusQ/src/StatusQ/Components/StatusTagSelector.qml
new file mode 100644
index 0000000000..036349554f
--- /dev/null
+++ b/ui/StatusQ/src/StatusQ/Components/StatusTagSelector.qml
@@ -0,0 +1,126 @@
+import QtQuick 2.14
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.14
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+
+Item {
+ id: root
+
+ implicitWidth: 448
+ implicitHeight: 44
+
+ property alias textEdit: edit
+ property alias text: edit.text
+ property string warningText: ""
+ property string toLabelText: ""
+ property int nameCountLimit: 5
+ property ListModel namesModel: ListModel { }
+
+ function find(model, criteria) {
+ for (var i = 0; i < model.count; ++i) if (criteria(model.get(i))) return model.get(i);
+ return null;
+ }
+
+ function insertTag(name, id) {
+ if (!find(namesModel, function(item) { return item.publicId === id }) && namesModel.count < root.nameCountLimit) {
+ namesModel.insert(namesModel.count, {"name": name, "publicId": id});
+ edit.clear();
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ radius: 8
+ color: Theme.palette.baseColor2
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 16
+ anchors.rightMargin: 16
+ spacing: 8
+ StatusBaseText {
+ Layout.preferredWidth: 22
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
+ color: Theme.palette.baseColor1
+ text: root.toLabelText
+ }
+
+ ListView {
+ id: namesList
+ Layout.preferredWidth: (count >= 5) ? (parent.width - warningTextLabel.width - 30) : childrenRect.width
+ implicitHeight: 30
+ visible: (count > 0)
+ Layout.alignment: Qt.AlignVCenter
+ model: namesModel
+ orientation: ListView.Horizontal
+ spacing: 8
+ clip: true
+ onWidthChanged: {
+ positionViewAtEnd();
+ }
+
+ delegate: Rectangle {
+ id: nameDelegate
+ width: (nameText.contentWidth + 34)
+ height: 30
+ color: mouseArea.containsMouse ? Theme.palette.miscColor1 : Theme.palette.primaryColor1
+ radius: 8
+ StatusBaseText {
+ id: nameText
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ anchors.verticalCenter: parent.verticalCenter
+ color: Theme.palette.indirectColor1
+ text: name
+ }
+ StatusIcon {
+ anchors.left: nameText.right
+ anchors.verticalCenter: parent.verticalCenter
+ color: Theme.palette.indirectColor1
+ icon: "close"
+ }
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ namesModel.remove(index, 1);
+ }
+ }
+ }
+ }
+
+ TextEdit {
+ id: edit
+ Layout.fillWidth: true
+ Layout.preferredHeight: 44
+ verticalAlignment: Text.AlignVCenter
+ visible: (namesModel.count < 5)
+ enabled: visible
+ focus: true
+ font.pixelSize: 15
+ font.family: Theme.palette.baseFont.name
+ color: Theme.palette.directColor1
+ Keys.onPressed: {
+ if ((event.key === Qt.Key_Backspace || event.key === Qt.Key_Escape)
+ && getText(cursorPosition, (cursorPosition-1)) === "") {
+ namesModel.remove((namesList.count-1), 1);
+ }
+ }
+ }
+
+ StatusBaseText {
+ id: warningTextLabel
+ visible: (namesModel.count === 5)
+ Layout.preferredWidth: 120
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
+ font.pixelSize: 10
+ color: Theme.palette.dangerColor1
+ text: root.warningText
+ }
+ }
+ }
+}
diff --git a/ui/StatusQ/src/StatusQ/Components/qmldir b/ui/StatusQ/src/StatusQ/Components/qmldir
index 568befdd14..51c84c918e 100644
--- a/ui/StatusQ/src/StatusQ/Components/qmldir
+++ b/ui/StatusQ/src/StatusQ/Components/qmldir
@@ -26,3 +26,4 @@ StatusExpandableItem 0.1 StatusExpandableItem.qml
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
StatusMessage 0.1 StatusMessage.qml
StatusMessageDetails 0.1 StatusMessageDetails.qml
+StatusTagSelector 0.1 StatusTagSelector.qml
diff --git a/ui/StatusQ/statusq.qrc b/ui/StatusQ/statusq.qrc
index 5834670378..3e118610f0 100644
--- a/ui/StatusQ/statusq.qrc
+++ b/ui/StatusQ/statusq.qrc
@@ -320,5 +320,6 @@
src/StatusQ/Controls/StatusProgressBar.qml
src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml
src/StatusQ/Components/StatusMemberListItem.qml
+ src/StatusQ/Components/StatusTagSelector.qml