import QtGraphicalEffects 1.0 import QtQuick 2.7 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.0 import QtQuick.Layouts 1.3 import CustomQmlTypes 1.0 import "../opaque" as Opaque import "../opaque/controls" as Awesome import "../utils.js" as Utils import "../widgets" as W import "../opaque/theme" W.Overlay { id: overlayRoot property bool loading property string historyState: "DefaultDeleteHistory" //horizontalPadding: 15 * gcd.themeScale Connections { target: mm onRowsInserted: { if (messagesListView.atYEnd) thymer.running = true } } // onRowsInserted is firing after the model is updated but before the delegate is inflated // causing positionViewAtEnd() to scroll to "just above the last message" // so we use this timer to delay scrolling by a few milliseconds Timer { id: thymer interval: 30 onTriggered: { thymer.running = false messagesListView.positionViewAtEnd() } } contentItem: ListView { id: messagesListView Layout.fillWidth: true width: parent.width model: mm spacing: 6 clip: true ScrollBar.vertical: Opaque.ScrollBar {id:scrollbar} maximumFlickVelocity: 1250 section.delegate: sectionHeading section.property: "Day" header: Component { Column { width: messagesListView.width Label { id: historyWarning wrapMode: Text.WordWrap width: messagesListView.width font.pointSize: Theme.textSmallPt font.weight: Font.Bold color: Theme.chatOverlayWarningTextColor horizontalAlignment: Text.AlignHCenter //: This conversation will be deleted when Cwtch is closed! Message history can be enabled per-conversation via the Settings menu in the upper right. text: overlayRoot.historyState == "DefaultDeleteHistory" ? qsTr("chat-history-default") : ( //: Message history is disabled. overlayRoot.historyState == "DeleteHistoryConfirmed" ? qsTr("chat-history-disabled") : //: Message history is enabled. qsTr("chat-history-enabled") ) } Loader { anchors.horizontalCenter: parent.horizontalCenter height: overlayRoot.historyState == "DefaultDeleteHistory" ? Theme.uiIconSizeM : 0 sourceComponent: overlayRoot.historyState == "DefaultDeleteHistory" ? settingsIcon : undefined } Component { id: settingsIcon Opaque.Icon { backgroundColor: Theme.backgroundMainColor iconColor: Theme.chatOverlayWarningTextColor source: gcd.assetPath + "core/peer_settings-24px.webp" size: Theme.uiIconSizeM sourceWidth: 72 sourceHeight: 72 width: Theme.uiIconSizeM height: Theme.uiIconSizeM } } Opaque.HLine {} } } delegate: W.Message { // unusual msg... syntax is due to qt stack weirdnesses // model injection doesn't work properly because MessageWrapper uses tagged QML properties // but reverting to struct properties prevents us from using mm.getMessage() in onRowsInserted sooooo property variant msg: mm.getMessage(index) property variant obj: JSON.parse(msg.rawMessage) visible: obj.o == 1 height: visible ? implicitHeight : -messagesListView.spacing handle: msg.peerID from: msg.peerID displayName: mm.getNick(msg.peerID) message: obj.o == 1 ? obj.d : "" rawMessage: msg.rawMessage image: mm.getImage(msg.peerID) messageID: msg.signature fromMe: msg.peerID == gcd.selectedProfile timestamp: parseInt(msg.timestamp) ackd: acknowledged error: msg.error calendarEvent: msg.peerID == "calendar" // listview doesnt do anchors right // https://stackoverflow.com/questions/31381997/why-does-anchors-fill-does-not-work-in-a-qml-listviews-delegates-subviews-and/31382307 width: messagesListView.width - scrollbar.width } Component { id: sectionHeading Rectangle {// ⟵ outer rect because anchors._Margin isnt supported here // with qt 5.15+ this↓ can be changed to... // required property string section property string txt: section color: Theme.backgroundMainColor width: parent.width height: texmet.height + 6 + 12// * gcd.themeScale anchors.horizontalCenter: parent.horizontalCenter Rectangle { opacity: 1 width: texmet.width + radius * 4 + 6 height: texmet.height + 6 color: Theme.messageFromOtherBackgroundColor radius: texmet.height / 2 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter Text { id: txtDate // ... and this can be changed to // text: parent.parent.section text: parent.parent.txt font.pixelSize: Theme.chatSize * gcd.themeScale color: Theme.messageFromOtherTextColor anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter } TextMetrics { id: texmet text: txtDate.text font.pixelSize: Theme.chatSize * gcd.themeScale } } } } Connections { target: gcd onClearMessages: function() { messagesListView.model = null messagesListView.model = mm messagesListView.positionViewAtEnd() thymer.running = true } onSupplyPeerSettings: function(onion, nick, authorization, saveHistory) { overlayRoot.historyState = saveHistory } } } onSendClicked: function(messageText) { var msg = JSON.stringify({"o":1, "d":messageText.replace(/\[\:newline\:\]/g,"\n")}) gcd.sendMessage(msg) } }