feat: refactor Message and add Compact message type
This commit is contained in:
parent
a0c5f8624c
commit
5951fcf131
|
@ -122,6 +122,10 @@ ScrollView {
|
|||
}
|
||||
model: messageList
|
||||
|
||||
ProfilePopup {
|
||||
id: profilePopup
|
||||
}
|
||||
|
||||
delegate: Message {
|
||||
id: msgDelegate
|
||||
fromAuthor: model.fromAuthor
|
||||
|
@ -152,7 +156,6 @@ ScrollView {
|
|||
scrollToBottom: scrollView.scrollToBottom
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*##^##
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "../../../../shared"
|
||||
import "../../../../shared/xss.js" as XSS
|
||||
import "../../../../imports"
|
||||
import "./MessageComponents"
|
||||
import "../components"
|
||||
|
||||
Item {
|
||||
|
@ -39,147 +35,52 @@ Item {
|
|||
property var profileClick: function () {}
|
||||
property var scrollToBottom: function () {}
|
||||
property var appSettings
|
||||
|
||||
property bool isCompact: true
|
||||
|
||||
id: messageItem
|
||||
width: parent.width
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
id: messageWrapper
|
||||
height: {
|
||||
switch(contentType) {
|
||||
case Constants.chatIdentifier:
|
||||
return channelIdentifier.height + channelIdentifier.verticalMargin
|
||||
case Constants.stickerType:
|
||||
return stickerId.height + 50 + (dateGroupLbl.visible ? 50 : 0)
|
||||
return childrenRect.height + 50
|
||||
default: return childrenRect.height
|
||||
}
|
||||
}
|
||||
|
||||
function clickMessage() {
|
||||
SelectedMessage.set(messageId, fromAuthor);
|
||||
profileClick(userName, fromAuthor, identicon);
|
||||
messageContextMenu.popup()
|
||||
}
|
||||
|
||||
Loader {
|
||||
active :true
|
||||
width: parent.width
|
||||
// TODO get prop from settings
|
||||
sourceComponent: {
|
||||
switch(contentType) {
|
||||
case Constants.chatIdentifier:
|
||||
return channelIdentifierComponent
|
||||
case Constants.systemMessagePrivateGroupType:
|
||||
return channelIdentifierComponent
|
||||
default:
|
||||
return childrenRect.height
|
||||
}
|
||||
}
|
||||
|
||||
function linkify(inputText) {
|
||||
// URLs starting with http://, https://, or ftp://
|
||||
var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
||||
var replacedText = inputText.replace(replacePattern1, "<a href='$1'>$1</a>");
|
||||
|
||||
// URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
||||
var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
||||
replacedText = replacedText.replace(replacePattern2, "$1<a href='http://$2'>$2</a>");
|
||||
|
||||
replacedText = XSS.filterXSS(replacedText)
|
||||
return replacedText;
|
||||
}
|
||||
|
||||
ProfilePopup {
|
||||
id: profilePopup
|
||||
}
|
||||
|
||||
Item {
|
||||
property int verticalMargin: 50
|
||||
id: channelIdentifier
|
||||
visible: authorCurrentMsg == ""
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: this.visible ? verticalMargin : 0
|
||||
height: this.visible ? childrenRect.height + verticalMargin : 0
|
||||
|
||||
Rectangle {
|
||||
id: circleId
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 120
|
||||
height: 120
|
||||
radius: 120
|
||||
border.width: chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne ? 2 : 0
|
||||
border.color: Style.current.grey
|
||||
color: {
|
||||
if (chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne) {
|
||||
return Style.current.transparent
|
||||
}
|
||||
return chatsModel.activeChannel.color
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: chatsModel.activeChannel.chatType == Constants.chatTypeOneToOne
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 120
|
||||
height: 120
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: chatsModel.activeChannel.identicon
|
||||
mipmap: true
|
||||
smooth: false
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: chatsModel.activeChannel.chatType != Constants.chatTypeOneToOne
|
||||
text: (chatsModel.activeChannel.name.charAt(0) == "#" ? chatsModel.activeChannel.name.charAt(1) : chatsModel.activeChannel.name.charAt(0)).toUpperCase()
|
||||
opacity: 0.7
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 51
|
||||
color: "white"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: channelName
|
||||
wrapMode: Text.Wrap
|
||||
text: {
|
||||
if (chatsModel.activeChannel.chatType != Constants.chatTypePublic) {
|
||||
return chatsModel.activeChannel.name;
|
||||
} else {
|
||||
return "#" + chatsModel.activeChannel.name;
|
||||
}
|
||||
}
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 22
|
||||
color: Style.current.textColor
|
||||
anchors.top: circleId.bottom
|
||||
anchors.topMargin: 16
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: chatsModel.activeChannel.chatType == Constants.chatTypePrivateGroupChat && !chatsModel.activeChannel.isMember(profileModel.profile.pubKey)
|
||||
anchors.top: channelName.bottom
|
||||
anchors.topMargin: 16
|
||||
id: joinOrDecline
|
||||
|
||||
StyledText {
|
||||
id: joinChat
|
||||
//% "Join chat"
|
||||
text: qsTrId("join-chat")
|
||||
font.pixelSize: 20
|
||||
color: Style.current.blue
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.joinGroup()
|
||||
return isCompact ? compactMessageComponent : messageComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
//% "Decline invitation"
|
||||
text: qsTrId("group-chat-decline-invitation")
|
||||
font.pixelSize: 20
|
||||
color: Style.current.blue
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: joinChat.bottom
|
||||
anchors.topMargin: Style.current.padding
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.leaveActiveChat()
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: channelIdentifierComponent
|
||||
ChannelIdentifier {
|
||||
authorCurrentMsg: messageItem.authorCurrentMsg
|
||||
}
|
||||
}
|
||||
|
||||
// Private group Messages
|
||||
Component {
|
||||
id: privateGroupHeaderComponent
|
||||
StyledText {
|
||||
wrapMode: Text.Wrap
|
||||
text: message
|
||||
|
@ -191,382 +92,21 @@ Item {
|
|||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: dateGroupLbl
|
||||
font.pixelSize: 13
|
||||
color: Style.current.darkGrey
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: {
|
||||
if (prevMessageIndex == -1) return ""; // identifier
|
||||
|
||||
let now = new Date()
|
||||
let yesterday = new Date()
|
||||
yesterday.setDate(now.getDate()-1)
|
||||
|
||||
let prevMsgTimestamp = chatsModel.messageList.getMessageData(prevMessageIndex, "timestamp")
|
||||
var currentMsgDate = new Date(parseInt(timestamp, 10));
|
||||
var prevMsgDate = prevMsgTimestamp === "" ? new Date(0) : new Date(parseInt(prevMsgTimestamp, 10));
|
||||
if(currentMsgDate.getDay() !== prevMsgDate.getDay()){
|
||||
if (now.toDateString() === currentMsgDate.toDateString()) {
|
||||
return qsTr("Today")
|
||||
} else if (yesterday.toDateString() === currentMsgDate.toDateString()) {
|
||||
//% "Yesterday"
|
||||
return qsTrId("yesterday")
|
||||
} else {
|
||||
const monthNames = [
|
||||
qsTr("January"),
|
||||
qsTr("February"),
|
||||
qsTr("March"),
|
||||
qsTr("April"),
|
||||
qsTr("May"),
|
||||
qsTr("June"),
|
||||
qsTr("July"),
|
||||
qsTr("August"),
|
||||
qsTr("September"),
|
||||
qsTr("October"),
|
||||
qsTr("November"),
|
||||
qsTr("December")
|
||||
];
|
||||
return monthNames[currentMsgDate.getMonth()] + ", " + currentMsgDate.getDay()
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
// Messages
|
||||
Image {
|
||||
id: chatImage
|
||||
width: 36
|
||||
height: 36
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.topMargin: 20
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: identicon
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg && !isCurrentUser
|
||||
mipmap: true
|
||||
smooth: false
|
||||
antialiasing: true
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
SelectedMessage.set(messageId, fromAuthor);
|
||||
profileClick(userName, fromAuthor, identicon);
|
||||
messageContextMenu.popup()
|
||||
}
|
||||
// Normal message
|
||||
Component {
|
||||
id: messageComponent
|
||||
NormalMessage {
|
||||
clickMessage: messageItem.clickMessage
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatName
|
||||
text: userName
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.topMargin: 0
|
||||
anchors.left: chatImage.right
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
readOnly: true
|
||||
wrapMode: Text.WordWrap
|
||||
selectByMouse: true
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg && !isCurrentUser
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
SelectedMessage.set(messageId, fromAuthor);
|
||||
profileClick(userName, fromAuthor, identicon)
|
||||
messageContextMenu.popup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
property int chatVerticalPadding: 7
|
||||
property int chatHorizontalPadding: 12
|
||||
|
||||
id: chatBox
|
||||
color: isSticker ? Style.current.background : (isCurrentUser ? Style.current.blue : Style.current.secondaryBackground)
|
||||
border.color: isSticker ? Style.current.border : Style.current.transparent
|
||||
border.width: 1
|
||||
height: (3 * chatVerticalPadding) + (contentType == Constants.stickerType ? stickerId.height : (chatText.height + chatReply.height))
|
||||
width: {
|
||||
switch(contentType){
|
||||
case Constants.stickerType:
|
||||
return stickerId.width + (2 * chatBox.chatHorizontalPadding);
|
||||
default:
|
||||
return plainText.length > 54 ? 400 : chatText.width + 2 * chatHorizontalPadding
|
||||
}
|
||||
}
|
||||
|
||||
radius: 16
|
||||
anchors.left: !isCurrentUser ? chatImage.right : undefined
|
||||
anchors.leftMargin: !isCurrentUser ? 8 : 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: !isCurrentUser ? 0 : Style.current.padding
|
||||
anchors.top: authorCurrentMsg != authorPrevMsg && !isCurrentUser ? chatImage.top : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top)
|
||||
anchors.topMargin: 0
|
||||
visible: isMessage || isEmoji
|
||||
|
||||
Rectangle {
|
||||
id: chatReply
|
||||
color: isCurrentUser ? Style.current.blue : Style.current.lightBlue
|
||||
visible: responseTo != "" && replyMessageIndex > -1
|
||||
height: chatReply.visible ? childrenRect.height : 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: chatReply.visible ? chatBox.chatVerticalPadding : 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: chatBox.chatHorizontalPadding
|
||||
|
||||
StyledTextEdit {
|
||||
id: lblReplyAuthor
|
||||
text: "↳" + repliedMessageAuthor
|
||||
color: Style.current.darkGrey
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
wrapMode: Text.Wrap
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: lblReplyMessage
|
||||
anchors.top: lblReplyAuthor.bottom
|
||||
anchors.topMargin: 5
|
||||
text: Emoji.parse(linkify(repliedMessageContent), "26x26");
|
||||
textFormat: Text.RichText
|
||||
color: Style.current.darkGrey
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
wrapMode: Text.Wrap
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
Separator {
|
||||
anchors.top: lblReplyMessage.bottom
|
||||
anchors.topMargin: 8
|
||||
anchors.left: lblReplyMessage.left
|
||||
anchors.right: lblReplyMessage.right
|
||||
anchors.rightMargin: chatBox.chatHorizontalPadding
|
||||
color: Style.current.darkGrey
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatText
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
if(contentType === Constants.stickerType) return "";
|
||||
let msg = linkify(message);
|
||||
if(isEmoji){
|
||||
return Emoji.parse(msg, "72x72");
|
||||
} else {
|
||||
return `<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
code {
|
||||
background-color: #1a356b;
|
||||
color: #FFFFFF;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
p {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
a.mention {
|
||||
color: ${isCurrentUser ? Style.current.black : Style.current.white}
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${Emoji.parse(msg, "26x26")}
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
}
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: parent.chatHorizontalPadding
|
||||
anchors.right: plainText.length > 52 ? parent.right : undefined
|
||||
anchors.rightMargin: plainText.length > 52 ? parent.chatHorizontalPadding : 0
|
||||
horizontalAlignment: !isCurrentUser ? Text.AlignLeft : Text.AlignRight
|
||||
wrapMode: Text.Wrap
|
||||
anchors.top: chatReply.bottom
|
||||
anchors.topMargin: chatBox.chatVerticalPadding
|
||||
font.pixelSize: 15
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
color: !isCurrentUser ? Style.current.textColor : Style.current.currentUserTextColor
|
||||
visible: contentType == Constants.messageType || isEmoji
|
||||
}
|
||||
|
||||
Image {
|
||||
id: stickerId
|
||||
horizontalAlignment: !isCurrentUser ? Text.AlignLeft : Text.AlignRight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: parent.chatHorizontalPadding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: chatBox.chatVerticalPadding
|
||||
width: 140
|
||||
height: 140
|
||||
source: contentType === Constants.stickerType ? ("https://ipfs.infura.io/ipfs/" + sticker) : ""
|
||||
visible: contentType === Constants.stickerType
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: chatText.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: {
|
||||
if(mouse.button & Qt.RightButton) {
|
||||
SelectedMessage.set(messageId, fromAuthor);
|
||||
profileClick(userName, fromAuthor, identicon);
|
||||
messageContextMenu.popup()
|
||||
return;
|
||||
}
|
||||
|
||||
let link = chatText.hoveredLink;
|
||||
if(link.startsWith("#")){
|
||||
chatsModel.joinChat(link.substring(1), Constants.chatTypePublic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link.startsWith('//')) {
|
||||
let pk = link.replace("//", "");
|
||||
profileClick(chatsModel.userNameOrAlias(pk), pk, chatsModel.generateIdenticon(pk))
|
||||
return;
|
||||
}
|
||||
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatTime
|
||||
color: Style.current.darkGrey
|
||||
text: {
|
||||
let messageDate = new Date(Math.floor(timestamp))
|
||||
let minutes = messageDate.getMinutes();
|
||||
let hours = messageDate.getHours();
|
||||
return (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes)
|
||||
}
|
||||
anchors.top: messageWrapper.appSettings.displayChatImages && imageUrls != "" ? imageChatBox.bottom : chatBox.bottom
|
||||
anchors.topMargin: 4
|
||||
anchors.bottomMargin: Style.current.padding
|
||||
anchors.right: messageWrapper.appSettings.displayChatImages && imageUrls != "" ? imageChatBox.right : chatBox.right
|
||||
anchors.rightMargin: isCurrentUser ? 5 : Style.current.padding
|
||||
font.pixelSize: 10
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
visible: (isEmoji || isMessage || isSticker)
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: sentMessage
|
||||
color: Style.current.darkGrey
|
||||
text: outgoingStatus == "sent" ?
|
||||
//% "Sent"
|
||||
qsTrId("status-sent") :
|
||||
//% "Sending..."
|
||||
qsTrId("sending")
|
||||
anchors.top: chatTime.top
|
||||
anchors.bottomMargin: Style.current.padding
|
||||
anchors.right: chatTime.left
|
||||
anchors.rightMargin: 5
|
||||
font.pixelSize: 10
|
||||
readOnly: true
|
||||
visible: isCurrentUser && (isEmoji || isMessage || isSticker)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
property int chatVerticalPadding: 12
|
||||
property int chatHorizontalPadding: 12
|
||||
property int imageWidth: 350
|
||||
|
||||
id: imageChatBox
|
||||
visible: messageWrapper.appSettings.displayChatImages && imageUrls != ""
|
||||
height: {
|
||||
if (!imageChatBox.visible) {
|
||||
return 0
|
||||
}
|
||||
|
||||
let h = chatVerticalPadding
|
||||
for (let i = 0; i < imageRepeater.count; i++) {
|
||||
h += imageRepeater.itemAt(i).height
|
||||
}
|
||||
return h + chatVerticalPadding * imageRepeater.count
|
||||
}
|
||||
color: isCurrentUser ? Style.current.blue : Style.current.lightBlue
|
||||
border.color: "transparent"
|
||||
width: imageWidth+ 2 * chatHorizontalPadding
|
||||
radius: 16
|
||||
anchors.left: !isCurrentUser ? chatImage.right : undefined
|
||||
anchors.leftMargin: !isCurrentUser ? 8 : 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: !isCurrentUser ? 0 : Style.current.padding
|
||||
anchors.top: messageWrapper.appSettings.displayChatImages && imageUrls != "" ? chatBox.bottom : chatTime.bottom
|
||||
anchors.topMargin: Style.current.smallPadding
|
||||
|
||||
Repeater {
|
||||
id: imageRepeater
|
||||
model: messageWrapper.appSettings.displayChatImages && imageUrls != "" ? imageUrls.split(" ") : []
|
||||
|
||||
Image {
|
||||
id: imageMessage
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: (index == 0) ? parent.top: parent.children[index-1].bottom
|
||||
anchors.topMargin: imageChatBox.chatVerticalPadding
|
||||
sourceSize.width: imageChatBox.imageWidth
|
||||
source: modelData
|
||||
onStatusChanged: {
|
||||
if (imageMessage.status == Image.Error) {
|
||||
imageMessage.height = 0
|
||||
imageMessage.visible = false
|
||||
imageChatBox.height = 0
|
||||
imageChatBox.visible = false
|
||||
} else if (imageMessage.status == Image.Ready) {
|
||||
messageWrapper.scrollToBottom(true, messageWrapper)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This rectangle's only job is to mask the corner to make it less rounded... yep
|
||||
Rectangle {
|
||||
color: parent.color
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: !isCurrentUser ? parent.left : undefined
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: 0
|
||||
radius: 4
|
||||
z: -1
|
||||
// Compact Messages
|
||||
Component {
|
||||
id: compactMessageComponent
|
||||
CompactMessage {
|
||||
clickMessage: messageItem.clickMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Item {
|
||||
property string authorCurrentMsg: "authorCurrentMsg"
|
||||
property int verticalMargin: 50
|
||||
|
||||
id: channelIdentifier
|
||||
visible: authorCurrentMsg == ""
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: this.visible ? verticalMargin : 0
|
||||
height: this.visible ? childrenRect.height + verticalMargin : 0
|
||||
|
||||
Rectangle {
|
||||
id: circleId
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 120
|
||||
height: 120
|
||||
radius: 120
|
||||
border.width: chatsModel.activeChannel.chatType === Constants.chatTypeOneToOne ? 2 : 0
|
||||
border.color: Style.current.grey
|
||||
color: {
|
||||
if (chatsModel.activeChannel.chatType === Constants.chatTypeOneToOne) {
|
||||
return Style.current.transparent
|
||||
}
|
||||
return chatsModel.activeChannel.color
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: chatsModel.activeChannel.chatType === Constants.chatTypeOneToOne
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 120
|
||||
height: 120
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: chatsModel.activeChannel.identicon
|
||||
mipmap: true
|
||||
smooth: false
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: chatsModel.activeChannel.chatType !== Constants.chatTypeOneToOne
|
||||
text: (chatsModel.activeChannel.name.charAt(0) === "#" ? chatsModel.activeChannel.name.charAt(1) : chatsModel.activeChannel.name.charAt(0)).toUpperCase()
|
||||
opacity: 0.7
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 51
|
||||
color: Style.current.white
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: channelName
|
||||
wrapMode: Text.Wrap
|
||||
text: {
|
||||
if (chatsModel.activeChannel.chatType !== Constants.chatTypePublic) {
|
||||
return chatsModel.activeChannel.name;
|
||||
} else {
|
||||
return "#" + chatsModel.activeChannel.name;
|
||||
}
|
||||
}
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 22
|
||||
color: Style.current.black
|
||||
anchors.top: circleId.bottom
|
||||
anchors.topMargin: 16
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: chatsModel.activeChannel.chatType === Constants.chatTypePrivateGroupChat && !chatsModel.activeChannel.isMember(profileModel.profile.pubKey)
|
||||
anchors.top: channelName.bottom
|
||||
anchors.topMargin: 16
|
||||
id: joinOrDecline
|
||||
|
||||
StyledText {
|
||||
id: joinChat
|
||||
//% "Join chat"
|
||||
text: qsTrId("join-chat")
|
||||
font.pixelSize: 20
|
||||
color: Style.current.blue
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.joinGroup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
//% "Decline invitation"
|
||||
text: qsTrId("group-chat-decline-invitation")
|
||||
font.pixelSize: 20
|
||||
color: Style.current.blue
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: joinChat.bottom
|
||||
anchors.topMargin: Style.current.padding
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
chatsModel.leaveActiveChat()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;autoSize:true;formeditorZoom:0.5;height:480;width:640}
|
||||
}
|
||||
##^##*/
|
|
@ -0,0 +1,45 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
id: chatReply
|
||||
color: Style.current.lightBlue
|
||||
visible: responseTo != "" && replyMessageIndex > -1
|
||||
// childrenRect.height shows a binding loop for soem reason, so we use heights instead
|
||||
height: this.visible ? lblReplyAuthor.height + lblReplyMessage.height + 5 + 8 : 0
|
||||
|
||||
StyledTextEdit {
|
||||
id: lblReplyAuthor
|
||||
text: "↳" + repliedMessageAuthor
|
||||
color: Style.current.darkGrey
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
wrapMode: Text.Wrap
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
StyledTextEdit {
|
||||
id: lblReplyMessage
|
||||
anchors.top: lblReplyAuthor.bottom
|
||||
anchors.topMargin: 5
|
||||
text: Emoji.parse(Utils.linkifyAndXSS(repliedMessageContent), "26x26");
|
||||
textFormat: Text.RichText
|
||||
color: Style.current.darkGrey
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
wrapMode: Text.Wrap
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
Separator {
|
||||
anchors.top: lblReplyMessage.bottom
|
||||
anchors.topMargin: 8
|
||||
anchors.left: lblReplyMessage.left
|
||||
anchors.right: lblReplyMessage.right
|
||||
anchors.rightMargin: chatTextItem.chatHorizontalPadding
|
||||
color: Style.current.darkGrey
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatText
|
||||
visible: contentType == Constants.messageType || isEmoji
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
if(contentType === Constants.stickerType) return "";
|
||||
let msg = Utils.linkifyAndXSS(message);
|
||||
if(isEmoji){
|
||||
return Emoji.parse(msg, "72x72");
|
||||
} else {
|
||||
return `<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
code {
|
||||
background-color: #1a356b;
|
||||
color: #FFFFFF;
|
||||
white-space: pre;
|
||||
}
|
||||
p {
|
||||
white-space: pre;
|
||||
}
|
||||
a.mention {
|
||||
color: ${isCurrentUser ? Style.current.black : Style.current.white}
|
||||
font-weight: bold;
|
||||
}
|
||||
blockquote {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${Emoji.parse(msg, "26x26")}
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
}
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: 15
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
color: Style.current.textColor
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatTime
|
||||
visible: (isEmoji || isMessage || isSticker)
|
||||
color: Style.current.darkGrey
|
||||
text: {
|
||||
let messageDate = new Date(Math.floor(timestamp))
|
||||
let minutes = messageDate.getMinutes();
|
||||
let hours = messageDate.getHours();
|
||||
return (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes)
|
||||
}
|
||||
font.pixelSize: 10
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Item {
|
||||
property var clickMessage: function () {}
|
||||
property int chatHorizontalPadding: 12
|
||||
property int chatVerticalPadding: 7
|
||||
|
||||
id: chatTextItem
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: authorCurrentMsg != authorPrevMsg ? Style.current.smallPadding : 0
|
||||
height: childrenRect.height + this.anchors.topMargin
|
||||
width: parent.width
|
||||
|
||||
|
||||
// FIXME @jonathanr: Adding this breaks the first line. Need to fix the height somehow
|
||||
// DateGroup {
|
||||
// id: dateGroupLbl
|
||||
// }
|
||||
|
||||
UserImage {
|
||||
id: chatImage
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
// anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.top: parent.top
|
||||
}
|
||||
|
||||
UsernameLabel {
|
||||
id: chatName
|
||||
anchors.leftMargin: chatTextItem.chatHorizontalPadding
|
||||
// anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.top: parent.top
|
||||
anchors.left: chatImage.right
|
||||
}
|
||||
|
||||
ChatReply {
|
||||
id: chatReply
|
||||
// anchors.top: chatName.visible ? chatName.bottom : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top)
|
||||
anchors.top: chatName.visible ? chatName.bottom : parent.top
|
||||
anchors.topMargin: chatName.visible && this.visible ? chatTextItem.chatVerticalPadding : 0
|
||||
anchors.left: chatImage.right
|
||||
anchors.leftMargin: chatTextItem.chatHorizontalPadding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: chatTextItem.chatHorizontalPadding
|
||||
}
|
||||
|
||||
ChatText {
|
||||
id: chatText
|
||||
anchors.top: chatReply.bottom
|
||||
anchors.topMargin: chatName.visible && this.visible ? chatTextItem.chatVerticalPadding : 0
|
||||
anchors.left: chatImage.right
|
||||
anchors.leftMargin: chatTextItem.chatHorizontalPadding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: chatTextItem.chatHorizontalPadding
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: stickerContainer
|
||||
visible: contentType === Constants.stickerType
|
||||
color: Style.current.transparent
|
||||
border.color: Style.current.grey
|
||||
border.width: 1
|
||||
radius: 16
|
||||
width: stickerId.width
|
||||
height: stickerId.height
|
||||
anchors.left: chatText.left
|
||||
anchors.top: chatName.visible ? chatName.bottom : parent.top
|
||||
anchors.topMargin: this.visible && chatName.visible ? chatTextItem.chatVerticalPadding : 0
|
||||
|
||||
Sticker {
|
||||
id: stickerId
|
||||
visible: stickerContainer.visible
|
||||
}
|
||||
}
|
||||
|
||||
MessageMouseArea {
|
||||
anchors.fill: stickerContainer.visible ? stickerContainer : chatText
|
||||
}
|
||||
|
||||
// TODO show date for not the first messsage (on hover maybe)
|
||||
ChatTime {
|
||||
id: chatTime
|
||||
visible: authorCurrentMsg != authorPrevMsg
|
||||
anchors.verticalCenter: chatName.verticalCenter
|
||||
anchors.left: chatName.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
}
|
||||
|
||||
SentMessage {
|
||||
id: sentMessage
|
||||
visible: isCurrentUser && outgoingStatus != "sent"
|
||||
anchors.verticalCenter: chatTime.verticalCenter
|
||||
anchors.left: chatTime.right
|
||||
anchors.rightMargin: 5
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
StyledText {
|
||||
id: dateGroupLbl
|
||||
font.pixelSize: 13
|
||||
color: Style.current.darkGrey
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: {
|
||||
if (prevMessageIndex == -1) return ""; // identifier
|
||||
|
||||
let now = new Date()
|
||||
let yesterday = new Date()
|
||||
yesterday.setDate(now.getDate()-1)
|
||||
|
||||
let prevMsgTimestamp = chatsModel.messageList.getMessageData(prevMessageIndex, "timestamp")
|
||||
var currentMsgDate = new Date(parseInt(timestamp, 10));
|
||||
var prevMsgDate = prevMsgTimestamp === "" ? new Date(0) : new Date(parseInt(prevMsgTimestamp, 10));
|
||||
if(currentMsgDate.getDay() !== prevMsgDate.getDay()){
|
||||
if (now.toDateString() === currentMsgDate.toDateString()) {
|
||||
return qsTr("Today")
|
||||
} else if (yesterday.toDateString() === currentMsgDate.toDateString()) {
|
||||
//% "Yesterday"
|
||||
return qsTrId("yesterday")
|
||||
} else {
|
||||
const monthNames = [
|
||||
qsTr("January"),
|
||||
qsTr("February"),
|
||||
qsTr("March"),
|
||||
qsTr("April"),
|
||||
qsTr("May"),
|
||||
qsTr("June"),
|
||||
qsTr("July"),
|
||||
qsTr("August"),
|
||||
qsTr("September"),
|
||||
qsTr("October"),
|
||||
qsTr("November"),
|
||||
qsTr("December")
|
||||
];
|
||||
return monthNames[currentMsgDate.getMonth()] + ", " + currentMsgDate.getDay()
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
visible: text !== ""
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: this.visible ? 20 : 0
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
property int chatVerticalPadding: 12
|
||||
property int chatHorizontalPadding: 12
|
||||
property int imageWidth: 350
|
||||
|
||||
id: imageChatBox
|
||||
height: {
|
||||
let h = chatVerticalPadding
|
||||
for (let i = 0; i < imageRepeater.count; i++) {
|
||||
h += imageRepeater.itemAt(i).height
|
||||
}
|
||||
return h + chatVerticalPadding * imageRepeater.count
|
||||
}
|
||||
color: isCurrentUser ? Style.current.blue : Style.current.lightBlue
|
||||
border.color: "transparent"
|
||||
width: imageWidth + 2 * chatHorizontalPadding
|
||||
radius: 16
|
||||
|
||||
Repeater {
|
||||
id: imageRepeater
|
||||
model: imageUrls.split(" ")
|
||||
|
||||
Image {
|
||||
id: imageMessage
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: (index == 0) ? parent.top: parent.children[index-1].bottom
|
||||
anchors.topMargin: imageChatBox.chatVerticalPadding
|
||||
sourceSize.width: imageChatBox.imageWidth
|
||||
source: modelData
|
||||
onStatusChanged: {
|
||||
if (imageMessage.status == Image.Error) {
|
||||
imageMessage.height = 0
|
||||
imageMessage.visible = false
|
||||
imageChatBox.height = 0
|
||||
imageChatBox.visible = false
|
||||
} else if (imageMessage.status == Image.Ready) {
|
||||
messageItem.scrollToBottom(true, messageItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This rectangle's only job is to mask the corner to make it less rounded... yep
|
||||
Rectangle {
|
||||
color: parent.color
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: !isCurrentUser ? parent.left : undefined
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: 0
|
||||
radius: 4
|
||||
z: -1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
MouseArea {
|
||||
cursorShape: chatText.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: {
|
||||
if(mouse.button & Qt.RightButton) {
|
||||
clickMessage()
|
||||
return;
|
||||
}
|
||||
|
||||
let link = chatText.hoveredLink;
|
||||
if(link.startsWith("#")){
|
||||
chatsModel.joinChat(link.substring(1), Constants.chatTypePublic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link.startsWith('//')) {
|
||||
let pk = link.replace("//", "");
|
||||
profileClick(chatsModel.userNameOrAlias(pk), pk, chatsModel.generateIdenticon(pk))
|
||||
return;
|
||||
}
|
||||
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Item {
|
||||
property var clickMessage: function () {}
|
||||
property bool showImages: messageItem.appSettings.displayChatImages && imageUrls != ""
|
||||
|
||||
id: chatTextItem
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: authorCurrentMsg != authorPrevMsg ? Style.current.smallPadding : 0
|
||||
height: childrenRect.height + this.anchors.topMargin
|
||||
width: parent.width
|
||||
|
||||
DateGroup {
|
||||
id: dateGroupLbl
|
||||
}
|
||||
|
||||
UserImage {
|
||||
id: chatImage
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg && !isCurrentUser
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
UsernameLabel {
|
||||
id: chatName
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg && !isCurrentUser
|
||||
text: userName
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top
|
||||
anchors.topMargin: 0
|
||||
anchors.left: chatImage.right
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
property int chatVerticalPadding: 7
|
||||
property int chatHorizontalPadding: 12
|
||||
|
||||
id: chatBox
|
||||
color: isSticker ? Style.current.background : (isCurrentUser ? Style.current.blue : Style.current.secondaryBackground)
|
||||
border.color: isSticker ? Style.current.border : Style.current.transparent
|
||||
border.width: 1
|
||||
height: (3 * chatVerticalPadding) + (contentType == Constants.stickerType ? stickerId.height : (chatText.height + chatReply.height))
|
||||
width: {
|
||||
switch(contentType){
|
||||
case Constants.stickerType:
|
||||
return stickerId.width + (2 * chatBox.chatHorizontalPadding);
|
||||
default:
|
||||
return plainText.length > 54 ? 400 : chatText.width + 2 * chatHorizontalPadding
|
||||
}
|
||||
}
|
||||
|
||||
radius: 16
|
||||
anchors.left: !isCurrentUser ? chatImage.right : undefined
|
||||
anchors.leftMargin: !isCurrentUser ? 8 : 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: !isCurrentUser ? 0 : Style.current.padding
|
||||
anchors.top: authorCurrentMsg != authorPrevMsg && !isCurrentUser ? chatImage.top : (dateGroupLbl.visible ? dateGroupLbl.bottom : parent.top)
|
||||
anchors.topMargin: 0
|
||||
visible: isMessage || isEmoji
|
||||
|
||||
ChatReply {
|
||||
id: chatReply
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: chatReply.visible ? chatBox.chatVerticalPadding : 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: chatBox.chatHorizontalPadding
|
||||
color: isCurrentUser ? Style.current.blue : Style.current.lightBlue
|
||||
|
||||
}
|
||||
|
||||
ChatText {
|
||||
id: chatText
|
||||
anchors.top: chatReply.bottom
|
||||
anchors.topMargin: chatBox.chatVerticalPadding
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: parent.chatHorizontalPadding
|
||||
anchors.right: plainText.length > 52 ? parent.right : undefined
|
||||
anchors.rightMargin: plainText.length > 52 ? parent.chatHorizontalPadding : 0
|
||||
horizontalAlignment: !isCurrentUser ? Text.AlignLeft : Text.AlignRight
|
||||
color: !isCurrentUser ? Style.current.textColor : Style.current.currentUserTextColor
|
||||
}
|
||||
|
||||
Sticker {
|
||||
id: stickerId
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: parent.chatHorizontalPadding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: chatBox.chatVerticalPadding
|
||||
}
|
||||
|
||||
MessageMouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
ChatTime {
|
||||
id: chatTime
|
||||
anchors.top: showImages ? imageLoader.bottom : chatBox.bottom
|
||||
anchors.topMargin: 4
|
||||
anchors.bottomMargin: Style.current.padding
|
||||
anchors.right: showImages ? imageLoader.right : chatBox.right
|
||||
anchors.rightMargin: isCurrentUser ? 5 : Style.current.padding
|
||||
}
|
||||
|
||||
SentMessage {
|
||||
id: sentMessage
|
||||
anchors.top: chatTime.top
|
||||
anchors.bottomMargin: Style.current.padding
|
||||
anchors.right: chatTime.left
|
||||
anchors.rightMargin: 5
|
||||
}
|
||||
|
||||
// This rectangle's only job is to mask the corner to make it less rounded... yep
|
||||
Rectangle {
|
||||
// TODO find a way to show the corner for stickers since they have a border
|
||||
visible: isMessage || isEmoji
|
||||
color: chatBox.color
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.bottom: chatBox.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: !isCurrentUser ? chatBox.left : undefined
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: !isCurrentUser ? undefined : chatBox.right
|
||||
anchors.rightMargin: 0
|
||||
radius: 4
|
||||
z: -1
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: imageLoader
|
||||
active: showImages
|
||||
sourceComponent: imageComponent
|
||||
anchors.left: !isCurrentUser ? chatImage.right : undefined
|
||||
anchors.leftMargin: !isCurrentUser ? 8 : 0
|
||||
anchors.right: !isCurrentUser ? undefined : parent.right
|
||||
anchors.rightMargin: !isCurrentUser ? 0 : Style.current.padding
|
||||
anchors.top: messageItem.appSettings.displayChatImages && imageUrls != "" ? chatBox.bottom : chatTime.bottom
|
||||
anchors.topMargin: Style.current.smallPadding
|
||||
}
|
||||
|
||||
Component {
|
||||
id: imageComponent
|
||||
ImageMessage {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
StyledText {
|
||||
id: sentMessage
|
||||
visible: isCurrentUser && (isEmoji || isMessage || isSticker)
|
||||
color: Style.current.darkGrey
|
||||
text: outgoingStatus == "sent" ?
|
||||
//% "Sent"
|
||||
qsTrId("status-sent") :
|
||||
//% "Sending..."
|
||||
qsTrId("sending")
|
||||
font.pixelSize: 10
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../imports"
|
||||
|
||||
Image {
|
||||
id: stickerId
|
||||
visible: contentType === Constants.stickerType
|
||||
width: 140
|
||||
height: this.visible ? 140 : 0
|
||||
source: this.visible ? ("https://ipfs.infura.io/ipfs/" + sticker) : ""
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
Rectangle {
|
||||
id: chatImage
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg
|
||||
width: identiconImage.width
|
||||
height: identiconImage.height
|
||||
border.width: 1
|
||||
border.color: Style.current.border
|
||||
radius: 50
|
||||
|
||||
Image {
|
||||
id: identiconImage
|
||||
width: 36
|
||||
height: chatImage.visible ? 36 : 0
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: !isCurrentUser ? identicon : profileModel.profile.identicon
|
||||
mipmap: true
|
||||
smooth: false
|
||||
antialiasing: true
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
clickMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import QtQuick 2.3
|
||||
import "../../../../../shared"
|
||||
import "../../../../../imports"
|
||||
|
||||
StyledTextEdit {
|
||||
id: chatName
|
||||
visible: (isMessage || isEmoji) && authorCurrentMsg != authorPrevMsg
|
||||
height: this.visible ? 18 : 0
|
||||
text: !isCurrentUser ? userName : qsTr("You")
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
readOnly: true
|
||||
wrapMode: Text.WordWrap
|
||||
selectByMouse: true
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
clickMessage()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ChannelIdentifier 1.0 ChannelIdentifier.qml
|
|
@ -4,3 +4,5 @@ ChatInput 1.0 ChatInput.qml
|
|||
EmptyChat 1.0 EmptyChat.qml
|
||||
ChatButtons 1.0 ChatButtons.qml
|
||||
ReplyArea 1.0 ReplyArea.qml
|
||||
Message 1.0 Message.qml
|
||||
CompactMessage 1.0 CompactMessage.qml
|
||||
|
|
|
@ -12,19 +12,6 @@ Item {
|
|||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
function linkify(inputText) {
|
||||
//URLs starting with http://, https://, or ftp://
|
||||
var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
||||
var replacedText = inputText.replace(replacePattern1, "<a href='$1'>$1</a>");
|
||||
|
||||
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
||||
var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
||||
replacedText = replacedText.replace(replacePattern2, "$1<a href='http://$2'>$2</a>");
|
||||
|
||||
replacedText = XSS.filterXSS(replacedText)
|
||||
return replacedText;
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: element8
|
||||
//% "Help menus: FAQ, Glossary, etc."
|
||||
|
@ -39,7 +26,7 @@ Item {
|
|||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: linkify(link)
|
||||
text: Utils.linkifyAndXSS(link)
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
|
||||
MouseArea {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pragma Singleton
|
||||
|
||||
import QtQuick 2.13
|
||||
import "../shared/xss.js" as XSS
|
||||
|
||||
QtObject {
|
||||
function isHex(value) {
|
||||
|
@ -39,4 +40,17 @@ QtObject {
|
|||
}
|
||||
return addr.substring(0, 2 + numberOfChars) + "..." + addr.substring(addr.length - numberOfChars);
|
||||
}
|
||||
|
||||
function linkifyAndXSS(inputText) {
|
||||
//URLs starting with http://, https://, or ftp://
|
||||
var replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
||||
var replacedText = inputText.replace(replacePattern1, "<a href='$1'>$1</a>");
|
||||
|
||||
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
||||
var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
||||
replacedText = replacedText.replace(replacePattern2, "$1<a href='http://$2'>$2</a>");
|
||||
|
||||
replacedText = XSS.filterXSS(replacedText)
|
||||
return replacedText;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,22 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
|||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
DISTFILES += \
|
||||
app/AppLayouts/Chat/ChatColumn/CompactMessage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ChannelIdentifier.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatReply \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatReply.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatText.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ChatTime.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/CompactMessage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/DateGroup.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/ImageMessage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/MessageMouseArea.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/NormalMessage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/SentMessage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/Sticker.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/UserImage.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/UsernameLabel.qml \
|
||||
app/AppLayouts/Chat/ChatColumn/MessageComponents/qmldir \
|
||||
app/AppLayouts/Chat/ContactsColumn/ClosedEmptyView.qml \
|
||||
app/AppLayouts/Chat/components/EmojiPopup.qml \
|
||||
app/AppLayouts/Chat/components/InviteFriendsPopup.qml \
|
||||
|
|
Loading…
Reference in New Issue