diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml
index 3cdfda22..3ffe7d9a 100644
--- a/resources/qml/MessageView.qml
+++ b/resources/qml/MessageView.qml
@@ -52,8 +52,8 @@ Item {
//onModelChanged: if (room) room.sendReset()
//reuseItems: true
boundsBehavior: Flickable.StopAtBounds
- displayMarginBeginning: height / 2
- displayMarginEnd: height / 2
+ displayMarginBeginning: height / 4
+ displayMarginEnd: height / 4
model: (filteredTimeline.filterByThread || filteredTimeline.filterByContent) ? filteredTimeline : room
//pixelAligned: true
spacing: 2
diff --git a/resources/qml/TimelineDefaultMessageStyle.qml b/resources/qml/TimelineDefaultMessageStyle.qml
index 1d12daef..0866fab6 100644
--- a/resources/qml/TimelineDefaultMessageStyle.qml
+++ b/resources/qml/TimelineDefaultMessageStyle.qml
@@ -18,7 +18,7 @@ TimelineEvent {
id: wrapper
ListView.delayRemove: true
width: chat.delegateMaxWidth
- height: Math.max((section.item?.height ?? 0) + gridContainer.implicitHeight + reactionRow.implicitHeight + unreadRow.height, 10)
+ height: Math.max((section.item?.height ?? 0) + gridContainer.implicitHeight + reactionRow.implicitHeight + unreadRow.height, 20)
anchors.horizontalCenter: ListView.view.contentItem.horizontalCenter
//room: chatRoot.roommodel
@@ -51,6 +51,8 @@ TimelineEvent {
property alias hovered: messageHover.hovered
property bool scrolledToThis: false
+ maxWidth: chat.delegateMaxWidth - avatarMargin - metadata.width
+
data: [
Loader {
id: section
@@ -131,7 +133,7 @@ TimelineEvent {
anchors.top: gridContainer.top
anchors.left: gridContainer.left
anchors.topMargin: -2
- anchors.leftMargin: wrapper.avatarMargin + 2
+ anchors.leftMargin: -2
color: "transparent"
border.color: Nheko.theme.red
border.width: wrapper.notificationlevel == MtxEvent.Highlight ? 1 : 0
@@ -139,11 +141,13 @@ TimelineEvent {
height: contentColumn.implicitHeight + 4
width: contentColumn.implicitWidth + 4
},
- RowLayout {
+ Row {
id: gridContainer
- width: wrapper.width
+ width: wrapper.width - wrapper.avatarMargin
+ x: wrapper.avatarMargin
y: section.visible && section.active ? section.y + section.height : 0
+ spacing: Nheko.paddingSmall
HoverHandler {
id: messageHover
@@ -154,23 +158,20 @@ TimelineEvent {
messageActions.model = wrapper;
messageActions.attached = wrapper;
messageActions.anchors.bottomMargin = -gridContainer.y
+ messageActions.anchors.rightMargin = metadata.width
}
}
}
}
- Item {
- Layout.preferredWidth: wrapper.avatarMargin
- }
-
AbstractButton {
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: qsTr("Part of a thread")
ToolTip.visible: hovered
- Layout.fillHeight: true
+ height: contentColumn.height
visible: wrapper.threadId
- Layout.preferredWidth: 4
+ width: 4
onClicked: wrapper.room.thread = wrapper.threadId
@@ -181,17 +182,16 @@ TimelineEvent {
color: TimelineManager.userColor(wrapper.threadId, palette.base)
}
}
- ColumnLayout {
+ Column {
id: contentColumn
- Layout.fillWidth: true
AbstractButton {
id: replyRow
visible: wrapper.reply
- Layout.fillWidth: true
- Layout.maximumHeight: timelineView.height / 8
- Layout.preferredWidth: replyRowLay.implicitWidth
- Layout.preferredHeight: replyRowLay.implicitHeight
+ //Layout.fillWidth: true
+ //Layout.maximumHeight: timelineView.height / 8
+ //Layout.preferredWidth: replyRowLay.implicitWidth
+ //Layout.preferredHeight: replyRowLay.implicitHeight
property color userColor: TimelineManager.userColor(wrapper.reply?.userId ?? '', palette.base)
@@ -202,32 +202,33 @@ TimelineEvent {
cursorShape: Qt.PointingHandCursor
}
- contentItem: RowLayout {
+ contentItem: Row {
id: replyRowLay
- anchors.fill: parent
-
+ spacing: Nheko.paddingSmall
Rectangle {
id: replyLine
- Layout.fillHeight: true
+ height: replyCol.height
color: replyRow.userColor
- Layout.preferredWidth: 4
+ width: 4
}
- ColumnLayout {
+ Column {
spacing: 0
+ id: replyCol
+
AbstractButton {
id: replyUserButton
- Layout.fillWidth: true
- contentItem: ElidedLabel {
+
+ contentItem: Label {
id: userName_
- fullText: wrapper.reply?.userName ?? ''
+ text: wrapper.reply?.userName ?? ''
color: replyRow.userColor
textFormat: Text.RichText
- width: parent.width
- elideWidth: width
+ width: wrapper.maxWidth
+ //elideWidth: wrapper.maxWidth
}
onClicked: wrapper.room.openUserProfile(wrapper.reply?.userId)
}
@@ -239,7 +240,7 @@ TimelineEvent {
}
background: Rectangle {
- width: replyRow.implicitContentWidth
+ //width: replyRow.implicitContentWidth
color: Qt.tint(palette.base, Qt.hsla(replyRow.userColor.hslHue, 0.5, replyRow.userColor.hslLightness, 0.1))
}
@@ -259,19 +260,16 @@ TimelineEvent {
]
}
- Item {
- // spacer to fill width if needed
- Layout.fillWidth: true
- }
-
+ },
RowLayout {
id: metadata
property int iconSize: Math.floor(fontMetrics.ascent * scaling)
property double scaling: Settings.bubbles ? 0.75 : 1
- Layout.alignment: Qt.AlignTop | Qt.AlignRight
- Layout.preferredWidth: implicitWidth
+ anchors.right: parent.right
+ y: section.visible && section.active ? section.y + section.height : 0
+
spacing: 2
visible: !isStateEvent
@@ -339,8 +337,7 @@ TimelineEvent {
}
}
- }
- },
+ },
Reactions {
id: reactionRow
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index 44726a63..cd1bdcd4 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -620,7 +620,6 @@ Item {
roleValue: MtxEvent.Member
ColumnLayout {
- width: parent?.width ?? 100
NoticeMessage {
body: formatted
diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml
index 9ef2e6cc..03623924 100644
--- a/resources/qml/delegates/TextMessage.qml
+++ b/resources/qml/delegates/TextMessage.qml
@@ -4,7 +4,7 @@
import ".."
import QtQuick.Controls
-import QtQuick.Layouts
+//import QtQuick.Layouts
import im.nheko
MatrixText {
@@ -41,7 +41,10 @@ MatrixText {
}" : "") + // TODO(Nico): Figure out how to support mobile
"</style>
" + formatted.replace(/<del>/g, "<s>").replace(/<\/del>/g, "</s>").replace(/<strike>/g, "<s>").replace(/<\/strike>/g, "</s>")
- Layout.maximumHeight: !keepFullText ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : implicitHeight
+ //Layout.maximumHeight: !keepFullText ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : implicitHeight
+
+ //EventDelegateChooser.fillWidth: true
+
clip: !keepFullText
selectByMouse: !Settings.mobileMode && !isReply
enabled: !Settings.mobileMode && !isReply
diff --git a/src/timeline/EventDelegateChooser.cpp b/src/timeline/EventDelegateChooser.cpp
index 2218d9ee..0060907d 100644
--- a/src/timeline/EventDelegateChooser.cpp
+++ b/src/timeline/EventDelegateChooser.cpp
@@ -131,7 +131,7 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
roleToPropIdx.insert(*role, i);
roles.emplace_back(*role);
- nhlog::ui()->critical("Found prop {}, idx {}, role {}", prop.name(), i, *role);
+ // nhlog::ui()->critical("Found prop {}, idx {}, role {}", prop.name(), i, *role);
} else {
nhlog::ui()->critical("Required property {} not found in model!", prop.name());
}
@@ -140,14 +140,15 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
nhlog::ui()->debug("Querying data for id {}", currentId.toStdString());
chooser.room_->multiData(currentId, forReply ? chooser.eventId_ : QString(), roles);
+ Qt::beginPropertyUpdateGroup();
for (const auto &role : roles) {
const auto &roleName = roleNames[role.role()];
- nhlog::ui()->critical("Setting role {}, {} to {}",
- role.role(),
- roleName.toStdString(),
- role.data().toString().toStdString());
+ // nhlog::ui()->critical("Setting role {}, {} to {}",
+ // role.role(),
+ // roleName.toStdString(),
+ // role.data().toString().toStdString());
- nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[role.role()]).name());
+ // nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[role.role()]).name());
mo->property(roleToPropIdx[role.role()]).write(obj, role.data());
if (const auto &req = requiredProperties.find(roleName); req != requiredProperties.end())
@@ -156,14 +157,15 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
if (isReplyNeeded) {
const auto roleName = QByteArray("isReply");
- nhlog::ui()->critical("Setting role {} to {}", roleName.toStdString(), forReply);
+ // nhlog::ui()->critical("Setting role {} to {}", roleName.toStdString(), forReply);
- nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[-1]).name());
+ // nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[-1]).name());
mo->property(roleToPropIdx[-1]).write(obj, forReply);
if (const auto &req = requiredProperties.find(roleName); req != requiredProperties.end())
QQmlIncubatorPrivate::get(this)->requiredProperties()->remove(*req);
}
+ Qt::endPropertyUpdateGroup();
// setInitialProperties(rolesToSet);
@@ -188,9 +190,12 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
auto mo = obj->metaObject();
chooser.room_->multiData(
currentId, forReply ? chooser.eventId_ : QString(), rolesToRequest);
+
+ Qt::beginPropertyUpdateGroup();
for (const auto &role : rolesToRequest) {
mo->property(roleToPropIdx[role.role()]).write(obj, role.data());
}
+ Qt::endPropertyUpdateGroup();
};
if (!forReply) {
@@ -257,11 +262,22 @@ EventDelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status sta
child->setParentItem(&chooser);
QQmlEngine::setObjectOwnership(child, QQmlEngine::ObjectOwnership::JavaScriptOwnership);
+
+ // connect(child, &QQuickItem::parentChanged, child, [child](QQuickItem *) {
+ // // QTBUG-115687
+ // if (child->flags().testFlag(QQuickItem::ItemObservesViewport)) {
+ // nhlog::ui()->critical("SETTING OBSERVES VIEWPORT");
+ // // Re-trigger the parent traversal to get subtreeTransformChangedEnabled turned
+ // on child->setFlag(QQuickItem::ItemObservesViewport);
+ // }
+ // });
+
if (forReply)
emit chooser.replyChanged();
else
emit chooser.mainChanged();
+ chooser.polish();
} else if (status == QQmlIncubator::Error) {
auto errors_ = errors();
for (const auto &e : qAsConst(errors_))
@@ -269,3 +285,49 @@ EventDelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status sta
}
}
+void
+EventDelegateChooser::updatePolish()
+{
+ auto mainChild = qobject_cast<QQuickItem *>(eventIncubator.object());
+ auto replyChild = qobject_cast<QQuickItem *>(replyIncubator.object());
+
+ nhlog::ui()->critical("POLISHING {}", (void *)this);
+
+ if (mainChild) {
+ auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+ qmlAttachedPropertiesObject<EventDelegateChooser>(mainChild));
+ Q_ASSERT(attached != nullptr);
+
+ // in theory we could also reset the width, but that doesn't seem to work nicely for text
+ // areas because of how they cache it.
+ mainChild->setWidth(maxWidth_);
+ mainChild->ensurePolished();
+ auto width = mainChild->implicitWidth();
+
+ if (width > maxWidth_ || attached->fillWidth())
+ width = maxWidth_;
+
+ nhlog::ui()->debug(
+ "Made event delegate width: {}, {}", width, mainChild->metaObject()->className());
+ mainChild->setWidth(width);
+ mainChild->ensurePolished();
+ }
+
+ if (replyChild) {
+ auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+ qmlAttachedPropertiesObject<EventDelegateChooser>(replyChild));
+ Q_ASSERT(attached != nullptr);
+
+ // in theory we could also reset the width, but that doesn't seem to work nicely for text
+ // areas because of how they cache it.
+ replyChild->setWidth(maxWidth_);
+ replyChild->ensurePolished();
+ auto width = replyChild->implicitWidth();
+
+ if (width > maxWidth_ || attached->fillWidth())
+ width = maxWidth_;
+
+ replyChild->setWidth(width);
+ replyChild->ensurePolished();
+ }
+}
diff --git a/src/timeline/EventDelegateChooser.h b/src/timeline/EventDelegateChooser.h
index 1cd2d65a..ff67ccd8 100644
--- a/src/timeline/EventDelegateChooser.h
+++ b/src/timeline/EventDelegateChooser.h
@@ -2,9 +2,6 @@
//
// SPDX-License-Identifier: GPL-3.0-or-later
-// A DelegateChooser like the one, that was added to Qt5.12 (in labs), but compatible with older Qt
-// versions see KDE/kquickitemviews see qtdeclarative/qqmldelagatecomponent
-
#pragma once
#include <QAbstractItemModel>
@@ -17,6 +14,32 @@
#include "TimelineModel.h"
+class EventDelegateChooserAttachedType : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged)
+ QML_ANONYMOUS
+public:
+ EventDelegateChooserAttachedType(QObject *parent)
+ : QObject(parent)
+ {
+ }
+ bool fillWidth() const { return fillWidth_; }
+ void setFillWidth(bool fill)
+ {
+ fillWidth_ = fill;
+ emit fillWidthChanged();
+ }
+signals:
+ void fillWidthChanged();
+
+private:
+ bool fillWidth_ = false, keepAspectRatio = false;
+ double aspectRatio = 1.;
+ int maxWidth = -1;
+ int maxHeight = -1;
+};
+
class EventDelegateChoice : public QObject
{
Q_OBJECT
@@ -51,14 +74,18 @@ class EventDelegateChooser : public QQuickItem
QML_ELEMENT
Q_CLASSINFO("DefaultProperty", "choices")
-public:
+ QML_ATTACHED(EventDelegateChooserAttachedType)
+
Q_PROPERTY(QQmlListProperty<EventDelegateChoice> choices READ choices CONSTANT FINAL)
Q_PROPERTY(QQuickItem *main READ main NOTIFY mainChanged FINAL)
Q_PROPERTY(QQuickItem *reply READ reply NOTIFY replyChanged FINAL)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged REQUIRED FINAL)
Q_PROPERTY(QString replyTo READ replyTo WRITE setReplyTo NOTIFY replyToChanged REQUIRED FINAL)
Q_PROPERTY(TimelineModel *room READ room WRITE setRoom NOTIFY roomChanged REQUIRED FINAL)
+ Q_PROPERTY(bool sameWidth READ sameWidth WRITE setSameWidth NOTIFY sameWidthChanged)
+ Q_PROPERTY(int maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
+public:
QQmlListProperty<EventDelegateChoice> choices();
[[nodiscard]] QQuickItem *main() const
@@ -70,6 +97,20 @@ public:
return qobject_cast<QQuickItem *>(replyIncubator.object());
}
+ bool sameWidth() const { return sameWidth_; }
+ void setSameWidth(bool width)
+ {
+ sameWidth_ = width;
+ emit sameWidthChanged();
+ }
+ bool maxWidth() const { return maxWidth_; }
+ void setMaxWidth(int width)
+ {
+ maxWidth_ = width;
+ emit maxWidthChanged();
+ polish();
+ }
+
void setRoom(TimelineModel *m)
{
if (m != room_) {
@@ -105,12 +146,21 @@ public:
void componentComplete() override;
+ static EventDelegateChooserAttachedType *qmlAttachedProperties(QObject *object)
+ {
+ return new EventDelegateChooserAttachedType(object);
+ }
+
+ void updatePolish() override;
+
signals:
void mainChanged();
void replyChanged();
void roomChanged();
void eventIdChanged();
void replyToChanged();
+ void sameWidthChanged();
+ void maxWidthChanged();
private:
struct DelegateIncubator final : public QQmlIncubator
@@ -142,6 +192,8 @@ private:
TimelineModel *room_{nullptr};
QString eventId_;
QString replyId;
+ bool sameWidth_ = false;
+ int maxWidth_ = 400;
static void appendChoice(QQmlListProperty<EventDelegateChoice> *, EventDelegateChoice *);
static qsizetype choiceCount(QQmlListProperty<EventDelegateChoice> *);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 3e0c6688..f5b9e142 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -601,12 +601,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
case UserName:
return QVariant(displayName(QString::fromStdString(acc::sender(event))));
case UserPowerlevel: {
- return static_cast<qlonglong>(mtx::events::state::PowerLevels{
- cache::client()
- ->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
- .value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
- .content}
- .user_level(acc::sender(event)));
+ return static_cast<qlonglong>(
+ permissions_.powerlevelEvent().user_level(acc::sender(event)));
}
case Day: {
|