From ccc6cd8dabdaf8ca66562e889147965f12fb19e9 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Sun, 1 Jul 2018 19:40:53 +0300 Subject: [PATCH] Mark encrypted messages with a lock icon --- include/Config.h | 1 + include/timeline/TimelineItem.h | 69 ++++++++--- resources/icons/ui/checkmark.png | Bin 0 -> 450 bytes resources/icons/ui/checkmark@2x.png | Bin 0 -> 551 bytes resources/icons/ui/clock.png | Bin 0 -> 779 bytes resources/icons/ui/clock@2x.png | Bin 0 -> 1638 bytes resources/icons/ui/lock.png | Bin 0 -> 602 bytes resources/icons/ui/lock@2x.png | Bin 0 -> 810 bytes resources/res.qrc | 6 + resources/styles/nheko.qss | 2 +- src/main.cc | 32 +++++ src/timeline/TimelineItem.cc | 185 ++++++++++++++++------------ src/timeline/TimelineView.cc | 7 +- 13 files changed, 200 insertions(+), 102 deletions(-) create mode 100644 resources/icons/ui/checkmark.png create mode 100644 resources/icons/ui/checkmark@2x.png create mode 100644 resources/icons/ui/clock.png create mode 100644 resources/icons/ui/clock@2x.png create mode 100644 resources/icons/ui/lock.png create mode 100644 resources/icons/ui/lock@2x.png diff --git a/include/Config.h b/include/Config.h index f8fd27cd..abf5dc05 100644 --- a/include/Config.h +++ b/include/Config.h @@ -97,6 +97,7 @@ constexpr int headerLeftMargin = 15; namespace fonts { constexpr int timestamp = 13; +constexpr int indicator = timestamp - 2; constexpr int dateSeparator = conf::fontSize; } // namespace fonts } // namespace timeline diff --git a/include/timeline/TimelineItem.h b/include/timeline/TimelineItem.h index 180623f4..95d4be3d 100644 --- a/include/timeline/TimelineItem.h +++ b/include/timeline/TimelineItem.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,46 @@ class VideoItem; class FileItem; class Avatar; +enum class StatusIndicatorState +{ + //! The encrypted message was received by the server. + Encrypted, + //! The plaintext message was received by the server. + Received, + //! The client sent the message. Not yet received. + Sent, + //! When the message is loaded from cache or backfill. + Empty, +}; + +//! +//! Used to notify the user about the status of a message. +//! +class StatusIndicator : public QWidget +{ + Q_OBJECT + +public: + explicit StatusIndicator(QWidget *parent); + void setState(StatusIndicatorState state); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + void paintIcon(QPainter &p, QIcon &icon); + + QIcon lockIcon_; + QIcon clockIcon_; + QIcon checkmarkIcon_; + + QColor iconColor_ = QColor("#999"); + + StatusIndicatorState state_ = StatusIndicatorState::Empty; + + static constexpr int MaxWidth = 24; +}; + class TextLabel : public QTextBrowser { Q_OBJECT @@ -192,7 +233,8 @@ public: DescInfo descriptionMessage() const { return descriptionMsg_; } QString eventId() const { return event_id_; } void setEventId(const QString &event_id) { event_id_ = event_id; } - void markReceived(); + void markReceived(bool isEncrypted); + void markSent(); bool isReceived() { return isReceived_; }; void setRoomId(QString room_id) { room_id_ = room_id; } void sendReadReceipt() const; @@ -228,6 +270,9 @@ private: void setupAvatarLayout(const QString &userName); void setupSimpleLayout(); + void adjustMessageLayout(); + void adjustMessageLayoutForWidget(); + //! Whether or not the event associated with the widget //! has been acknowledged by the server. bool isReceived_ = false; @@ -247,7 +292,6 @@ private: QHBoxLayout *topLayout_ = nullptr; QHBoxLayout *messageLayout_ = nullptr; QVBoxLayout *mainLayout_ = nullptr; - QVBoxLayout *headerLayout_ = nullptr; QHBoxLayout *widgetLayout_ = nullptr; Avatar *userAvatar_; @@ -255,8 +299,9 @@ private: QFont font_; QFont usernameFont_; + StatusIndicator *statusIndicator_; + QLabel *timestamp_; - QLabel *checkmark_; QLabel *userName_; TextLabel *body_; }; @@ -285,20 +330,13 @@ TimelineItem::setupLocalWidgetLayout(Widget *widget, const QString &userid, bool generateBody(userid, displayName, ""); setupAvatarLayout(displayName); - headerLayout_->addLayout(widgetLayout_); - messageLayout_->addLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); }); } else { setupSimpleLayout(); - - messageLayout_->addLayout(widgetLayout_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayoutForWidget(); } template @@ -331,18 +369,11 @@ TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSen generateBody(sender, displayName, ""); setupAvatarLayout(displayName); - headerLayout_->addLayout(widgetLayout_); - messageLayout_->addLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); }); } else { setupSimpleLayout(); - - messageLayout_->addLayout(widgetLayout_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayoutForWidget(); } diff --git a/resources/icons/ui/checkmark.png b/resources/icons/ui/checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..281fda3c7aee20cf992c740b318d93a98840510f GIT binary patch literal 450 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKVoO(lM(;)FYXLbXo9DUV~EG`f zn1QsC`3nIzA2stQf^I&F?$)aWgC!+AulHpgF=0#pG>P|6$NneFtXc$9)Niq!+M?W} z5M^!Lc7l=3jjfJNysiAnO@78XQ!?a=7#QAvoF-G&UR48hn`((`L`h0wNvc(HQ7VvP zFfuT-&^0jEH82b@G_f+Wure~%HZZa>FnF=_$Z8Y~x%nxXX_dG&%=}R!4%8qCvLQG> qt)x7$D3zhSyj(9cFS|H7u^?41zbJk7I~ysWA_h-aKbLh*2~7Y6dyo$R literal 0 HcmV?d00001 diff --git a/resources/icons/ui/checkmark@2x.png b/resources/icons/ui/checkmark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3f85fa3916aa10d193d6002f8c4109880fbdf5ac GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5Sk6T)4~G!o#8OzHqRX zz3~3%EMi~~#OWWW@o=uV$BIvEY|)YbdS1$Z7WezNWRHmbhEK*%r~a?}x1y$XzV`dw ze%yBX=hts^^q*vIFp)E*CdR3cSyp~t!gKMDH4#m{`iCo`8}gYr<>xybJFYt6(?iZD zH4#qJn!fvc9Q&=BawGbOD)0R{6XvY5sDG6!wNro%NSrPI}81*c<-sv7YA=U;wC=xJHzuB$lLF zB^RXvDF!10LknF4b6o?&5JM9yBMU1db8Q17D+2?WR}XfeXvob^$xN%nts!@N1SoDL vK{f>ErERK(!v>gTe~DWM4f@ruHe literal 0 HcmV?d00001 diff --git a/resources/icons/ui/clock.png b/resources/icons/ui/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..3d97e35884031bde99ba765ed9decc50f92718b2 GIT binary patch literal 779 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 + icons/ui/lock.png + icons/ui/lock@2x.png + icons/ui/clock.png + icons/ui/clock@2x.png + icons/ui/checkmark.png + icons/ui/checkmark@2x.png icons/ui/cursor.png icons/ui/cursor@2x.png icons/ui/settings.png diff --git a/resources/styles/nheko.qss b/resources/styles/nheko.qss index 067b361c..1cba4c82 100644 --- a/resources/styles/nheko.qss +++ b/resources/styles/nheko.qss @@ -48,7 +48,7 @@ CommunitiesList > * { } FlatButton { - qproperty-foregroundColor: #14272d; + qproperty-foregroundColor: #495057; } FileItem { diff --git a/src/main.cc b/src/main.cc index 7ef5834e..bc264931 100644 --- a/src/main.cc +++ b/src/main.cc @@ -38,6 +38,36 @@ #include "RunGuard.h" #include "version.hpp" +#if defined(Q_OS_LINUX) +#include +#include + +void +stacktraceHandler(int signum) +{ + auto dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + + std::signal(signum, SIG_DFL); + boost::stacktrace::safe_dump_to(dir.toStdString() + "/backtrace.dump"); + std::raise(SIGABRT); +} + +void +registerSignalHandlers() +{ + std::signal(SIGSEGV, &stacktraceHandler); + std::signal(SIGABRT, &stacktraceHandler); +} + +#else + +// No implementation for systems with no stacktrace support. +void +registerSignalHandlers() +{} + +#endif + QPoint screenCenter(int width, int height) { @@ -126,6 +156,8 @@ main(int argc, char *argv[]) createCacheDirectory(); + registerSignalHandlers(); + try { nhlog::init(QString("%1/nheko.log") .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) diff --git a/src/timeline/TimelineItem.cc b/src/timeline/TimelineItem.cc index bbe3ff34..7fc54962 100644 --- a/src/timeline/TimelineItem.cc +++ b/src/timeline/TimelineItem.cc @@ -24,6 +24,7 @@ #include "ChatPage.h" #include "Config.h" #include "Logging.hpp" +#include "Painter.h" #include "timeline/TimelineItem.h" #include "timeline/widgets/AudioItem.h" @@ -31,11 +32,90 @@ #include "timeline/widgets/ImageItem.h" #include "timeline/widgets/VideoItem.h" -constexpr const static char *CHECKMARK = "✓"; - constexpr int MSG_RIGHT_MARGIN = 7; constexpr int MSG_PADDING = 20; +StatusIndicator::StatusIndicator(QWidget *parent) + : QWidget(parent) +{ + lockIcon_.addFile(":/icons/icons/ui/lock.png"); + clockIcon_.addFile(":/icons/icons/ui/clock.png"); + checkmarkIcon_.addFile(":/icons/icons/ui/checkmark.png"); +} + +void +StatusIndicator::paintIcon(QPainter &p, QIcon &icon) +{ + auto pixmap = icon.pixmap(width()); + + QPainter painter(&pixmap); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(pixmap.rect(), p.pen().color()); + + QIcon(pixmap).paint(&p, rect(), Qt::AlignCenter, QIcon::Normal); +} + +void +StatusIndicator::paintEvent(QPaintEvent *) +{ + if (state_ == StatusIndicatorState::Empty) + return; + + Painter p(this); + PainterHighQualityEnabler hq(p); + + p.setPen(iconColor_); + + switch (state_) { + case StatusIndicatorState::Sent: { + paintIcon(p, clockIcon_); + break; + } + case StatusIndicatorState::Encrypted: + paintIcon(p, lockIcon_); + break; + case StatusIndicatorState::Received: { + paintIcon(p, checkmarkIcon_); + break; + } + case StatusIndicatorState::Empty: + break; + } +} + +void +StatusIndicator::setState(StatusIndicatorState state) +{ + state_ = state; + update(); +} + +void +TimelineItem::adjustMessageLayoutForWidget() +{ + messageLayout_->addLayout(widgetLayout_, 1); + messageLayout_->addWidget(statusIndicator_); + messageLayout_->addWidget(timestamp_); + + messageLayout_->setAlignment(statusIndicator_, Qt::AlignTop); + messageLayout_->setAlignment(timestamp_, Qt::AlignTop); + + mainLayout_->addLayout(messageLayout_); +} + +void +TimelineItem::adjustMessageLayout() +{ + messageLayout_->addWidget(body_, 1); + messageLayout_->addWidget(statusIndicator_); + messageLayout_->addWidget(timestamp_); + + messageLayout_->setAlignment(statusIndicator_, Qt::AlignTop); + messageLayout_->setAlignment(timestamp_, Qt::AlignTop); + + mainLayout_->addLayout(messageLayout_); +} + void TimelineItem::init() { @@ -102,14 +182,13 @@ TimelineItem::init() mainLayout_->setContentsMargins(conf::timeline::headerLeftMargin, 0, 0, 0); mainLayout_->setSpacing(0); - QFont checkmarkFont; - checkmarkFont.setPixelSize(conf::timeline::fonts::timestamp); + QFont timestampFont; + timestampFont.setPixelSize(conf::timeline::fonts::indicator); + QFontMetrics tsFm(timestampFont); - // Setting fixed width for checkmark because systems may have a differing width for a - // space and the Unicode checkmark. - checkmark_ = new QLabel(this); - checkmark_->setFont(checkmarkFont); - checkmark_->setFixedWidth(QFontMetrics{checkmarkFont}.width(CHECKMARK)); + statusIndicator_ = new StatusIndicator(this); + statusIndicator_->setFixedWidth(tsFm.height() - tsFm.leading()); + statusIndicator_->setFixedHeight(tsFm.height() - tsFm.leading()); } /* @@ -147,20 +226,14 @@ TimelineItem::TimelineItem(mtx::events::MessageType ty, generateBody(userid, displayName, body); setupAvatarLayout(displayName); - messageLayout_->addLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); }); } else { generateBody(body); setupSimpleLayout(); - - messageLayout_->addWidget(body_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayout(); } TimelineItem::TimelineItem(ImageItem *image, @@ -316,20 +389,14 @@ TimelineItem::TimelineItem(const mtx::events::RoomEventaddLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); }); } else { generateBody(body); setupSimpleLayout(); - - messageLayout_->addWidget(body_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayout(); } /* @@ -364,20 +431,14 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent generateBody(sender, displayName, emoteMsg); setupAvatarLayout(displayName); - messageLayout_->addLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); }); } else { generateBody(emoteMsg); setupSimpleLayout(); - - messageLayout_->addWidget(body_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayout(); } /* @@ -417,28 +478,31 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent generateBody(sender, displayName, body); setupAvatarLayout(displayName); - messageLayout_->addLayout(headerLayout_, 1); - AvatarProvider::resolve( room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); }); } else { generateBody(body); setupSimpleLayout(); - - messageLayout_->addWidget(body_, 1); } - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - mainLayout_->addLayout(messageLayout_); + adjustMessageLayout(); } void -TimelineItem::markReceived() +TimelineItem::markSent() +{ + statusIndicator_->setState(StatusIndicatorState::Sent); +} + +void +TimelineItem::markReceived(bool isEncrypted) { isReceived_ = true; - checkmark_->setText(CHECKMARK); - checkmark_->setAlignment(Qt::AlignTop); + + if (isEncrypted) + statusIndicator_->setState(StatusIndicatorState::Encrypted); + else + statusIndicator_->setState(StatusIndicatorState::Received); sendReadReceipt(); } @@ -506,17 +570,10 @@ 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_->setAlignment(Qt::AlignTop); timestamp_->setFont(timestampFont); timestamp_->setText( QString(" %1 ").arg(time.toString("HH:mm"))); - timestamp_->setContentsMargins(0, topMargin, 0, 0); - timestamp_->setStyleSheet( - QString("font-size: %1px;").arg(conf::timeline::fonts::timestamp)); } QString @@ -557,15 +614,8 @@ TimelineItem::setupAvatarLayout(const QString &userName) topLayout_->insertWidget(0, userAvatar_); topLayout_->setAlignment(userAvatar_, Qt::AlignTop); - headerLayout_ = new QVBoxLayout; - headerLayout_->setMargin(0); - headerLayout_->setSpacing(conf::timeline::headerSpacing); - if (userName_) - headerLayout_->addWidget(userName_); - - if (body_) - headerLayout_->addWidget(body_); + mainLayout_->insertWidget(0, userName_); } void @@ -647,33 +697,8 @@ TimelineItem::addAvatar() userName_->setFont(usernameFont_); userName_->setText(fm.elidedText(displayName, Qt::ElideRight, 500)); - QWidget *widget = nullptr; - - // Extract the widget before we delete its layout. - if (widgetLayout_) - widget = widgetLayout_->itemAt(0)->widget(); - - // Remove all items from the layout. - QLayoutItem *item; - while ((item = messageLayout_->takeAt(0)) != 0) - delete item; - setupAvatarLayout(displayName); - // Restore widget's layout. - if (widget) { - widgetLayout_ = new QHBoxLayout(); - widgetLayout_->setContentsMargins(0, 2, 0, 2); - widgetLayout_->addWidget(widget); - widgetLayout_->addStretch(1); - - headerLayout_->addLayout(widgetLayout_); - } - - messageLayout_->addLayout(headerLayout_, 1); - messageLayout_->addWidget(checkmark_); - messageLayout_->addWidget(timestamp_); - AvatarProvider::resolve( room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); }); } diff --git a/src/timeline/TimelineView.cc b/src/timeline/TimelineView.cc index 47e92a3b..58387161 100644 --- a/src/timeline/TimelineView.cc +++ b/src/timeline/TimelineView.cc @@ -625,7 +625,7 @@ TimelineView::updatePendingMessage(const std::string &txn_id, const QString &eve // If the response comes after we have received the event from sync // we've already marked the widget as received. if (!msg.widget->isReceived()) { - msg.widget->markReceived(); + msg.widget->markReceived(msg.is_encrypted); pending_sent_msgs_.append(msg); } } else { @@ -690,6 +690,9 @@ TimelineView::sendNextPendingMessage() nhlog::ui()->info("[{}] sending next queued message", m.txn_id); + if (m.widget) + m.widget->markSent(); + if (m.is_encrypted) { nhlog::ui()->info("[{}] sending encrypted event", m.txn_id); prepareEncryptedMessage(std::move(m)); @@ -835,7 +838,7 @@ TimelineView::removePendingMessage(const std::string &txn_id) for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); ++it) { if (it->txn_id == txn_id) { if (it->widget) - it->widget->markReceived(); + it->widget->markReceived(it->is_encrypted); nhlog::ui()->info("[{}] received sync before message response", txn_id); return;