Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ChatPage.qml 8.46 KiB
import QtQuick 2.0
import QtQuick.Layouts 1.0
import Sailfish.Pickers 1.0
import Sailfish.Silica 1.0
import Sailfish.Silica.private 1.0
import dev.neko.spoon 1.0

Page {
    id: chatPage

    property alias room: chatView.model

    // The effective value will be restricted by ApplicationWindow.allowedOrientations
    allowedOrientations: Orientation.All

    SilicaFlickable {
        anchors.fill: parent

        Column {
            anchors.fill: parent

            PageHeader {
                id: header

                title: room.name
            }

            SilicaListView {
                id: chatView

                property bool atEnd: false
                property int maxIndex: -1

                height: parent.height - header.height
                contentHeight: height
                cacheBuffer: 1000
                clip: true
                boundsBehavior: Flickable.StopAtBounds
                anchors.left: parent.left
                anchors.right: parent.right
                ListView.onAdd: {
                    console.log("atYEnd::" + atYEnd);
                    atEnd = atYEnd;
                }
                onCountChanged: {
                    console.log("atEnd::" + atEnd);
                    if (atEnd) {
                        scrollToBottom();
                        currentIndex = count - 1;
                    }
                }
                onMovementEnded: {
                    atEnd = false;
                    console.log("movement ended");
                    if (chatView.atYBeginning) {
                        console.log("load older messages");
                        room.fetchOlderMessages();
                    }
                    if (chatView.atYEnd) {
                        console.log("at end");
                        atEnd = true;
                    } else {
                        console.log("not at end");
                        atEnd = false;
                    }
                    var lastIndex = maxIndex;
                    for (var child in chatView.contentItem.children) {
                        if (chatView.contentItem.children[child].isFullyVisible && chatView.contentItem.children[child].index > maxIndex)
                            lastIndex = chatView.contentItem.children[child].index;
                    }
                    if (lastIndex > maxIndex)
                        maxIndex = lastIndex;

                }
                onMaxIndexChanged: {
                    console.log("max index: " + maxIndex);
                    room.markRead(maxIndex);
                }
                Component.onCompleted: {
                    maxIndex = room.lastRead();
                    if (maxIndex = count - 1)
                        atEnd = true;

                    positionViewAtIndex(maxIndex, ListView.Contain);
                }

                ScrollDecorator {
                    flickable: chatView
                }

                footer: Row {
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height: messageText.height

                    TextArea {
                        id: messageText

                        anchors.bottom: parent.bottom
                        placeholderText: qsTr("Enter your message")
                        label: qsTr("Matrix")
                        labelVisible: true
                        wrapMode: Text.Wrap
                        width: parent.width - sendButton.width
                    }

                    IconButton {
                        id: sendButton

                        anchors.top: parent.top
                        icon.source: "image://theme/icon-m-send"
                        onClicked: {
                            if (messageText.text != "")
                                room.sendTextMessage(messageText.text);

                            messageText.text = "";
                        }
                    }

                }

                delegate: ListItem {
                    id: messageItem

                    contentHeight: content.height + 2 * Theme.paddingMedium
                    width: chatView.width

                    BubbleBackground {
                        id: bubble

                        property int fullMessageWidth: parent.width - 2 * Theme.paddingLarge
                        property int yoff: Math.round(messageItem.y - chatView.contentY - 1)
                        property bool isFullyVisible: yoff + messageItem.height < chatView.height
                        property int index: model.index

                        color: Theme.rgba(Theme.primaryColor, Theme.opacityFaint)
                        opacity: model.IsSender ? Theme.opacityFaint : Theme.opacityHigh
                        radius: Theme.paddingLarge
                        height: content.implicitHeight + 2 * Theme.paddingSmall
                        width: content.implicitWidth + 2 * Theme.paddingSmall
                        roundedCorners: BubbleBackground.NoCorners | (model.IsSender ? BubbleBackground.BottomLeft : BubbleBackground.BottomRight)

                        anchors {
                            topMargin: Theme.paddingSmall
                            bottomMargin: Theme.paddingSmall
                            leftMargin: Theme.paddingMedium
                            rightMargin: Theme.paddingMedium
                            right: model.IsSender ? parent.right : undefined
                            left: !model.IsSender ? parent.left : undefined
                            top: parent.top
                            bottom: parent.bottom
                        }

                        Behavior on width {
                            NumberAnimation {
                                duration: 100
                                easing.type: Easing.InOutQuad
                            }

                        }

                    }

                    ColumnLayout {
                        id: content

                        anchors {
                            margins: Theme.paddingSmall
                            right: model.IsSender ? bubble.right : undefined
                            left: !model.IsSender ? bubble.left : undefined
                            top: bubble.top
                            bottom: bubble.bottom
                        }

                        Text {
                            text: room.userIdToUserName(model.UserId)
                            color: room.userColor(model.UserId, "#00000000")
                            Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
                            horizontalAlignment: Text.AlignRight
                        }

                        Message {
                            id: loader

                            Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
                            modelData: model
                            opacity: 1
                        }

                        Text {
                            id: ts

                            Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
                            text: model.Timestamp.toLocaleString()
                            color: Theme.highlightColor
                            font.pixelSize: Theme.fontSizeTiny
                            horizontalAlignment: Text.AlignRight
                        }

                    }

                }

            }

        }

        PushUpMenu {
            MenuItem {
                text: qsTr("Send image")
                onClicked: pageStack.push(multiImagePickerDialog)
            }

            MenuItem {
                text: qsTr("Send video")
                onClicked: console.log("Clicked option 1")
            }

            MenuItem {
                text: qsTr("Send audio")
                onClicked: console.log("Clicked option 1")
            }

            MenuItem {
                text: qsTr("Send file")
                onClicked: console.log("Clicked option 1")
            }

        }

    }

    Component {
        id: multiImagePickerDialog

        MultiImagePickerDialog {
            onAccepted: {
                var urls = [];
                var mimetypes = [];
                for (var i = 0; i < selectedContent.count; ++i) {
                    urls.push(selectedContent.get(i).url);
                    mimetypes.push(selectedContent.get(i).mimeType);
                }
                room.sendImages(urls, mimetypes);
            }
            onRejected: selectedFiles = ""
        }

    }

}