Newer
Older
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
// SPDX-FileCopyrightText: 2023 Nheko Contributors
import "./delegates"
import "./device-verification"
import "./emoji"
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Window 2.13
import im.nheko 1.0
Item {
id: timelineView
onRoomChanged: if (room != null) room.triggerSpecialEffects()
// focus message input on key press, but not on Ctrl-C and such.
Keys.onPressed: if (event.text && !topBar.searchHasFocus) TimelineManager.focusMessageInput();
Shortcut {
sequence: StandardKey.Close
onActivated: Rooms.resetCurrentRoom()
}
visible: !room && !TimelineManager.isInitialSync && (!roomPreview || !roomPreview.roomid)
anchors.centerIn: parent
text: qsTr("No room open")
font.pointSize: 24
color: Nheko.colors.text
anchors.centerIn: parent
foreground: Nheko.colors.mid
running: TimelineManager.isInitialSync
// height is somewhat arbitrary here... don't set width because width scales w/ height
height: parent.height / 16
opacity: hh.hovered ? 0.3 : 1
Behavior on opacity {
NumberAnimation { duration: 100; }
}
HoverHandler {
id: hh
}
Jedi18
committed
}
ColumnLayout {
id: timelineLayout
visible: room != null && !room.isSpace
enabled: visible
showBackButton: timelineView.showBackButton
Rectangle {
Layout.fillWidth: true
height: 1
Rectangle {
id: msgView
Layout.fillWidth: true
Layout.fillHeight: true
color: Nheko.colors.base
ColumnLayout {
anchors.fill: parent
spacing: 0
StackLayout {
id: stackLayout
currentIndex: 0
function onRoomChanged() {
stackLayout.currentIndex = 0;
MessageView {
implicitHeight: msgView.height - typingIndicator.height
Loader {
source: CallManager.isOnCall && CallManager.callType != CallType.VOICE ? "voip/VideoCall.qml" : ""
onLoaded: TimelineManager.setVideoCallItem()
TypingIndicator {
id: typingIndicator
}
CallInviteBar {
id: callInviteBar
Layout.fillWidth: true
z: 3
}
ActiveCallBar {
Layout.fillWidth: true
z: 3
}
Rectangle {
Layout.fillWidth: true
z: 3
height: 1
UploadBox {
NotificationWarning {
}
MessageInput {
property string roomId: room ? room.roomId : (roomPreview ? roomPreview.roomid : "")
property string roomName: room ? room.roomName : (roomPreview ? roomPreview.roomName : "")
property string roomTopic: room ? room.roomTopic : (roomPreview ? roomPreview.roomTopic : "")
property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "")
property string reason: roomPreview ? roomPreview.reason : ""
visible: room != null && room.isSpace || roomPreview != null
enabled: visible
anchors.fill: parent
anchors.margins: Nheko.paddingLarge
spacing: Nheko.paddingLarge
Item {
Layout.fillHeight: true
}
url: parent.avatarUrl.replace("mxc://", "image://MxcImage/")
height: 130
width: 130
Layout.alignment: Qt.AlignHCenter
enabled: false
}
RowLayout {
spacing: Nheko.paddingMedium
MatrixText {
text: preview.roomName == "" ? qsTr("No preview available") : preview.roomName
font.pixelSize: 24
}
ImageButton {
image: ":/icons/icons/ui/settings.svg"
visible: !!room
hoverEnabled: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Settings")
onClicked: TimelineManager.openRoomSettings(room.roomId)
}
spacing: Nheko.paddingMedium
MatrixText {
text: qsTr("%n member(s)", "", room ? room.roomMemberCount : 0)
}
ImageButton {
image: ":/icons/icons/ui/people.svg"
hoverEnabled: true
ToolTip.visible: hovered
ToolTip.text: qsTr("View members of %1").arg(room ? room.roomName : "")
onClicked: TimelineManager.openRoomMembers(room)
}
}
ScrollView {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.leftMargin: Nheko.paddingLarge
Layout.rightMargin: Nheko.paddingLarge
text: TimelineManager.escapeEmoji(preview.roomTopic)
wrapMode: TextEdit.WordWrap
textFormat: TextEdit.RichText
readOnly: true
background: null
selectByMouse: true
color: Nheko.colors.text
horizontalAlignment: TextEdit.AlignHCenter
onLinkActivated: Nheko.openLink(link)
CursorShape {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
}
FlatButton {
visible: roomPreview && !roomPreview.isInvite
Layout.alignment: Qt.AlignHCenter
text: qsTr("join the conversation")
onClicked: Rooms.joinPreview(roomPreview.roomid)
}
FlatButton {
visible: roomPreview && roomPreview.isInvite
Layout.alignment: Qt.AlignHCenter
text: qsTr("accept invite")
onClicked: Rooms.acceptInvite(roomPreview.roomid)
}
FlatButton {
visible: roomPreview && roomPreview.isInvite
Layout.alignment: Qt.AlignHCenter
text: qsTr("decline invite")
onClicked: Rooms.declineInvite(roomPreview.roomid)
}
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
ScrollView {
id: reasonField
property bool showReason: false
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.leftMargin: Nheko.paddingLarge
Layout.rightMargin: Nheko.paddingLarge
visible: preview.reason !== "" && showReason
TextArea {
text: TimelineManager.escapeEmoji(preview.reason)
wrapMode: TextEdit.WordWrap
textFormat: TextEdit.RichText
readOnly: true
background: null
selectByMouse: true
color: Nheko.colors.text
horizontalAlignment: TextEdit.AlignHCenter
}
}
Button {
id: showReasonButton
Layout.alignment: Qt.AlignHCenter
//Layout.fillWidth: true
Layout.leftMargin: Nheko.paddingLarge
Layout.rightMargin: Nheko.paddingLarge
visible: preview.reason !== ""
text: reasonField.showReason ? qsTr("Hide invite reason") : qsTr("Show invite reason")
onClicked: {
reasonField.showReason = !reasonField.showReason;
}
}
Item {
visible: room != null
Layout.preferredHeight: Math.ceil(fontMetrics.lineSpacing * 2)
}
Item {
Layout.fillHeight: true
}
}
Nicolas Werner
committed
ImageButton {
id: backToRoomsButton
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: Nheko.paddingMedium
width: Nheko.avatarSize
height: Nheko.avatarSize
visible: (room == null || room.isSpace) && showBackButton
Nicolas Werner
committed
enabled: visible
image: ":/icons/icons/ui/angle-arrow-left.svg"
Nicolas Werner
committed
ToolTip.visible: hovered
ToolTip.text: qsTr("Back to room list")
onClicked: Rooms.resetCurrentRoom()
}
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
ParticleSystem { id: confettiParticleSystem }
Emitter {
id: confettiEmitter
width: parent.width * 3/4
enabled: false
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height
emitRate: Math.min(400 * Math.sqrt(parent.width * parent.height) / 870, 1000)
lifeSpan: 15000
system: confettiParticleSystem
velocityFromMovement: 8
size: 16
sizeVariation: 4
velocity: PointDirection {
x: 0
y: -Math.min(450 * parent.height / 700, 1000)
xVariation: Math.min(4 * parent.width / 7, 450)
yVariation: 250
}
ImageParticle {
system: confettiParticleSystem
source: "qrc:/confettiparticle.svg"
rotationVelocity: 0
rotationVelocityVariation: 360
colorVariation: 1
color: "white"
entryEffect: ImageParticle.None
xVector: PointDirection {
x: 1
y: 0
xVariation: 0.2
yVariation: 0.2
}
yVector: PointDirection {
x: 0
y: 0.5
xVariation: 0.2
yVariation: 0.2
}
}
}
Gravity {
system: confettiParticleSystem
anchors.fill: parent
magnitude: 350
angle: 90
}
NhekoDropArea {
roomid: room ? room.roomId : ""
Connections {
function onOpenReadReceiptsDialog(rr) {
var dialog = readReceiptsDialog.createObject(timelineRoot, {
"readReceipts": rr,
"room": room
});
dialog.show();
}
function onShowRawMessageDialog(rawMessage) {
var dialog = Qt.createComponent("qrc:/qml/dialogs/RawMessageDialog.qml").createObject(timelineRoot, {
"rawMessage": rawMessage
});
dialog.show();
function onConfetti()
{
if (!Settings.fancyEffects)
return
confettiEmitter.pulse(parent.height * 2)
room.markSpecialEffectsDone()
}
target: room
}