mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-11 06:47:01 +00:00
feat(StatusQ.Components): Adding StatusTagSelector component
Added StatusTagSelector component needed for creating new chat channels, either ono on one or group based on updated designs on Figma Also added corresponding page in API Documentation Closes #526
This commit is contained in:
parent
4cb28fee12
commit
08aced147f
103
ui/StatusQ/sandbox/demoapp/ChatChannelView.qml
Normal file
103
ui/StatusQ/sandbox/demoapp/ChatChannelView.qml
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
232
ui/StatusQ/sandbox/demoapp/CreateChatView.qml
Normal file
232
ui/StatusQ/sandbox/demoapp/CreateChatView.qml
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
import StatusQ.Popups 0.1
|
import StatusQ.Popups 0.1
|
||||||
@ -11,6 +12,7 @@ import "data" 1.0
|
|||||||
|
|
||||||
StatusAppThreePanelLayout {
|
StatusAppThreePanelLayout {
|
||||||
id: root
|
id: root
|
||||||
|
property bool createChat: false
|
||||||
|
|
||||||
leftPanel: Item {
|
leftPanel: Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@ -23,113 +25,35 @@ StatusAppThreePanelLayout {
|
|||||||
text: "Chat"
|
text: "Chat"
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
RowLayout {
|
||||||
id: searchInputWrapper
|
id: searchInputWrapper
|
||||||
anchors.top: headline.bottom
|
|
||||||
anchors.topMargin: 16
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: searchInput.height
|
height: searchInput.height
|
||||||
|
anchors.top: headline.bottom
|
||||||
|
anchors.topMargin: 16
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
|
||||||
StatusBaseInput {
|
StatusBaseInput {
|
||||||
id: searchInput
|
id: searchInput
|
||||||
|
Layout.fillWidth: true
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||||
anchors.left: parent.left
|
Layout.leftMargin: 17
|
||||||
anchors.right: actionButton.left
|
implicitHeight: 36
|
||||||
anchors.leftMargin: 16
|
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
height: 36
|
|
||||||
topPadding: 8
|
topPadding: 8
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
placeholderText: "Search"
|
placeholderText: "Search"
|
||||||
icon.name: "search"
|
icon.name: "search"
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusRoundButton {
|
StatusIconTabButton {
|
||||||
id: actionButton
|
icon.name: "public-chat"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
}
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 8
|
|
||||||
width: 32
|
|
||||||
height: 32
|
|
||||||
|
|
||||||
type: StatusRoundButton.Type.Secondary
|
StatusIconTabButton {
|
||||||
icon.name: "add"
|
icon.name: "edit"
|
||||||
state: "default"
|
onClicked: {
|
||||||
|
root.createChat = !root.createChat;
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 {
|
rightPanel: Item {
|
||||||
anchors.fill: parent
|
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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,58 @@ import StatusQ.Components 0.1
|
|||||||
|
|
||||||
QtObject {
|
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 {
|
property var demoChatListItems: ListModel {
|
||||||
id: demoChatListItems
|
id: demoChatListItems
|
||||||
ListElement {
|
ListElement {
|
||||||
|
@ -255,6 +255,11 @@ StatusWindow {
|
|||||||
selected: viewLoader.source.toString().includes(title)
|
selected: viewLoader.source.toString().includes(title)
|
||||||
onClicked: mainPageView.page("StatusExpandableSettingsItem");
|
onClicked: mainPageView.page("StatusExpandableSettingsItem");
|
||||||
}
|
}
|
||||||
|
StatusNavigationListItem {
|
||||||
|
title: "StatusTagSelector"
|
||||||
|
selected: viewLoader.source.toString().includes(title)
|
||||||
|
onClicked: mainPageView.page(title);
|
||||||
|
}
|
||||||
StatusListSectionHeadline { text: "StatusQ.Popup" }
|
StatusListSectionHeadline { text: "StatusQ.Popup" }
|
||||||
StatusNavigationListItem {
|
StatusNavigationListItem {
|
||||||
title: "StatusPopupMenu"
|
title: "StatusPopupMenu"
|
||||||
|
56
ui/StatusQ/sandbox/pages/StatusTagSelectorPage.qml
Normal file
56
ui/StatusQ/sandbox/pages/StatusTagSelectorPage.qml
Normal file
@ -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")
|
||||||
|
}
|
||||||
|
}
|
126
ui/StatusQ/src/StatusQ/Components/StatusTagSelector.qml
Normal file
126
ui/StatusQ/src/StatusQ/Components/StatusTagSelector.qml
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,3 +26,4 @@ StatusExpandableItem 0.1 StatusExpandableItem.qml
|
|||||||
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
|
StatusSmartIdenticon 0.1 StatusSmartIdenticon.qml
|
||||||
StatusMessage 0.1 StatusMessage.qml
|
StatusMessage 0.1 StatusMessage.qml
|
||||||
StatusMessageDetails 0.1 StatusMessageDetails.qml
|
StatusMessageDetails 0.1 StatusMessageDetails.qml
|
||||||
|
StatusTagSelector 0.1 StatusTagSelector.qml
|
||||||
|
@ -320,5 +320,6 @@
|
|||||||
<file>src/StatusQ/Controls/StatusProgressBar.qml</file>
|
<file>src/StatusQ/Controls/StatusProgressBar.qml</file>
|
||||||
<file>src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml</file>
|
<file>src/StatusQ/Controls/StatusPasswordStrengthIndicator.qml</file>
|
||||||
<file>src/StatusQ/Components/StatusMemberListItem.qml</file>
|
<file>src/StatusQ/Components/StatusMemberListItem.qml</file>
|
||||||
|
<file>src/StatusQ/Components/StatusTagSelector.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user