mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 03:00:46 +03:00
Add menu to enable or disable stickers globally
This commit is contained in:
parent
0c798554b5
commit
eafbab6ae1
16 changed files with 674 additions and 17 deletions
|
@ -355,6 +355,8 @@ set(SRC_FILES
|
|||
src/RegisterPage.cpp
|
||||
src/SSOHandler.cpp
|
||||
src/CombinedImagePackModel.cpp
|
||||
src/SingleImagePackModel.cpp
|
||||
src/ImagePackListModel.cpp
|
||||
src/TrayIcon.cpp
|
||||
src/UserSettingsPage.cpp
|
||||
src/UsersModel.cpp
|
||||
|
@ -559,6 +561,8 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||
src/RegisterPage.h
|
||||
src/SSOHandler.h
|
||||
src/CombinedImagePackModel.h
|
||||
src/SingleImagePackModel.h
|
||||
src/ImagePackListModel.h
|
||||
src/TrayIcon.h
|
||||
src/UserSettingsPage.h
|
||||
src/UsersModel.h
|
||||
|
|
|
@ -249,6 +249,17 @@ ApplicationWindow {
|
|||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Sticker & Emote Settings")
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Change")
|
||||
ToolTip.text: qsTr("Change what packs are enabled, remove packs or create new ones")
|
||||
onClicked: TimelineManager.openImagePackSettings(roomSettings.roomId)
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Item {
|
||||
// for adding extra space between sections
|
||||
Layout.fillWidth: true
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import "./delegates"
|
||||
import "./device-verification"
|
||||
import "./dialogs"
|
||||
import "./emoji"
|
||||
import "./voip"
|
||||
import Qt.labs.platform 1.1 as Platform
|
||||
|
@ -87,6 +88,14 @@ Page {
|
|||
|
||||
}
|
||||
|
||||
Component {
|
||||
id: packSettingsComponent
|
||||
|
||||
ImagePackSettingsDialog {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Ctrl+K"
|
||||
onActivated: {
|
||||
|
@ -120,6 +129,12 @@ Page {
|
|||
});
|
||||
userProfile.show();
|
||||
}
|
||||
onShowImagePackSettings: {
|
||||
var packSet = packSettingsComponent.createObject(timelineRoot, {
|
||||
"packlist": packlist
|
||||
});
|
||||
packSet.show();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
|
309
resources/qml/dialogs/ImagePackSettingsDialog.qml
Normal file
309
resources/qml/dialogs/ImagePackSettingsDialog.qml
Normal file
|
@ -0,0 +1,309 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import ".."
|
||||
import "../components"
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import im.nheko 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: win
|
||||
|
||||
property ImagePackListModel packlist
|
||||
property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3)
|
||||
property SingleImagePackModel currentPack: packlist.packAt(currentPackIndex)
|
||||
property int currentPackIndex: 0
|
||||
readonly property int stickerDim: 128
|
||||
readonly property int stickerDimPad: 128 + Nheko.paddingSmall
|
||||
|
||||
title: qsTr("Image pack settings")
|
||||
x: MainWindow.x + (MainWindow.width / 2) - (width / 2)
|
||||
y: MainWindow.y + (MainWindow.height / 2) - (height / 2)
|
||||
height: 400
|
||||
width: 600
|
||||
palette: Nheko.colors
|
||||
color: Nheko.colors.base
|
||||
modality: Qt.NonModal
|
||||
flags: Qt.Dialog
|
||||
|
||||
AdaptiveLayout {
|
||||
id: adaptiveView
|
||||
|
||||
anchors.fill: parent
|
||||
singlePageMode: false
|
||||
pageIndex: 0
|
||||
|
||||
AdaptiveLayoutElement {
|
||||
id: packlistC
|
||||
|
||||
visible: Settings.groupView
|
||||
minimumWidth: 200
|
||||
collapsedWidth: 200
|
||||
preferredWidth: 300
|
||||
maximumWidth: 300
|
||||
|
||||
ListView {
|
||||
model: packlist
|
||||
clip: true
|
||||
|
||||
ScrollHelper {
|
||||
flickable: parent
|
||||
anchors.fill: parent
|
||||
enabled: !Settings.mobileMode
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
id: packItem
|
||||
|
||||
property color background: Nheko.colors.window
|
||||
property color importantText: Nheko.colors.text
|
||||
property color unimportantText: Nheko.colors.buttonText
|
||||
property color bubbleBackground: Nheko.colors.highlight
|
||||
property color bubbleText: Nheko.colors.highlightedText
|
||||
required property string displayName
|
||||
required property string avatarUrl
|
||||
required property bool fromAccountData
|
||||
required property bool fromCurrentRoom
|
||||
required property int index
|
||||
|
||||
color: background
|
||||
height: avatarSize + 2 * Nheko.paddingMedium
|
||||
width: ListView.view.width
|
||||
state: "normal"
|
||||
states: [
|
||||
State {
|
||||
name: "highlight"
|
||||
when: hovered.hovered && !(index == currentPackIndex)
|
||||
|
||||
PropertyChanges {
|
||||
target: packItem
|
||||
background: Nheko.colors.dark
|
||||
importantText: Nheko.colors.brightText
|
||||
unimportantText: Nheko.colors.brightText
|
||||
bubbleBackground: Nheko.colors.highlight
|
||||
bubbleText: Nheko.colors.highlightedText
|
||||
}
|
||||
|
||||
},
|
||||
State {
|
||||
name: "selected"
|
||||
when: index == currentPackIndex
|
||||
|
||||
PropertyChanges {
|
||||
target: packItem
|
||||
background: Nheko.colors.highlight
|
||||
importantText: Nheko.colors.highlightedText
|
||||
unimportantText: Nheko.colors.highlightedText
|
||||
bubbleBackground: Nheko.colors.highlightedText
|
||||
bubbleText: Nheko.colors.highlight
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
TapHandler {
|
||||
margin: -Nheko.paddingSmall
|
||||
onSingleTapped: currentPackIndex = index
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hovered
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Nheko.paddingMedium
|
||||
anchors.fill: parent
|
||||
anchors.margins: Nheko.paddingMedium
|
||||
|
||||
Avatar {
|
||||
// In the future we could show an online indicator by setting the userid for the avatar
|
||||
//userid: Nheko.currentUser.userid
|
||||
|
||||
id: avatar
|
||||
|
||||
enabled: false
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
height: avatarSize
|
||||
width: avatarSize
|
||||
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
displayName: packItem.displayName
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: textContent
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 100
|
||||
width: parent.width - avatar.width
|
||||
Layout.preferredWidth: parent.width - avatar.width
|
||||
spacing: Nheko.paddingSmall
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ElidedLabel {
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
color: packItem.importantText
|
||||
elideWidth: textContent.width - Nheko.paddingMedium
|
||||
fullText: displayName
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ElidedLabel {
|
||||
color: packItem.unimportantText
|
||||
font.pixelSize: fontMetrics.font.pixelSize * 0.9
|
||||
elideWidth: textContent.width - Nheko.paddingSmall
|
||||
fullText: {
|
||||
if (fromAccountData)
|
||||
return qsTr("Private pack");
|
||||
else if (fromCurrentRoom)
|
||||
return qsTr("Pack from this room");
|
||||
else
|
||||
return qsTr("Globally enabled pack");
|
||||
}
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AdaptiveLayoutElement {
|
||||
id: packinfoC
|
||||
|
||||
Rectangle {
|
||||
color: Nheko.colors.window
|
||||
|
||||
ColumnLayout {
|
||||
id: packinfo
|
||||
|
||||
property string packName: currentPack ? currentPack.packname : ""
|
||||
property string avatarUrl: currentPack ? currentPack.avatarUrl : ""
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Nheko.paddingLarge
|
||||
spacing: Nheko.paddingLarge
|
||||
|
||||
Avatar {
|
||||
url: packinfo.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
displayName: packinfo.packName
|
||||
height: 100
|
||||
width: 100
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
enabled: false
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: packinfo.packName
|
||||
font.pixelSize: 24
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: currentPack && currentPack.roomid != ""
|
||||
columns: 2
|
||||
rowSpacing: Nheko.paddingMedium
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Enable globally")
|
||||
}
|
||||
|
||||
ToggleButton {
|
||||
ToolTip.text: qsTr("Enables this pack to be used in all rooms")
|
||||
checked: currentPack ? currentPack.isGloballyEnabled : false
|
||||
onClicked: currentPack.isGloballyEnabled = !currentPack.isGloballyEnabled
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GridView {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
model: currentPack
|
||||
cellWidth: stickerDimPad
|
||||
cellHeight: stickerDimPad
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
clip: true
|
||||
currentIndex: -1 // prevent sorting from stealing focus
|
||||
cacheBuffer: 500
|
||||
|
||||
ScrollHelper {
|
||||
flickable: parent
|
||||
anchors.fill: parent
|
||||
enabled: !Settings.mobileMode
|
||||
}
|
||||
|
||||
// Individual emoji
|
||||
delegate: AbstractButton {
|
||||
width: stickerDim
|
||||
height: stickerDim
|
||||
hoverEnabled: true
|
||||
ToolTip.text: ":" + model.shortcode + ": - " + model.body
|
||||
ToolTip.visible: hovered
|
||||
|
||||
contentItem: Image {
|
||||
height: stickerDim
|
||||
width: stickerDim
|
||||
source: model.url.replace("mxc://", "image://MxcImage/")
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: hovered ? Nheko.colors.highlight : 'transparent'
|
||||
radius: 5
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
footer: DialogButtonBox {
|
||||
id: buttons
|
||||
|
||||
Button {
|
||||
text: qsTr("Close")
|
||||
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
|
||||
onClicked: win.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -160,6 +160,7 @@
|
|||
<file>qml/device-verification/Failed.qml</file>
|
||||
<file>qml/device-verification/Success.qml</file>
|
||||
<file>qml/dialogs/InputDialog.qml</file>
|
||||
<file>qml/dialogs/ImagePackSettingsDialog.qml</file>
|
||||
<file>qml/ui/Ripple.qml</file>
|
||||
<file>qml/ui/Spinner.qml</file>
|
||||
<file>qml/ui/animations/BlinkAnimation.qml</file>
|
||||
|
|
|
@ -3383,26 +3383,30 @@ Cache::getChildRoomIds(const std::string &room_id)
|
|||
}
|
||||
|
||||
std::vector<ImagePackInfo>
|
||||
Cache::getImagePacks(const std::string &room_id, bool stickers)
|
||||
Cache::getImagePacks(const std::string &room_id, std::optional<bool> stickers)
|
||||
{
|
||||
auto txn = ro_txn(env_);
|
||||
std::vector<ImagePackInfo> infos;
|
||||
|
||||
auto addPack = [&infos, stickers](const mtx::events::msc2545::ImagePack &pack) {
|
||||
if (!pack.pack || (stickers ? pack.pack->is_sticker() : pack.pack->is_emoji())) {
|
||||
auto addPack = [&infos, stickers](const mtx::events::msc2545::ImagePack &pack,
|
||||
const std::string &source_room,
|
||||
const std::string &state_key) {
|
||||
if (!pack.pack || !stickers.has_value() ||
|
||||
(stickers.value() ? pack.pack->is_sticker() : pack.pack->is_emoji())) {
|
||||
ImagePackInfo info;
|
||||
if (pack.pack)
|
||||
info.packname = pack.pack->display_name;
|
||||
info.source_room = source_room;
|
||||
info.state_key = state_key;
|
||||
info.pack.pack = pack.pack;
|
||||
|
||||
for (const auto &img : pack.images) {
|
||||
if (img.second.overrides_usage() &&
|
||||
(stickers ? !img.second.is_sticker() : !img.second.is_emoji()))
|
||||
continue;
|
||||
|
||||
info.images.insert(img);
|
||||
info.pack.images.insert(img);
|
||||
}
|
||||
|
||||
if (!info.images.empty())
|
||||
if (!info.pack.images.empty())
|
||||
infos.push_back(std::move(info));
|
||||
}
|
||||
};
|
||||
|
@ -3414,7 +3418,7 @@ Cache::getImagePacks(const std::string &room_id, bool stickers)
|
|||
std::get_if<mtx::events::EphemeralEvent<mtx::events::msc2545::ImagePack>>(
|
||||
&*accountpack);
|
||||
if (tmp)
|
||||
addPack(tmp->content);
|
||||
addPack(tmp->content, "", "");
|
||||
}
|
||||
|
||||
// packs from rooms, that were enabled globally
|
||||
|
@ -3433,7 +3437,7 @@ Cache::getImagePacks(const std::string &room_id, bool stickers)
|
|||
if (auto pack =
|
||||
getStateEvent<mtx::events::msc2545::ImagePack>(
|
||||
txn, room_id2, state_id))
|
||||
addPack(pack->content);
|
||||
addPack(pack->content, room_id2, state_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3441,16 +3445,23 @@ Cache::getImagePacks(const std::string &room_id, bool stickers)
|
|||
|
||||
// packs from current room
|
||||
if (auto pack = getStateEvent<mtx::events::msc2545::ImagePack>(txn, room_id)) {
|
||||
addPack(pack->content);
|
||||
addPack(pack->content, room_id, "");
|
||||
}
|
||||
for (const auto &pack :
|
||||
getStateEventsWithType<mtx::events::msc2545::ImagePack>(txn, room_id)) {
|
||||
addPack(pack.content);
|
||||
addPack(pack.content, room_id, pack.state_key);
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
std::optional<mtx::events::collections::RoomAccountDataEvents>
|
||||
Cache::getAccountData(mtx::events::EventType type, const std::string &room_id)
|
||||
{
|
||||
auto txn = ro_txn(env_);
|
||||
return getAccountData(txn, type, room_id);
|
||||
}
|
||||
|
||||
std::optional<mtx::events::collections::RoomAccountDataEvents>
|
||||
Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id)
|
||||
{
|
||||
|
|
|
@ -113,6 +113,7 @@ struct RoomSearchResult
|
|||
|
||||
struct ImagePackInfo
|
||||
{
|
||||
std::string packname;
|
||||
std::map<std::string, mtx::events::msc2545::PackImage> images;
|
||||
mtx::events::msc2545::ImagePack pack;
|
||||
std::string source_room;
|
||||
std::string state_key;
|
||||
};
|
||||
|
|
|
@ -97,6 +97,12 @@ public:
|
|||
return getStateEvent<T>(txn, room_id, state_key);
|
||||
}
|
||||
|
||||
//! retrieve a specific event from account data
|
||||
//! pass empty room_id for global account data
|
||||
std::optional<mtx::events::collections::RoomAccountDataEvents> getAccountData(
|
||||
mtx::events::EventType type,
|
||||
const std::string &room_id = "");
|
||||
|
||||
//! Retrieve member info from a room.
|
||||
std::vector<RoomMember> getMembers(const std::string &room_id,
|
||||
std::size_t startIndex = 0,
|
||||
|
@ -225,7 +231,8 @@ public:
|
|||
std::vector<std::string> getParentRoomIds(const std::string &room_id);
|
||||
std::vector<std::string> getChildRoomIds(const std::string &room_id);
|
||||
|
||||
std::vector<ImagePackInfo> getImagePacks(const std::string &room_id, bool stickers);
|
||||
std::vector<ImagePackInfo> getImagePacks(const std::string &room_id,
|
||||
std::optional<bool> stickers);
|
||||
|
||||
//! Mark a room that uses e2e encryption.
|
||||
void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id);
|
||||
|
|
|
@ -16,9 +16,10 @@ CombinedImagePackModel::CombinedImagePackModel(const std::string &roomId,
|
|||
auto packs = cache::client()->getImagePacks(room_id, stickers);
|
||||
|
||||
for (const auto &pack : packs) {
|
||||
QString packname = QString::fromStdString(pack.packname);
|
||||
QString packname =
|
||||
pack.pack.pack ? QString::fromStdString(pack.pack.pack->display_name) : "";
|
||||
|
||||
for (const auto &img : pack.images) {
|
||||
for (const auto &img : pack.pack.images) {
|
||||
ImageDesc i{};
|
||||
i.shortcode = QString::fromStdString(img.first);
|
||||
i.packname = packname;
|
||||
|
|
76
src/ImagePackListModel.cpp
Normal file
76
src/ImagePackListModel.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "ImagePackListModel.h"
|
||||
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "Cache_p.h"
|
||||
#include "SingleImagePackModel.h"
|
||||
|
||||
ImagePackListModel::ImagePackListModel(const std::string &roomId, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, room_id(roomId)
|
||||
{
|
||||
auto packs_ = cache::client()->getImagePacks(room_id, std::nullopt);
|
||||
|
||||
for (const auto &pack : packs_) {
|
||||
packs.push_back(
|
||||
QSharedPointer<SingleImagePackModel>(new SingleImagePackModel(pack)));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ImagePackListModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return (int)packs.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
ImagePackListModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{Roles::DisplayName, "displayName"},
|
||||
{Roles::AvatarUrl, "avatarUrl"},
|
||||
{Roles::FromAccountData, "fromAccountData"},
|
||||
{Roles::FromCurrentRoom, "fromCurrentRoom"},
|
||||
{Roles::StateKey, "statekey"},
|
||||
{Roles::RoomId, "roomid"},
|
||||
};
|
||||
}
|
||||
|
||||
QVariant
|
||||
ImagePackListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (hasIndex(index.row(), index.column(), index.parent())) {
|
||||
const auto &pack = packs.at(index.row());
|
||||
switch (role) {
|
||||
case Roles::DisplayName:
|
||||
return pack->packname();
|
||||
case Roles::AvatarUrl:
|
||||
return pack->avatarUrl();
|
||||
case Roles::FromAccountData:
|
||||
return pack->roomid().isEmpty();
|
||||
case Roles::FromCurrentRoom:
|
||||
return pack->roomid().toStdString() == this->room_id;
|
||||
case Roles::StateKey:
|
||||
return pack->statekey();
|
||||
case Roles::RoomId:
|
||||
return pack->roomid();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
SingleImagePackModel *
|
||||
ImagePackListModel::packAt(int row)
|
||||
{
|
||||
if (row < 0 || static_cast<size_t>(row) >= packs.size())
|
||||
return {};
|
||||
auto e = packs.at(row).get();
|
||||
QQmlEngine::setObjectOwnership(e, QQmlEngine::CppOwnership);
|
||||
return e;
|
||||
}
|
37
src/ImagePackListModel.h
Normal file
37
src/ImagePackListModel.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QQmlEngine>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class SingleImagePackModel;
|
||||
class ImagePackListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Roles
|
||||
{
|
||||
DisplayName = Qt::UserRole,
|
||||
AvatarUrl,
|
||||
FromAccountData,
|
||||
FromCurrentRoom,
|
||||
StateKey,
|
||||
RoomId,
|
||||
};
|
||||
|
||||
ImagePackListModel(const std::string &roomId, QObject *parent = nullptr);
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Q_INVOKABLE SingleImagePackModel *packAt(int row);
|
||||
|
||||
private:
|
||||
std::string room_id;
|
||||
|
||||
std::vector<QSharedPointer<SingleImagePackModel>> packs;
|
||||
};
|
100
src/SingleImagePackModel.cpp
Normal file
100
src/SingleImagePackModel.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "SingleImagePackModel.h"
|
||||
|
||||
#include "Cache_p.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
SingleImagePackModel::SingleImagePackModel(ImagePackInfo pack_, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, roomid_(std::move(pack_.source_room))
|
||||
, statekey_(std::move(pack_.state_key))
|
||||
, pack(std::move(pack_.pack))
|
||||
{
|
||||
if (!pack.pack)
|
||||
pack.pack = mtx::events::msc2545::ImagePack::PackDescription{};
|
||||
|
||||
for (const auto &e : pack.images)
|
||||
shortcodes.push_back(e.first);
|
||||
}
|
||||
|
||||
int
|
||||
SingleImagePackModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return (int)shortcodes.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
SingleImagePackModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{Roles::Url, "url"},
|
||||
{Roles::ShortCode, "shortCode"},
|
||||
{Roles::Body, "body"},
|
||||
{Roles::IsEmote, "isEmote"},
|
||||
{Roles::IsSticker, "isSticker"},
|
||||
};
|
||||
}
|
||||
|
||||
QVariant
|
||||
SingleImagePackModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (hasIndex(index.row(), index.column(), index.parent())) {
|
||||
const auto &img = pack.images.at(shortcodes.at(index.row()));
|
||||
switch (role) {
|
||||
case Url:
|
||||
return QString::fromStdString(img.url);
|
||||
case ShortCode:
|
||||
return QString::fromStdString(shortcodes.at(index.row()));
|
||||
case Body:
|
||||
return QString::fromStdString(img.body);
|
||||
case IsEmote:
|
||||
return img.overrides_usage() ? img.is_emoji() : pack.pack->is_emoji();
|
||||
case IsSticker:
|
||||
return img.overrides_usage() ? img.is_sticker() : pack.pack->is_sticker();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
SingleImagePackModel::isGloballyEnabled() const
|
||||
{
|
||||
if (auto roomPacks =
|
||||
cache::client()->getAccountData(mtx::events::EventType::ImagePackRooms)) {
|
||||
if (auto tmp = std::get_if<
|
||||
mtx::events::EphemeralEvent<mtx::events::msc2545::ImagePackRooms>>(
|
||||
&*roomPacks)) {
|
||||
if (tmp->content.rooms.count(roomid_) &&
|
||||
tmp->content.rooms.at(roomid_).count(statekey_))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void
|
||||
SingleImagePackModel::setGloballyEnabled(bool enabled)
|
||||
{
|
||||
mtx::events::msc2545::ImagePackRooms content{};
|
||||
if (auto roomPacks =
|
||||
cache::client()->getAccountData(mtx::events::EventType::ImagePackRooms)) {
|
||||
if (auto tmp = std::get_if<
|
||||
mtx::events::EphemeralEvent<mtx::events::msc2545::ImagePackRooms>>(
|
||||
&*roomPacks)) {
|
||||
content = tmp->content;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
content.rooms[roomid_][statekey_] = {};
|
||||
else
|
||||
content.rooms[roomid_].erase(statekey_);
|
||||
|
||||
http::client()->put_account_data(content, [this](mtx::http::RequestErr) {
|
||||
// emit this->globallyEnabledChanged();
|
||||
});
|
||||
}
|
61
src/SingleImagePackModel.h
Normal file
61
src/SingleImagePackModel.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include <mtx/events/mscs/image_packs.hpp>
|
||||
|
||||
#include "CacheStructs.h"
|
||||
|
||||
class SingleImagePackModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString roomid READ roomid CONSTANT)
|
||||
Q_PROPERTY(QString statekey READ statekey CONSTANT)
|
||||
Q_PROPERTY(QString attribution READ statekey CONSTANT)
|
||||
Q_PROPERTY(QString packname READ packname CONSTANT)
|
||||
Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
|
||||
Q_PROPERTY(bool isStickerPack READ isStickerPack CONSTANT)
|
||||
Q_PROPERTY(bool isEmotePack READ isEmotePack CONSTANT)
|
||||
Q_PROPERTY(bool isGloballyEnabled READ isGloballyEnabled WRITE setGloballyEnabled NOTIFY
|
||||
globallyEnabledChanged)
|
||||
public:
|
||||
enum Roles
|
||||
{
|
||||
Url = Qt::UserRole,
|
||||
ShortCode,
|
||||
Body,
|
||||
IsEmote,
|
||||
IsSticker,
|
||||
};
|
||||
|
||||
SingleImagePackModel(ImagePackInfo pack_, QObject *parent = nullptr);
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
QString roomid() const { return QString::fromStdString(roomid_); }
|
||||
QString statekey() const { return QString::fromStdString(statekey_); }
|
||||
QString packname() const { return QString::fromStdString(pack.pack->display_name); }
|
||||
QString attribution() const { return QString::fromStdString(pack.pack->attribution); }
|
||||
QString avatarUrl() const { return QString::fromStdString(pack.pack->avatar_url); }
|
||||
bool isStickerPack() const { return pack.pack->is_sticker(); }
|
||||
bool isEmotePack() const { return pack.pack->is_emoji(); }
|
||||
|
||||
bool isGloballyEnabled() const;
|
||||
void setGloballyEnabled(bool enabled);
|
||||
|
||||
signals:
|
||||
void globallyEnabledChanged();
|
||||
|
||||
private:
|
||||
std::string roomid_;
|
||||
std::string statekey_;
|
||||
|
||||
mtx::events::msc2545::ImagePack pack;
|
||||
std::vector<std::string> shortcodes;
|
||||
};
|
|
@ -20,12 +20,14 @@
|
|||
#include "DelegateChooser.h"
|
||||
#include "DeviceVerificationFlow.h"
|
||||
#include "EventAccessors.h"
|
||||
#include "ImagePackListModel.h"
|
||||
#include "InviteesModel.h"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "MxcImageProvider.h"
|
||||
#include "RoomsModel.h"
|
||||
#include "SingleImagePackModel.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "UsersModel.h"
|
||||
#include "dialogs/ImageOverlay.h"
|
||||
|
@ -185,6 +187,18 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||
"Room Settings needs to be instantiated on the C++ side");
|
||||
qmlRegisterUncreatableType<TimelineModel>(
|
||||
"im.nheko", 1, 0, "Room", "Room needs to be instantiated on the C++ side");
|
||||
qmlRegisterUncreatableType<ImagePackListModel>(
|
||||
"im.nheko",
|
||||
1,
|
||||
0,
|
||||
"ImagePackListModel",
|
||||
"ImagePackListModel needs to be instantiated on the C++ side");
|
||||
qmlRegisterUncreatableType<SingleImagePackModel>(
|
||||
"im.nheko",
|
||||
1,
|
||||
0,
|
||||
"SingleImagePackModel",
|
||||
"SingleImagePackModel needs to be instantiated on the C++ side");
|
||||
qmlRegisterUncreatableType<InviteesModel>(
|
||||
"im.nheko",
|
||||
1,
|
||||
|
@ -436,6 +450,12 @@ TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId)
|
|||
});
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::openImagePackSettings(QString roomid)
|
||||
{
|
||||
emit showImagePackSettings(new ImagePackListModel(roomid.toStdString(), this));
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ class ColorImageProvider;
|
|||
class UserSettings;
|
||||
class ChatPage;
|
||||
class DeviceVerificationFlow;
|
||||
class ImagePackListModel;
|
||||
|
||||
class TimelineViewManager : public QObject
|
||||
{
|
||||
|
@ -57,6 +58,7 @@ public:
|
|||
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
||||
bool isWindowFocused() const { return isWindowFocused_; }
|
||||
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId);
|
||||
Q_INVOKABLE void openImagePackSettings(QString roomid);
|
||||
Q_INVOKABLE QColor userColor(QString id, QColor background);
|
||||
Q_INVOKABLE QString escapeEmoji(QString str) const;
|
||||
Q_INVOKABLE QString htmlEscape(QString str) const { return str.toHtmlEscaped(); }
|
||||
|
@ -93,6 +95,7 @@ signals:
|
|||
void openRoomSettingsDialog(RoomSettings *settings);
|
||||
void openInviteUsersDialog(InviteesModel *invitees);
|
||||
void openProfile(UserProfile *profile);
|
||||
void showImagePackSettings(ImagePackListModel *packlist);
|
||||
|
||||
public slots:
|
||||
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||
|
|
|
@ -136,4 +136,4 @@ private:
|
|||
RoomInfo info_;
|
||||
int notifications_ = 0;
|
||||
int accessRules_ = 0;
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue