From 32c83405771b2f7a751783529d17e1b84dad4224 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Thu, 30 Nov 2017 13:53:28 +0200 Subject: Create directories for related files --- include/EmojiCategory.h | 59 ------- include/EmojiItemDelegate.h | 40 ----- include/EmojiPanel.h | 55 ------ include/EmojiPickButton.h | 48 ----- include/EmojiProvider.h | 41 ----- include/FileItem.h | 98 ----------- include/ImageItem.h | 78 --------- include/ImageOverlayDialog.h | 46 ----- include/JoinRoomDialog.h | 22 --- include/LeaveRoomDialog.h | 22 --- include/LogoutDialog.h | 39 ----- include/TextInputWidget.h | 3 +- include/TimelineItem.h | 155 ----------------- include/TimelineView.h | 310 --------------------------------- include/TimelineViewManager.h | 80 --------- include/dialogs/ImageOverlayDialog.h | 46 +++++ include/dialogs/JoinRoomDialog.h | 22 +++ include/dialogs/LeaveRoomDialog.h | 22 +++ include/dialogs/LogoutDialog.h | 39 +++++ include/emoji/EmojiCategory.h | 59 +++++++ include/emoji/EmojiItemDelegate.h | 40 +++++ include/emoji/EmojiPanel.h | 55 ++++++ include/emoji/EmojiPickButton.h | 48 +++++ include/emoji/EmojiProvider.h | 41 +++++ include/timeline/TimelineItem.h | 155 +++++++++++++++++ include/timeline/TimelineView.h | 310 +++++++++++++++++++++++++++++++++ include/timeline/TimelineViewManager.h | 80 +++++++++ include/timeline/widgets/FileItem.h | 98 +++++++++++ include/timeline/widgets/ImageItem.h | 78 +++++++++ 29 files changed, 1095 insertions(+), 1094 deletions(-) delete mode 100644 include/EmojiCategory.h delete mode 100644 include/EmojiItemDelegate.h delete mode 100644 include/EmojiPanel.h delete mode 100644 include/EmojiPickButton.h delete mode 100644 include/EmojiProvider.h delete mode 100644 include/FileItem.h delete mode 100644 include/ImageItem.h delete mode 100644 include/ImageOverlayDialog.h delete mode 100644 include/JoinRoomDialog.h delete mode 100644 include/LeaveRoomDialog.h delete mode 100644 include/LogoutDialog.h delete mode 100644 include/TimelineItem.h delete mode 100644 include/TimelineView.h delete mode 100644 include/TimelineViewManager.h create mode 100644 include/dialogs/ImageOverlayDialog.h create mode 100644 include/dialogs/JoinRoomDialog.h create mode 100644 include/dialogs/LeaveRoomDialog.h create mode 100644 include/dialogs/LogoutDialog.h create mode 100644 include/emoji/EmojiCategory.h create mode 100644 include/emoji/EmojiItemDelegate.h create mode 100644 include/emoji/EmojiPanel.h create mode 100644 include/emoji/EmojiPickButton.h create mode 100644 include/emoji/EmojiProvider.h create mode 100644 include/timeline/TimelineItem.h create mode 100644 include/timeline/TimelineView.h create mode 100644 include/timeline/TimelineViewManager.h create mode 100644 include/timeline/widgets/FileItem.h create mode 100644 include/timeline/widgets/ImageItem.h (limited to 'include') diff --git a/include/EmojiCategory.h b/include/EmojiCategory.h deleted file mode 100644 index be0110f2..00000000 --- a/include/EmojiCategory.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include - -#include "EmojiItemDelegate.h" - -class EmojiProvider; - -class EmojiCategory : public QWidget -{ - Q_OBJECT - -public: - EmojiCategory(QString category, QList emoji, QWidget *parent = nullptr); - ~EmojiCategory(); - -signals: - void emojiSelected(const QString &emoji); - -protected: - void paintEvent(QPaintEvent *event) override; - -private slots: - void clickIndex(const QModelIndex &index) - { - emit emojiSelected(index.data(Qt::UserRole).toString()); - }; - -private: - QVBoxLayout *mainLayout_; - - QStandardItemModel *itemModel_; - QListView *emojiListView_; - - Emoji *data_; - EmojiItemDelegate *delegate_; - - QLabel *category_; -}; diff --git a/include/EmojiItemDelegate.h b/include/EmojiItemDelegate.h deleted file mode 100644 index 15d61f49..00000000 --- a/include/EmojiItemDelegate.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include - -#include "EmojiProvider.h" - -class EmojiItemDelegate : public QStyledItemDelegate -{ - Q_OBJECT - -public: - explicit EmojiItemDelegate(QObject *parent = nullptr); - ~EmojiItemDelegate(); - - void paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const override; - -private: - Emoji *data_; -}; diff --git a/include/EmojiPanel.h b/include/EmojiPanel.h deleted file mode 100644 index 9eecc8e0..00000000 --- a/include/EmojiPanel.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -#include "EmojiProvider.h" - -class EmojiCategory; - -class EmojiPanel : public QWidget -{ - Q_OBJECT - -public: - EmojiPanel(QWidget *parent = nullptr); - -signals: - void mouseLeft(); - void emojiSelected(const QString &emoji); - -protected: - void leaveEvent(QEvent *event); - void paintEvent(QPaintEvent *event); - -private: - void showEmojiCategory(const EmojiCategory *category); - - EmojiProvider emoji_provider_; - - QScrollArea *scrollArea_; - - int shadowMargin_; - - // Panel dimensions. - int width_; - int height_; - - int categoryIconSize_; -}; diff --git a/include/EmojiPickButton.h b/include/EmojiPickButton.h deleted file mode 100644 index 8ef9be9e..00000000 --- a/include/EmojiPickButton.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include - -#include "FlatButton.h" - -class EmojiPanel; - -class EmojiPickButton : public FlatButton -{ - Q_OBJECT -public: - explicit EmojiPickButton(QWidget *parent = nullptr); - -signals: - void emojiSelected(const QString &emoji); - -protected: - void enterEvent(QEvent *e) override; - void leaveEvent(QEvent *e) override; - -private: - // Vertical distance from panel's bottom. - int vertical_distance_ = 10; - - // Horizontal distance from panel's bottom right corner. - int horizontal_distance_ = 70; - - QSharedPointer panel_; -}; diff --git a/include/EmojiProvider.h b/include/EmojiProvider.h deleted file mode 100644 index 847157fd..00000000 --- a/include/EmojiProvider.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -struct Emoji -{ - // Unicode code. - QString unicode; - // Keyboard shortcut e.g :emoji: - QString shortname; -}; - -class EmojiProvider -{ -public: - static const QList people; - static const QList nature; - static const QList food; - static const QList activity; - static const QList travel; - static const QList objects; - static const QList symbols; - static const QList flags; -}; diff --git a/include/FileItem.h b/include/FileItem.h deleted file mode 100644 index ebb18111..00000000 --- a/include/FileItem.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "File.h" -#include "MatrixClient.h" -#include "MessageEvent.h" - -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - -constexpr int MaxWidth = 400; -constexpr int Height = 70; -constexpr int IconRadius = 22; -constexpr int IconDiameter = IconRadius * 2; -constexpr int HorizontalPadding = 12; -constexpr int TextPadding = 15; -constexpr int DownloadIconRadius = IconRadius - 4; - -constexpr double VerticalPadding = Height - 2 * IconRadius; -constexpr double IconYCenter = Height / 2; -constexpr double IconXCenter = HorizontalPadding + IconRadius; - -class FileItem : public QWidget -{ - Q_OBJECT - - Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor) - Q_PROPERTY(QColor iconColor WRITE setIconColor READ iconColor) - Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) - -public: - FileItem(QSharedPointer client, - const events::MessageEvent &event, - QWidget *parent = nullptr); - - FileItem(QSharedPointer client, - const QString &url, - const QString &filename, - QWidget *parent = nullptr); - - QSize sizeHint() const override; - - void setTextColor(const QColor &color) { textColor_ = color; } - void setIconColor(const QColor &color) { iconColor_ = color; } - void setBackgroundColor(const QColor &color) { backgroundColor_ = color; } - - QColor textColor() const { return textColor_; } - QColor iconColor() const { return iconColor_; } - QColor backgroundColor() const { return backgroundColor_; } - -protected: - void paintEvent(QPaintEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - -private slots: - void fileDownloaded(const QString &event_id, const QByteArray &data); - -private: - QString calculateFileSize(int nbytes) const; - void openUrl(); - void init(); - - QUrl url_; - QString text_; - QString readableFileSize_; - QString filenameToSave_; - - events::MessageEvent event_; - QSharedPointer client_; - - QIcon icon_; - - QColor textColor_ = QColor("white"); - QColor iconColor_ = QColor("#38A3D8"); - QColor backgroundColor_ = QColor("#333"); -}; diff --git a/include/ImageItem.h b/include/ImageItem.h deleted file mode 100644 index c4f6998a..00000000 --- a/include/ImageItem.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include - -#include "Image.h" -#include "MatrixClient.h" -#include "MessageEvent.h" - -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - -class ImageItem : public QWidget -{ - Q_OBJECT -public: - ImageItem(QSharedPointer client, - const events::MessageEvent &event, - QWidget *parent = nullptr); - - ImageItem(QSharedPointer client, - const QString &url, - const QString &filename, - QWidget *parent = nullptr); - - void setImage(const QPixmap &image); - - QSize sizeHint() const override; - -protected: - void paintEvent(QPaintEvent *event) override; - void mousePressEvent(QMouseEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - -private slots: - void imageDownloaded(const QString &event_id, const QPixmap &img); - -private: - void scaleImage(); - void openUrl(); - - int max_width_ = 500; - int max_height_ = 300; - - int width_; - int height_; - - QPixmap scaled_image_; - QPixmap image_; - - QUrl url_; - QString text_; - - int bottom_height_ = 30; - - events::MessageEvent event_; - - QSharedPointer client_; -}; diff --git a/include/ImageOverlayDialog.h b/include/ImageOverlayDialog.h deleted file mode 100644 index 5159c665..00000000 --- a/include/ImageOverlayDialog.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include - -class ImageOverlayDialog : public QWidget -{ - Q_OBJECT -public: - ImageOverlayDialog(QPixmap image, QWidget *parent = nullptr); - -protected: - void mousePressEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *event) override; - -signals: - void closing(); - -private: - void scaleImage(int width, int height); - - QPixmap originalImage_; - QPixmap image_; - - QRect content_; - QRect close_button_; - QRect screen_; -}; diff --git a/include/JoinRoomDialog.h b/include/JoinRoomDialog.h deleted file mode 100644 index 84184733..00000000 --- a/include/JoinRoomDialog.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include - -class FlatButton; - -class JoinRoomDialog : public QFrame -{ - Q_OBJECT -public: - JoinRoomDialog(QWidget *parent = nullptr); - -signals: - void closing(bool isJoining, QString roomAlias); - -private: - FlatButton *confirmBtn_; - FlatButton *cancelBtn_; - - QLineEdit *roomAliasEdit_; -}; diff --git a/include/LeaveRoomDialog.h b/include/LeaveRoomDialog.h deleted file mode 100644 index eab022f7..00000000 --- a/include/LeaveRoomDialog.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -class FlatButton; - -class LeaveRoomDialog : public QFrame -{ - Q_OBJECT -public: - explicit LeaveRoomDialog(QWidget *parent = nullptr); - -protected: - void paintEvent(QPaintEvent *event) override; - -signals: - void closing(bool isLeaving); - -private: - FlatButton *confirmBtn_; - FlatButton *cancelBtn_; -}; diff --git a/include/LogoutDialog.h b/include/LogoutDialog.h deleted file mode 100644 index a1a5ee4f..00000000 --- a/include/LogoutDialog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include - -class FlatButton; - -class LogoutDialog : public QFrame -{ - Q_OBJECT -public: - explicit LogoutDialog(QWidget *parent = nullptr); - -protected: - void paintEvent(QPaintEvent *event) override; - -signals: - void closing(bool isLoggingOut); - -private: - FlatButton *confirmBtn_; - FlatButton *cancelBtn_; -}; diff --git a/include/TextInputWidget.h b/include/TextInputWidget.h index 80c16740..ede7b18a 100644 --- a/include/TextInputWidget.h +++ b/include/TextInputWidget.h @@ -24,11 +24,12 @@ #include #include -#include "EmojiPickButton.h" #include "FlatButton.h" #include "Image.h" #include "LoadingIndicator.h" +#include "emoji/EmojiPickButton.h" + namespace msgs = matrix::events::messages; class FilteredTextEdit : public QTextEdit diff --git a/include/TimelineItem.h b/include/TimelineItem.h deleted file mode 100644 index 9646405c..00000000 --- a/include/TimelineItem.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "AvatarProvider.h" -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "MessageEvent.h" -#include "Notice.h" -#include "RoomInfoListItem.h" -#include "Text.h" -#include "TimelineViewManager.h" - -class ImageItem; -class FileItem; -class Avatar; - -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - -class TimelineItem : public QWidget -{ - Q_OBJECT -public: - TimelineItem(const events::MessageEvent &e, - bool with_sender, - QWidget *parent = 0); - TimelineItem(const events::MessageEvent &e, - bool with_sender, - QWidget *parent = 0); - TimelineItem(const events::MessageEvent &e, - bool with_sender, - QWidget *parent = 0); - - // For local messages. - // m.text & m.emote - TimelineItem(events::MessageEventType ty, - const QString &userid, - QString body, - bool withSender, - QWidget *parent = 0); - // m.image - TimelineItem(ImageItem *item, const QString &userid, bool withSender, QWidget *parent = 0); - TimelineItem(FileItem *item, const QString &userid, bool withSender, QWidget *parent = 0); - - TimelineItem(ImageItem *img, - const events::MessageEvent &e, - bool with_sender, - QWidget *parent); - TimelineItem(FileItem *file, - const events::MessageEvent &e, - bool with_sender, - QWidget *parent); - - void setUserAvatar(const QImage &pixmap); - DescInfo descriptionMessage() const { return descriptionMsg_; } - QString eventId() const { return event_id_; } - - ~TimelineItem(); - -protected: - void paintEvent(QPaintEvent *event) override; - -private: - void init(); - - template - void setupLocalWidgetLayout(Widget *widget, - const QString &userid, - const QString &msgDescription, - bool withSender); - - 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(); - - QString replaceEmoji(const QString &body); - QString event_id_; - - DescInfo descriptionMsg_; - - QHBoxLayout *topLayout_; - QVBoxLayout *sideLayout_; // Avatar or Timestamp - QVBoxLayout *mainLayout_; // Header & Message body - - QHBoxLayout *headerLayout_; // Username (&) Timestamp - - Avatar *userAvatar_; - - QFont font_; - - QLabel *timestamp_; - QLabel *userName_; - QLabel *body_; -}; - -template -void -TimelineItem::setupLocalWidgetLayout(Widget *widget, - const QString &userid, - const QString &msgDescription, - bool withSender) -{ - auto displayName = TimelineViewManager::displayName(userid); - auto timestamp = QDateTime::currentDateTime(); - - descriptionMsg_ = { - "You", userid, QString(" %1").arg(msgDescription), descriptiveTime(timestamp)}; - - generateTimestamp(timestamp); - - auto widgetLayout = new QHBoxLayout(); - widgetLayout->setContentsMargins(0, 5, 0, 0); - widgetLayout->addWidget(widget); - widgetLayout->addStretch(1); - - if (withSender) { - generateBody(displayName, ""); - setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(userid, this); - } else { - setupSimpleLayout(); - } - - mainLayout_->addLayout(widgetLayout); -} diff --git a/include/TimelineView.h b/include/TimelineView.h deleted file mode 100644 index 898a304e..00000000 --- a/include/TimelineView.h +++ /dev/null @@ -1,310 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Emote.h" -#include "File.h" -#include "Image.h" -#include "MatrixClient.h" -#include "MessageEvent.h" -#include "Notice.h" -#include "Text.h" -#include "TimelineItem.h" - -class FloatingButton; -class RoomMessages; -class ScrollBar; -class Timeline; -struct DescInfo; - -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 -{ - matrix::events::MessageEventType ty; - int txn_id; - QString body; - QString filename; - QString event_id; - TimelineItem *widget; - - PendingMessage(matrix::events::MessageEventType ty, - int txn_id, - QString body, - QString filename, - QString event_id, - TimelineItem *widget) - : ty(ty) - , txn_id(txn_id) - , body(body) - , filename(filename) - , event_id(event_id) - , widget(widget) - {} -}; - -// In which place new TimelineItems should be inserted. -enum class TimelineDirection -{ - Top, - Bottom, -}; - -class TimelineView : public QWidget -{ - Q_OBJECT - -public: - TimelineView(const Timeline &timeline, - QSharedPointer client, - const QString &room_id, - QWidget *parent = 0); - TimelineView(QSharedPointer client, - const QString &room_id, - QWidget *parent = 0); - - // Add new events at the end of the timeline. - int addEvents(const Timeline &timeline); - void addUserMessage(matrix::events::MessageEventType ty, const QString &msg); - - template - void addUserMessage(const QString &url, const QString &filename); - void updatePendingMessage(int txn_id, QString event_id); - void scrollDown(); - -public slots: - 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); - - // Whether or not the initial batch has been loaded. - bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; } - - void handleFailedMessage(int txnid); - -private slots: - void sendNextPendingMessage(); - -signals: - void updateLastTimelineMessage(const QString &user, const DescInfo &info); - void clearUnreadMessageCount(const QString &room_id); - -protected: - void paintEvent(QPaintEvent *event) override; - void showEvent(QShowEvent *event) override; - bool event(QEvent *event) override; - -private: - void init(); - void addTimelineItem(TimelineItem *item, TimelineDirection direction); - void updateLastSender(const QString &user_id, TimelineDirection direction); - void notifyForLastEvent(); - void readLastEvent() const; - QString getLastEventId() const; - - template - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); - - // TODO: Remove this eventually. - template - TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); - - // For events with custom display widgets. - template - TimelineItem *createTimelineItem(const Event &event, bool withSender); - - // For events without custom display widgets. - // TODO: All events should have custom widgets. - template - TimelineItem *createTimelineItem(const Event &event, bool withSender); - - // 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 QString &txnid, const QString &sender, const QString &userid); - void removePendingMessage(const QString &txnid); - - bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); } - - void handleNewUserMessage(PendingMessage msg); - - // Return nullptr if the event couldn't be parsed. - TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction); - - QVBoxLayout *top_layout_; - QVBoxLayout *scroll_layout_; - - QScrollArea *scroll_area_; - ScrollBar *scrollbar_; - QWidget *scroll_widget_; - - QString lastSender_; - QString firstSender_; - QString room_id_; - QString prev_batch_token_; - QString local_user_; - - bool isPaginationInProgress_ = false; - - // Keeps track whether or not the user has visited the view. - bool isInitialized = false; - bool isTimelineFinished = false; - bool isInitialSync = true; - - const int SCROLL_BAR_GAP = 200; - - QTimer *paginationTimer_; - - int scroll_height_ = 0; - int previous_max_height_ = 0; - - int oldPosition_; - int oldHeight_; - - FloatingButton *scrollDownBtn_; - - TimelineDirection lastMessageDirection_; - - // The events currently rendered. Used for duplicate detection. - QMap eventIds_; - QQueue pending_msgs_; - QList pending_sent_msgs_; - QSharedPointer client_; -}; - -template -void -TimelineView::addUserMessage(const QString &url, const QString &filename) -{ - QSettings settings; - auto user_id = settings.value("auth/user_id").toString(); - auto with_sender = lastSender_ != user_id; - - auto widget = new Widget(client_, url, filename, this); - - TimelineItem *view_item = new TimelineItem(widget, user_id, with_sender, scroll_widget_); - scroll_layout_->addWidget(view_item); - - lastMessageDirection_ = TimelineDirection::Bottom; - - QApplication::processEvents(); - - lastSender_ = user_id; - - int txn_id = client_->incrementTransactionId(); - - PendingMessage message(MsgType, txn_id, url, filename, "", view_item); - handleNewUserMessage(message); -} - -template -TimelineItem * -TimelineView::createTimelineItem(const Event &event, bool withSender) -{ - TimelineItem *item = new TimelineItem(event, withSender, scroll_widget_); - return item; -} - -template -TimelineItem * -TimelineView::createTimelineItem(const Event &event, bool withSender) -{ - auto eventWidget = new Widget(client_, event); - auto item = new TimelineItem(eventWidget, event, withSender, scroll_widget_); - - return item; -} - -template -TimelineItem * -TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) -{ - Event event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - qWarning() << e.what() << data; - return nullptr; - } - - if (isDuplicate(event.eventId())) - return nullptr; - - eventIds_[event.eventId()] = true; - - QString txnid = event.unsignedData().transactionId(); - if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { - removePendingMessage(txnid); - return nullptr; - } - - auto with_sender = isSenderRendered(event.sender(), direction); - - updateLastSender(event.sender(), direction); - - return createTimelineItem(event, with_sender); -} - -template -TimelineItem * -TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) -{ - Event event; - - try { - event.deserialize(data); - } catch (const DeserializationException &e) { - qWarning() << e.what() << data; - return nullptr; - } - - if (isDuplicate(event.eventId())) - return nullptr; - - eventIds_[event.eventId()] = true; - - QString txnid = event.unsignedData().transactionId(); - if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { - removePendingMessage(txnid); - return nullptr; - } - - auto with_sender = isSenderRendered(event.sender(), direction); - - updateLastSender(event.sender(), direction); - - return createTimelineItem(event, with_sender); -} diff --git a/include/TimelineViewManager.h b/include/TimelineViewManager.h deleted file mode 100644 index 854c2550..00000000 --- a/include/TimelineViewManager.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * nheko Copyright (C) 2017 Konstantinos Sideris - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include - -#include "MessageEvent.h" - -class JoinedRoom; -class MatrixClient; -class RoomInfoListItem; -class Rooms; -class TimelineView; -struct DescInfo; - -class TimelineViewManager : public QStackedWidget -{ - Q_OBJECT - -public: - TimelineViewManager(QSharedPointer client, QWidget *parent); - ~TimelineViewManager(); - - // Initialize with timeline events. - void initialize(const Rooms &rooms); - // Empty initialization. - void initialize(const QList &rooms); - - void addRoom(const JoinedRoom &room, const QString &room_id); - void addRoom(const QString &room_id); - - void sync(const Rooms &rooms); - void clearAll(); - - // Check if all the timelines have been loaded. - bool hasLoaded() const; - - static QString chooseRandomColor(); - static QString displayName(const QString &userid); - - static QMap DISPLAY_NAMES; - -signals: - void clearRoomMessageCount(QString roomid); - void unreadMessages(QString roomid, int count); - void updateRoomsLastMessage(const QString &user, const DescInfo &info); - -public slots: - void setHistoryView(const QString &room_id); - void queueTextMessage(const QString &msg); - void queueEmoteMessage(const QString &msg); - void queueImageMessage(const QString &roomid, const QString &filename, const QString &url); - void queueFileMessage(const QString &roomid, const QString &filename, const QString &url); - -private slots: - void messageSent(const QString &eventid, const QString &roomid, int txnid); - void messageSendFailed(const QString &roomid, int txnid); - -private: - QString active_room_; - QMap> views_; - QSharedPointer client_; -}; diff --git a/include/dialogs/ImageOverlayDialog.h b/include/dialogs/ImageOverlayDialog.h new file mode 100644 index 00000000..5159c665 --- /dev/null +++ b/include/dialogs/ImageOverlayDialog.h @@ -0,0 +1,46 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +class ImageOverlayDialog : public QWidget +{ + Q_OBJECT +public: + ImageOverlayDialog(QPixmap image, QWidget *parent = nullptr); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void paintEvent(QPaintEvent *event) override; + +signals: + void closing(); + +private: + void scaleImage(int width, int height); + + QPixmap originalImage_; + QPixmap image_; + + QRect content_; + QRect close_button_; + QRect screen_; +}; diff --git a/include/dialogs/JoinRoomDialog.h b/include/dialogs/JoinRoomDialog.h new file mode 100644 index 00000000..84184733 --- /dev/null +++ b/include/dialogs/JoinRoomDialog.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +class FlatButton; + +class JoinRoomDialog : public QFrame +{ + Q_OBJECT +public: + JoinRoomDialog(QWidget *parent = nullptr); + +signals: + void closing(bool isJoining, QString roomAlias); + +private: + FlatButton *confirmBtn_; + FlatButton *cancelBtn_; + + QLineEdit *roomAliasEdit_; +}; diff --git a/include/dialogs/LeaveRoomDialog.h b/include/dialogs/LeaveRoomDialog.h new file mode 100644 index 00000000..eab022f7 --- /dev/null +++ b/include/dialogs/LeaveRoomDialog.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +class FlatButton; + +class LeaveRoomDialog : public QFrame +{ + Q_OBJECT +public: + explicit LeaveRoomDialog(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *event) override; + +signals: + void closing(bool isLeaving); + +private: + FlatButton *confirmBtn_; + FlatButton *cancelBtn_; +}; diff --git a/include/dialogs/LogoutDialog.h b/include/dialogs/LogoutDialog.h new file mode 100644 index 00000000..a1a5ee4f --- /dev/null +++ b/include/dialogs/LogoutDialog.h @@ -0,0 +1,39 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +class FlatButton; + +class LogoutDialog : public QFrame +{ + Q_OBJECT +public: + explicit LogoutDialog(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *event) override; + +signals: + void closing(bool isLoggingOut); + +private: + FlatButton *confirmBtn_; + FlatButton *cancelBtn_; +}; diff --git a/include/emoji/EmojiCategory.h b/include/emoji/EmojiCategory.h new file mode 100644 index 00000000..be0110f2 --- /dev/null +++ b/include/emoji/EmojiCategory.h @@ -0,0 +1,59 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +#include "EmojiItemDelegate.h" + +class EmojiProvider; + +class EmojiCategory : public QWidget +{ + Q_OBJECT + +public: + EmojiCategory(QString category, QList emoji, QWidget *parent = nullptr); + ~EmojiCategory(); + +signals: + void emojiSelected(const QString &emoji); + +protected: + void paintEvent(QPaintEvent *event) override; + +private slots: + void clickIndex(const QModelIndex &index) + { + emit emojiSelected(index.data(Qt::UserRole).toString()); + }; + +private: + QVBoxLayout *mainLayout_; + + QStandardItemModel *itemModel_; + QListView *emojiListView_; + + Emoji *data_; + EmojiItemDelegate *delegate_; + + QLabel *category_; +}; diff --git a/include/emoji/EmojiItemDelegate.h b/include/emoji/EmojiItemDelegate.h new file mode 100644 index 00000000..15d61f49 --- /dev/null +++ b/include/emoji/EmojiItemDelegate.h @@ -0,0 +1,40 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "EmojiProvider.h" + +class EmojiItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit EmojiItemDelegate(QObject *parent = nullptr); + ~EmojiItemDelegate(); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + +private: + Emoji *data_; +}; diff --git a/include/emoji/EmojiPanel.h b/include/emoji/EmojiPanel.h new file mode 100644 index 00000000..9eecc8e0 --- /dev/null +++ b/include/emoji/EmojiPanel.h @@ -0,0 +1,55 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include "EmojiProvider.h" + +class EmojiCategory; + +class EmojiPanel : public QWidget +{ + Q_OBJECT + +public: + EmojiPanel(QWidget *parent = nullptr); + +signals: + void mouseLeft(); + void emojiSelected(const QString &emoji); + +protected: + void leaveEvent(QEvent *event); + void paintEvent(QPaintEvent *event); + +private: + void showEmojiCategory(const EmojiCategory *category); + + EmojiProvider emoji_provider_; + + QScrollArea *scrollArea_; + + int shadowMargin_; + + // Panel dimensions. + int width_; + int height_; + + int categoryIconSize_; +}; diff --git a/include/emoji/EmojiPickButton.h b/include/emoji/EmojiPickButton.h new file mode 100644 index 00000000..8ef9be9e --- /dev/null +++ b/include/emoji/EmojiPickButton.h @@ -0,0 +1,48 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include "FlatButton.h" + +class EmojiPanel; + +class EmojiPickButton : public FlatButton +{ + Q_OBJECT +public: + explicit EmojiPickButton(QWidget *parent = nullptr); + +signals: + void emojiSelected(const QString &emoji); + +protected: + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + +private: + // Vertical distance from panel's bottom. + int vertical_distance_ = 10; + + // Horizontal distance from panel's bottom right corner. + int horizontal_distance_ = 70; + + QSharedPointer panel_; +}; diff --git a/include/emoji/EmojiProvider.h b/include/emoji/EmojiProvider.h new file mode 100644 index 00000000..847157fd --- /dev/null +++ b/include/emoji/EmojiProvider.h @@ -0,0 +1,41 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +struct Emoji +{ + // Unicode code. + QString unicode; + // Keyboard shortcut e.g :emoji: + QString shortname; +}; + +class EmojiProvider +{ +public: + static const QList people; + static const QList nature; + static const QList food; + static const QList activity; + static const QList travel; + static const QList objects; + static const QList symbols; + static const QList flags; +}; diff --git a/include/timeline/TimelineItem.h b/include/timeline/TimelineItem.h new file mode 100644 index 00000000..9646405c --- /dev/null +++ b/include/timeline/TimelineItem.h @@ -0,0 +1,155 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "AvatarProvider.h" +#include "Emote.h" +#include "File.h" +#include "Image.h" +#include "MessageEvent.h" +#include "Notice.h" +#include "RoomInfoListItem.h" +#include "Text.h" +#include "TimelineViewManager.h" + +class ImageItem; +class FileItem; +class Avatar; + +namespace events = matrix::events; +namespace msgs = matrix::events::messages; + +class TimelineItem : public QWidget +{ + Q_OBJECT +public: + TimelineItem(const events::MessageEvent &e, + bool with_sender, + QWidget *parent = 0); + TimelineItem(const events::MessageEvent &e, + bool with_sender, + QWidget *parent = 0); + TimelineItem(const events::MessageEvent &e, + bool with_sender, + QWidget *parent = 0); + + // For local messages. + // m.text & m.emote + TimelineItem(events::MessageEventType ty, + const QString &userid, + QString body, + bool withSender, + QWidget *parent = 0); + // m.image + TimelineItem(ImageItem *item, const QString &userid, bool withSender, QWidget *parent = 0); + TimelineItem(FileItem *item, const QString &userid, bool withSender, QWidget *parent = 0); + + TimelineItem(ImageItem *img, + const events::MessageEvent &e, + bool with_sender, + QWidget *parent); + TimelineItem(FileItem *file, + const events::MessageEvent &e, + bool with_sender, + QWidget *parent); + + void setUserAvatar(const QImage &pixmap); + DescInfo descriptionMessage() const { return descriptionMsg_; } + QString eventId() const { return event_id_; } + + ~TimelineItem(); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + void init(); + + template + void setupLocalWidgetLayout(Widget *widget, + const QString &userid, + const QString &msgDescription, + bool withSender); + + 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(); + + QString replaceEmoji(const QString &body); + QString event_id_; + + DescInfo descriptionMsg_; + + QHBoxLayout *topLayout_; + QVBoxLayout *sideLayout_; // Avatar or Timestamp + QVBoxLayout *mainLayout_; // Header & Message body + + QHBoxLayout *headerLayout_; // Username (&) Timestamp + + Avatar *userAvatar_; + + QFont font_; + + QLabel *timestamp_; + QLabel *userName_; + QLabel *body_; +}; + +template +void +TimelineItem::setupLocalWidgetLayout(Widget *widget, + const QString &userid, + const QString &msgDescription, + bool withSender) +{ + auto displayName = TimelineViewManager::displayName(userid); + auto timestamp = QDateTime::currentDateTime(); + + descriptionMsg_ = { + "You", userid, QString(" %1").arg(msgDescription), descriptiveTime(timestamp)}; + + generateTimestamp(timestamp); + + auto widgetLayout = new QHBoxLayout(); + widgetLayout->setContentsMargins(0, 5, 0, 0); + widgetLayout->addWidget(widget); + widgetLayout->addStretch(1); + + if (withSender) { + generateBody(displayName, ""); + setupAvatarLayout(displayName); + mainLayout_->addLayout(headerLayout_); + + AvatarProvider::resolve(userid, this); + } else { + setupSimpleLayout(); + } + + mainLayout_->addLayout(widgetLayout); +} diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h new file mode 100644 index 00000000..898a304e --- /dev/null +++ b/include/timeline/TimelineView.h @@ -0,0 +1,310 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Emote.h" +#include "File.h" +#include "Image.h" +#include "MatrixClient.h" +#include "MessageEvent.h" +#include "Notice.h" +#include "Text.h" +#include "TimelineItem.h" + +class FloatingButton; +class RoomMessages; +class ScrollBar; +class Timeline; +struct DescInfo; + +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 +{ + matrix::events::MessageEventType ty; + int txn_id; + QString body; + QString filename; + QString event_id; + TimelineItem *widget; + + PendingMessage(matrix::events::MessageEventType ty, + int txn_id, + QString body, + QString filename, + QString event_id, + TimelineItem *widget) + : ty(ty) + , txn_id(txn_id) + , body(body) + , filename(filename) + , event_id(event_id) + , widget(widget) + {} +}; + +// In which place new TimelineItems should be inserted. +enum class TimelineDirection +{ + Top, + Bottom, +}; + +class TimelineView : public QWidget +{ + Q_OBJECT + +public: + TimelineView(const Timeline &timeline, + QSharedPointer client, + const QString &room_id, + QWidget *parent = 0); + TimelineView(QSharedPointer client, + const QString &room_id, + QWidget *parent = 0); + + // Add new events at the end of the timeline. + int addEvents(const Timeline &timeline); + void addUserMessage(matrix::events::MessageEventType ty, const QString &msg); + + template + void addUserMessage(const QString &url, const QString &filename); + void updatePendingMessage(int txn_id, QString event_id); + void scrollDown(); + +public slots: + 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); + + // Whether or not the initial batch has been loaded. + bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; } + + void handleFailedMessage(int txnid); + +private slots: + void sendNextPendingMessage(); + +signals: + void updateLastTimelineMessage(const QString &user, const DescInfo &info); + void clearUnreadMessageCount(const QString &room_id); + +protected: + void paintEvent(QPaintEvent *event) override; + void showEvent(QShowEvent *event) override; + bool event(QEvent *event) override; + +private: + void init(); + void addTimelineItem(TimelineItem *item, TimelineDirection direction); + void updateLastSender(const QString &user_id, TimelineDirection direction); + void notifyForLastEvent(); + void readLastEvent() const; + QString getLastEventId() const; + + template + TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + + // TODO: Remove this eventually. + template + TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction); + + // For events with custom display widgets. + template + TimelineItem *createTimelineItem(const Event &event, bool withSender); + + // For events without custom display widgets. + // TODO: All events should have custom widgets. + template + TimelineItem *createTimelineItem(const Event &event, bool withSender); + + // 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 QString &txnid, const QString &sender, const QString &userid); + void removePendingMessage(const QString &txnid); + + bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); } + + void handleNewUserMessage(PendingMessage msg); + + // Return nullptr if the event couldn't be parsed. + TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction); + + QVBoxLayout *top_layout_; + QVBoxLayout *scroll_layout_; + + QScrollArea *scroll_area_; + ScrollBar *scrollbar_; + QWidget *scroll_widget_; + + QString lastSender_; + QString firstSender_; + QString room_id_; + QString prev_batch_token_; + QString local_user_; + + bool isPaginationInProgress_ = false; + + // Keeps track whether or not the user has visited the view. + bool isInitialized = false; + bool isTimelineFinished = false; + bool isInitialSync = true; + + const int SCROLL_BAR_GAP = 200; + + QTimer *paginationTimer_; + + int scroll_height_ = 0; + int previous_max_height_ = 0; + + int oldPosition_; + int oldHeight_; + + FloatingButton *scrollDownBtn_; + + TimelineDirection lastMessageDirection_; + + // The events currently rendered. Used for duplicate detection. + QMap eventIds_; + QQueue pending_msgs_; + QList pending_sent_msgs_; + QSharedPointer client_; +}; + +template +void +TimelineView::addUserMessage(const QString &url, const QString &filename) +{ + QSettings settings; + auto user_id = settings.value("auth/user_id").toString(); + auto with_sender = lastSender_ != user_id; + + auto widget = new Widget(client_, url, filename, this); + + TimelineItem *view_item = new TimelineItem(widget, user_id, with_sender, scroll_widget_); + scroll_layout_->addWidget(view_item); + + lastMessageDirection_ = TimelineDirection::Bottom; + + QApplication::processEvents(); + + lastSender_ = user_id; + + int txn_id = client_->incrementTransactionId(); + + PendingMessage message(MsgType, txn_id, url, filename, "", view_item); + handleNewUserMessage(message); +} + +template +TimelineItem * +TimelineView::createTimelineItem(const Event &event, bool withSender) +{ + TimelineItem *item = new TimelineItem(event, withSender, scroll_widget_); + return item; +} + +template +TimelineItem * +TimelineView::createTimelineItem(const Event &event, bool withSender) +{ + auto eventWidget = new Widget(client_, event); + auto item = new TimelineItem(eventWidget, event, withSender, scroll_widget_); + + return item; +} + +template +TimelineItem * +TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) +{ + Event event; + + try { + event.deserialize(data); + } catch (const DeserializationException &e) { + qWarning() << e.what() << data; + return nullptr; + } + + if (isDuplicate(event.eventId())) + return nullptr; + + eventIds_[event.eventId()] = true; + + QString txnid = event.unsignedData().transactionId(); + if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { + removePendingMessage(txnid); + return nullptr; + } + + auto with_sender = isSenderRendered(event.sender(), direction); + + updateLastSender(event.sender(), direction); + + return createTimelineItem(event, with_sender); +} + +template +TimelineItem * +TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction) +{ + Event event; + + try { + event.deserialize(data); + } catch (const DeserializationException &e) { + qWarning() << e.what() << data; + return nullptr; + } + + if (isDuplicate(event.eventId())) + return nullptr; + + eventIds_[event.eventId()] = true; + + QString txnid = event.unsignedData().transactionId(); + if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) { + removePendingMessage(txnid); + return nullptr; + } + + auto with_sender = isSenderRendered(event.sender(), direction); + + updateLastSender(event.sender(), direction); + + return createTimelineItem(event, with_sender); +} diff --git a/include/timeline/TimelineViewManager.h b/include/timeline/TimelineViewManager.h new file mode 100644 index 00000000..854c2550 --- /dev/null +++ b/include/timeline/TimelineViewManager.h @@ -0,0 +1,80 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "MessageEvent.h" + +class JoinedRoom; +class MatrixClient; +class RoomInfoListItem; +class Rooms; +class TimelineView; +struct DescInfo; + +class TimelineViewManager : public QStackedWidget +{ + Q_OBJECT + +public: + TimelineViewManager(QSharedPointer client, QWidget *parent); + ~TimelineViewManager(); + + // Initialize with timeline events. + void initialize(const Rooms &rooms); + // Empty initialization. + void initialize(const QList &rooms); + + void addRoom(const JoinedRoom &room, const QString &room_id); + void addRoom(const QString &room_id); + + void sync(const Rooms &rooms); + void clearAll(); + + // Check if all the timelines have been loaded. + bool hasLoaded() const; + + static QString chooseRandomColor(); + static QString displayName(const QString &userid); + + static QMap DISPLAY_NAMES; + +signals: + void clearRoomMessageCount(QString roomid); + void unreadMessages(QString roomid, int count); + void updateRoomsLastMessage(const QString &user, const DescInfo &info); + +public slots: + void setHistoryView(const QString &room_id); + void queueTextMessage(const QString &msg); + void queueEmoteMessage(const QString &msg); + void queueImageMessage(const QString &roomid, const QString &filename, const QString &url); + void queueFileMessage(const QString &roomid, const QString &filename, const QString &url); + +private slots: + void messageSent(const QString &eventid, const QString &roomid, int txnid); + void messageSendFailed(const QString &roomid, int txnid); + +private: + QString active_room_; + QMap> views_; + QSharedPointer client_; +}; diff --git a/include/timeline/widgets/FileItem.h b/include/timeline/widgets/FileItem.h new file mode 100644 index 00000000..ebb18111 --- /dev/null +++ b/include/timeline/widgets/FileItem.h @@ -0,0 +1,98 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "File.h" +#include "MatrixClient.h" +#include "MessageEvent.h" + +namespace events = matrix::events; +namespace msgs = matrix::events::messages; + +constexpr int MaxWidth = 400; +constexpr int Height = 70; +constexpr int IconRadius = 22; +constexpr int IconDiameter = IconRadius * 2; +constexpr int HorizontalPadding = 12; +constexpr int TextPadding = 15; +constexpr int DownloadIconRadius = IconRadius - 4; + +constexpr double VerticalPadding = Height - 2 * IconRadius; +constexpr double IconYCenter = Height / 2; +constexpr double IconXCenter = HorizontalPadding + IconRadius; + +class FileItem : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor) + Q_PROPERTY(QColor iconColor WRITE setIconColor READ iconColor) + Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) + +public: + FileItem(QSharedPointer client, + const events::MessageEvent &event, + QWidget *parent = nullptr); + + FileItem(QSharedPointer client, + const QString &url, + const QString &filename, + QWidget *parent = nullptr); + + QSize sizeHint() const override; + + void setTextColor(const QColor &color) { textColor_ = color; } + void setIconColor(const QColor &color) { iconColor_ = color; } + void setBackgroundColor(const QColor &color) { backgroundColor_ = color; } + + QColor textColor() const { return textColor_; } + QColor iconColor() const { return iconColor_; } + QColor backgroundColor() const { return backgroundColor_; } + +protected: + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + +private slots: + void fileDownloaded(const QString &event_id, const QByteArray &data); + +private: + QString calculateFileSize(int nbytes) const; + void openUrl(); + void init(); + + QUrl url_; + QString text_; + QString readableFileSize_; + QString filenameToSave_; + + events::MessageEvent event_; + QSharedPointer client_; + + QIcon icon_; + + QColor textColor_ = QColor("white"); + QColor iconColor_ = QColor("#38A3D8"); + QColor backgroundColor_ = QColor("#333"); +}; diff --git a/include/timeline/widgets/ImageItem.h b/include/timeline/widgets/ImageItem.h new file mode 100644 index 00000000..c4f6998a --- /dev/null +++ b/include/timeline/widgets/ImageItem.h @@ -0,0 +1,78 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +#include "Image.h" +#include "MatrixClient.h" +#include "MessageEvent.h" + +namespace events = matrix::events; +namespace msgs = matrix::events::messages; + +class ImageItem : public QWidget +{ + Q_OBJECT +public: + ImageItem(QSharedPointer client, + const events::MessageEvent &event, + QWidget *parent = nullptr); + + ImageItem(QSharedPointer client, + const QString &url, + const QString &filename, + QWidget *parent = nullptr); + + void setImage(const QPixmap &image); + + QSize sizeHint() const override; + +protected: + void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + +private slots: + void imageDownloaded(const QString &event_id, const QPixmap &img); + +private: + void scaleImage(); + void openUrl(); + + int max_width_ = 500; + int max_height_ = 300; + + int width_; + int height_; + + QPixmap scaled_image_; + QPixmap image_; + + QUrl url_; + QString text_; + + int bottom_height_ = 30; + + events::MessageEvent event_; + + QSharedPointer client_; +}; -- cgit 1.5.1