summary refs log tree commit diff
path: root/src/TimelineItem.cc
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-30 13:53:28 +0200
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2017-11-30 13:53:28 +0200
commit32c83405771b2f7a751783529d17e1b84dad4224 (patch)
tree70b51c8f019bfcaae99207fba8d0214e4b69e94d /src/TimelineItem.cc
parentUse templates for the TimelineItem generation (diff)
downloadnheko-32c83405771b2f7a751783529d17e1b84dad4224.tar.xz
Create directories for related files
Diffstat (limited to 'src/TimelineItem.cc')
-rw-r--r--src/TimelineItem.cc506
1 files changed, 0 insertions, 506 deletions
diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc
deleted file mode 100644

index 7297abc3..00000000 --- a/src/TimelineItem.cc +++ /dev/null
@@ -1,506 +0,0 @@ -/* - * 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 <QFontDatabase> -#include <QRegExp> -#include <QSettings> -#include <QTextEdit> - -#include "Avatar.h" -#include "Config.h" -#include "FileItem.h" -#include "ImageItem.h" -#include "Sync.h" -#include "TimelineItem.h" - -static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)"); -static const QString URL_HTML = "<a href=\"\\1\">\\1</a>"; - -namespace events = matrix::events; -namespace msgs = matrix::events::messages; - -void -TimelineItem::init() -{ - userAvatar_ = nullptr; - timestamp_ = nullptr; - userName_ = nullptr; - body_ = nullptr; - - font_.setPixelSize(conf::fontSize); - - QFontMetrics fm(font_); - - 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_->addLayout(sideLayout_); - topLayout_->addLayout(mainLayout_, 1); - - sideLayout_->setMargin(0); - sideLayout_->setSpacing(0); - - mainLayout_->setContentsMargins(conf::timeline::headerLeftMargin, 0, 0, 0); - mainLayout_->setSpacing(0); - - headerLayout_->setMargin(0); - headerLayout_->setSpacing(conf::timeline::headerSpacing); -} - -/* - * For messages created locally. - */ -TimelineItem::TimelineItem(events::MessageEventType ty, - const QString &userid, - QString body, - bool withSender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - auto displayName = TimelineViewManager::displayName(userid); - auto timestamp = QDateTime::currentDateTime(); - - if (ty == events::MessageEventType::Emote) { - body = QString("* %1 %2").arg(displayName).arg(body); - descriptionMsg_ = {"", userid, body, descriptiveTime(timestamp)}; - } else { - descriptionMsg_ = { - "You: ", userid, body, descriptiveTime(QDateTime::currentDateTime())}; - } - - body = body.toHtmlEscaped(); - body.replace(URL_REGEX, URL_HTML); - body.replace("\n", "<br/>"); - generateTimestamp(timestamp); - - if (withSender) { - generateBody(displayName, body); - setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(userid, this); - } else { - generateBody(body); - setupSimpleLayout(); - } - - mainLayout_->addWidget(body_); -} - -TimelineItem::TimelineItem(ImageItem *image, - const QString &userid, - bool withSender, - QWidget *parent) - : QWidget{parent} -{ - init(); - - setupLocalWidgetLayout<ImageItem>(image, userid, "sent an image", withSender); -} - -TimelineItem::TimelineItem(FileItem *file, const QString &userid, bool withSender, QWidget *parent) - : QWidget{parent} -{ - init(); - - setupLocalWidgetLayout<FileItem>(file, userid, "sent a file", withSender); -} - -/* - * Used to display images. The avatar and the username are displayed. - */ -TimelineItem::TimelineItem(ImageItem *image, - const events::MessageEvent<msgs::Image> &event, - bool with_sender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - event_id_ = event.eventId(); - - 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()))}; - - generateTimestamp(timestamp); - - auto imageLayout = new QHBoxLayout(); - imageLayout->setContentsMargins(0, 5, 0, 0); - imageLayout->addWidget(image); - imageLayout->addStretch(1); - - if (with_sender) { - generateBody(displayName, ""); - setupAvatarLayout(displayName); - - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(event.sender(), this); - } else { - setupSimpleLayout(); - } - - mainLayout_->addLayout(imageLayout); -} - -TimelineItem::TimelineItem(FileItem *file, - const events::MessageEvent<msgs::File> &event, - bool with_sender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - event_id_ = event.eventId(); - - 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 a file", - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; - - generateTimestamp(timestamp); - - auto fileLayout = new QHBoxLayout(); - fileLayout->setContentsMargins(0, 5, 0, 0); - fileLayout->addWidget(file); - fileLayout->addStretch(1); - - if (with_sender) { - generateBody(displayName, ""); - setupAvatarLayout(displayName); - - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(event.sender(), this); - } else { - setupSimpleLayout(); - } - - mainLayout_->addLayout(fileLayout); -} - -/* - * Used to display remote notice messages. - */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, - bool with_sender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - event_id_ = event.eventId(); - - 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()); - - generateTimestamp(timestamp); - - body.replace(URL_REGEX, URL_HTML); - body.replace("\n", "<br/>"); - body = "<i>" + body + "</i>"; - - if (with_sender) { - auto displayName = TimelineViewManager::displayName(event.sender()); - - generateBody(displayName, body); - setupAvatarLayout(displayName); - - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(event.sender(), this); - } else { - generateBody(body); - setupSimpleLayout(); - } - - mainLayout_->addWidget(body_); -} - -/* - * Used to display remote emote messages. - */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event, - bool with_sender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - event_id_ = event.eventId(); - - auto body = event.content().body().trimmed(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - auto displayName = TimelineViewManager::displayName(event.sender()); - auto emoteMsg = QString("* %1 %2").arg(displayName).arg(body); - - descriptionMsg_ = {"", - event.sender(), - emoteMsg, - descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))}; - - generateTimestamp(timestamp); - emoteMsg = emoteMsg.toHtmlEscaped(); - emoteMsg.replace(URL_REGEX, URL_HTML); - emoteMsg.replace("\n", "<br/>"); - - if (with_sender) { - generateBody(displayName, emoteMsg); - setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(event.sender(), this); - } else { - generateBody(emoteMsg); - setupSimpleLayout(); - } - - mainLayout_->addWidget(body_); -} - -/* - * Used to display remote text messages. - */ -TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, - bool with_sender, - QWidget *parent) - : QWidget(parent) -{ - init(); - - event_id_ = event.eventId(); - - auto body = event.content().body().trimmed(); - 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()))}; - - generateTimestamp(timestamp); - - body = body.toHtmlEscaped(); - body.replace(URL_REGEX, URL_HTML); - body.replace("\n", "<br/>"); - - if (with_sender) { - generateBody(displayName, body); - setupAvatarLayout(displayName); - - mainLayout_->addLayout(headerLayout_); - - AvatarProvider::resolve(event.sender(), this); - } else { - generateBody(body); - setupSimpleLayout(); - } - - mainLayout_->addWidget(body_); -} - -// Only the body is displayed. -void -TimelineItem::generateBody(const QString &body) -{ - QString content("<span> %1 </span>"); - - 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); -} - -// The username/timestamp is displayed along with the message body. -void -TimelineItem::generateBody(const QString &userid, const QString &body) -{ - auto sender = userid; - - if (userid.startsWith("@")) { - // TODO: Fix this by using a UserId type. - if (userid.split(":")[0].split("@").size() > 1) - sender = userid.split(":")[0].split("@")[1]; - } - - QFont usernameFont = font_; - usernameFont.setBold(true); - - userName_ = new QLabel(this); - userName_->setFont(usernameFont); - userName_->setText(sender); - - if (body.isEmpty()) - return; - - body_ = new QLabel(this); - body_->setFont(font_); - body_->setWordWrap(true); - body_->setText(QString("<span> %1 </span>").arg(replaceEmoji(body))); - body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); - body_->setOpenExternalLinks(true); - body_->setMargin(0); -} - -void -TimelineItem::generateTimestamp(const QDateTime &time) -{ - QFont timestampFont; - timestampFont.setPixelSize(conf::timeline::fonts::timestamp); - - QFontMetrics fm(timestampFont); - int topMargin = QFontMetrics(font_).ascent() - fm.ascent(); - - timestamp_ = new QLabel(this); - timestamp_->setFont(timestampFont); - timestamp_->setText(time.toString("HH:mm")); - timestamp_->setContentsMargins(0, topMargin, 0, 0); - timestamp_->setStyleSheet( - QString("font-size: %1px;").arg(conf::timeline::fonts::timestamp)); -} - -QString -TimelineItem::replaceEmoji(const QString &body) -{ - QString fmtBody = ""; - - QVector<uint> utf32_string = body.toUcs4(); - - for (auto &code : utf32_string) { - // TODO: Be more precise here. - if (code > 9000) - fmtBody += QString("<span style=\"font-family: Emoji " - "One; font-size: %1px\">") - .arg(conf::emojiSize) + - QString::fromUcs4(&code, 1) + "</span>"; - else - fmtBody += QString::fromUcs4(&code, 1); - } - - return fmtBody; -} - -void -TimelineItem::setupAvatarLayout(const QString &userName) -{ - topLayout_->setContentsMargins(conf::timeline::msgMargin, conf::timeline::msgMargin, 0, 0); - - userAvatar_ = new Avatar(this); - userAvatar_->setLetter(QChar(userName[0]).toUpper()); - 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()); - - sideLayout_->addWidget(userAvatar_); - sideLayout_->addStretch(1); - - headerLayout_->addWidget(userName_); - headerLayout_->addWidget(timestamp_, 1); -} - -void -TimelineItem::setupSimpleLayout() -{ - sideLayout_->addWidget(timestamp_); - - // Keep only the time in plain text. - QTextEdit htmlText(timestamp_->text()); - QString plainText = htmlText.toPlainText(); - - 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); - - 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); -} - -void -TimelineItem::setUserAvatar(const QImage &avatar) -{ - if (userAvatar_ == nullptr) - return; - - userAvatar_->setImage(avatar); -} - -QString -TimelineItem::descriptiveTime(const QDateTime &then) -{ - auto now = QDateTime::currentDateTime(); - - 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"); - - return then.toString("dd/MM/yy"); -} - -TimelineItem::~TimelineItem() {} - -void -TimelineItem::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -}