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

Add simple audio message widget

parent a8166462
No related branches found
No related tags found
No related merge requests found
......@@ -113,6 +113,7 @@ Rectangle {
case MtxEvent.ImageMessage: return "delegates/ImageMessage.qml"
case MtxEvent.FileMessage: return "delegates/FileMessage.qml"
//case MtxEvent.VideoMessage: return "delegates/VideoMessage.qml"
case MtxEvent.AudioMessage: return "delegates/AudioMessage.qml"
case MtxEvent.Redacted: return "delegates/Redacted.qml"
default: return "delegates/placeholder.qml"
}
......
import QtQuick 2.6
import QtQuick.Layouts 1.6
import QtMultimedia 5.12
Rectangle {
radius: 10
color: colors.dark
height: row.height + 24
width: parent.width
RowLayout {
id: row
anchors.centerIn: parent
width: parent.width - 24
spacing: 15
Rectangle {
id: button
color: colors.light
radius: 22
height: 44
width: 44
Image {
id: img
anchors.centerIn: parent
source: "qrc:/icons/icons/ui/arrow-pointing-down.png"
fillMode: Image.Pad
}
MouseArea {
anchors.fill: parent
onClicked: {
switch (button.state) {
case "": timelineManager.cacheMedia(eventData.url, eventData.mimetype); break;
case "stopped":
audio.play(); console.log("play");
button.state = "playing"
break
case "playing":
audio.pause(); console.log("pause");
button.state = "stopped"
break
}
}
cursorShape: Qt.PointingHandCursor
}
MediaPlayer {
id: audio
onError: console.log(errorString)
}
Connections {
target: timelineManager
onMediaCached: {
if (mxcUrl == eventData.url) {
audio.source = "file://" + cacheUrl
button.state = "stopped"
console.log("media loaded: " + mxcUrl + " at " + cacheUrl)
}
console.log("media cached: " + mxcUrl + " at " + cacheUrl)
}
}
states: [
State {
name: "stopped"
PropertyChanges { target: img; source: "qrc:/icons/icons/ui/play-sign.png" }
},
State {
name: "playing"
PropertyChanges { target: img; source: "qrc:/icons/icons/ui/pause-symbol.png" }
}
]
}
ColumnLayout {
id: col
Text {
Layout.fillWidth: true
text: eventData.body
textFormat: Text.PlainText
elide: Text.ElideRight
color: colors.text
}
Text {
Layout.fillWidth: true
text: eventData.filesize
textFormat: Text.PlainText
elide: Text.ElideRight
color: colors.text
}
}
}
}
import QtQuick 2.6
import QtQuick.Layouts 1.6
Row {
Rectangle {
radius: 10
color: colors.dark
height: row.height
width: row.width
height: row.height + 24
width: parent.width
Row {
RowLayout {
id: row
anchors.centerIn: parent
width: parent.width - 24
spacing: 15
padding: 12
Rectangle {
id: button
color: colors.light
radius: 22
height: 44
......@@ -32,26 +35,23 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
}
}
Column {
TextEdit {
ColumnLayout {
id: col
Text {
Layout.fillWidth: true
text: eventData.body
textFormat: TextEdit.PlainText
readOnly: true
wrapMode: Text.Wrap
selectByMouse: true
textFormat: Text.PlainText
elide: Text.ElideRight
color: colors.text
}
TextEdit {
Text {
Layout.fillWidth: true
text: eventData.filesize
textFormat: TextEdit.PlainText
readOnly: true
wrapMode: Text.Wrap
selectByMouse: true
textFormat: Text.PlainText
elide: Text.ElideRight
color: colors.text
}
}
}
}
Rectangle {
}
}
......@@ -122,6 +122,7 @@
<file>qml/delegates/TextMessage.qml</file>
<file>qml/delegates/NoticeMessage.qml</file>
<file>qml/delegates/ImageMessage.qml</file>
<file>qml/delegates/AudioMessage.qml</file>
<file>qml/delegates/FileMessage.qml</file>
<file>qml/delegates/Redacted.qml</file>
<file>qml/delegates/placeholder.qml</file>
......
......@@ -4,6 +4,7 @@
#include <QMetaType>
#include <QMimeDatabase>
#include <QQmlContext>
#include <QStandardPaths>
#include "Logging.h"
#include "MxcImageProvider.h"
......@@ -143,6 +144,64 @@ TimelineViewManager::saveMedia(QString mxcUrl,
});
}
void
TimelineViewManager::cacheMedia(QString mxcUrl, QString mimeType)
{
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {
emit mediaCached(mxcUrl, mxcUrl);
return;
}
QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix();
const auto url = mxcUrl.toStdString();
QFileInfo filename(QString("%1/media_cache/%2.%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.arg(QString(mxcUrl).remove("mxc://"))
.arg(suffix));
if (QDir::cleanPath(filename.path()) != filename.path()) {
nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url);
return;
}
QDir().mkpath(filename.path());
if (filename.isReadable()) {
emit mediaCached(mxcUrl, filename.filePath());
return;
}
http::client()->download(
url,
[this, mxcUrl, filename, url](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve image {}: {} {}",
url,
err->matrix_error.error,
static_cast<int>(err->status_code));
return;
}
try {
QFile file(filename.filePath());
if (!file.open(QIODevice::WriteOnly))
return;
file.write(QByteArray(data.data(), data.size()));
file.close();
} catch (const std::exception &e) {
nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
emit mediaCached(mxcUrl, filename.filePath());
});
}
void
TimelineViewManager::updateReadReceipts(const QString &room_id,
const std::vector<QString> &event_ids)
......
......@@ -42,6 +42,7 @@ public:
QString originalFilename,
QString mimeType,
qml_mtx_events::EventType eventType) const;
Q_INVOKABLE void cacheMedia(QString mxcUrl, QString mimeType);
// Qml can only pass enum as int
Q_INVOKABLE void openImageOverlay(QString mxcUrl,
QString originalFilename,
......@@ -63,6 +64,7 @@ signals:
void clearRoomMessageCount(QString roomid);
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
void activeTimelineChanged(TimelineModel *timeline);
void mediaCached(QString mxcUrl, QString cacheUrl);
public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
......
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