|
|
|
@ -161,6 +161,7 @@ Page { |
|
|
|
|
ColumnLayout { |
|
|
|
|
visible: TimelineManager.timeline != null |
|
|
|
|
anchors.fill: parent |
|
|
|
|
spacing: 0 |
|
|
|
|
|
|
|
|
|
Rectangle { |
|
|
|
|
id: topBar |
|
|
|
@ -168,7 +169,7 @@ Page { |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
implicitHeight: topLayout.height + 16 |
|
|
|
|
z: 3 |
|
|
|
|
color: colors.base |
|
|
|
|
color: colors.window |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
anchors.fill: parent |
|
|
|
@ -283,143 +284,156 @@ Page { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ListView { |
|
|
|
|
id: chat |
|
|
|
|
|
|
|
|
|
property int delegateMaxWidth: (Settings.timelineMaxWidth > 100 && (parent.width - Settings.timelineMaxWidth) > scrollbar.width * 2) ? Settings.timelineMaxWidth : (parent.width - scrollbar.width * 2) |
|
|
|
|
Rectangle { |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
height: 1 |
|
|
|
|
z: 3 |
|
|
|
|
color: colors.mid |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cacheBuffer: 400 |
|
|
|
|
Rectangle { |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
Layout.fillHeight: true |
|
|
|
|
model: TimelineManager.timeline |
|
|
|
|
boundsBehavior: Flickable.StopAtBounds |
|
|
|
|
pixelAligned: true |
|
|
|
|
spacing: 4 |
|
|
|
|
verticalLayoutDirection: ListView.BottomToTop |
|
|
|
|
onCountChanged: { |
|
|
|
|
if (atYEnd) |
|
|
|
|
model.currentIndex = 0; |
|
|
|
|
|
|
|
|
|
} // Mark last event as read, since we are at the bottom |
|
|
|
|
|
|
|
|
|
ScrollHelper { |
|
|
|
|
flickable: parent |
|
|
|
|
anchors.fill: parent |
|
|
|
|
} |
|
|
|
|
color: colors.base |
|
|
|
|
|
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.MoveToPreviousPage |
|
|
|
|
onActivated: { |
|
|
|
|
chat.contentY = chat.contentY - chat.height / 2; |
|
|
|
|
chat.returnToBounds(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ListView { |
|
|
|
|
id: chat |
|
|
|
|
|
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.MoveToNextPage |
|
|
|
|
onActivated: { |
|
|
|
|
chat.contentY = chat.contentY + chat.height / 2; |
|
|
|
|
chat.returnToBounds(); |
|
|
|
|
property int delegateMaxWidth: (Settings.timelineMaxWidth > 100 && (parent.width - Settings.timelineMaxWidth) > scrollbar.width * 2) ? Settings.timelineMaxWidth : (parent.width - scrollbar.width * 2) |
|
|
|
|
|
|
|
|
|
cacheBuffer: 400 |
|
|
|
|
anchors.fill: parent |
|
|
|
|
model: TimelineManager.timeline |
|
|
|
|
boundsBehavior: Flickable.StopAtBounds |
|
|
|
|
pixelAligned: true |
|
|
|
|
spacing: 4 |
|
|
|
|
verticalLayoutDirection: ListView.BottomToTop |
|
|
|
|
onCountChanged: { |
|
|
|
|
if (atYEnd) |
|
|
|
|
model.currentIndex = 0; |
|
|
|
|
|
|
|
|
|
} // Mark last event as read, since we are at the bottom |
|
|
|
|
|
|
|
|
|
ScrollHelper { |
|
|
|
|
flickable: parent |
|
|
|
|
anchors.fill: parent |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.Cancel |
|
|
|
|
onActivated: chat.model.reply = undefined |
|
|
|
|
} |
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.MoveToPreviousPage |
|
|
|
|
onActivated: { |
|
|
|
|
chat.contentY = chat.contentY - chat.height / 2; |
|
|
|
|
chat.returnToBounds(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Shortcut { |
|
|
|
|
sequence: "Alt+Up" |
|
|
|
|
onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0) |
|
|
|
|
} |
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.MoveToNextPage |
|
|
|
|
onActivated: { |
|
|
|
|
chat.contentY = chat.contentY + chat.height / 2; |
|
|
|
|
chat.returnToBounds(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Shortcut { |
|
|
|
|
sequence: "Alt+Down" |
|
|
|
|
onActivated: { |
|
|
|
|
var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1; |
|
|
|
|
chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : undefined; |
|
|
|
|
Shortcut { |
|
|
|
|
sequence: StandardKey.Cancel |
|
|
|
|
onActivated: chat.model.reply = undefined |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Component { |
|
|
|
|
id: userProfileComponent |
|
|
|
|
Shortcut { |
|
|
|
|
sequence: "Alt+Up" |
|
|
|
|
onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
UserProfile { |
|
|
|
|
Shortcut { |
|
|
|
|
sequence: "Alt+Down" |
|
|
|
|
onActivated: { |
|
|
|
|
var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1; |
|
|
|
|
chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : undefined; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
Component { |
|
|
|
|
id: userProfileComponent |
|
|
|
|
|
|
|
|
|
section { |
|
|
|
|
property: "section" |
|
|
|
|
} |
|
|
|
|
UserProfile { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Component { |
|
|
|
|
id: sectionHeader |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Column { |
|
|
|
|
property var modelData |
|
|
|
|
property string section |
|
|
|
|
property string nextSection |
|
|
|
|
section { |
|
|
|
|
property: "section" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
topPadding: 4 |
|
|
|
|
bottomPadding: 4 |
|
|
|
|
spacing: 8 |
|
|
|
|
visible: !!modelData |
|
|
|
|
width: parent.width |
|
|
|
|
height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8 |
|
|
|
|
Component { |
|
|
|
|
id: sectionHeader |
|
|
|
|
|
|
|
|
|
Label { |
|
|
|
|
id: dateBubble |
|
|
|
|
Column { |
|
|
|
|
property var modelData |
|
|
|
|
property string section |
|
|
|
|
property string nextSection |
|
|
|
|
|
|
|
|
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined |
|
|
|
|
visible: section.includes(" ") |
|
|
|
|
text: chat.model.formatDateSeparator(modelData.timestamp) |
|
|
|
|
color: colors.text |
|
|
|
|
height: fontMetrics.height * 1.4 |
|
|
|
|
width: contentWidth * 1.2 |
|
|
|
|
horizontalAlignment: Text.AlignHCenter |
|
|
|
|
verticalAlignment: Text.AlignVCenter |
|
|
|
|
topPadding: 4 |
|
|
|
|
bottomPadding: 4 |
|
|
|
|
spacing: 8 |
|
|
|
|
visible: !!modelData |
|
|
|
|
width: parent.width |
|
|
|
|
height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8 |
|
|
|
|
|
|
|
|
|
Label { |
|
|
|
|
id: dateBubble |
|
|
|
|
|
|
|
|
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined |
|
|
|
|
visible: section.includes(" ") |
|
|
|
|
text: chat.model.formatDateSeparator(modelData.timestamp) |
|
|
|
|
color: colors.text |
|
|
|
|
height: fontMetrics.height * 1.4 |
|
|
|
|
width: contentWidth * 1.2 |
|
|
|
|
horizontalAlignment: Text.AlignHCenter |
|
|
|
|
verticalAlignment: Text.AlignVCenter |
|
|
|
|
|
|
|
|
|
background: Rectangle { |
|
|
|
|
radius: parent.height / 2 |
|
|
|
|
color: colors.window |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
background: Rectangle { |
|
|
|
|
radius: parent.height / 2 |
|
|
|
|
color: colors.base |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
Row { |
|
|
|
|
height: userName.height |
|
|
|
|
spacing: 8 |
|
|
|
|
|
|
|
|
|
Row { |
|
|
|
|
height: userName.height |
|
|
|
|
spacing: 8 |
|
|
|
|
Avatar { |
|
|
|
|
width: avatarSize |
|
|
|
|
height: avatarSize |
|
|
|
|
url: chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") |
|
|
|
|
displayName: modelData.userName |
|
|
|
|
userid: modelData.userId |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
anchors.fill: parent |
|
|
|
|
onClicked: chat.model.openUserProfile(modelData.userId) |
|
|
|
|
cursorShape: Qt.PointingHandCursor |
|
|
|
|
propagateComposedEvents: true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Avatar { |
|
|
|
|
width: avatarSize |
|
|
|
|
height: avatarSize |
|
|
|
|
url: chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") |
|
|
|
|
displayName: modelData.userName |
|
|
|
|
userid: modelData.userId |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
anchors.fill: parent |
|
|
|
|
onClicked: chat.model.openUserProfile(modelData.userId) |
|
|
|
|
cursorShape: Qt.PointingHandCursor |
|
|
|
|
propagateComposedEvents: true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
Label { |
|
|
|
|
id: userName |
|
|
|
|
|
|
|
|
|
text: TimelineManager.escapeEmoji(modelData.userName) |
|
|
|
|
color: TimelineManager.userColor(modelData.userId, colors.window) |
|
|
|
|
textFormat: Text.RichText |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
anchors.fill: parent |
|
|
|
|
Layout.alignment: Qt.AlignHCenter |
|
|
|
|
onClicked: chat.model.openUserProfile(modelData.userId) |
|
|
|
|
cursorShape: Qt.PointingHandCursor |
|
|
|
|
propagateComposedEvents: true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Label { |
|
|
|
|
id: userName |
|
|
|
|
|
|
|
|
|
text: TimelineManager.escapeEmoji(modelData.userName) |
|
|
|
|
color: TimelineManager.userColor(modelData.userId, colors.window) |
|
|
|
|
textFormat: Text.RichText |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
anchors.fill: parent |
|
|
|
|
Layout.alignment: Qt.AlignHCenter |
|
|
|
|
onClicked: chat.model.openUserProfile(modelData.userId) |
|
|
|
|
cursorShape: Qt.PointingHandCursor |
|
|
|
|
propagateComposedEvents: true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -428,140 +442,130 @@ Page { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ScrollBar.vertical: ScrollBar { |
|
|
|
|
id: scrollbar |
|
|
|
|
} |
|
|
|
|
ScrollBar.vertical: ScrollBar { |
|
|
|
|
id: scrollbar |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
delegate: Item { |
|
|
|
|
id: wrapper |
|
|
|
|
|
|
|
|
|
// This would normally be previousSection, but our model's order is inverted. |
|
|
|
|
property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1 |
|
|
|
|
property Item section |
|
|
|
|
|
|
|
|
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined |
|
|
|
|
width: chat.delegateMaxWidth |
|
|
|
|
height: section ? section.height + timelinerow.height : timelinerow.height |
|
|
|
|
onSectionBoundaryChanged: { |
|
|
|
|
if (sectionBoundary) { |
|
|
|
|
var properties = { |
|
|
|
|
"modelData": model.dump, |
|
|
|
|
"section": ListView.section, |
|
|
|
|
"nextSection": ListView.nextSection |
|
|
|
|
}; |
|
|
|
|
section = sectionHeader.createObject(wrapper, properties); |
|
|
|
|
} else { |
|
|
|
|
section.destroy(); |
|
|
|
|
section = null; |
|
|
|
|
delegate: Item { |
|
|
|
|
id: wrapper |
|
|
|
|
|
|
|
|
|
// This would normally be previousSection, but our model's order is inverted. |
|
|
|
|
property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1 |
|
|
|
|
property Item section |
|
|
|
|
|
|
|
|
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined |
|
|
|
|
width: chat.delegateMaxWidth |
|
|
|
|
height: section ? section.height + timelinerow.height : timelinerow.height |
|
|
|
|
onSectionBoundaryChanged: { |
|
|
|
|
if (sectionBoundary) { |
|
|
|
|
var properties = { |
|
|
|
|
"modelData": model.dump, |
|
|
|
|
"section": ListView.section, |
|
|
|
|
"nextSection": ListView.nextSection |
|
|
|
|
}; |
|
|
|
|
section = sectionHeader.createObject(wrapper, properties); |
|
|
|
|
} else { |
|
|
|
|
section.destroy(); |
|
|
|
|
section = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TimelineRow { |
|
|
|
|
id: timelinerow |
|
|
|
|
TimelineRow { |
|
|
|
|
id: timelinerow |
|
|
|
|
|
|
|
|
|
y: section ? section.y + section.height : 0 |
|
|
|
|
} |
|
|
|
|
y: section ? section.y + section.height : 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Connections { |
|
|
|
|
function onMovementEnded() { |
|
|
|
|
if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) |
|
|
|
|
chat.model.currentIndex = index; |
|
|
|
|
Connections { |
|
|
|
|
function onMovementEnded() { |
|
|
|
|
if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) |
|
|
|
|
chat.model.currentIndex = index; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
target: chat |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
target: chat |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
footer: BusyIndicator { |
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter |
|
|
|
|
running: chat.model && chat.model.paginationInProgress |
|
|
|
|
height: 50 |
|
|
|
|
width: 50 |
|
|
|
|
z: 3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
footer: BusyIndicator { |
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter |
|
|
|
|
running: chat.model && chat.model.paginationInProgress |
|
|
|
|
height: 50 |
|
|
|
|
width: 50 |
|
|
|
|
z: 3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Item { |
|
|
|
|
id: chatFooter |
|
|
|
|
|
|
|
|
|
implicitHeight: Math.max(fontMetrics.height * 1.2, footerContent.height) |
|
|
|
|
implicitHeight: Math.max(fontMetrics.height * 1.2, typingDisplay.height) |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
z: 3 |
|
|
|
|
|
|
|
|
|
Column { |
|
|
|
|
id: footerContent |
|
|
|
|
Rectangle { |
|
|
|
|
id: typingRect |
|
|
|
|
|
|
|
|
|
color: colors.base |
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.right: parent.right |
|
|
|
|
anchors.bottom: parent.bottom |
|
|
|
|
height: (chat.model && chat.model.typingUsers.length > 0) ? typingDisplay.height : 0 |
|
|
|
|
z: 3 |
|
|
|
|
|
|
|
|
|
Rectangle { |
|
|
|
|
id: typingRect |
|
|
|
|
Label { |
|
|
|
|
id: typingDisplay |
|
|
|
|
|
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.leftMargin: 10 |
|
|
|
|
anchors.right: parent.right |
|
|
|
|
color: (chat.model && chat.model.typingUsers.length > 0) ? colors.window : "transparent" |
|
|
|
|
height: typingDisplay.height |
|
|
|
|
|
|
|
|
|
Label { |
|
|
|
|
id: typingDisplay |
|
|
|
|
anchors.rightMargin: 10 |
|
|
|
|
anchors.bottom: parent.bottom |
|
|
|
|
color: colors.text |
|
|
|
|
text: chat.model ? chat.model.formatTypingUsers(chat.model.typingUsers, colors.base) : "" |
|
|
|
|
textFormat: Text.RichText |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.leftMargin: 10 |
|
|
|
|
anchors.right: parent.right |
|
|
|
|
anchors.rightMargin: 10 |
|
|
|
|
color: colors.text |
|
|
|
|
text: chat.model ? chat.model.formatTypingUsers(chat.model.typingUsers, colors.window) : "" |
|
|
|
|
textFormat: Text.RichText |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Rectangle { |
|
|
|
|
id: replyPopup |
|
|
|
|
Rectangle { |
|
|
|
|
id: replyPopup |
|
|
|
|
|
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.right: parent.right |
|
|
|
|
visible: chat.model && chat.model.reply |
|
|
|
|
// Height of child, plus margins, plus border |
|
|
|
|
height: replyPreview.height + 10 |
|
|
|
|
color: colors.base |
|
|
|
|
|
|
|
|
|
Reply { |
|
|
|
|
id: replyPreview |
|
|
|
|
|
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.leftMargin: 10 |
|
|
|
|
anchors.right: closeReplyButton.left |
|
|
|
|
anchors.rightMargin: 20 |
|
|
|
|
anchors.bottom: parent.bottom |
|
|
|
|
modelData: chat.model ? chat.model.getDump(chat.model.reply, chat.model.id) : { |
|
|
|
|
} |
|
|
|
|
userColor: TimelineManager.userColor(modelData.userId, colors.window) |
|
|
|
|
} |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
visible: chat.model && chat.model.reply |
|
|
|
|
// Height of child, plus margins, plus border |
|
|
|
|
implicitHeight: replyPreview.height + 10 |
|
|
|
|
color: colors.window |
|
|
|
|
z: 3 |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
id: closeReplyButton |
|
|
|
|
|
|
|
|
|
anchors.right: parent.right |
|
|
|
|
anchors.rightMargin: 15 |
|
|
|
|
anchors.top: replyPreview.top |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 16 |
|
|
|
|
height: 16 |
|
|
|
|
image: ":/icons/icons/ui/remove-symbol.png" |
|
|
|
|
ToolTip.visible: closeReplyButton.hovered |
|
|
|
|
ToolTip.text: qsTr("Close") |
|
|
|
|
onClicked: chat.model.reply = undefined |
|
|
|
|
} |
|
|
|
|
Reply { |
|
|
|
|
id: replyPreview |
|
|
|
|
|
|
|
|
|
anchors.left: parent.left |
|
|
|
|
anchors.leftMargin: 10 |
|
|
|
|
anchors.right: closeReplyButton.left |
|
|
|
|
anchors.rightMargin: 20 |
|
|
|
|
anchors.bottom: parent.bottom |
|
|
|
|
modelData: chat.model ? chat.model.getDump(chat.model.reply, chat.model.id) : { |
|
|
|
|
} |
|
|
|
|
userColor: TimelineManager.userColor(modelData.userId, colors.window) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
id: closeReplyButton |
|
|
|
|
|
|
|
|
|
anchors.right: parent.right |
|
|
|
|
anchors.rightMargin: 15 |
|
|
|
|
anchors.top: replyPreview.top |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 16 |
|
|
|
|
height: 16 |
|
|
|
|
image: ":/icons/icons/ui/remove-symbol.png" |
|
|
|
|
ToolTip.visible: closeReplyButton.hovered |
|
|
|
|
ToolTip.text: qsTr("Close") |
|
|
|
|
onClicked: chat.model.reply = undefined |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -571,6 +575,99 @@ Page { |
|
|
|
|
z: 3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Rectangle { |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
z: 3 |
|
|
|
|
height: 1 |
|
|
|
|
color: colors.mid |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Rectangle { |
|
|
|
|
color: colors.window |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
Layout.preferredHeight: textInput.height |
|
|
|
|
Layout.minimumHeight: 40 |
|
|
|
|
|
|
|
|
|
RowLayout { |
|
|
|
|
id: inputBar |
|
|
|
|
|
|
|
|
|
anchors.fill: parent |
|
|
|
|
spacing: 16 |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
Layout.alignment: Qt.AlignBottom |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 22 |
|
|
|
|
height: 22 |
|
|
|
|
image: ":/icons/icons/ui/place-call.png" |
|
|
|
|
Layout.topMargin: 8 |
|
|
|
|
Layout.bottomMargin: 8 |
|
|
|
|
Layout.leftMargin: 16 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
Layout.alignment: Qt.AlignBottom |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 22 |
|
|
|
|
height: 22 |
|
|
|
|
image: ":/icons/icons/ui/paper-clip-outline.png" |
|
|
|
|
Layout.topMargin: 8 |
|
|
|
|
Layout.bottomMargin: 8 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ScrollView { |
|
|
|
|
id: textInput |
|
|
|
|
|
|
|
|
|
Layout.alignment: Qt.AlignBottom |
|
|
|
|
Layout.maximumHeight: Window.height / 4 |
|
|
|
|
Layout.fillWidth: true |
|
|
|
|
|
|
|
|
|
TextArea { |
|
|
|
|
placeholderText: qsTr("Write a message...") |
|
|
|
|
placeholderTextColor: colors.buttonText |
|
|
|
|
color: colors.text |
|
|
|
|
wrapMode: TextEdit.Wrap |
|
|
|
|
|
|
|
|
|
MouseArea { |
|
|
|
|
// workaround for wrong cursor shape on some platforms |
|
|
|
|
anchors.fill: parent |
|
|
|
|
acceptedButtons: Qt.NoButton |
|
|
|
|
cursorShape: Qt.IBeamCursor |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
background: Rectangle { |
|
|
|
|
color: colors.window |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 22 |
|
|
|
|
height: 22 |
|
|
|
|
image: ":/icons/icons/ui/smile.png" |
|
|
|
|
Layout.topMargin: 8 |
|
|
|
|
Layout.bottomMargin: 8 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ImageButton { |
|
|
|
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom |
|
|
|
|
hoverEnabled: true |
|
|
|
|
width: 22 |
|
|
|
|
height: 22 |
|
|
|
|
image: ":/icons/icons/ui/cursor.png" |
|
|
|
|
Layout.topMargin: 8 |
|
|
|
|
Layout.bottomMargin: 8 |
|
|
|
|
Layout.rightMargin: 16 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|