Show widgets as links

This commit is contained in:
Nicolas Werner 2022-02-04 18:47:17 +01:00
parent 00116e8128
commit 7b00411dc4
8 changed files with 132 additions and 11 deletions

View File

@ -402,7 +402,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG dc55f64862aeaf02d75383fbdadcbf64ea585506
GIT_TAG 29b46c872576d88797178d3c147e8b12b1ac8693
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

View File

@ -191,7 +191,7 @@ modules:
buildsystem: cmake-ninja
name: mtxclient
sources:
- commit: dc55f64862aeaf02d75383fbdadcbf64ea585506
- commit: 29b46c872576d88797178d3c147e8b12b1ac8693
#tag: v0.6.1
type: git
url: https://github.com/Nheko-Reborn/mtxclient.git

View File

@ -36,7 +36,7 @@ Pane {
TapHandler {
onSingleTapped: {
if (eventPoint.position.y > topBar.height - (pinnedMessages.visible ? pinnedMessages.height : 0)) {
if (eventPoint.position.y > topBar.height - (pinnedMessages.visible ? pinnedMessages.height : 0) - (widgets.visible ? widgets.height : 0)) {
eventPoint.accepted = true
return;
}
@ -300,6 +300,42 @@ Pane {
}
ScrollHelper {
flickable: parent
anchors.fill: parent
enabled: !Settings.mobileMode
}
}
}
ScrollView {
id: widgets
Layout.row: 3
Layout.column: 2
Layout.columnSpan: 3
Layout.fillWidth: true
Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 1.5)
visible: !!room && room.widgetLinks.length > 0 && !Settings.hiddenWidgets.includes(roomId)
clip: true
palette: Nheko.colors
ScrollBar.horizontal.visible: false
ListView {
spacing: Nheko.paddingSmall
model: room ? room.widgetLinks : undefined
delegate: MatrixText {
required property var modelData
color: Nheko.colors.text
text: modelData
}
ScrollHelper {
flickable: parent
anchors.fill: parent
@ -311,7 +347,7 @@ Pane {
CursorShape {
anchors.fill: parent
anchors.bottomMargin: pinnedMessages.visible ? pinnedMessages.height : 0
anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0)
cursorShape: Qt.PointingHandCursor
}
}

View File

@ -96,10 +96,12 @@ public:
return getStateEvent<T>(txn, room_id, state_key);
}
template<typename T>
std::vector<mtx::events::StateEvent<T>> getStateEventsWithType(const std::string &room_id)
std::vector<mtx::events::StateEvent<T>>
getStateEventsWithType(const std::string &room_id,
mtx::events::EventType type = mtx::events::state_content_to_type<T>)
{
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
return getStateEventsWithType<T>(txn, room_id);
return getStateEventsWithType<T>(txn, room_id, type);
}
//! retrieve a specific event from account data
@ -494,13 +496,11 @@ private:
template<typename T>
std::vector<mtx::events::StateEvent<T>>
getStateEventsWithType(lmdb::txn &txn, const std::string &room_id)
getStateEventsWithType(lmdb::txn &txn,
const std::string &room_id,
mtx::events::EventType type = mtx::events::state_content_to_type<T>)
{
constexpr auto type = mtx::events::state_content_to_type<T>;
static_assert(type != mtx::events::EventType::Unsupported,
"Not a supported type in state events.");
if (room_id.empty())
return {};

View File

@ -124,6 +124,7 @@ UserSettings::load(std::optional<QString> profile)
deviceId_ = settings.value(prefix + "auth/device_id", "").toString();
hiddenTags_ = settings.value(prefix + "user/hidden_tags", QStringList{}).toStringList();
hiddenPins_ = settings.value(prefix + "user/hidden_pins", QStringList{}).toStringList();
hiddenWidgets_ = settings.value(prefix + "user/hidden_widgets", QStringList{}).toStringList();
recentReactions_ =
settings.value(prefix + "user/recent_reactions", QStringList{}).toStringList();
@ -217,6 +218,14 @@ UserSettings::setHiddenPins(QStringList hiddenTags)
emit hiddenPinsChanged();
}
void
UserSettings::setHiddenWidgets(QStringList hiddenTags)
{
hiddenWidgets_ = hiddenTags;
save();
emit hiddenWidgetsChanged();
}
void
UserSettings::setRecentReactions(QStringList recent)
{
@ -735,6 +744,7 @@ UserSettings::save()
settings.setValue(prefix + "user/online_key_backup", useOnlineKeyBackup_);
settings.setValue(prefix + "user/hidden_tags", hiddenTags_);
settings.setValue(prefix + "user/hidden_pins", hiddenPins_);
settings.setValue(prefix + "user/hidden_widgets", hiddenWidgets_);
settings.setValue(prefix + "user/recent_reactions", recentReactions_);
QVariantList v;

View File

@ -107,6 +107,8 @@ class UserSettings : public QObject
Q_PROPERTY(QStringList hiddenPins READ hiddenPins WRITE setHiddenPins NOTIFY hiddenPinsChanged)
Q_PROPERTY(QStringList recentReactions READ recentReactions WRITE setRecentReactions NOTIFY
recentReactionsChanged)
Q_PROPERTY(QStringList hiddenWidgets READ hiddenWidgets WRITE setHiddenWidgets NOTIFY
hiddenWidgetsChanged)
UserSettings();
@ -175,6 +177,7 @@ public:
void setDisableCertificateValidation(bool disabled);
void setHiddenTags(QStringList hiddenTags);
void setHiddenPins(QStringList hiddenTags);
void setHiddenWidgets(QStringList hiddenTags);
void setRecentReactions(QStringList recent);
void setUseIdenticon(bool state);
void setCollapsedSpaces(QList<QStringList> spaces);
@ -234,6 +237,7 @@ public:
bool disableCertificateValidation() const { return disableCertificateValidation_; }
QStringList hiddenTags() const { return hiddenTags_; }
QStringList hiddenPins() const { return hiddenPins_; }
QStringList hiddenWidgets() const { return hiddenWidgets_; }
QStringList recentReactions() const { return recentReactions_; }
bool useIdenticon() const { return useIdenticon_ && JdenticonProvider::isAvailable(); }
QList<QStringList> collapsedSpaces() const { return collapsedSpaces_; }
@ -286,6 +290,7 @@ signals:
void disableCertificateValidationChanged(bool disabled);
void useIdenticonChanged(bool state);
void hiddenPinsChanged();
void hiddenWidgetsChanged();
void recentReactionsChanged();
private:
@ -342,6 +347,7 @@ private:
QString homeserver_;
QStringList hiddenTags_;
QStringList hiddenPins_;
QStringList hiddenWidgets_;
QStringList recentReactions_;
QList<QStringList> collapsedSpaces_;
bool useIdenticon_;

View File

@ -285,6 +285,9 @@ qml_mtx_events::fromRoomEventType(qml_mtx_events::EventType t)
/// m.room.pinned_events
case qml_mtx_events::PinnedEvents:
return mtx::events::EventType::RoomPinnedEvents;
/// m.widget
case qml_mtx_events::Widget:
return mtx::events::EventType::Widget;
// m.sticker
case qml_mtx_events::Sticker:
return mtx::events::EventType::Sticker;
@ -852,6 +855,8 @@ TimelineModel::syncState(const mtx::responses::State &s)
emit roomTopicChanged();
else if (std::holds_alternative<StateEvent<state::PinnedEvents>>(e))
emit pinnedMessagesChanged();
else if (std::holds_alternative<StateEvent<state::Widget>>(e))
emit widgetLinksChanged();
else if (std::holds_alternative<StateEvent<state::PowerLevels>>(e)) {
permissions_.invalidate();
emit permissionsChanged();
@ -916,6 +921,8 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
emit roomTopicChanged();
else if (std::holds_alternative<StateEvent<state::PinnedEvents>>(e))
emit pinnedMessagesChanged();
else if (std::holds_alternative<StateEvent<state::Widget>>(e))
emit widgetLinksChanged();
else if (std::holds_alternative<StateEvent<state::PowerLevels>>(e)) {
permissions_.invalidate();
emit permissionsChanged();
@ -2225,6 +2232,63 @@ TimelineModel::pinnedMessages() const
return list;
}
QStringList
TimelineModel::widgetLinks() const
{
auto evs =
cache::client()->getStateEventsWithType<mtx::events::state::Widget>(room_id_.toStdString());
auto evs2 = cache::client()->getStateEventsWithType<mtx::events::state::Widget>(
room_id_.toStdString(), mtx::events::EventType::Widget);
evs.insert(
evs.end(), std::make_move_iterator(evs2.begin()), std::make_move_iterator(evs2.end()));
if (evs.empty())
return {};
QStringList list;
auto user = utils::localUser();
auto av = QUrl::toPercentEncoding(avatarUrl(user));
auto disp = QUrl::toPercentEncoding(displayName(user));
auto theme = UserSettings::instance()->theme();
if (theme == QStringLiteral("system"))
theme.clear();
user = QUrl::toPercentEncoding(user);
list.reserve(evs.size());
for (const auto &p : evs) {
auto url = QString::fromStdString(p.content.url);
for (const auto &[k, v] : p.content.data)
url.replace("$" + QString::fromStdString(k),
QUrl::toPercentEncoding(QString::fromStdString(v)));
url.replace("$matrix_user_id", user);
url.replace("$matrix_room_id", QUrl::toPercentEncoding(room_id_));
url.replace("$matrix_display_name", disp);
url.replace("$matrix_avatar_url", av);
url.replace("$matrix_widget_id",
QUrl::toPercentEncoding(QString::fromStdString(p.content.id)));
// url.replace("$matrix_client_theme", theme);
url.replace("$org.matrix.msc2873.client_theme", theme);
url.replace("$org.matrix.msc2873.client_id", "im.nheko");
// compat with some widgets, i.e. FOSDEM
url.replace("$theme", theme);
url = QUrl::toPercentEncoding(url, "/:?&@=%");
list.push_back(
QLatin1String("<a href='%1'>%2</a>")
.arg(url,
QString::fromStdString(p.content.name.empty() ? p.state_key : p.content.name)
.toHtmlEscaped()));
}
return list;
}
crypto::Trust
TimelineModel::trustlevel() const
{

View File

@ -91,6 +91,8 @@ enum EventType
Sticker,
// m.tag
Tag,
// m.widget
Widget,
/// m.room.message
AudioMessage,
EmoteMessage,
@ -178,6 +180,7 @@ class TimelineModel : public QAbstractListModel
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged)
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
Q_PROPERTY(QStringList pinnedMessages READ pinnedMessages NOTIFY pinnedMessagesChanged)
Q_PROPERTY(QStringList widgetLinks READ widgetLinks NOTIFY widgetLinksChanged)
Q_PROPERTY(int roomMemberCount READ roomMemberCount NOTIFY roomMemberCountChanged)
Q_PROPERTY(bool isEncrypted READ isEncrypted NOTIFY encryptionChanged)
Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
@ -365,6 +368,7 @@ public slots:
QString plainRoomName() const;
QString roomTopic() const;
QStringList pinnedMessages() const;
QStringList widgetLinks() const;
InputBar *input() { return &input_; }
Permissions *permissions() { return &permissions_; }
QString roomAvatarUrl() const;
@ -407,6 +411,7 @@ signals:
void plainRoomNameChanged();
void roomTopicChanged();
void pinnedMessagesChanged();
void widgetLinksChanged();
void roomAvatarUrlChanged();
void roomMemberCountChanged();
void isDirectChanged();