diff options
-rw-r--r-- | .clang-format | 10 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | include/TimelineItem.h | 74 | ||||
-rw-r--r-- | include/TimelineView.h | 159 | ||||
-rw-r--r-- | include/TimelineViewManager.h | 42 | ||||
-rw-r--r-- | src/TimelineItem.cc | 438 | ||||
-rw-r--r-- | src/TimelineView.cc | 552 | ||||
-rw-r--r-- | src/TimelineViewManager.cc | 262 |
8 files changed, 751 insertions, 787 deletions
diff --git a/.clang-format b/.clang-format index 48a81211..1f74e789 100644 --- a/.clang-format +++ b/.clang-format @@ -1,10 +1,12 @@ --- Language: Cpp AccessModifierOffset: -8 -AlignAfterOpenBracket: true +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true AlignEscapedNewlinesLeft: false AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: true +AllowShortFunctionsOnASingleLine: Empty AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false BasedOnStyle: Mozilla @@ -12,10 +14,10 @@ BinPackArguments: false BinPackParameters: false BreakBeforeBraces: Linux BreakConstructorInitializersBeforeComma: true -ColumnLimit: 120 -ContinuationIndentWidth: 8 +ColumnLimit: 100 +CompactNamespaces: false IndentCaseLabels: false IndentWidth: 8 +KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 1 PointerAlignment: Right -UseTab: Always diff --git a/.gitignore b/.gitignore index fd54f2b6..591744d7 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ result *.dmg dist/MacOS/nheko.app/Contents/MacOS/nheko +.clang diff --git a/include/TimelineItem.h b/include/TimelineItem.h index af2e273c..df43c26d 100644 --- a/include/TimelineItem.h +++ b/include/TimelineItem.h @@ -32,65 +32,65 @@ #include "Text.h" namespace events = matrix::events; -namespace msgs = matrix::events::messages; +namespace msgs = matrix::events::messages; class TimelineItem : public QWidget { - Q_OBJECT + Q_OBJECT public: - TimelineItem(const events::MessageEvent<msgs::Notice> &e, - bool with_sender, - const QString &color, - QWidget *parent = 0); - TimelineItem(const events::MessageEvent<msgs::Text> &e, - bool with_sender, - const QString &color, - QWidget *parent = 0); + TimelineItem(const events::MessageEvent<msgs::Notice> &e, + bool with_sender, + QWidget *parent = 0); + TimelineItem(const events::MessageEvent<msgs::Text> &e, + bool with_sender, + QWidget *parent = 0); - // For local messages. - TimelineItem(const QString &userid, const QString &color, QString body, QWidget *parent = 0); - TimelineItem(QString body, QWidget *parent = 0); + // For local messages. + TimelineItem(const QString &userid, QString body, QWidget *parent = 0); + TimelineItem(QString body, QWidget *parent = 0); - TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, const QString &color, QWidget *parent); - TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, QWidget *parent); + TimelineItem(ImageItem *img, + const events::MessageEvent<msgs::Image> &e, + bool with_sender, + QWidget *parent); - void setUserAvatar(const QImage &pixmap); - inline DescInfo descriptionMessage() const; + void setUserAvatar(const QImage &pixmap); + inline DescInfo descriptionMessage() const; - ~TimelineItem(); + ~TimelineItem(); private: - void init(); + void init(); - void generateBody(const QString &body); - void generateBody(const QString &userid, const QString &color, const QString &body); - void generateTimestamp(const QDateTime &time); - QString descriptiveTime(const QDateTime &then); + void generateBody(const QString &body); + void generateBody(const QString &userid, const QString &body); + void generateTimestamp(const QDateTime &time); + QString descriptiveTime(const QDateTime &then); - void setupAvatarLayout(const QString &userName); - void setupSimpleLayout(); + void setupAvatarLayout(const QString &userName); + void setupSimpleLayout(); - QString replaceEmoji(const QString &body); + QString replaceEmoji(const QString &body); - DescInfo descriptionMsg_; + DescInfo descriptionMsg_; - QHBoxLayout *topLayout_; - QVBoxLayout *sideLayout_; // Avatar or Timestamp - QVBoxLayout *mainLayout_; // Header & Message body + QHBoxLayout *topLayout_; + QVBoxLayout *sideLayout_; // Avatar or Timestamp + QVBoxLayout *mainLayout_; // Header & Message body - QHBoxLayout *headerLayout_; // Username (&) Timestamp + QHBoxLayout *headerLayout_; // Username (&) Timestamp - Avatar *userAvatar_; + Avatar *userAvatar_; - QFont font_; + QFont font_; - QLabel *timestamp_; - QLabel *userName_; - QLabel *body_; + QLabel *timestamp_; + QLabel *userName_; + QLabel *body_; }; inline DescInfo TimelineItem::descriptionMessage() const { - return descriptionMsg_; + return descriptionMsg_; } diff --git a/include/TimelineView.h b/include/TimelineView.h index 17c2610a..c6eef266 100644 --- a/include/TimelineView.h +++ b/include/TimelineView.h @@ -32,122 +32,121 @@ #include "RoomInfoListItem.h" #include "Text.h" -namespace msgs = matrix::events::messages; +namespace msgs = matrix::events::messages; namespace events = matrix::events; // Contains info about a message shown in the history view // but not yet confirmed by the homeserver through sync. struct PendingMessage { - int txn_id; - QString body; - QString event_id; - TimelineItem *widget; - - PendingMessage(int txn_id, QString body, QString event_id, TimelineItem *widget) - : txn_id(txn_id) - , body(body) - , event_id(event_id) - , widget(widget) - { - } + int txn_id; + QString body; + QString event_id; + TimelineItem *widget; + + PendingMessage(int txn_id, QString body, QString event_id, TimelineItem *widget) + : txn_id(txn_id) + , body(body) + , event_id(event_id) + , widget(widget) + { + } }; // In which place new TimelineItems should be inserted. enum class TimelineDirection { - Top, - Bottom, + Top, + Bottom, }; class TimelineView : public QWidget { - Q_OBJECT + Q_OBJECT public: - TimelineView(const Timeline &timeline, - QSharedPointer<MatrixClient> client, - const QString &room_id, - QWidget *parent = 0); - TimelineView(QSharedPointer<MatrixClient> client, const QString &room_id, QWidget *parent = 0); - - TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Image> &e, - const QString &color, - bool with_sender); - TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Notice> &e, - const QString &color, - bool with_sender); - TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Text> &e, - const QString &color, - bool with_sender); - - // Add new events at the end of the timeline. - int addEvents(const Timeline &timeline); - void addUserTextMessage(const QString &msg, int txn_id); - void updatePendingMessage(int txn_id, QString event_id); - void scrollDown(); + TimelineView(const Timeline &timeline, + QSharedPointer<MatrixClient> client, + const QString &room_id, + QWidget *parent = 0); + TimelineView(QSharedPointer<MatrixClient> client, + const QString &room_id, + QWidget *parent = 0); + + TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Image> &e, + bool with_sender); + TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Notice> &e, + bool with_sender); + TimelineItem *createTimelineItem(const events::MessageEvent<msgs::Text> &e, + bool with_sender); + + // Add new events at the end of the timeline. + int addEvents(const Timeline &timeline); + void addUserTextMessage(const QString &msg, int txn_id); + void updatePendingMessage(int txn_id, QString event_id); + void scrollDown(); public slots: - void sliderRangeChanged(int min, int max); - void sliderMoved(int position); - void fetchHistory(); + void sliderRangeChanged(int min, int max); + void sliderMoved(int position); + void fetchHistory(); - // Add old events at the top of the timeline. - void addBackwardsEvents(const QString &room_id, const RoomMessages &msgs); + // Add old events at the top of the timeline. + void addBackwardsEvents(const QString &room_id, const RoomMessages &msgs); signals: - void updateLastTimelineMessage(const QString &user, const DescInfo &info); + void updateLastTimelineMessage(const QString &user, const DescInfo &info); private: - void init(); - void removePendingMessage(const events::MessageEvent<msgs::Text> &e); - void addTimelineItem(TimelineItem *item, TimelineDirection direction); - void updateLastSender(const QString &user_id, TimelineDirection direction); - void notifyForLastEvent(); + void init(); + void removePendingMessage(const events::MessageEvent<msgs::Text> &e); + void addTimelineItem(TimelineItem *item, TimelineDirection direction); + void updateLastSender(const QString &user_id, TimelineDirection direction); + void notifyForLastEvent(); - // Used to determine whether or not we should prefix a message with the sender's name. - bool isSenderRendered(const QString &user_id, TimelineDirection direction); - bool isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &userid); - inline bool isDuplicate(const QString &event_id); + // Used to determine whether or not we should prefix a message with the sender's name. + bool isSenderRendered(const QString &user_id, TimelineDirection direction); + bool isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &userid); + inline bool isDuplicate(const QString &event_id); - // Return nullptr if the event couldn't be parsed. - TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction); + // Return nullptr if the event couldn't be parsed. + TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction); - QVBoxLayout *top_layout_; - QVBoxLayout *scroll_layout_; + QVBoxLayout *top_layout_; + QVBoxLayout *scroll_layout_; - QScrollArea *scroll_area_; - ScrollBar *scrollbar_; - QWidget *scroll_widget_; + QScrollArea *scroll_area_; + ScrollBar *scrollbar_; + QWidget *scroll_widget_; - QString lastSender_; - QString firstSender_; - QString room_id_; - QString prev_batch_token_; - QString local_user_; + QString lastSender_; + QString firstSender_; + QString room_id_; + QString prev_batch_token_; + QString local_user_; - bool isPaginationInProgress_ = false; - bool isInitialized = false; - bool isTimelineFinished = false; - bool isInitialSync = true; - bool isPaginationScrollPending_ = false; + bool isPaginationInProgress_ = false; + bool isInitialized = false; + bool isTimelineFinished = false; + bool isInitialSync = true; + bool isPaginationScrollPending_ = false; - const int SCROLL_BAR_GAP = 400; + const int SCROLL_BAR_GAP = 400; - QTimer *paginationTimer_; + QTimer *paginationTimer_; - int scroll_height_ = 0; - int previous_max_height_ = 0; + int scroll_height_ = 0; + int previous_max_height_ = 0; - int oldPosition_; - int oldHeight_; + int oldPosition_; + int oldHeight_; - // The events currently rendered. Used for duplicate detection. - QMap<QString, bool> eventIds_; - QList<PendingMessage> pending_msgs_; - QSharedPointer<MatrixClient> client_; + // The events currently rendered. Used for duplicate detection. + QMap<QString, bool> eventIds_; + QList<PendingMessage> pending_msgs_; + QSharedPointer<MatrixClient> client_; }; inline bool TimelineView::isDuplicate(const QString &event_id) { - return eventIds_.contains(event_id); + return eventIds_.contains(event_id); } diff --git a/include/TimelineViewManager.h b/include/TimelineViewManager.h index 64140e3a..85e186dc 100644 --- a/include/TimelineViewManager.h +++ b/include/TimelineViewManager.h @@ -29,39 +29,37 @@ class TimelineViewManager : public QStackedWidget { - Q_OBJECT + Q_OBJECT public: - TimelineViewManager(QSharedPointer<MatrixClient> client, QWidget *parent); - ~TimelineViewManager(); + TimelineViewManager(QSharedPointer<MatrixClient> client, QWidget *parent); + ~TimelineViewManager(); - // Initialize with timeline events. - void initialize(const Rooms &rooms); - // Empty initialization. - void initialize(const QList<QString> &rooms); - void sync(const Rooms &rooms); - void clearAll(); + // Initialize with timeline events. + void initialize(const Rooms &rooms); + // Empty initialization. + void initialize(const QList<QString> &rooms); + void sync(const Rooms &rooms); + void clearAll(); - static QString chooseRandomColor(); - static QString getUserColor(const QString &userid); - static QString displayName(const QString &userid); + static QString chooseRandomColor(); + static QString displayName(const QString &userid); - static QMap<QString, QString> NICK_COLORS; - static QMap<QString, QString> DISPLAY_NAMES; + static QMap<QString, QString> DISPLAY_NAMES; signals: - void unreadMessages(QString roomid, int count); - void updateRoomsLastMessage(const QString &user, const DescInfo &info); + void unreadMessages(QString roomid, int count); + void updateRoomsLastMessage(const QString &user, const DescInfo &info); public slots: - void setHistoryView(const QString &room_id); - void sendTextMessage(const QString &msg); + void setHistoryView(const QString &room_id); + void sendTextMessage(const QString &msg); private slots: - void messageSent(const QString &eventid, const QString &roomid, int txnid); + void messageSent(const QString &eventid, const QString &roomid, int txnid); private: - QString active_room_; - QMap<QString, QSharedPointer<TimelineView>> views_; - QSharedPointer<MatrixClient> client_; + QString active_room_; + QMap<QString, QSharedPointer<TimelineView>> views_; + QSharedPointer<MatrixClient> client_; }; diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc index 70cecca4..cfa5a988 100644 --- a/src/TimelineItem.cc +++ b/src/TimelineItem.cc @@ -31,62 +31,62 @@ static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)"); static const QString URL_HTML = "<a href=\"\\1\" style=\"color: #333333\">\\1</a>"; namespace events = matrix::events; -namespace msgs = matrix::events::messages; +namespace msgs = matrix::events::messages; void TimelineItem::init() { - userAvatar_ = nullptr; - timestamp_ = nullptr; - userName_ = nullptr; - body_ = nullptr; + userAvatar_ = nullptr; + timestamp_ = nullptr; + userName_ = nullptr; + body_ = nullptr; - font_.setPixelSize(conf::fontSize); + font_.setPixelSize(conf::fontSize); - QFontMetrics fm(font_); + QFontMetrics fm(font_); - topLayout_ = new QHBoxLayout(this); - sideLayout_ = new QVBoxLayout(); - mainLayout_ = new QVBoxLayout(); - headerLayout_ = new QHBoxLayout(); + topLayout_ = new QHBoxLayout(this); + sideLayout_ = new QVBoxLayout(); + mainLayout_ = new QVBoxLayout(); + headerLayout_ = new QHBoxLayout(); - topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin, 0, 0); - topLayout_->setSpacing(0); + topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin, 0, 0); + topLayout_->setSpacing(0); - topLayout_->addLayout(sideLayout_); - topLayout_->addLayout(mainLayout_, 1); + topLayout_->addLayout(sideLayout_); + topLayout_->addLayout(mainLayout_, 1); - sideLayout_->setMargin(0); - sideLayout_->setSpacing(0); + sideLayout_->setMargin(0); + sideLayout_->setSpacing(0); - mainLayout_->setContentsMargins(conf::timeline::headerLeftMargin, 0, 0, 0); - mainLayout_->setSpacing(0); + mainLayout_->setContentsMargins(conf::timeline::headerLeftMargin, 0, 0, 0); + mainLayout_->setSpacing(0); - headerLayout_->setMargin(0); - headerLayout_->setSpacing(conf::timeline::headerSpacing); + headerLayout_->setMargin(0); + headerLayout_->setSpacing(conf::timeline::headerSpacing); } /* * For messages created locally. The avatar and the username are displayed. */ -TimelineItem::TimelineItem(const QString &userid, const QString &color, QString body, QWidget *parent) +TimelineItem::TimelineItem(const QString &userid, QString body, QWidget *parent) : QWidget(parent) { - init(); - descriptionMsg_ = { "You: ", userid, body, descriptiveTime(QDateTime::currentDateTime()) }; + init(); + descriptionMsg_ = { "You: ", userid, body, descriptiveTime(QDateTime::currentDateTime()) }; - body.replace(URL_REGEX, URL_HTML); - auto displayName = TimelineViewManager::displayName(userid); + body.replace(URL_REGEX, URL_HTML); + auto displayName = TimelineViewManager::displayName(userid); - generateTimestamp(QDateTime::currentDateTime()); - generateBody(displayName, color, body); + generateTimestamp(QDateTime::currentDateTime()); + generateBody(displayName, body); - setupAvatarLayout(displayName); + setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); - mainLayout_->addWidget(body_); + mainLayout_->addLayout(headerLayout_); + mainLayout_->addWidget(body_); - AvatarProvider::resolve(userid, this); + AvatarProvider::resolve(userid, this); } /* @@ -95,323 +95,301 @@ TimelineItem::TimelineItem(const QString &userid, const QString &color, QString TimelineItem::TimelineItem(QString body, QWidget *parent) : QWidget(parent) { - QSettings settings; - auto userid = settings.value("auth/user_id").toString(); + QSettings settings; + auto userid = settings.value("auth/user_id").toString(); - init(); - descriptionMsg_ = { "You: ", userid, body, descriptiveTime(QDateTime::currentDateTime()) }; + init(); + descriptionMsg_ = { "You: ", userid, body, descriptiveTime(QDateTime::currentDateTime()) }; - body.replace(URL_REGEX, URL_HTML); + body.replace(URL_REGEX, URL_HTML); - generateTimestamp(QDateTime::currentDateTime()); - generateBody(body); + generateTimestamp(QDateTime::currentDateTime()); + generateBody(body); - setupSimpleLayout(); + setupSimpleLayout(); - mainLayout_->addWidget(body_); + mainLayout_->addWidget(body_); } /* * Used to display images. The avatar and the username are displayed. */ TimelineItem::TimelineItem(ImageItem *image, - const events::MessageEvent<msgs::Image> &event, - const QString &color, - QWidget *parent) + const events::MessageEvent<msgs::Image> &event, + bool with_sender, + QWidget *parent) : QWidget(parent) { - init(); + init(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + auto displayName = TimelineViewManager::displayName(event.sender()); - QSettings settings; - descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName, - event.sender(), - " sent an image", - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; + QSettings settings; + descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName, + event.sender(), + " sent an image", + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; - generateTimestamp(timestamp); - generateBody(displayName, color, ""); + generateTimestamp(timestamp); - setupAvatarLayout(displayName); + auto imageLayout = new QHBoxLayout(); + imageLayout->setMargin(0); + imageLayout->addWidget(image); + imageLayout->addStretch(1); - auto imageLayout = new QHBoxLayout(); - imageLayout->addWidget(image); - imageLayout->addStretch(1); + if (with_sender) { + generateBody(displayName, ""); + setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); - mainLayout_->addLayout(imageLayout); + mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); -} - -/* - * Used to display images. Only the image is displayed. - */ -TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, QWidget *parent) - : QWidget(parent) -{ - init(); - - auto displayName = TimelineViewManager::displayName(event.sender()); + AvatarProvider::resolve(event.sender(), this); + } else { + setupSimpleLayout(); + } - QSettings settings; - descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName, - event.sender(), - " sent an image", - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; - - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - generateTimestamp(timestamp); - - setupSimpleLayout(); - - auto imageLayout = new QHBoxLayout(); - imageLayout->setMargin(0); - imageLayout->addWidget(image); - imageLayout->addStretch(1); - - mainLayout_->addLayout(imageLayout); + mainLayout_->addLayout(imageLayout); } /* * Used to display remote notice messages. */ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, - bool with_sender, - const QString &color, - QWidget *parent) + bool with_sender, + QWidget *parent) : QWidget(parent) { - init(); - descriptionMsg_ = { TimelineViewManager::displayName(event.sender()), - event.sender(), - " sent a notification", - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; + init(); + descriptionMsg_ = { TimelineViewManager::displayName(event.sender()), + event.sender(), + " sent a notification", + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; - auto body = event.content().body().trimmed().toHtmlEscaped(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + auto body = event.content().body().trimmed().toHtmlEscaped(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - generateTimestamp(timestamp); + generateTimestamp(timestamp); - body.replace(URL_REGEX, URL_HTML); - body = "<i style=\"color: #565E5E\">" + body + "</i>"; + body.replace(URL_REGEX, URL_HTML); + body = "<i style=\"color: #565E5E\">" + body + "</i>"; - if (with_sender) { - auto displayName = TimelineViewManager::displayName(event.sender()); + if (with_sender) { + auto displayName = TimelineViewManager::displayName(event.sender()); - generateBody(displayName, color, body); - setupAvatarLayout(displayName); + generateBody(displayName, body); + setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); + mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); - } else { - generateBody(body); - setupSimpleLayout(); - } + AvatarProvider::resolve(event.sender(), this); + } else { + generateBody(body); + setupSimpleLayout(); + } - mainLayout_->addWidget(body_); + mainLayout_->addWidget(body_); } /* * Used to display remote text messages. */ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, - bool with_sender, - const QString &color, - QWidget *parent) + bool with_sender, + QWidget *parent) : QWidget(parent) { - init(); + init(); - auto body = event.content().body().trimmed().toHtmlEscaped(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); + auto body = event.content().body().trimmed().toHtmlEscaped(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + auto displayName = TimelineViewManager::displayName(event.sender()); - QSettings settings; - descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName, - event.sender(), - QString(": %1").arg(body), - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; + QSettings settings; + descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName, + event.sender(), + QString(": %1").arg(body), + descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) }; - generateTimestamp(timestamp); + generateTimestamp(timestamp); - body.replace(URL_REGEX, URL_HTML); + body.replace(URL_REGEX, URL_HTML); - if (with_sender) { - auto displayName = TimelineViewManager::displayName(event.sender()); + if (with_sender) { + auto displayName = TimelineViewManager::displayName(event.sender()); - generateBody(displayName, color, body); - setupAvatarLayout(displayName); + generateBody(displayName, body); + setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); + mainLayout_->addLayout(headerLayout_); - AvatarProvider::resolve(event.sender(), this); - } else { - generateBody(body); - setupSimpleLayout(); - } + AvatarProvider::resolve(event.sender(), this); + } else { + generateBody(body); + setupSimpleLayout(); + } - mainLayout_->addWidget(body_); + mainLayout_->addWidget(body_); } // Only the body is displayed. void TimelineItem::generateBody(const QString &body) { - QString content("<span style=\"color: black;\"> %1 </span>"); + QString content("<span style=\"color: black;\"> %1 </span>"); - body_ = new QLabel(this); - body_->setFont(font_); - body_->setWordWrap(true); - body_->setText(content.arg(replaceEmoji(body))); - body_->setMargin(0); + body_ = new QLabel(this); + body_->setFont(font_); + body_->setWordWrap(true); + body_->setText(content.arg(replaceEmoji(body))); + body_->setMargin(0); - body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - body_->setOpenExternalLinks(true); + body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); + body_->setOpenExternalLinks(true); } // The username/timestamp is displayed along with the message body. void -TimelineItem::generateBody(const QString &userid, const QString &color, const QString &body) +TimelineItem::generateBody(const QString &userid, const QString &body) { - auto sender = userid; + auto sender = userid; - // TODO: Fix this by using a UserId type. - if (userid.split(":")[0].split("@").size() > 1) - sender = userid.split(":")[0].split("@")[1]; + // TODO: Fix this by using a UserId type. + if (userid.split(":")[0].split("@").size() > 1) + sender = userid.split(":")[0].split("@")[1]; - QString userContent("<span style=\"color: %1\"> %2 </span>"); - QString bodyContent("<span style=\"color: #171717;\"> %1 </span>"); + QString userContent("<span style=\"color: #171717\"> %1 </span>"); + QString bodyContent("<span style=\"color: #171717;\"> %1 </span>"); - QFont usernameFont = font_; - usernameFont.setBold(true); + QFont usernameFont = font_; + usernameFont.setBold(true); - userName_ = new QLabel(this); - userName_->setFont(usernameFont); - userName_->setText(userContent.arg(color).arg(sender)); + userName_ = new QLabel(this); + userName_->setFont(usernameFont); + userName_->setText(userContent.arg(sender)); - if (body.isEmpty()) - return; + if (body.isEmpty()) + return; - body_ = new QLabel(this); - body_->setFont(font_); - body_->setWordWrap(true); - body_->setText(bodyContent.arg(replaceEmoji(body))); - body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - body_->setOpenExternalLinks(true); - body_->setMargin(0); + body_ = new QLabel(this); + body_->setFont(font_); + body_->setWordWrap(true); + body_->setText(bodyContent.arg(replaceEmoji(body))); + body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); + body_->setOpenExternalLinks(true); + body_->setMargin(0); } void TimelineItem::generateTimestamp(const QDateTime &time) { - QString msg("<span style=\"color: #5d6565;\"> %1 </span>"); + QString msg("<span style=\"color: #5d6565;\"> %1 </span>"); - QFont timestampFont; - timestampFont.setPixelSize(conf::timeline::fonts::timestamp); + QFont timestampFont; + timestampFont.setPixelSize(conf::timeline::fonts::timestamp); - QFontMetrics fm(timestampFont); - int topMargin = QFontMetrics(font_).ascent() - fm.ascent(); + QFontMetrics fm(timestampFont); + int topMargin = QFontMetrics(font_).ascent() - fm.ascent(); - timestamp_ = new QLabel(this); - timestamp_->setFont(timestampFont); - timestamp_->setText(msg.arg(time.toString("HH:mm"))); - timestamp_->setContentsMargins(0, topMargin, 0, 0); + timestamp_ = new QLabel(this); + timestamp_->setFont(timestampFont); + timestamp_->setText(msg.arg(time.toString("HH:mm"))); + timestamp_->setContentsMargins(0, topMargin, 0, 0); } QString TimelineItem::replaceEmoji(const QString &body) { - QString fmtBody = ""; - - for (auto &c : body) { - int code = c.unicode(); - - // TODO: Be more precise here. - if (code > 9000) - fmtBody += QString("<span style=\"font-family: Emoji One; font-size: %1px\">") - .arg(conf::emojiSize) + - QString(c) + "</span>"; - else - fmtBody += c; - } - - return fmtBody; + QString fmtBody = ""; + + for (auto &c : body) { + int code = c.unicode(); + + // TODO: Be more precise here. + if (code > 9000) + fmtBody += QString("<span style=\"font-family: Emoji " + "One; font-size: %1px\">") + .arg(conf::emojiSize) + + QString(c) + "</span>"; + else + fmtBody += c; + } + + return fmtBody; } void TimelineItem::setupAvatarLayout(const QString &userName) { - topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin, 0, 0); + topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin, 0, 0); - userAvatar_ = new Avatar(this); - userAvatar_->setLetter(QChar(userName[0]).toUpper()); - userAvatar_->setBackgroundColor(QColor("#eee")); - userAvatar_->setTextColor(QColor("black")); - userAvatar_->setSize(conf::timeline::avatarSize); + userAvatar_ = new Avatar(this); + userAvatar_->setLetter(QChar(userName[0]).toUpper()); + userAvatar_->setBackgroundColor(QColor("#eee")); + userAvatar_->setTextColor(QColor("black")); + userAvatar_->setSize(conf::timeline::avatarSize); - // TODO: The provided user name should be a UserId class - if (userName[0] == '@' && userName.size() > 1) - userAvatar_->setLetter(QChar(userName[1]).toUpper()); + // TODO: The provided user name should be a UserId class + if (userName[0] == '@' && userName.size() > 1) + userAvatar_->setLetter(QChar(userName[1]).toUpper()); - sideLayout_->addWidget(userAvatar_); - sideLayout_->addStretch(1); + sideLayout_->addWidget(userAvatar_); + sideLayout_->addStretch(1); - headerLayout_->addWidget(userName_); - headerLayout_->addWidget(timestamp_, 1); + headerLayout_->addWidget(userName_); + headerLayout_->addWidget(timestamp_, 1); } void TimelineItem::setupSimpleLayout() { - sideLayout_->addWidget(timestamp_); + sideLayout_->addWidget(timestamp_); - // Keep only the time in plain text. - QTextEdit htmlText(timestamp_->text()); - QString plainText = htmlText.toPlainText(); + // Keep only the time in plain text. + QTextEdit htmlText(timestamp_->text()); + QString plainText = htmlText.toPlainText(); - timestamp_->adjustSize(); + timestamp_->adjustSize(); - // Align the end of the avatar bubble with the end of the timestamp for - // messages with and without avatar. Otherwise their bodies would not be aligned. - int tsWidth = timestamp_->fontMetrics().width(plainText); - int offset = std::max(0, conf::timeline::avatarSize - tsWidth); + // Align the end of the avatar bubble with the end of the timestamp for + // messages with and without avatar. Otherwise their bodies would not be + // aligned. + int tsWidth = timestamp_->fontMetrics().width(plainText); + int offset = std::max(0, conf::timeline::avatarSize - tsWidth); - int defaultFontHeight = QFontMetrics(font_).ascent(); + int defaultFontHeight = QFontMetrics(font_).ascent(); - timestamp_->setAlignment(Qt::AlignTop); - timestamp_->setContentsMargins(offset + 1, defaultFontHeight - timestamp_->fontMetrics().ascent(), 0, 0); - topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin / 3, 0, 0); + timestamp_->setAlignment(Qt::AlignTop); + timestamp_->setContentsMargins( + offset + 1, defaultFontHeight - timestamp_->fontMetrics().ascent(), 0, 0); + topLayout_->setContentsMargins( + conf::timeline::msgMargin, conf::timeline::msgMargin / 3, 0, 0); } void TimelineItem::setUserAvatar(const QImage &avatar) { - if (userAvatar_ == nullptr) - return; + if (userAvatar_ == nullptr) + return; - userAvatar_->setImage(avatar); + userAvatar_->setImage(avatar); } QString TimelineItem::descriptiveTime(const QDateTime &then) { - auto now = QDateTime::currentDateTime(); + auto now = QDateTime::currentDateTime(); - auto days = then.daysTo(now); + auto days = then.daysTo(now); - if (days == 0) { - return then.toString("HH:mm"); - } else if (days < 2) { - return QString("Yesterday"); - } else if (days < 365) { - return then.toString("dd/MM"); - } + if (days == 0) + return then.toString("HH:mm"); + else if (days < 2) + return QString("Yesterday"); + else if (days < 365) + return then.toString("dd/MM"); - return then.toString("dd/MM/yy"); + return then.toString("dd/MM/yy"); } TimelineItem::~TimelineItem() diff --git a/src/TimelineView.cc b/src/TimelineView.cc index 80afcfa2..114e5fda 100644 --- a/src/TimelineView.cc +++ b/src/TimelineView.cc @@ -32,455 +32,457 @@ #include "TimelineViewManager.h" namespace events = matrix::events; -namespace msgs = matrix::events::messages; +namespace msgs = matrix::events::messages; TimelineView::TimelineView(const Timeline &timeline, - QSharedPointer<MatrixClient> client, - const QString &room_id, - QWidget *parent) + QSharedPointer<MatrixClient> client, + const QString &room_id, + QWidget *parent) : QWidget(parent) , room_id_{ room_id } , client_{ client } { - QSettings settings; - local_user_ = settings.value("auth/user_id").toString(); + QSettings settings; + local_user_ = settings.value("auth/user_id").toString(); - init(); - addEvents(timeline); + init(); + addEvents(timeline); } -TimelineView::TimelineView(QSharedPointer<MatrixClient> client, const QString &room_id, QWidget *parent) +TimelineView::TimelineView(QSharedPointer<MatrixClient> client, + const QString &room_id, + QWidget *parent) : QWidget(parent) , room_id_{ room_id } , client_{ client } { - QSettings settings; - local_user_ = settings.value("auth/user_id").toString(); + QSettings settings; + local_user_ = settings.value("auth/user_id").toString(); - init(); - client_->messages(room_id_, ""); + init(); + client_->messages(room_id_, ""); } void TimelineView::sliderRangeChanged(int min, int max) { - Q_UNUSED(min); + Q_UNUSED(min); - if (!scroll_area_->verticalScrollBar()->isVisible()) { - scroll_area_->verticalScrollBar()->setValue(max); - return; - } + if (!scroll_area_->verticalScrollBar()->isVisible()) { + scroll_area_->verticalScrollBar()->setValue(max); + return; + } - if (max - scroll_area_->verticalScrollBar()->value() < SCROLL_BAR_GAP) - scroll_area_->verticalScrollBar()->setValue(max); + if (max - scroll_area_->verticalScrollBar()->value() < SCROLL_BAR_GAP) + scroll_area_->verticalScrollBar()->setValue(max); - if (isPaginationScrollPending_) { - isPaginationScrollPending_ = false; + if (isPaginationScrollPending_) { + isPaginationScrollPending_ = false; - int currentHeight = scroll_widget_->size().height(); - int diff = currentHeight - oldHeight_; - int newPosition = oldPosition_ + diff; + int currentHeight = scroll_widget_->size().height(); + int diff = currentHeight - oldHeight_; + int newPosition = oldPosition_ + diff; - // Keep the scroll bar to the bottom if we are coming from - // an scrollbar without height i.e scrollbar->value() == 0 - if (oldPosition_ == 0) - newPosition = max; + // Keep the scroll bar to the bottom if we are coming from + // an scrollbar without height i.e scrollbar->value() == 0 + if (oldPosition_ == 0) + newPosition = max; - scroll_area_->verticalScrollBar()->setValue(newPosition); - } + scroll_area_->verticalScrollBar()->setValue(newPosition); + } } void TimelineView::fetchHistory() { - bool hasEnoughMessages = scroll_area_->verticalScrollBar()->value() != 0; + bool hasEnoughMessages = scroll_area_->verticalScrollBar()->value() != 0; - if (!hasEnoughMessages && !isTimelineFinished) { - isPaginationInProgress_ = true; - client_->messages(room_id_, prev_batch_token_); - paginationTimer_->start(500); - return; - } + if (!hasEnoughMessages && !isTimelineFinished) { + isPaginationInProgress_ = true; + client_->messages(room_id_, prev_batch_token_); + paginationTimer_->start(500); + return; + } - paginationTimer_->stop(); + paginationTimer_->stop(); } void TimelineView::scrollDown() { - int current = scroll_area_->verticalScrollBar()->value(); - int max = scroll_area_->verticalScrollBar()->maximum(); - - // The first time we enter the room move the scroll bar to the bottom. - if (!isInitialized) { - scroll_area_->verticalScrollBar()->setValue(max); - isInitialized = true; - return; - } - - // If the gap is small enough move the scroll bar down. e.g when a new message appears. - if (max - current < SCROLL_BAR_GAP) - scroll_area_->verticalScrollBar()->setValue(max); + int current = scroll_area_->verticalScrollBar()->value(); + int max = scroll_area_->verticalScrollBar()->maximum(); + + // The first time we enter the room move the scroll bar to the bottom. + if (!isInitialized) { + scroll_area_->verticalScrollBar()->setValue(max); + isInitialized = true; + return; + } + + // If the gap is small enough move the scroll bar down. e.g when a new + // message appears. + if (max - current < SCROLL_BAR_GAP) + scroll_area_->verticalScrollBar()->setValue(max); } void TimelineView::sliderMoved(int position) { - if (!scroll_area_->verticalScrollBar()->isVisible()) - return; - - // The scrollbar is high enough so we can start retrieving old events. - if (position < SCROLL_BAR_GAP) { - if (isTimelineFinished) - return; - - // Prevent user from moving up when there is pagination in progress. - // TODO: Keep a map of the event ids to filter out duplicates. - if (isPaginationInProgress_) - return; - - isPaginationInProgress_ = true; - - // FIXME: Maybe move this to TimelineViewManager to remove the extra calls? - client_->messages(room_id_, prev_batch_token_); - } + if (!scroll_area_->verticalScrollBar()->isVisible()) + return; + + // The scrollbar is high enough so we can start retrieving old events. + if (position < SCROLL_BAR_GAP) { + if (isTimelineFinished) + return; + + // Prevent user from moving up when there is pagination in + // progress. + // TODO: Keep a map of the event ids to filter out duplicates. + if (isPaginationInProgress_) + return; + + isPaginationInProgress_ = true; + + // FIXME: Maybe move this to TimelineViewManager to remove the + // extra calls? + client_->messages(room_id_, prev_batch_token_); + } } void TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msgs) { - if (room_id_ != room_id) - return; + if (room_id_ != room_id) + return; - if (msgs.chunk().count() == 0) { - isTimelineFinished = true; - return; - } + if (msgs.chunk().count() == 0) { + isTimelineFinished = true; + return; + } - isTimelineFinished = false; - QList<TimelineItem *> items; + isTimelineFinished = false; + QList<TimelineItem *> items; - // Parse in reverse order to determine where we should not show sender's name. - auto it = msgs.chunk().constEnd(); - while (it != msgs.chunk().constBegin()) { - --it; + // Parse in reverse order to determine where we should not show sender's + // name. + auto it = msgs.chunk().constEnd(); + while (it != msgs.chunk().constBegin()) { + --it; - TimelineItem *item = parseMessageEvent((*it).toObject(), TimelineDirection::Top); + TimelineItem *item = parseMessageEvent((*it).toObject(), TimelineDirection::Top); - if (item != nullptr) - items.push_back(item); - } + if (item != nullptr) + items.push_back(item); + } - // Reverse again to render them. - std::reverse(items.begin(), items.end()); + // Reverse again to render them. + std::reverse(items.begin(), items.end()); - oldPosition_ = scroll_area_->verticalScrollBar()->value(); - oldHeight_ = scroll_widget_->size().height(); + oldPosition_ = scroll_area_->verticalScrollBar()->value(); + oldHeight_ = scroll_widget_->size().height(); - for (const auto &item : items) - addTimelineItem(item, TimelineDirection::Top); + for (const auto &item : items) + addTimelineItem(item, TimelineDirection::Top); - prev_batch_token_ = msgs.end(); - isPaginationInProgress_ = false; - isPaginationScrollPending_ = true; + prev_batch_token_ = msgs.end(); + isPaginationInProgress_ = false; + isPaginationScrollPending_ = true; - // Exclude the top stretch. - if (!msgs.chunk().isEmpty() && scroll_layout_->count() > 1) - notifyForLastEvent(); + // Exclude the top stretch. + if (!msgs.chunk().isEmpty() && scroll_layout_->count() > 1) + notifyForLastEvent(); - // If this batch is the first being rendered (i.e the first and the last events - // originate from this batch), set the last sender. - if (lastSender_.isEmpty() && !items.isEmpty()) - lastSender_ = items.constFirst()->descriptionMessage().userid; + // If this batch is the first being rendered (i.e the first and the last + // events originate from this batch), set the last sender. + if (lastSender_.isEmpty() && !items.isEmpty()) + lastSender_ = items.constFirst()->descriptionMessage().userid; } TimelineItem * TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection direction) { - events::EventType ty = events::extractEventType(event); + events::EventType ty = events::extractEventType(event); - if (ty == events::EventType::RoomMessage) { - events::MessageEventType msg_type = events::extractMessageEventType(event); + if (ty == events::EventType::RoomMessage) { + events::MessageEventType msg_type = events::extractMessageEventType(event); - if (msg_type == events::MessageEventType::Text) { - events::MessageEvent<msgs::Text> text; + if (msg_type == events::MessageEventType::Text) { + events::MessageEvent<msgs::Text> text; - try { - text.deserialize(event); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - return nullptr; - } + try { + text.deserialize(event); + } catch (const DeserializationException &e) { + qWarning() << e.what() << event; + return nullptr; + } - if (isDuplicate(text.eventId())) - return nullptr; + if (isDuplicate(text.eventId())) + return nullptr; - eventIds_[text.eventId()] = true; + eventIds_[text.eventId()] = true; - if (isPendingMessage(text, local_user_)) { - removePendingMessage(text); - return nullptr; - } + if (isPendingMessage(text, local_user_)) { + removePendingMessage(text); + return nullptr; + } - auto with_sender = isSenderRendered(text.sender(), direction); - auto color = TimelineViewManager::getUserColor(text.sender()); + auto with_sender = isSenderRendered(text.sender(), direction); - updateLastSender(text.sender(), direction); + updateLastSender(text.sender(), direction); - return createTimelineItem(text, color, with_sender); - } else if (msg_type == events::MessageEventType::Notice) { - events::MessageEvent<msgs::Notice> notice; + return createTimelineItem(text, with_sender); + } else if (msg_type == events::MessageEventType::Notice) { + events::MessageEvent<msgs::Notice> notice; - try { - notice.deserialize(event); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - return nullptr; - } + try { + notice.deserialize(event); + } catch (const DeserializationException &e) { + qWarning() << e.what() << event; + return nullptr; + } - if (isDuplicate(notice.eventId())) - return nullptr; - ; + if (isDuplicate(notice.eventId())) + return nullptr; + ; - eventIds_[notice.eventId()] = true; + eventIds_[notice.eventId()] = true; - auto with_sender = isSenderRendered(notice.sender(), direction); - auto color = TimelineViewManager::getUserColor(notice.sender()); + auto with_sender = isSenderRendered(notice.sender(), direction); - updateLastSender(notice.sender(), direction); + updateLastSender(notice.sender(), direction); - return createTimelineItem(notice, color, with_sender); - } else if (msg_type == events::MessageEventType::Image) { - events::MessageEvent<msgs::Image> img; + return createTimelineItem(notice, with_sender); + } else if (msg_type == events::MessageEventType::Image) { + events::MessageEvent<msgs::Image> img; - try { - img.deserialize(event); - } catch (const DeserializationException &e) { - qWarning() << e.what() << event; - return nullptr; - } + try { + img.deserialize(event); + } catch (const DeserializationException &e) { + qWarning() << e.what() << event; + return nullptr; + } - if (isDuplicate(img.eventId())) - return nullptr; + if (isDuplicate(img.eventId())) + return nullptr; - eventIds_[img.eventId()] = true; + eventIds_[img.eventId()] = true; - auto with_sender = isSenderRendered(img.sender(), direction); - auto color = TimelineViewManager::getUserColor(img.sender()); + auto with_sender = isSenderRendered(img.sender(), direction); - updateLastSender(img.sender(), direction); + updateLastSender(img.sender(), direction); - return createTimelineItem(img, color, with_sender); - } else if (msg_type == events::MessageEventType::Unknown) { - qWarning() << "Unknown message type" << event; - return nullptr; - } - } + return createTimelineItem(img, with_sender); + } else if (msg_type == events::MessageEventType::Unknown) { + qWarning() << "Unknown message type" << event; + return nullptr; + } + } - return nullptr; + return nullptr; } int TimelineView::addEvents(const Timeline &timeline) { - int message_count = 0; + int message_count = 0; - QSettings settings; - QString localUser = settings.value("auth/user_id").toString(); + QSettings settings; + QString localUser = settings.value("auth/user_id").toString(); - for (const auto &event : timeline.events()) { - TimelineItem *item = parseMessageEvent(event.toObject(), TimelineDirection::Bottom); + for (const auto &event : timeline.events()) { + TimelineItem *item = parseMessageEvent(event.toObject(), TimelineDirection::Bottom); - if (item != nullptr) { - addTimelineItem(item, TimelineDirection::Bottom); + if (item != nullptr) { + addTimelineItem(item, TimelineDirection::Bottom); - if (localUser != event.toObject().value("sender").toString()) - message_count += 1; - } - } + if (localUser != event.toObject().value("sender").toString()) + message_count += 1; + } + } - if (isInitialSync) { - prev_batch_token_ = timeline.previousBatch(); - isInitialSync = false; + if (isInitialSync) { + prev_batch_token_ = timeline.previousBatch(); + isInitialSync = false; - client_->messages(room_id_, prev_batch_token_); - } + client_->messages(room_id_, prev_batch_token_); + } - // Exclude the top stretch. - if (!timeline.events().isEmpty() && scroll_layout_->count() > 1) - notifyForLastEvent(); + // Exclude the top stretch. + if (!timeline.events().isEmpty() && scroll_layout_->count() > 1) + notifyForLastEvent(); - return message_count; + return message_count; } void TimelineView::init() { - top_layout_ = new QVBoxLayout(this); - top_layout_->setSpacing(0); - top_layout_->setMargin(0); + top_layout_ = new QVBoxLayout(this); + top_layout_->setSpacing(0); + top_layout_->setMargin(0); - scroll_area_ = new QScrollArea(this); - scroll_area_->setWidgetResizable(true); - scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll_area_ = new QScrollArea(this); + scroll_area_->setWidgetResizable(true); + scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollbar_ = new ScrollBar(scroll_area_); - scroll_area_->setVerticalScrollBar(scrollbar_); + scrollbar_ = new ScrollBar(scroll_area_); + scroll_area_->setVerticalScrollBar(scrollbar_); - scroll_widget_ = new QWidget(); + scroll_widget_ = new QWidget(); - scroll_layout_ = new QVBoxLayout(); - scroll_layout_->addStretch(1); - scroll_layout_->setSpacing(0); + scroll_layout_ = new QVBoxLayout(); + scroll_layout_->addStretch(1); + scroll_layout_->setSpacing(0); - scroll_widget_->setLayout(scroll_layout_); + scroll_widget_->setLayout(scroll_layout_); - scroll_area_->setWidget(scroll_widget_); + scroll_area_->setWidget(scroll_widget_); - top_layout_->addWidget(scroll_area_); + top_layout_->addWidget(scroll_area_); - setLayout(top_layout_); + setLayout(top_layout_); - paginationTimer_ = new QTimer(this); - connect(paginationTimer_, &QTimer::timeout, this, &TimelineView::fetchHistory); + paginationTimer_ = new QTimer(this); + connect(paginationTimer_, &QTimer::timeout, this, &TimelineView::fetchHistory); - connect(client_.data(), &MatrixClient::messagesRetrieved, this, &TimelineView::addBackwardsEvents); + connect(client_.data(), + &MatrixClient::messagesRetrieved, + this, + &TimelineView::addBackwardsEvents); - connect(scroll_area_->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(sliderMoved(int))); - connect(scroll_area_->verticalScrollBar(), - SIGNAL(rangeChanged(int, int)), - this, - SLOT(sliderRangeChanged(int, int))); + connect(scroll_area_->verticalScrollBar(), + SIGNAL(valueChanged(int)), + this, + SLOT(sliderMoved(int))); + connect(scroll_area_->verticalScrollBar(), + SIGNAL(rangeChanged(int, int)), + this, + SLOT(sliderRangeChanged(int, int))); } void TimelineView::updateLastSender(const QString &user_id, TimelineDirection direction) { - if (direction == TimelineDirection::Bottom) - lastSender_ = user_id; - else - firstSender_ = user_id; + if (direction == TimelineDirection::Bottom) + lastSender_ = user_id; + else + firstSender_ = user_id; } bool TimelineView::isSenderRendered(const QString &user_id, TimelineDirection direction) { - if (direction == TimelineDirection::Bottom) - return lastSender_ != user_id; - else - return firstSender_ != user_id; + if (direction == TimelineDirection::Bottom) + return lastSender_ != user_id; + else + return firstSender_ != user_id; } TimelineItem * -TimelineView::createTimelineItem(const events::MessageEvent<msgs::Image> &event, const QString &color, bool with_sender) +TimelineView::createTimelineItem(const events::MessageEvent<msgs::Image> &event, bool with_sender) { - auto image = new ImageItem(client_, event); - - if (with_sender) { - auto item = new TimelineItem(image, event, color, scroll_widget_); - return item; - } + auto image = new ImageItem(client_, event); + auto item = new TimelineItem(image, event, with_sender, scroll_widget_); - auto item = new TimelineItem(image, event, scroll_widget_); - return item; + return item; } TimelineItem * -TimelineView::createTimelineItem(const events::MessageEvent<msgs::Notice> &event, - const QString &color, - bool with_sender) +TimelineView::createTimelineItem(const events::MessageEvent<msgs::Notice> &event, bool with_sender) { - TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_); - return item; + TimelineItem *item = new TimelineItem(event, with_sender, scroll_widget_); + return item; } TimelineItem * -TimelineView::createTimelineItem(const events::MessageEvent<msgs::Text> &event, const QString &color, bool with_sender) +TimelineView::createTimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender) { - TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_); - return item; + TimelineItem *item = new TimelineItem(event, with_sender, scroll_widget_); + return item; } void TimelineView::addTimelineItem(TimelineItem *item, TimelineDirection direction) { - if (direction == TimelineDirection::Bottom) - scroll_layout_->addWidget(item); - else - scroll_layout_->insertWidget(1, item); + if (direction == TimelineDirection::Bottom) + scroll_layout_->addWidget(item); + else + scroll_layout_->insertWidget(1, item); } void TimelineView::updatePendingMessage(int txn_id, QString event_id) { - for (auto &msg : pending_msgs_) { - if (msg.txn_id == txn_id) { - msg.event_id = event_id; - break; - } - } + for (auto &msg : pending_msgs_) { + if (msg.txn_id == txn_id) { + msg.event_id = event_id; + break; + } + } } bool -TimelineView::isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &local_userid) +TimelineView::isPendingMessage(const events::MessageEvent<msgs::Text> &e, + const QString &local_userid) { - if (e.sender() != local_userid) - return false; + if (e.sender() != local_userid) + return false; - for (const auto &msg : pending_msgs_) { - if (msg.event_id == e.eventId() || msg.body == e.content().body()) - return true; - } + for (const auto &msg : pending_msgs_) { + if (msg.event_id == e.eventId() || msg.body == e.content().body()) + return true; + } - return false; + return false; } void TimelineView::removePendingMessage(const events::MessageEvent<msgs::Text> &e) { - for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) { - int index = std::distance(pending_msgs_.begin(), it); - - if (it->event_id == e.eventId() || it->body == e.content().body()) { - pending_msgs_.removeAt(index); - break; - } - } + for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) { + int index = std::distance(pending_msgs_.begin(), it); + + if (it->event_id == e.eventId() || it->body == e.content().body()) { + pending_msgs_.removeAt(index); + break; + } + } } void TimelineView::addUserTextMessage(const QString &body, int txn_id) { - QSettings settings; - auto user_id = settings.value("auth/user_id").toString(); + QSettings settings; + auto user_id = settings.value("auth/user_id").toString(); - auto with_sender = lastSender_ != user_id; - auto color = TimelineViewManager::getUserColor(user_id); + auto with_sender = lastSender_ != user_id; - TimelineItem *view_item; + TimelineItem *view_item; - if (with_sender) - view_item = new TimelineItem(user_id, color, body, scroll_widget_); - else - view_item = new TimelineItem(body, scroll_widget_); + if (with_sender) + view_item = new TimelineItem(user_id, body, scroll_widget_); + else + view_item = new TimelineItem(body, scroll_widget_); - scroll_layout_->addWidget(view_item); + scroll_layout_->addWidget(view_item); - lastSender_ = user_id; + lastSender_ = user_id; - PendingMessage message(txn_id, body, "", view_item); + PendingMessage message(txn_id, body, "", view_item); - pending_msgs_.push_back(message); + pending_msgs_.push_back(message); } void TimelineView::notifyForLastEvent() { - auto lastItem = scroll_layout_->itemAt(scroll_layout_->count() - 1); - auto *lastTimelineItem = qobject_cast<TimelineItem *>(lastItem->widget()); + auto lastItem = scroll_layout_->itemAt(scroll_layout_->count() - 1); + auto *lastTimelineItem = qobject_cast<TimelineItem *>(lastItem->widget()); - if (lastTimelineItem) - emit updateLastTimelineMessage(room_id_, lastTimelineItem->descriptionMessage()); - else - qWarning() << "Cast to TimelineView failed" << room_id_; + if (lastTimelineItem) + emit updateLastTimelineMessage(room_id_, lastTimelineItem->descriptionMessage()); + else + qWarning() << "Cast to TimelineView failed" << room_id_; } diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc index a02e89e9..3cb61889 100644 --- a/src/TimelineViewManager.cc +++ b/src/TimelineViewManager.cc @@ -30,12 +30,12 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<MatrixClient> client, QW : QStackedWidget(parent) , client_(client) { - setStyleSheet("QWidget { background: #f8fbfe; color: #e8e8e8; border: none;}"); + setStyleSheet("QWidget { background: #f8fbfe; color: #e8e8e8; border: none;}"); - connect(client_.data(), - SIGNAL(messageSent(const QString &, const QString &, int)), - this, - SLOT(messageSent(const QString &, const QString &, int))); + connect(client_.data(), + SIGNAL(messageSent(const QString &, const QString &, int)), + this, + SLOT(messageSent(const QString &, const QString &, int))); } TimelineViewManager::~TimelineViewManager() @@ -45,195 +45,179 @@ TimelineViewManager::~TimelineViewManager() void TimelineViewManager::messageSent(const QString &event_id, const QString &roomid, int txn_id) { - // We save the latest valid transaction ID for later use. - QSettings settings; - settings.setValue("client/transaction_id", txn_id + 1); + // We save the latest valid transaction ID for later use. + QSettings settings; + settings.setValue("client/transaction_id", txn_id + 1); - auto view = views_[roomid]; - view->updatePendingMessage(txn_id, event_id); + auto view = views_[roomid]; + view->updatePendingMessage(txn_id, event_id); } void TimelineViewManager::sendTextMessage(const QString &msg) { - auto room_id = active_room_; - auto view = views_[room_id]; + auto room_id = active_room_; + auto view = views_[room_id]; - view->addUserTextMessage(msg, client_->transactionId()); - client_->sendTextMessage(room_id, msg); + view->addUserTextMessage(msg, client_->transactionId()); + client_->sendTextMessage(room_id, msg); } void TimelineViewManager::clearAll() { - NICK_COLORS.clear(); + for (auto view : views_) + removeWidget(view.data()); - for (auto view : views_) - removeWidget(view.data()); - - views_.clear(); + views_.clear(); } void TimelineViewManager::initialize(const Rooms &rooms) { - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { - auto roomid = it.key(); + for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { + auto roomid = it.key(); - // Create a history view with the room events. - TimelineView *view = new TimelineView(it.value().timeline(), client_, it.key()); - views_.insert(it.key(), QSharedPointer<TimelineView>(view)); + // Create a history view with the room events. + TimelineView *view = new TimelineView(it.value().timeline(), client_, it.key()); + views_.insert(it.key(), QSharedPointer<TimelineView>(view)); - connect(view, - &TimelineView::updateLastTimelineMessage, - this, - &TimelineViewManager::updateRoomsLastMessage); + connect(view, + &TimelineView::updateLastTimelineMessage, + this, + &TimelineViewManager::updateRoomsLastMessage); - // Add the view in the widget stack. - addWidget(view); - } + // Add the view in the widget stack. + addWidget(view); + } } void TimelineViewManager::initialize(const QList<QString> &rooms) { - for (const auto &roomid : rooms) { - // Create a history view without any events. - TimelineView *view = new TimelineView(client_, roomid); - views_.insert(roomid, QSharedPointer<TimelineView>(view)); - - connect(view, - &TimelineView::updateLastTimelineMessage, - this, - &TimelineViewManager::updateRoomsLastMessage); - - // Add the view in the widget stack. - addWidget(view); - } + for (const auto &roomid : rooms) { + // Create a history view without any events. + TimelineView *view = new TimelineView(client_, roomid); + views_.insert(roomid, QSharedPointer<TimelineView>(view)); + + connect(view, + &TimelineView::updateLastTimelineMessage, + this, + &TimelineViewManager::updateRoomsLastMessage); + + // Add the view in the widget stack. + addWidget(view); + } } void TimelineViewManager::sync(const Rooms &rooms) { - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { - auto roomid = it.key(); + for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { + auto roomid = it.key(); - if (!views_.contains(roomid)) { - qDebug() << "Ignoring event from unknown room" << roomid; - continue; - } + if (!views_.contains(roomid)) { + qDebug() << "Ignoring event from unknown room" << roomid; + continue; + } - auto view = views_.value(roomid); + auto view = views_.value(roomid); - int msgs_added = view->addEvents(it.value().timeline()); + int msgs_added = view->addEvents(it.value().timeline()); - if (msgs_added > 0) { - // TODO: When the app window gets active the current - // unread count (if any) should be cleared. - auto isAppActive = QApplication::activeWindow() != nullptr; + if (msgs_added > 0) { + // TODO: When the app window gets active the current + // unread count (if any) should be cleared. + auto isAppActive = QApplication::activeWindow() != nullptr; - if (roomid != active_room_ || !isAppActive) - emit unreadMessages(roomid, msgs_added); - } - } + if (roomid != active_room_ || !isAppActive) + emit unreadMessages(roomid, msgs_added); + } + } } void TimelineViewManager::setHistoryView(const QString &room_id) { - if (!views_.contains(room_id)) { - qDebug() << "Room ID from RoomList is not present in ViewManager" << room_id; - return; - } + if (!views_.contains(room_id)) { + qDebug() << "Room ID from RoomList is not present in ViewManager" << room_id; + return; + } - active_room_ = room_id; - auto view = views_.value(room_id); + active_room_ = room_id; + auto view = views_.value(room_id); - setCurrentWidget(view.data()); + setCurrentWidget(view.data()); - view->fetchHistory(); - view->scrollDown(); + view->fetchHistory(); + view->scrollDown(); } -QMap<QString, QString> TimelineViewManager::NICK_COLORS; QMap<QString, QString> TimelineViewManager::DISPLAY_NAMES; QString TimelineViewManager::chooseRandomColor() { - std::random_device random_device; - std::mt19937 engine{ random_device() }; - std::uniform_real_distribution<float> dist(0, 1); - - float hue = dist(engine); - float saturation = 0.9; - float value = 0.7; - - int hue_i = hue * 6; - - float f = hue * 6 - hue_i; - - float p = value * (1 - saturation); - float q = value * (1 - f * saturation); - float t = value * (1 - (1 - f) * saturation); - - float r = 0; - float g = 0; - float b = 0; - - if (hue_i == 0) { - r = value; - g = t; - b = p; - } else if (hue_i == 1) { - r = q; - g = value; - b = p; - } else if (hue_i == 2) { - r = p; - g = value; - b = t; - } else if (hue_i == 3) { - r = p; - g = q; - b = value; - } else if (hue_i == 4) { - r = t; - g = p; - b = value; - } else if (hue_i == 5) { - r = value; - g = p; - b = q; - } - - int ri = r * 256; - int gi = g * 256; - int bi = b * 256; - - QColor color(ri, gi, bi); - - return color.name(); -} - -QString -TimelineViewManager::getUserColor(const QString &userid) -{ - auto color = NICK_COLORS.value(userid); - - if (color.isEmpty()) { - color = chooseRandomColor(); - NICK_COLORS.insert(userid, color); - } - - return color; + std::random_device random_device; + std::mt19937 engine{ random_device() }; + std::uniform_real_distribution<float> dist(0, 1); + + float hue = dist(engine); + float saturation = 0.9; + float value = 0.7; + + int hue_i = hue * 6; + + float f = hue * 6 - hue_i; + + float p = value * (1 - saturation); + float q = value * (1 - f * saturation); + float t = value * (1 - (1 - f) * saturation); + + float r = 0; + float g = 0; + float b = 0; + + if (hue_i == 0) { + r = value; + g = t; + b = p; + } else if (hue_i == 1) { + r = q; + g = value; + b = p; + } else if (hue_i == 2) { + r = p; + g = value; + b = t; + } else if (hue_i == 3) { + r = p; + g = q; + b = value; + } else if (hue_i == 4) { + r = t; + g = p; + b = value; + } else if (hue_i == 5) { + r = value; + g = p; + b = q; + } + + int ri = r * 256; + int gi = g * 256; + int bi = b * 256; + + QColor color(ri, gi, bi); + + return color.name(); } QString TimelineViewManager::displayName(const QString &userid) { - if (DISPLAY_NAMES.contains(userid)) - return DISPLAY_NAMES.value(userid); + if (DISPLAY_NAMES.contains(userid)) + return DISPLAY_NAMES.value(userid); - return userid; + return userid; } |