Skip to content
Snippets Groups Projects
Commit b684bb5c authored by Nicolas Werner's avatar Nicolas Werner
Browse files

Rough image sending

parent c6c128e9
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@ import QtQuick 2.0
import QtQuick.Layouts 1.0
import Sailfish.Silica 1.0
import Sailfish.Silica.private 1.0
import Sailfish.Pickers 1.0
import dev.neko.spoon 1.0
Page {
......@@ -12,206 +13,252 @@ Page {
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
Column {
SilicaFlickable {
anchors.fill: parent
PageHeader {
id: header
Column {
anchors.fill: parent
title: room.roomName()
PageHeader {
id: header
anchors {
left: parent.left
right: parent.right
}
title: room.roomName()
Connections {
target: room
onRoomNameChanged: header.title = name
}
anchors {
left: parent.left
right: parent.right
}
}
Connections {
target: room
onRoomNameChanged: header.title = name
}
SilicaListView {
id: chatView
property bool atEnd: false
property int maxIndex: -1
height: parent.height - bot.height - header.height
contentHeight: height
cacheBuffer: 1000
clip: true
boundsBehavior: Flickable.DragOverBounds
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;
SilicaListView {
id: chatView
property bool atEnd: false
property int maxIndex: -1
height: parent.height - bot.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;
}
}
onMovementEnded: {
atEnd = false;
console.log("movement ended");
if (chatView.atYBeginning) {
console.log("load older messages");
room.fetchOlderMessages();
onCountChanged: {
console.log("atEnd::" + atEnd);
if (atEnd) {
scrollToBottom();
currentIndex = count - 1;
}
}
if (chatView.atYEnd) {
console.log("at end");
atEnd = true;
} else {
console.log("not at end");
onMovementEnded: {
atEnd = false;
}
var lastIndex = maxIndex;
for (var child in chatView.contentItem.children) {
if (chatView.contentItem.children[child].isFullyVisible && chatView.contentItem.children[child].index > maxIndex)
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)
}
if (lastIndex > maxIndex)
maxIndex = lastIndex;
}
onMaxIndexChanged: {
console.log("max index: " + maxIndex);
room.markRead(maxIndex);
}
Component.onCompleted: {
maxIndex = room.lastRead();
if (maxIndex = count - 1)
}
onMaxIndexChanged: {
console.log("max index: " + maxIndex);
room.markRead(maxIndex);
}
Component.onCompleted: {
maxIndex = room.lastRead();
if (maxIndex = count - 1)
atEnd = true;
positionViewAtIndex(maxIndex, ListView.Contain);
}
positionViewAtIndex(maxIndex, ListView.Contain);
}
ScrollDecorator {
flickable: chatView
}
ScrollDecorator {
flickable: chatView
}
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
}
}
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
}
}
}
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
}
Row {
id: bot
Text {
text: room.userIdToUserName(model.UserId)
color: room.userColor(model.UserId, "#00000000")
Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
horizontalAlignment: Text.AlignRight
}
anchors.left: parent.left
anchors.right: parent.right
height: messageText.height
Message {
id: loader
TextArea {
id: messageText
Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
modelData: model
opacity: 1
}
anchors.bottom: parent.bottom
placeholderText: qsTr("Enter your message")
label: qsTr("Matrix")
labelVisible: true
wrapMode: Text.Wrap
width: parent.width - sendButton.width
}
Text {
id: ts
IconButton {
id: sendButton
Layout.alignment: model.IsSender ? Qt.AlignRight : Qt.AlignLeft
text: model.Timestamp.toLocaleString()
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeTiny
horizontalAlignment: Text.AlignRight
}
anchors.top: parent.top
icon.source: "image://theme/icon-m-send"
onClicked: {
if (messageText.text != "")
room.sendTextMessage(messageText.text);
messageText.text = "";
}
}
}
}
Row {
id: bot
PushUpMenu {
MenuItem {
text: qsTr("Send image")
onClicked: pageStack.push(multiImagePickerDialog)
}
anchors.left: parent.left
anchors.right: parent.right
height: messageText.height
MenuItem {
text: qsTr("Send video")
onClicked: console.log("Clicked option 1")
}
TextArea {
id: messageText
MenuItem {
text: qsTr("Send audio")
onClicked: console.log("Clicked option 1")
}
anchors.bottom: parent.bottom
placeholderText: qsTr("Enter your message")
label: qsTr("Matrix")
labelVisible: true
wrapMode: Text.Wrap
width: parent.width - sendButton.width
MenuItem {
text: qsTr("Send file")
onClicked: console.log("Clicked option 1")
}
IconButton {
id: sendButton
}
anchors.top: parent.top
icon.source: "image://theme/icon-m-send"
onClicked: {
if (messageText.text != "")
room.sendTextMessage(messageText.text);
}
messageText.text = "";
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 = ""
}
}
}
......@@ -2,6 +2,8 @@
#include <QGuiApplication>
#include <QFile>
#include <QImageReader>
#include <QMetaType>
#include <QSharedPointer>
#include <QtMath>
......@@ -418,6 +420,50 @@ void Room::sendTextMessage(QString message) {
});
}
void Room::sendImages(QList<QUrl> images, QList<QString> mimetypes) {
for (int i = 0; i < images.size(); i++) {
auto file = QFile(images.at(i).toLocalFile());
if (!file.open(QIODevice::ReadOnly)) {
qCritical() << "Failed to open image" << images.at(i).fileName();
return;
}
auto temp = file.readAll();
std::string data(temp.data(), temp.size());
auto size = QImageReader(images.at(i).toLocalFile()).size();
qDebug() << "Sending image " << images.at(i).fileName() << " size " << size;
http::client().upload(data, mimetypes.at(i).toStdString(), images.at(i).fileName().toStdString(),
[this, size, filesize = temp.size(), filename = images.at(i).fileName().toStdString()](
const mtx::responses::ContentURI &uri, mtx::http::RequestErr err) {
if (err) {
qDebug() << "failed to upload image: " << *err;
return;
}
mtx::events::msg::Image img = {};
img.msgtype = "m.image";
img.body = filename;
img.url = uri.content_uri;
img.info.h = size.height();
img.info.w = size.width();
http::client().send_room_message<msg::Image, mtx::events::EventType::RoomMessage>(
this->id, http::client().generate_txn_id(), img,
[this](const mtx::responses::EventId &res, mtx::http::RequestErr err) {
if (err) {
qDebug() << "failed to send message: " << *err;
return;
}
qDebug()
<< "send event as: $" << QString::fromStdString(res.event_id.to_string());
});
});
}
}
QHash<int, QByteArray> Room::roleNames() const {
QHash<int, QByteArray> roles;
roles[Type] = "Type";
......
......@@ -10,6 +10,8 @@
#include <QColor>
#include <QDateTime>
#include <QString>
#include <QUrl>
#include <QVector>
#include <mtx/events/collections.hpp>
......@@ -168,6 +170,7 @@ struct Room : public QAbstractListModel {
void setUnread(int unread) { this->unreadNotifications = unread; }
void fetchOlderMessages();
void sendTextMessage(QString message);
void sendImages(QList<QUrl> images, QList<QString> mimetypes);
void markRead(int index);
int lastRead();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment