diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | include/AvatarProvider.h | 47 | ||||
-rw-r--r-- | include/MatrixClient.h | 4 | ||||
-rw-r--r-- | include/TimelineItem.h | 25 | ||||
-rw-r--r-- | src/AvatarProvider.cc | 83 | ||||
-rw-r--r-- | src/ChatPage.cc | 13 | ||||
-rw-r--r-- | src/MatrixClient.cc | 52 | ||||
-rw-r--r-- | src/TimelineItem.cc | 285 | ||||
-rw-r--r-- | src/main.cc | 2 |
9 files changed, 412 insertions, 101 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f6f88e4f..51e1993b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") endif() set(SRC_FILES + src/AvatarProvider.cc src/ChatPage.cc src/Deserializable.cc src/EmojiCategory.cc @@ -160,6 +161,7 @@ include_directories(include/events) include_directories(include/events/messages) qt5_wrap_cpp(MOC_HEADERS + include/AvatarProvider.h include/ChatPage.h include/EmojiCategory.h include/EmojiItemDelegate.h diff --git a/include/AvatarProvider.h b/include/AvatarProvider.h new file mode 100644 index 00000000..29c8152b --- /dev/null +++ b/include/AvatarProvider.h @@ -0,0 +1,47 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QImage> +#include <QObject> +#include <QSharedPointer> +#include <QUrl> + +#include "MatrixClient.h" +#include "TimelineItem.h" + +class AvatarProvider : public QObject +{ + Q_OBJECT + +public: + static void init(QSharedPointer<MatrixClient> client); + static void resolve(const QString &userId, TimelineItem *item); + static void setAvatarUrl(const QString &userId, const QUrl &url); + + static void clear(); + +private: + static void updateAvatar(const QString &uid, const QImage &img); + + static QSharedPointer<MatrixClient> client_; + static QMap<QString, QList<TimelineItem *>> toBeResolved_; + + static QMap<QString, QImage> userAvatars_; + static QMap<QString, QUrl> avatarUrls_; +}; diff --git a/include/MatrixClient.h b/include/MatrixClient.h index 2fdb57f0..2fde1c1e 100644 --- a/include/MatrixClient.h +++ b/include/MatrixClient.h @@ -41,6 +41,7 @@ public: void registerUser(const QString &username, const QString &password, const QString &server) noexcept; void versions() noexcept; void fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url); + void fetchUserAvatar(const QString &userId, const QUrl &avatarUrl); void fetchOwnAvatar(const QUrl &avatar_url); void downloadImage(const QString &event_id, const QUrl &url); void messages(const QString &room_id, const QString &from_token) noexcept; @@ -69,6 +70,7 @@ signals: void registerSuccess(const QString &userid, const QString &homeserver, const QString &token); void roomAvatarRetrieved(const QString &roomid, const QPixmap &img); + void userAvatarRetrieved(const QString &userId, const QImage &img); void ownAvatarRetrieved(const QPixmap &img); void imageDownloaded(const QString &event_id, const QPixmap &img); @@ -95,6 +97,7 @@ private: Messages, Register, RoomAvatar, + UserAvatar, SendTextMessage, Sync, Versions, @@ -111,6 +114,7 @@ private: void onInitialSyncResponse(QNetworkReply *reply); void onSyncResponse(QNetworkReply *reply); void onRoomAvatarResponse(QNetworkReply *reply); + void onUserAvatarResponse(QNetworkReply *reply); void onImageResponse(QNetworkReply *reply); void onMessagesResponse(QNetworkReply *reply); diff --git a/include/TimelineItem.h b/include/TimelineItem.h index 5db823b0..c0cf1c7b 100644 --- a/include/TimelineItem.h +++ b/include/TimelineItem.h @@ -24,6 +24,7 @@ #include "ImageItem.h" #include "Sync.h" +#include "Avatar.h" #include "Image.h" #include "MessageEvent.h" #include "Notice.h" @@ -46,19 +47,35 @@ public: 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); + void setUserAvatar(const QImage &pixmap); + ~TimelineItem(); private: + void init(); + void generateBody(const QString &body); void generateBody(const QString &userid, const QString &color, const QString &body); void generateTimestamp(const QDateTime &time); + void setupAvatarLayout(const QString &userName); + void setupSimpleLayout(); + QString replaceEmoji(const QString &body); - void setupLayout(); + QHBoxLayout *topLayout_; + QVBoxLayout *sideLayout_; // Avatar or Timestamp + QVBoxLayout *mainLayout_; // Header & Message body + + QHBoxLayout *headerLayout_; // Username (&) Timestamp + + Avatar *userAvatar_; - QHBoxLayout *top_layout_; + QLabel *timestamp_; + QLabel *userName_; + QLabel *body_; - QLabel *time_label_; - QLabel *content_label_; + QFont bodyFont_; + QFont usernameFont_; + QFont timestampFont_; }; diff --git a/src/AvatarProvider.cc b/src/AvatarProvider.cc new file mode 100644 index 00000000..7481b781 --- /dev/null +++ b/src/AvatarProvider.cc @@ -0,0 +1,83 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "AvatarProvider.h" + +QSharedPointer<MatrixClient> AvatarProvider::client_; + +QMap<QString, QImage> AvatarProvider::userAvatars_; +QMap<QString, QUrl> AvatarProvider::avatarUrls_; +QMap<QString, QList<TimelineItem *>> AvatarProvider::toBeResolved_; + +void AvatarProvider::init(QSharedPointer<MatrixClient> client) +{ + client_ = client; + + connect(client_.data(), &MatrixClient::userAvatarRetrieved, &AvatarProvider::updateAvatar); +} + +void AvatarProvider::updateAvatar(const QString &uid, const QImage &img) +{ + if (toBeResolved_.contains(uid)) { + auto items = toBeResolved_[uid]; + + // Update all the timeline items with the resolved avatar. + for (const auto item : items) + item->setUserAvatar(img); + + toBeResolved_.remove(uid); + } + + userAvatars_.insert(uid, img); +} + +void AvatarProvider::resolve(const QString &userId, TimelineItem *item) +{ + if (userAvatars_.contains(userId)) { + auto img = userAvatars_[userId]; + + item->setUserAvatar(img); + + return; + } + + if (avatarUrls_.contains(userId)) { + // Add the current timeline item to the waiting list for this avatar. + if (!toBeResolved_.contains(userId)) { + client_->fetchUserAvatar(userId, avatarUrls_[userId]); + + QList<TimelineItem *> timelineItems; + timelineItems.push_back(item); + + toBeResolved_.insert(userId, timelineItems); + } else { + toBeResolved_[userId].push_back(item); + } + } +} + +void AvatarProvider::setAvatarUrl(const QString &userId, const QUrl &url) +{ + avatarUrls_.insert(userId, url); +} + +void AvatarProvider::clear() +{ + userAvatars_.clear(); + avatarUrls_.clear(); + toBeResolved_.clear(); +} diff --git a/src/ChatPage.cc b/src/ChatPage.cc index 0b09693b..4e9120d2 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc @@ -27,6 +27,7 @@ #include "AliasesEventContent.h" #include "AvatarEventContent.h" +#include "AvatarProvider.h" #include "CanonicalAliasEventContent.h" #include "CreateEventContent.h" #include "HistoryVisibilityEventContent.h" @@ -173,6 +174,8 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent) SIGNAL(ownAvatarRetrieved(const QPixmap &)), this, SLOT(setOwnAvatar(const QPixmap &))); + + AvatarProvider::init(client); } void ChatPage::logout() @@ -203,6 +206,8 @@ void ChatPage::logout() settingsManager_.clear(); room_avatars_.clear(); + AvatarProvider::clear(); + emit close(); } @@ -300,6 +305,14 @@ void ChatPage::initialSyncCompleted(const SyncResponse &response) state_manager_.insert(it.key(), room_state); settingsManager_.insert(it.key(), QSharedPointer<RoomSettings>(new RoomSettings(it.key()))); + + for (const auto membership : room_state.memberships) { + auto uid = membership.sender(); + auto url = membership.content().avatarUrl(); + + if (!url.toString().isEmpty()) + AvatarProvider::setAvatarUrl(uid, url); + } } view_manager_->initialize(response.rooms()); diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc index a605623f..927db541 100644 --- a/src/MatrixClient.cc +++ b/src/MatrixClient.cc @@ -287,6 +287,29 @@ void MatrixClient::onRoomAvatarResponse(QNetworkReply *reply) emit roomAvatarRetrieved(roomid, pixmap); } +void MatrixClient::onUserAvatarResponse(QNetworkReply *reply) +{ + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (status == 0 || status >= 400) { + qWarning() << reply->errorString(); + return; + } + + auto data = reply->readAll(); + + if (data.size() == 0) + return; + + auto roomid = reply->property("userid").toString(); + + QImage img; + img.loadFromData(data); + + emit userAvatarRetrieved(roomid, img); +} void MatrixClient::onGetOwnAvatarResponse(QNetworkReply *reply) { reply->deleteLater(); @@ -392,6 +415,9 @@ void MatrixClient::onResponse(QNetworkReply *reply) case Endpoint::RoomAvatar: onRoomAvatarResponse(reply); break; + case Endpoint::UserAvatar: + onUserAvatarResponse(reply); + break; case Endpoint::GetOwnAvatar: onGetOwnAvatarResponse(reply); break; @@ -591,6 +617,32 @@ void MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url reply->setProperty("endpoint", static_cast<int>(Endpoint::RoomAvatar)); } +void MatrixClient::fetchUserAvatar(const QString &userId, const QUrl &avatarUrl) +{ + QList<QString> url_parts = avatarUrl.toString().split("mxc://"); + + if (url_parts.size() != 2) { + qDebug() << "Invalid format for user avatar " << avatarUrl.toString(); + return; + } + + QUrlQuery query; + query.addQueryItem("width", "128"); + query.addQueryItem("height", "128"); + query.addQueryItem("method", "crop"); + + QString media_url = QString("%1/_matrix/media/r0/thumbnail/%2").arg(getHomeServer().toString(), url_parts[1]); + + QUrl endpoint(media_url); + endpoint.setQuery(query); + + QNetworkRequest avatar_request(endpoint); + + QNetworkReply *reply = get(avatar_request); + reply->setProperty("userid", userId); + reply->setProperty("endpoint", static_cast<int>(Endpoint::UserAvatar)); +} + void MatrixClient::downloadImage(const QString &event_id, const QUrl &url) { QNetworkRequest image_request(url); diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc index b1c58e6a..cf8d5e85 100644 --- a/src/TimelineItem.cc +++ b/src/TimelineItem.cc @@ -17,8 +17,10 @@ #include <QDateTime> #include <QDebug> +#include <QFontDatabase> #include <QRegExp> +#include "AvatarProvider.h" #include "ImageItem.h" #include "TimelineItem.h" #include "TimelineViewManager.h" @@ -29,65 +31,119 @@ static const QString URL_HTML = "<a href=\"\\1\" style=\"color: #333333\">\\1</a namespace events = matrix::events; namespace msgs = matrix::events::messages; +void TimelineItem::init() +{ + userAvatar_ = nullptr; + timestamp_ = nullptr; + userName_ = nullptr; + body_ = nullptr; + + QFontDatabase db; + + bodyFont_ = db.font("Open Sans", "Regular", 10); + usernameFont_ = db.font("Open Sans", "Bold", 10); + timestampFont_ = db.font("Open Sans", "Regular", 7); + + topLayout_ = new QHBoxLayout(this); + sideLayout_ = new QVBoxLayout(); + mainLayout_ = new QVBoxLayout(); + headerLayout_ = new QHBoxLayout(); + + topLayout_->setContentsMargins(7, 0, 0, 0); + topLayout_->setSpacing(9); + + topLayout_->addLayout(sideLayout_); + topLayout_->addLayout(mainLayout_, 1); +} + TimelineItem::TimelineItem(const QString &userid, const QString &color, QString body, QWidget *parent) : QWidget(parent) { + init(); + body.replace(URL_REGEX, URL_HTML); + auto displayName = TimelineViewManager::displayName(userid); generateTimestamp(QDateTime::currentDateTime()); - generateBody(TimelineViewManager::displayName(userid), color, body); - setupLayout(); + generateBody(displayName, color, body); + + setupAvatarLayout(displayName); + + mainLayout_->addLayout(headerLayout_); + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(0); + + AvatarProvider::resolve(userid, this); } TimelineItem::TimelineItem(QString body, QWidget *parent) : QWidget(parent) { + init(); + body.replace(URL_REGEX, URL_HTML); generateTimestamp(QDateTime::currentDateTime()); generateBody(body); - setupLayout(); + + setupSimpleLayout(); + + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(2); } TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, const QString &color, QWidget *parent) : QWidget(parent) { + init(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + auto displayName = TimelineViewManager::displayName(event.sender()); + generateTimestamp(timestamp); - generateBody(TimelineViewManager::displayName(event.sender()), color, ""); + generateBody(displayName, color, ""); - top_layout_ = new QHBoxLayout(); - top_layout_->setMargin(0); - top_layout_->addWidget(time_label_); + setupAvatarLayout(displayName); - auto right_layout = new QVBoxLayout(); - right_layout->addWidget(content_label_); - right_layout->addWidget(image); + auto imageLayout = new QHBoxLayout(); + imageLayout->addWidget(image); + imageLayout->addStretch(1); - top_layout_->addLayout(right_layout); - top_layout_->addStretch(1); + mainLayout_->addLayout(headerLayout_); + mainLayout_->addLayout(imageLayout); + mainLayout_->setContentsMargins(0, 4, 0, 0); + mainLayout_->setSpacing(0); - setLayout(top_layout_); + AvatarProvider::resolve(event.sender(), this); } TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, QWidget *parent) : QWidget(parent) { + init(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); generateTimestamp(timestamp); - top_layout_ = new QHBoxLayout(); - top_layout_->setMargin(0); - top_layout_->addWidget(time_label_); - top_layout_->addWidget(image, 1); - top_layout_->addStretch(1); + setupSimpleLayout(); - setLayout(top_layout_); + auto imageLayout = new QHBoxLayout(); + imageLayout->setMargin(0); + imageLayout->addWidget(image); + imageLayout->addStretch(1); + + mainLayout_->addLayout(imageLayout); + mainLayout_->setContentsMargins(0, 4, 0, 0); + mainLayout_->setSpacing(2); } TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool with_sender, const QString &color, QWidget *parent) : QWidget(parent) { + init(); + auto body = event.content().body().trimmed().toHtmlEscaped(); auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); @@ -96,17 +152,34 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool body.replace(URL_REGEX, URL_HTML); body = "<i style=\"color: #565E5E\">" + body + "</i>"; - if (with_sender) - generateBody(TimelineViewManager::displayName(event.sender()), color, body); - else + if (with_sender) { + auto displayName = TimelineViewManager::displayName(event.sender()); + + generateBody(displayName, color, body); + setupAvatarLayout(displayName); + + mainLayout_->addLayout(headerLayout_); + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(0); + + AvatarProvider::resolve(event.sender(), this); + } else { generateBody(body); - setupLayout(); + setupSimpleLayout(); + + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(2); + } } TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender, const QString &color, QWidget *parent) : QWidget(parent) { + init(); + auto body = event.content().body().trimmed().toHtmlEscaped(); auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); @@ -114,34 +187,45 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool w body.replace(URL_REGEX, URL_HTML); - if (with_sender) - generateBody(TimelineViewManager::displayName(event.sender()), color, body); - else + if (with_sender) { + auto displayName = TimelineViewManager::displayName(event.sender()); + generateBody(displayName, color, body); + + setupAvatarLayout(displayName); + + mainLayout_->addLayout(headerLayout_); + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(0); + + AvatarProvider::resolve(event.sender(), this); + } else { generateBody(body); - setupLayout(); + setupSimpleLayout(); + + mainLayout_->addWidget(body_); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(2); + } } +// Only the body is displayed. void TimelineItem::generateBody(const QString &body) { - content_label_ = new QLabel(this); - content_label_->setWordWrap(true); - content_label_->setAlignment(Qt::AlignTop); - content_label_->setStyleSheet("margin: 0;"); - QString content( - "<html>" - "<head/>" - "<body>" - " <span style=\"font-size: 10pt; color: #171919;\">" - " %1" - " </span>" - "</body>" - "</html>"); - content_label_->setText(content.arg(replaceEmoji(body))); - content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - content_label_->setOpenExternalLinks(true); + QString content("<span style=\"color: #171919;\">%1</span>"); + + body_ = new QLabel(this); + body_->setWordWrap(true); + body_->setFont(bodyFont_); + body_->setText(content.arg(replaceEmoji(body))); + body_->setAlignment(Qt::AlignTop); + + 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) { auto sender = userid; @@ -150,64 +234,35 @@ void TimelineItem::generateBody(const QString &userid, const QString &color, con if (userid.split(":")[0].split("@").size() > 1) sender = userid.split(":")[0].split("@")[1]; - content_label_ = new QLabel(this); - content_label_->setWordWrap(true); - content_label_->setAlignment(Qt::AlignTop); - content_label_->setStyleSheet("margin: 0;"); - QString content( - "<html>" - "<head/>" - "<body>" - " <span style=\"font-size: 10pt; font-weight: 600; color: %1\">" - " %2" - " </span>" - " <span style=\"font-size: 10pt; color: #171919;\">" - " %3" - " </span>" - "</body>" - "</html>"); - content_label_->setText(content.arg(color).arg(sender).arg(replaceEmoji(body))); - content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - content_label_->setOpenExternalLinks(true); -} + QString userContent("<span style=\"color: %1\"> %2 </span>"); + QString bodyContent("<span style=\"color: #171717;\"> %1 </span>"); -void TimelineItem::generateTimestamp(const QDateTime &time) -{ - auto local_time = time.toString("HH:mm"); - - time_label_ = new QLabel(this); - QString msg( - "<html>" - "<head/>" - "<body>" - " <span style=\"font-size: 7pt; color: #5d6565;\">" - " %1" - " </span>" - "</body>" - "</html>"); - time_label_->setText(msg.arg(local_time)); - time_label_->setStyleSheet("margin-left: 7px; margin-right: 7px; margin-top: 0;"); - time_label_->setAlignment(Qt::AlignTop); -} + userName_ = new QLabel(this); + userName_->setFont(usernameFont_); + userName_->setText(userContent.arg(color).arg(sender)); + userName_->setAlignment(Qt::AlignTop); -void TimelineItem::setupLayout() -{ - if (time_label_ == nullptr) { - qWarning() << "TimelineItem: Time label is not initialized"; + if (body.isEmpty()) return; - } - if (content_label_ == nullptr) { - qWarning() << "TimelineItem: Content label is not initialized"; - return; - } + body_ = new QLabel(this); + body_->setFont(bodyFont_); + body_->setWordWrap(true); + body_->setAlignment(Qt::AlignTop); + body_->setText(bodyContent.arg(replaceEmoji(body))); + body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); + body_->setOpenExternalLinks(true); +} - top_layout_ = new QHBoxLayout(); - top_layout_->setMargin(0); - top_layout_->addWidget(time_label_); - top_layout_->addWidget(content_label_, 1); +void TimelineItem::generateTimestamp(const QDateTime &time) +{ + QString msg("<span style=\"color: #5d6565;\"> %1 </span>"); - setLayout(top_layout_); + timestamp_ = new QLabel(this); + timestamp_->setFont(timestampFont_); + timestamp_->setText(msg.arg(time.toString("HH:mm"))); + timestamp_->setAlignment(Qt::AlignTop); + timestamp_->setStyleSheet("margin-top: 2px;"); } QString TimelineItem::replaceEmoji(const QString &body) @@ -227,6 +282,46 @@ QString TimelineItem::replaceEmoji(const QString &body) return fmtBody; } +void TimelineItem::setupAvatarLayout(const QString &userName) +{ + topLayout_->setContentsMargins(7, 6, 0, 0); + + userAvatar_ = new Avatar(this); + userAvatar_->setLetter(QChar(userName[0]).toUpper()); + userAvatar_->setBackgroundColor(QColor("#eee")); + userAvatar_->setTextColor(QColor("black")); + userAvatar_->setSize(32); + + // 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_->setMargin(0); + sideLayout_->setSpacing(0); + + headerLayout_->addWidget(userName_); + headerLayout_->addWidget(timestamp_, 1); + headerLayout_->setMargin(0); +} + +void TimelineItem::setupSimpleLayout() +{ + sideLayout_->addWidget(timestamp_); + sideLayout_->addStretch(1); + + topLayout_->setContentsMargins(9, 0, 0, 0); +} + +void TimelineItem::setUserAvatar(const QImage &avatar) +{ + if (userAvatar_ == nullptr) + return; + + userAvatar_->setImage(avatar); +} + TimelineItem::~TimelineItem() { } diff --git a/src/main.cc b/src/main.cc index e6d4c4e7..bf165cab 100644 --- a/src/main.cc +++ b/src/main.cc @@ -36,9 +36,7 @@ int main(int argc, char *argv[]) QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-Regular.ttf"); QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-Italic.ttf"); QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-Bold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-BoldItalic.ttf"); QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-Semibold.ttf"); - QFontDatabase::addApplicationFont(":/fonts/fonts/OpenSans/OpenSans-SemiboldItalic.ttf"); QFontDatabase::addApplicationFont(":/fonts/fonts/EmojiOne/emojione-android.ttf"); app.setWindowIcon(QIcon(":/logos/nheko.png")); |