Media Model
Create a media model for all the media message in the timeline and then setup `NeoChatMaximizeComponent` so that it can use the media model to scroll through all loaded images and video in the current room. Depends upon libraries/kirigami-addons!105 FEATURE: 467411
This commit is contained in:
committed by
Tobias Fella
parent
81928d8b93
commit
c55b40c9c6
@@ -36,6 +36,7 @@ add_library(neochat STATIC
|
|||||||
blurhash.cpp
|
blurhash.cpp
|
||||||
blurhashimageprovider.cpp
|
blurhashimageprovider.cpp
|
||||||
models/collapsestateproxymodel.cpp
|
models/collapsestateproxymodel.cpp
|
||||||
|
models/mediamessagefiltermodel.cpp
|
||||||
urlhelper.cpp
|
urlhelper.cpp
|
||||||
windowcontroller.cpp
|
windowcontroller.cpp
|
||||||
linkpreviewer.cpp
|
linkpreviewer.cpp
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#include "models/keywordnotificationrulemodel.h"
|
#include "models/keywordnotificationrulemodel.h"
|
||||||
#include "models/livelocationsmodel.h"
|
#include "models/livelocationsmodel.h"
|
||||||
#include "models/locationsmodel.h"
|
#include "models/locationsmodel.h"
|
||||||
|
#include "models/mediamessagefiltermodel.h"
|
||||||
#include "models/messageeventmodel.h"
|
#include "models/messageeventmodel.h"
|
||||||
#include "models/messagefiltermodel.h"
|
#include "models/messagefiltermodel.h"
|
||||||
#include "models/publicroomlistmodel.h"
|
#include "models/publicroomlistmodel.h"
|
||||||
@@ -237,6 +238,7 @@ int main(int argc, char *argv[])
|
|||||||
qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel");
|
qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel");
|
||||||
qmlRegisterType<ReactionModel>("org.kde.neochat", 1, 0, "ReactionModel");
|
qmlRegisterType<ReactionModel>("org.kde.neochat", 1, 0, "ReactionModel");
|
||||||
qmlRegisterType<CollapseStateProxyModel>("org.kde.neochat", 1, 0, "CollapseStateProxyModel");
|
qmlRegisterType<CollapseStateProxyModel>("org.kde.neochat", 1, 0, "CollapseStateProxyModel");
|
||||||
|
qmlRegisterType<MediaMessageFilterModel>("org.kde.neochat", 1, 0, "MediaMessageFilterModel");
|
||||||
qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel");
|
qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel");
|
||||||
qmlRegisterType<UserFilterModel>("org.kde.neochat", 1, 0, "UserFilterModel");
|
qmlRegisterType<UserFilterModel>("org.kde.neochat", 1, 0, "UserFilterModel");
|
||||||
qmlRegisterType<PublicRoomListModel>("org.kde.neochat", 1, 0, "PublicRoomListModel");
|
qmlRegisterType<PublicRoomListModel>("org.kde.neochat", 1, 0, "PublicRoomListModel");
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
StateEventsRole, /**< List of state events in the aggregated state. */
|
StateEventsRole, /**< List of state events in the aggregated state. */
|
||||||
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
|
AuthorListRole, /**< List of the first 5 unique authors of the aggregated state event. */
|
||||||
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
|
ExcessAuthorsRole, /**< The number of unique authors beyond the first 5. */
|
||||||
|
LastRole, // Keep this last
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
79
src/models/mediamessagefiltermodel.cpp
Normal file
79
src/models/mediamessagefiltermodel.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||||
|
|
||||||
|
#include "mediamessagefiltermodel.h"
|
||||||
|
#include "models/messageeventmodel.h"
|
||||||
|
#include <room.h>
|
||||||
|
|
||||||
|
MediaMessageFilterModel::MediaMessageFilterModel(QObject *parent)
|
||||||
|
: QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaMessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
|
{
|
||||||
|
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||||
|
|
||||||
|
if (index.data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Image
|
||||||
|
|| index.data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Video) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (role == SourceRole) {
|
||||||
|
if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Image) {
|
||||||
|
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["source"].toUrl();
|
||||||
|
} else if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Video) {
|
||||||
|
auto progressInfo = mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>();
|
||||||
|
|
||||||
|
if (progressInfo.completed()) {
|
||||||
|
return mapToSource(index).data(MessageEventModel::ProgressInfoRole).value<Quotient::FileTransferInfo>().localPath;
|
||||||
|
} else {
|
||||||
|
return QUrl();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return QUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (role == TempSourceRole) {
|
||||||
|
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["tempInfo"].toMap()["source"].toUrl();
|
||||||
|
}
|
||||||
|
if (role == TypeRole) {
|
||||||
|
if (mapToSource(index).data(MessageEventModel::DelegateTypeRole).toInt() == MessageEventModel::DelegateType::Image) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (role == CaptionRole) {
|
||||||
|
return mapToSource(index).data(Qt::DisplayRole);
|
||||||
|
}
|
||||||
|
if (role == SourceWidthRole) {
|
||||||
|
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["width"].toFloat();
|
||||||
|
}
|
||||||
|
if (role == SourceHeightRole) {
|
||||||
|
return mapToSource(index).data(MessageEventModel::MediaInfoRole).toMap()["height"].toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceModel()->data(mapToSource(index), role);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> MediaMessageFilterModel::roleNames() const
|
||||||
|
{
|
||||||
|
auto roles = sourceModel()->roleNames();
|
||||||
|
roles[SourceRole] = "source";
|
||||||
|
roles[TempSourceRole] = "tempSource";
|
||||||
|
roles[TypeRole] = "type";
|
||||||
|
roles[CaptionRole] = "caption";
|
||||||
|
roles[SourceWidthRole] = "sourceWidth";
|
||||||
|
roles[SourceHeightRole] = "sourceHeight";
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MediaMessageFilterModel::getRowForSourceItem(int sourceRow) const
|
||||||
|
{
|
||||||
|
return mapFromSource(sourceModel()->index(sourceRow, 0)).row();
|
||||||
|
}
|
||||||
56
src/models/mediamessagefiltermodel.h
Normal file
56
src/models/mediamessagefiltermodel.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include "models/collapsestateproxymodel.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class MediaMessageFilterModel
|
||||||
|
*
|
||||||
|
* This model filters a MessageEventModel for image and video messages.
|
||||||
|
*
|
||||||
|
* @sa MessageEventModel
|
||||||
|
*/
|
||||||
|
class MediaMessageFilterModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Defines the model roles.
|
||||||
|
*/
|
||||||
|
enum Roles {
|
||||||
|
SourceRole = CollapseStateProxyModel::LastRole + 1, /**< The mxc source URL for the item. */
|
||||||
|
TempSourceRole, /**< Source for the temporary content (either blurhash or mxc URL). */
|
||||||
|
TypeRole, /**< The type of the media (image or video). */
|
||||||
|
CaptionRole, /**< The caption for the item. */
|
||||||
|
SourceWidthRole, /**< The width of the source item. */
|
||||||
|
SourceHeightRole, /**< The height of the source item. */
|
||||||
|
};
|
||||||
|
Q_ENUM(Roles)
|
||||||
|
|
||||||
|
MediaMessageFilterModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Custom filter to show only image and video messages.
|
||||||
|
*/
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the given role value at the given index.
|
||||||
|
*
|
||||||
|
* @sa QSortFilterProxyModel::data
|
||||||
|
*/
|
||||||
|
[[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a mapping from Role enum values to role names.
|
||||||
|
*
|
||||||
|
* @sa Roles, QAbstractProxyModel::roleNames()
|
||||||
|
*/
|
||||||
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE int getRowForSourceItem(int sourceRow) const;
|
||||||
|
};
|
||||||
@@ -61,7 +61,7 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
|||||||
roles[ShowReadMarkersRole] = "showReadMarkers";
|
roles[ShowReadMarkersRole] = "showReadMarkers";
|
||||||
roles[ReactionRole] = "reaction";
|
roles[ReactionRole] = "reaction";
|
||||||
roles[ShowReactionsRole] = "showReactions";
|
roles[ShowReactionsRole] = "showReactions";
|
||||||
roles[SourceRole] = "source";
|
roles[SourceRole] = "jsonSource";
|
||||||
roles[MimeTypeRole] = "mimeType";
|
roles[MimeTypeRole] = "mimeType";
|
||||||
roles[AuthorIdRole] = "authorId";
|
roles[AuthorIdRole] = "authorId";
|
||||||
roles[VerifiedRole] = "verified";
|
roles[VerifiedRole] = "verified";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.15 as QQC2
|
import QtQuick.Controls 2.15 as QQC2
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import Qt.labs.platform 1.1
|
import Qt.labs.platform 1.1 as Platform
|
||||||
|
|
||||||
import org.kde.kirigami 2.13 as Kirigami
|
import org.kde.kirigami 2.13 as Kirigami
|
||||||
import org.kde.kirigamiaddons.labs.components 1.0 as Components
|
import org.kde.kirigamiaddons.labs.components 1.0 as Components
|
||||||
@@ -14,39 +14,46 @@ import org.kde.neochat 1.0
|
|||||||
Components.AlbumMaximizeComponent {
|
Components.AlbumMaximizeComponent {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property string eventId
|
readonly property string currentEventId: model.data(model.index(content.currentIndex, 0), MessageEventModel.EventIdRole)
|
||||||
|
|
||||||
required property var time
|
readonly property var currentAuthor: model.data(model.index(content.currentIndex, 0), MessageEventModel.AuthorRole)
|
||||||
|
|
||||||
required property var author
|
readonly property var currentTime: model.data(model.index(content.currentIndex, 0), MessageEventModel.TimeRole)
|
||||||
|
|
||||||
required property int delegateType
|
readonly property string currentPlainText: model.data(model.index(content.currentIndex, 0), MessageEventModel.PlainText)
|
||||||
|
|
||||||
required property string plainText
|
readonly property var currentMimeType: model.data(model.index(content.currentIndex, 0), MessageEventModel.MimeTypeRole)
|
||||||
|
|
||||||
required property string caption
|
readonly property var currentProgressInfo: model.data(model.index(content.currentIndex, 0), MessageEventModel.ProgressInfoRole)
|
||||||
|
|
||||||
required property var mediaInfo
|
readonly property var currentJsonSource: model.data(model.index(content.currentIndex, 0), MessageEventModel.SourceRole)
|
||||||
|
|
||||||
required property var progressInfo
|
autoLoad: false
|
||||||
|
|
||||||
required property var mimeType
|
downloadAction: Components.DownloadAction {
|
||||||
|
id: downloadAction
|
||||||
required property var source
|
onTriggered: {
|
||||||
|
currentRoom.downloadFile(root.currentEventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + root.currentEventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(root.currentEventId))
|
||||||
property list<Components.AlbumModelItem> items: [
|
|
||||||
Components.AlbumModelItem {
|
|
||||||
type: root.delegateType === MessageEventModel.Image || root.delegateType === MessageEventModel.Sticker ? Components.AlbumModelItem.Image : Components.AlbumModelItem.Video
|
|
||||||
source: root.delegateType === MessageEventModel.Video ? root.progressInfo.localPath : root.mediaInfo.source
|
|
||||||
tempSource: root.mediaInfo.tempInfo.source
|
|
||||||
caption: root.caption
|
|
||||||
sourceWidth: root.mediaInfo.width
|
|
||||||
sourceHeight: root.mediaInfo.height
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
model: items
|
Connections {
|
||||||
initialIndex: 0
|
target: currentRoom
|
||||||
|
|
||||||
|
function onFileTransferProgress(id, progress, total) {
|
||||||
|
if (id == root.currentEventId) {
|
||||||
|
downloadAction.progress = progress / total * 100.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: content
|
||||||
|
|
||||||
|
function onCurrentIndexChanged() {
|
||||||
|
downloadAction.progress = currentProgressInfo.progress / currentProgressInfo.total * 100.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leading: RowLayout {
|
leading: RowLayout {
|
||||||
Kirigami.Avatar {
|
Kirigami.Avatar {
|
||||||
@@ -54,22 +61,23 @@ Components.AlbumMaximizeComponent {
|
|||||||
implicitWidth: Kirigami.Units.iconSizes.medium
|
implicitWidth: Kirigami.Units.iconSizes.medium
|
||||||
implicitHeight: Kirigami.Units.iconSizes.medium
|
implicitHeight: Kirigami.Units.iconSizes.medium
|
||||||
|
|
||||||
name: root.author.displayName
|
name: root.currentAuthor.name ?? root.currentAuthor.displayName
|
||||||
source: root.author.avatarSource
|
source: root.currentAuthor.avatarSource
|
||||||
color: root.author.color
|
color: root.currentAuthor.color
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 0
|
spacing: 0
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
id: userLabel
|
id: userLabel
|
||||||
text: root.author.displayName
|
|
||||||
color: root.author.color
|
text: root.currentAuthor.name ?? root.currentAuthor.displayName
|
||||||
|
color: root.currentAuthor.color
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
id: dateTimeLabel
|
id: dateTimeLabel
|
||||||
text: root.time.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
text: root.currentTime.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||||
color: Kirigami.Theme.disabledTextColor
|
color: Kirigami.Theme.disabledTextColor
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
@@ -77,13 +85,13 @@ Components.AlbumMaximizeComponent {
|
|||||||
}
|
}
|
||||||
onItemRightClicked: {
|
onItemRightClicked: {
|
||||||
const contextMenu = fileDelegateContextMenu.createObject(parent, {
|
const contextMenu = fileDelegateContextMenu.createObject(parent, {
|
||||||
author: root.author,
|
author: root.currentAuthor,
|
||||||
eventId: root.eventId,
|
eventId: root.currentEventId,
|
||||||
source: root.source,
|
source: root.currentJsonSource,
|
||||||
file: parent,
|
file: parent,
|
||||||
mimeType: root.mimeType,
|
mimeType: root.currentMimeType,
|
||||||
progressInfo: root.progressInfo,
|
progressInfo: root.currentProgressInfo,
|
||||||
plainText: root.plainText,
|
plainMessage: root.currentPlainText
|
||||||
});
|
});
|
||||||
contextMenu.closeFullscreen.connect(root.close)
|
contextMenu.closeFullscreen.connect(root.close)
|
||||||
contextMenu.open();
|
contextMenu.open();
|
||||||
@@ -91,12 +99,12 @@ Components.AlbumMaximizeComponent {
|
|||||||
onSaveItem: {
|
onSaveItem: {
|
||||||
var dialog = saveAsDialog.createObject(QQC2.ApplicationWindow.overlay)
|
var dialog = saveAsDialog.createObject(QQC2.ApplicationWindow.overlay)
|
||||||
dialog.open()
|
dialog.open()
|
||||||
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(root.eventId)
|
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(root.currentEventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: saveAsDialog
|
id: saveAsDialog
|
||||||
FileDialog {
|
Platform.FileDialog {
|
||||||
fileMode: FileDialog.SaveFile
|
fileMode: FileDialog.SaveFile
|
||||||
folder: root.saveFolder
|
folder: root.saveFolder
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
|
|||||||
@@ -147,32 +147,10 @@ TimelineContainer {
|
|||||||
img.QQC2.ToolTip.hide()
|
img.QQC2.ToolTip.hide()
|
||||||
img.paused = true
|
img.paused = true
|
||||||
root.ListView.view.interactive = false
|
root.ListView.view.interactive = false
|
||||||
var popup = maximizeImageComponent.createObject(QQC2.ApplicationWindow.overlay, {
|
root.ListView.view.showMaximizedMedia(root.index)
|
||||||
eventId: root.eventId,
|
|
||||||
time: root.time,
|
|
||||||
author: root.author,
|
|
||||||
delegateType: root.delegateType,
|
|
||||||
plainText: root.plainText,
|
|
||||||
caption: root.display,
|
|
||||||
mediaInfo: root.mediaInfo,
|
|
||||||
progressInfo: root.progressInfo,
|
|
||||||
mimeType: root.mimeType,
|
|
||||||
source: root.source
|
|
||||||
})
|
|
||||||
popup.closed.connect(() => {
|
|
||||||
root.ListView.view.interactive = true
|
|
||||||
img.paused = false
|
|
||||||
popup.destroy()
|
|
||||||
})
|
|
||||||
popup.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
|
||||||
id: maximizeImageComponent
|
|
||||||
NeochatMaximizeComponent {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadAndOpen() {
|
function downloadAndOpen() {
|
||||||
if (downloaded) {
|
if (downloaded) {
|
||||||
openSavedFile()
|
openSavedFile()
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ ColumnLayout {
|
|||||||
/**
|
/**
|
||||||
* @brief The full message source JSON.
|
* @brief The full message source JSON.
|
||||||
*/
|
*/
|
||||||
required property var source
|
required property var jsonSource
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The x position of the message bubble.
|
* @brief The x position of the message bubble.
|
||||||
@@ -590,7 +590,7 @@ ColumnLayout {
|
|||||||
const contextMenu = fileDelegateContextMenu.createObject(root, {
|
const contextMenu = fileDelegateContextMenu.createObject(root, {
|
||||||
author: root.author,
|
author: root.author,
|
||||||
eventId: root.eventId,
|
eventId: root.eventId,
|
||||||
source: root.source,
|
source: root.jsonSource,
|
||||||
file: file,
|
file: file,
|
||||||
mimeType: root.mimeType,
|
mimeType: root.mimeType,
|
||||||
progressInfo: root.progressInfo,
|
progressInfo: root.progressInfo,
|
||||||
@@ -605,7 +605,7 @@ ColumnLayout {
|
|||||||
selectedText: selectedText,
|
selectedText: selectedText,
|
||||||
author: root.author,
|
author: root.author,
|
||||||
eventId: root.eventId,
|
eventId: root.eventId,
|
||||||
source: root.source,
|
source: root.jsonSource,
|
||||||
eventType: root.delegateType,
|
eventType: root.delegateType,
|
||||||
plainText: root.plainText,
|
plainText: root.plainText,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -355,30 +355,10 @@ TimelineContainer {
|
|||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.ListView.view.interactive = false
|
root.ListView.view.interactive = false
|
||||||
vid.pause()
|
vid.pause()
|
||||||
var popup = maximizeVideoComponent.createObject(QQC2.ApplicationWindow.overlay, {
|
root.ListView.view.showMaximizedMedia(root.index)
|
||||||
eventId: root.eventId,
|
|
||||||
time: root.time,
|
|
||||||
author: root.author,
|
|
||||||
delegateType: root.delegateType,
|
|
||||||
plainText: root.plainText,
|
|
||||||
caption: root.display,
|
|
||||||
mediaInfo: root.mediaInfo,
|
|
||||||
progressInfo: root.progressInfo,
|
|
||||||
mimeType: root.mimeType,
|
|
||||||
source: root.source
|
|
||||||
})
|
|
||||||
popup.closed.connect(() => {
|
|
||||||
root.ListView.view.interactive = true
|
|
||||||
popup.destroy()
|
|
||||||
})
|
|
||||||
popup.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component {
|
|
||||||
id: maximizeVideoComponent
|
|
||||||
NeochatMaximizeComponent {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
background: Kirigami.ShadowedRectangle {
|
background: Kirigami.ShadowedRectangle {
|
||||||
radius: 4
|
radius: 4
|
||||||
|
|||||||
@@ -40,14 +40,16 @@ QQC2.ScrollView {
|
|||||||
|
|
||||||
model: !isLoaded ? undefined : collapseStateProxyModel
|
model: !isLoaded ? undefined : collapseStateProxyModel
|
||||||
|
|
||||||
|
MessageEventModel {
|
||||||
|
id: messageEventModel
|
||||||
|
room: root.currentRoom
|
||||||
|
}
|
||||||
|
|
||||||
CollapseStateProxyModel {
|
CollapseStateProxyModel {
|
||||||
id: collapseStateProxyModel
|
id: collapseStateProxyModel
|
||||||
sourceModel: MessageFilterModel {
|
sourceModel: MessageFilterModel {
|
||||||
id: sortedMessageEventModel
|
id: sortedMessageEventModel
|
||||||
sourceModel: MessageEventModel {
|
sourceModel: messageEventModel
|
||||||
id: messageEventModel
|
|
||||||
room: root.currentRoom
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +397,28 @@ QQC2.ScrollView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaMessageFilterModel {
|
||||||
|
id: mediaMessageFilterModel
|
||||||
|
sourceModel: collapseStateProxyModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: maximizeComponent
|
||||||
|
NeochatMaximizeComponent {
|
||||||
|
model: mediaMessageFilterModel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMaximizedMedia(index) {
|
||||||
|
var popup = maximizeComponent.createObject(QQC2.ApplicationWindow.overlay, {
|
||||||
|
initialIndex: index === -1 ? -1 : mediaMessageFilterModel.getRowForSourceItem(index)
|
||||||
|
})
|
||||||
|
popup.closed.connect(() => {
|
||||||
|
messageListView.interactive = true
|
||||||
|
popup.destroy()
|
||||||
|
})
|
||||||
|
popup.open()
|
||||||
|
}
|
||||||
|
|
||||||
function showUserDetail(user) {
|
function showUserDetail(user) {
|
||||||
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, {
|
||||||
|
|||||||
Reference in New Issue
Block a user