libQuotient
A Qt library for building matrix clients
roommember.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
2 // SPDX-License-Identifier: LGPL-2.1-or-later
3 
4 #pragma once
5 
6 #include "quotient_common.h"
7 #include "uri.h"
8 #include "avatar.h"
9 
10 #include <QtCore/QObject>
11 
12 namespace Quotient {
13 class Room;
14 class RoomMemberEvent;
15 
16 //! \brief Representation of a user state in a room
17 //!
18 //! The class is intentionally a read-only data object that is effectively a wrapper around an
19 //! `m.room.member` event for the desired user. This is designed to provide the data in a format
20 //! ready for visualizing a user (avatar or name) in the context of the room it was generated in.
21 //! This means that if a user has set a unique name or avatar for a particular room that is what
22 //! will be returned.
23 //!
24 //! \note The RoomMember class is not intended for interacting with the user's profile.
25 //! For that a Quotient::User object should be obtained from a Quotient::Connection as that
26 //! has the support functions for modifying profile information.
27 //! \warning RoomMember is a gadget class and should not be kept between syncs. It does not track
28 //! changes of the member state therefore some member changes (i.e. leaving the room) may
29 //! render a RoomMember dangling, when calling any of its methods leads to undefined
30 //! behaviour.
31 //! \sa User
32 class QUOTIENT_API RoomMember {
33  Q_GADGET
34  Q_PROPERTY(bool isEmpty READ isEmpty CONSTANT)
35  Q_PROPERTY(QString id READ id CONSTANT)
36  Q_PROPERTY(Uri uri READ uri CONSTANT)
37  Q_PROPERTY(bool isLocalMember READ isLocalMember CONSTANT)
38  Q_PROPERTY(QString displayName READ displayName CONSTANT)
39  Q_PROPERTY(QString htmlSafeDisplayName READ htmlSafeDisplayName CONSTANT)
40  Q_PROPERTY(QString fullName READ fullName CONSTANT)
41  Q_PROPERTY(QString htmlSafeFullName READ htmlSafeFullName CONSTANT)
42  Q_PROPERTY(QString disambiguatedName READ disambiguatedName CONSTANT)
43  Q_PROPERTY(QString htmlSafeDisambiguatedName READ htmlSafeDisambiguatedName CONSTANT)
44  Q_PROPERTY(int hue READ hue CONSTANT)
45  Q_PROPERTY(qreal hueF READ hueF CONSTANT)
46  Q_PROPERTY(QColor color READ color CONSTANT)
47  Q_PROPERTY(QUrl avatarUrl READ avatarUrl CONSTANT)
48  Q_PROPERTY(int powerLevel READ powerLevel CONSTANT)
49 
50 public:
51  RoomMember() = default;
52 
53  explicit RoomMember(const Room* room, const RoomMemberEvent* member);
54 
55  bool isEmpty() const { return _member == nullptr; }
56 
57  bool operator==(const RoomMember& other) const;
58 
59  //! @brief Get unique stable user id
60  //!
61  //! The Matrix user ID is generated by the server and is never changed.
62  QString id() const;
63 
64  //! @brief The matrix.to URI for the user
65  //!
66  //! Typically used when you want to visit a user (see
67  //! Quotient::UriResolverBase::visitResource()).
68  //!
69  //! @sa Quotient::UriResolverBase::visitResource()
70  Uri uri() const;
71 
72  //! Whether this member is the local user
73  bool isLocalMember() const;
74 
75  //! The membership state of the member
76  Membership membershipState() const;
77 
78  //! \brief The raw unmodified display name for the user in the given room
79  //!
80  //! The value will be empty if no display name has been set.
81  //!
82  //! \warning This value is not sanitized or HTML escape so use appropriately.
83  //! For ready to display values use displayName() or fullName() for
84  //! plain text and htmlSafeDisplayName() or htmlSafeFullName() fo
85  //! rich text.
86  //!
87  //! \sa displayName(), htmlSafeDisplayName(), fullName(), htmlSafeFullName()
88  QString name() const;
89 
90  //! \brief Get the user display name ready for display
91  //!
92  //! This function always aims to return something that can be displayed in a
93  //! UI, so if no display name is set the user's Matrix ID will be returned.
94  //!
95  //! The output is sanitized and suitable for a plain text field. For a rich
96  //! field use htmlSafeDisplayName().
97  //!
98  //! \sa htmlSafeDisplayName()
99  QString displayName() const;
100 
101  //! \brief Get the user display name ready for display
102  //!
103  //! This function always aims to return something that can be displayed in a
104  //! UI, so if no display name is set the user's Matrix ID will be returned.
105  //!
106  //! The output is sanitized and html escaped ready for a rich text field. For
107  //! a plain field use displayName().
108  //!
109  //! \sa displayName()
110  QString htmlSafeDisplayName() const;
111 
112  //! \brief Get user name and id in a single string
113  //!
114  //! This function always aims to return something that can be displayed in a
115  //! UI, so if no display name is set the just user's Matrix ID will be returned.
116  //! The constructed string follows the format 'name (id)' which the spec
117  //! recommends for users disambiguation in a room context and in other places.
118  //!
119  //! The output is sanitized and suitable for a plain text field. For a rich
120  //! field use htmlSafeFullName().
121  //!
122  //! \sa htmlSafeFullName()
123  QString fullName() const;
124 
125  //! \brief Get user name and id in a single string
126  //!
127  //! This function always aims to return something that can be displayed in a
128  //! UI, so if no display name is set the just user's Matrix ID will be returned.
129  //! The constructed string follows the format 'name (id)' which the spec
130  //! recommends for users disambiguation in a room context and in other places.
131  //!
132  //! The output is sanitized and html escaped ready for a rich text field. For
133  //! a plain field use fullName().
134  //!
135  //! \sa fullName()
136  QString htmlSafeFullName() const;
137 
138  //! \brief Get the disambiguated user name
139  //!
140  //! This function always aims to return something that can be displayed in a
141  //! UI, so if no display name is set the just user's Matrix ID will be returned.
142  //! The output is equivalent to fullName() if there is another user in the room
143  //! with the same name. Otherwise it is equivalent to displayName().
144  //!
145  //! The output is sanitized and suitable for a plain text field. For a rich
146  //! field use htmlSafeDisambiguatedName().
147  //!
148  //! \sa htmlSafeDisambiguatedName(), fullName(), displayName()
149  QString disambiguatedName() const;
150 
151  //! \brief Get the disambiguated user name
152  //!
153  //! This function always aims to return something that can be displayed in a
154  //! UI, so if no display name is set the just user's Matrix ID will be returned.
155  //! The output is equivalent to htmlSafeFullName() if there is another user in the room
156  //! with the same name. Otherwise it is equivalent to htmlSafeDisplayName().
157  //!
158  //! The output is sanitized and html escaped ready for a rich text field. For
159  //! a plain field use disambiguatedName().
160  //!
161  //! \sa disambiguatedName(), htmlSafeFullName(), htmlSafeDisplayName()
162  QString htmlSafeDisambiguatedName() const;
163 
164  //! \brief Check whether the name or id of the member contains a substring
165  //!
166  //! This is useful for a predicate to filter room members.
167  //! \sa MemberMatcher
168  Q_INVOKABLE bool matches(QStringView substr, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
169 
170  //! \brief Hue color component of this user based on the user's Matrix ID
171  //!
172  //! The implementation is based on XEP-0392:
173  //! https://xmpp.org/extensions/xep-0392.html
174  //! Naming and ranges are the same as QColor's hue methods:
175  //! https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision
176  int hue() const;
177 
178  //! \brief HueF color component of this user based on the user's Matrix ID
179  //!
180  //! The implementation is based on XEP-0392:
181  //! https://xmpp.org/extensions/xep-0392.html
182  //! Naming and ranges are the same as QColor's hue methods:
183  //! https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision
184  qreal hueF() const;
185 
186  //! \brief Color based on the user's Matrix ID
187  //!
188  //! See https://github.com/quotient-im/libQuotient/wiki/User-color-coding-standard-draft-proposal
189  //! for the methodology.
190  QColor color() const;
191 
192  const Avatar& avatarObject() const;
193 
194  //! \brief The mxc URL as a string for the user avatar in the room
195  //!
196  //! This can be empty if none set.
197  QString avatarMediaId() const;
198 
199  //! \brief The mxc URL for the user avatar in the room
200  //!
201  //! This can be empty if none set.
202  QUrl avatarUrl() const;
203 
204  QImage avatar(int width, int height, Avatar::get_callback_t callback) const;
205 
206  QImage avatar(int dimension, Avatar::get_callback_t callback) const;
207 
208  //! \brief The power level of the member.
209  //!
210  //! This is in the context of the current room. Will return the default power
211  //! level for the room if not specifically set.
212  int powerLevel() const;
213 
214 private:
215  const Room* _room = nullptr;
216  const RoomMemberEvent* _member = nullptr;
217 
218  qreal _hueF = 0;
219 };
220 
221 //! \brief A factory to get a functional object matching room members against a substring
222 //!
223 //! This is a convenience wrapper to use RoomMember::matches() in standard algorithms.
224 inline auto memberMatcher(auto substr, Qt::CaseSensitivity cs = Qt::CaseSensitive)
225 {
226 #ifdef __cpp_lib_bind_back
227  return std::bind_back(&RoomMember::matches, substr, cs);
228 #else
229  return [substr, cs](const RoomMember& m) { return m.matches(substr, cs); };
230 #endif
231 }
232 
233 struct QUOTIENT_API MemberSorter {
234  bool operator()(const RoomMember& u1, const RoomMember& u2) const
235  {
236  return operator()(u1.displayName(), u2.displayName());
237  }
238  bool operator()(const RoomMember& u1, QStringView u2name) const
239  {
240  return operator()(u1.displayName(), u2name);
241  }
242  bool operator()(QStringView u1name, const RoomMember& u2) const
243  {
244  return operator()(u1name, u2.displayName());
245  }
246  bool operator()(QStringView u1name, QStringView u2name) const;
247 
248 #if Quotient_VERSION_MAJOR == 0 && Quotient_VERSION_MINOR < 10
249  template <template <class> class ContT>
250  [[deprecated("Use Quotient::lowerBoundIndex() or std::ranges::lower_bound() instead")]] //
251  typename ContT<RoomMember>::size_type
252  lowerBoundIndex(const ContT<RoomMember>& c, const auto& v) const
253  {
254  return std::ranges::lower_bound(c, v, *this) - c.begin();
255  }
256 #endif
257 };
258 
259 } // namespace Quotient