2022-02-15 21:00:05 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
import utils 1.0
|
2022-03-22 08:29:58 +00:00
|
|
|
import shared.status 1.0
|
2022-02-15 21:00:05 +00:00
|
|
|
|
|
|
|
Page {
|
|
|
|
id: root
|
|
|
|
anchors.fill: parent
|
|
|
|
Behavior on anchors.bottomMargin { NumberAnimation { duration: 30 }}
|
2022-03-22 08:29:58 +00:00
|
|
|
|
2022-02-15 21:00:05 +00:00
|
|
|
property ListModel contactsModel: ListModel { }
|
|
|
|
property var rootStore
|
2022-03-22 08:29:58 +00:00
|
|
|
property var emojiPopup: null
|
2022-02-15 21:00:05 +00:00
|
|
|
|
|
|
|
ListView {
|
|
|
|
id: contactsModelListView
|
2022-03-22 08:29:58 +00:00
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
2022-02-15 21:00:05 +00:00
|
|
|
model: root.rootStore.contactsModel
|
|
|
|
delegate: Item {
|
|
|
|
property string publicId: model.pubKey
|
|
|
|
property string name: model.name
|
|
|
|
property string icon: model.icon
|
|
|
|
property bool isIdenticon: model.isIdenticon
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Connections {
|
|
|
|
target: rootStore
|
|
|
|
onOpenCreateChatChanged: {
|
|
|
|
if (root.rootStore.openCreateChat) {
|
|
|
|
for (var i = 0; i < contactsModelListView.count; i ++) {
|
|
|
|
var entry = contactsModelListView.itemAtIndex(i);
|
|
|
|
contactsModel.insert(contactsModel.count,
|
|
|
|
{"publicId": entry.publicId, "name": entry.name,
|
|
|
|
"icon": entry.icon, "isIdenticon": entry.isIdenticon});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tagSelector.namesModel.clear();
|
|
|
|
contactsModel.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function createChat() {
|
|
|
|
if (tagSelector.namesModel.count === 1) {
|
|
|
|
var ensName = tagSelector.namesModel.get(0).name.includes(".eth") ? tagSelector.namesModel.get(0).name : "";
|
|
|
|
root.rootStore.chatCommunitySectionModule.createOneToOneChat("", tagSelector.namesModel.get(0).publicId, ensName);
|
|
|
|
} else {
|
|
|
|
var groupName = "";
|
|
|
|
var publicIds = [];
|
|
|
|
for (var i = 0; i < tagSelector.namesModel.count; i++) {
|
|
|
|
groupName += (tagSelector.namesModel.get(i).name + (i === tagSelector.namesModel.count - 1 ? "" : "&"));
|
|
|
|
publicIds.push(tagSelector.namesModel.get(i).publicId);
|
|
|
|
}
|
|
|
|
root.rootStore.chatCommunitySectionModule.createGroupChat("",groupName, JSON.stringify(publicIds));
|
|
|
|
}
|
2022-03-22 08:29:58 +00:00
|
|
|
|
|
|
|
chatInput.textInput.clear();
|
|
|
|
chatInput.textInput.textFormat = TextEdit.PlainText;
|
|
|
|
chatInput.textInput.textFormat = TextEdit.RichText;
|
2022-02-15 21:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
visible: (opacity > 0.01)
|
|
|
|
onVisibleChanged: {
|
|
|
|
if (!visible) {
|
|
|
|
tagSelector.namesModel.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opacity: (root.rootStore.openCreateChat) ? 1.0 : 0.0
|
|
|
|
Behavior on opacity { NumberAnimation {}}
|
|
|
|
background: Rectangle {
|
|
|
|
anchors.fill: parent
|
2022-03-22 08:29:58 +00:00
|
|
|
color: Theme.palette.statusAppLayout.rightPanelBackgroundColor
|
2022-02-15 21:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
header: RowLayout {
|
|
|
|
id: headerRow
|
|
|
|
width: parent.width
|
|
|
|
height: tagSelector.height
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.topMargin: 8
|
|
|
|
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("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});
|
|
|
|
userListView.model = sortedList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
userListView.model = contactsModel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusButton {
|
|
|
|
id: confirmButton
|
|
|
|
implicitHeight: 44
|
|
|
|
enabled: (tagSelector.namesModel.count > 0)
|
|
|
|
text: "Confirm"
|
|
|
|
onClicked: {
|
2022-03-22 08:29:58 +00:00
|
|
|
root.rootStore.createChatInitMessage = chatInput.textInput.text;
|
|
|
|
root.rootStore.createChatFileUrls = chatInput.fileUrls;
|
2022-02-15 21:00:05 +00:00
|
|
|
root.createChat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
contentItem: Item {
|
|
|
|
anchors.fill: parent
|
|
|
|
anchors.topMargin: headerRow.height + 32
|
|
|
|
|
|
|
|
Item {
|
2022-03-22 08:29:58 +00:00
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.bottom: chatInput.visible? chatInput.top : parent.bottom
|
2022-02-15 21:00:05 +00:00
|
|
|
visible: (contactsModel.count > 0)
|
|
|
|
|
2022-03-22 08:29:58 +00:00
|
|
|
Component.onCompleted: {
|
|
|
|
if (visible) {
|
|
|
|
tagSelector.textEdit.forceActiveFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-15 21:00:05 +00:00
|
|
|
StatusBaseText {
|
|
|
|
id: contactsLabel
|
|
|
|
font.pixelSize: 15
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.leftMargin: 8
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
text: qsTr("Contacts")
|
|
|
|
}
|
2022-03-22 08:29:58 +00:00
|
|
|
|
2022-02-15 21:00:05 +00:00
|
|
|
Control {
|
|
|
|
width: 360
|
|
|
|
anchors {
|
|
|
|
top: contactsLabel.bottom
|
|
|
|
topMargin: Style.current.halfPadding
|
|
|
|
bottom: !statusPopupMenuBackgroundContent.visible ? parent.bottom : undefined
|
|
|
|
}
|
|
|
|
height: Style.current.padding + (!statusPopupMenuBackgroundContent.visible ? parent.height :
|
|
|
|
(((userListView.count * 64) > parent.height) ? parent.height : (userListView.count * 64)))
|
|
|
|
x: (statusPopupMenuBackgroundContent.visible && (tagSelector.namesModel.count > 0) &&
|
|
|
|
((tagSelector.textEdit.x + Style.current.bigPadding + statusPopupMenuBackgroundContent.width) < parent.width))
|
|
|
|
? (tagSelector.textEdit.x + Style.current.bigPadding) : 0
|
|
|
|
background: Rectangle {
|
|
|
|
id: statusPopupMenuBackgroundContent
|
|
|
|
anchors.fill: parent
|
|
|
|
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.fill: parent
|
|
|
|
anchors.topMargin: 8
|
|
|
|
anchors.bottomMargin: 8
|
|
|
|
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.rightMargin: Style.current.halfPadding
|
|
|
|
anchors.leftMargin: Style.current.halfPadding
|
|
|
|
radius: Style.current.radius
|
|
|
|
visible: (tagSelector.sortedList.count > 0)
|
|
|
|
color: (wrapper.hovered) ? Theme.palette.baseColor2 : "transparent"
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusSmartIdenticon {
|
|
|
|
id: contactImage
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.leftMargin: 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
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-22 08:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StatusChatInput {
|
|
|
|
id: chatInput
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.right: parent.right
|
|
|
|
visible: tagSelector.namesModel.count > 0
|
|
|
|
chatType: tagSelector.namesModel.count == 1? Constants.chatType.oneToOne : Constants.chatType.privateGroupChat
|
|
|
|
|
|
|
|
emojiPopup: root.emojiPopup
|
|
|
|
recentStickers: root.rootStore.stickersModuleInst.recent
|
|
|
|
stickerPackList: root.rootStore.stickersModuleInst.stickerPacks
|
|
|
|
|
|
|
|
onSendTransactionCommandButtonClicked: {
|
|
|
|
root.rootStore.createChatStartSendTransactionProcess = true;
|
|
|
|
root.createChat();
|
|
|
|
}
|
|
|
|
|
|
|
|
onReceiveTransactionCommandButtonClicked: {
|
|
|
|
root.rootStore.createChatStartReceiveTransactionProcess = true;
|
|
|
|
root.createChat();
|
|
|
|
}
|
|
|
|
|
|
|
|
onStickerSelected: {
|
|
|
|
root.rootStore.createChatStickerHashId = hashId;
|
|
|
|
root.rootStore.createChatStickerPackId = packId;
|
|
|
|
root.createChat();
|
|
|
|
}
|
|
|
|
|
|
|
|
onSendMessage: {
|
|
|
|
root.rootStore.createChatFileUrls = chatInput.fileUrls;
|
|
|
|
root.rootStore.createChatInitMessage = chatInput.textInput.text;
|
|
|
|
root.createChat();
|
2022-02-15 21:00:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
width: parent.width
|
|
|
|
height: contentHeight
|
|
|
|
anchors.centerIn: parent
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
visible: (contactsModel.count === 0)
|
|
|
|
wrapMode: Text.WordWrap
|
|
|
|
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 able to
|
|
|
|
chat with them once they have accepted your contact request.")
|
|
|
|
Component.onCompleted: {
|
|
|
|
if (visible) {
|
|
|
|
tagSelector.enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|