Add a timeline message when encryption is enabled

pull/1/head
Konstantinos Sideris 6 years ago
parent 67458dd2f8
commit 9a0e18dea7
  1. 2
      CMakeLists.txt
  2. 43
      include/timeline/TimelineView.h
  3. 47
      include/ui/InfoMessage.hpp
  4. 2
      resources/styles/nheko-dark.qss
  5. 2
      resources/styles/nheko.qss
  6. 2
      resources/styles/system.qss
  7. 111
      src/timeline/TimelineView.cc
  8. 79
      src/ui/InfoMessage.cpp

@ -170,6 +170,7 @@ set(SRC_FILES
src/ui/Avatar.cc
src/ui/Badge.cc
src/ui/LoadingIndicator.cc
src/ui/InfoMessage.cpp
src/ui/FlatButton.cc
src/ui/FloatingButton.cc
src/ui/Label.cc
@ -283,6 +284,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/ui/Avatar.h
include/ui/Badge.h
include/ui/LoadingIndicator.h
include/ui/InfoMessage.hpp
include/ui/FlatButton.h
include/ui/Label.h
include/ui/FloatingButton.h

@ -107,40 +107,6 @@ enum class TimelineDirection
Bottom,
};
class DateSeparator : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor boxColor WRITE setBoxColor READ boxColor)
public:
DateSeparator(QDateTime datetime, QWidget *parent = nullptr);
void setTextColor(QColor color) { textColor_ = color; }
void setBoxColor(QColor color) { boxColor_ = color; }
QColor textColor() const { return textColor_; }
QColor boxColor() const { return boxColor_; }
protected:
void paintEvent(QPaintEvent *event) override;
private:
static constexpr int VPadding = 6;
static constexpr int HPadding = 12;
static constexpr int HMargin = 20;
int width_;
int height_;
QString msg_;
QFont font_;
QColor textColor_ = QColor("black");
QColor boxColor_ = QColor("white");
};
class TimelineView : public QWidget
{
Q_OBJECT
@ -162,7 +128,6 @@ public:
uint64_t size);
void updatePendingMessage(const std::string &txn_id, const QString &event_id);
void scrollDown();
QLabel *createDateSeparator(QDateTime datetime);
//! Remove an item from the timeline with the given Event ID.
void removeEvent(const QString &event_id);
@ -220,7 +185,7 @@ private:
void getMessages();
//! HACK: Fixing layout flickering when adding to the bottom
//! of the timeline.
void pushTimelineItem(TimelineItem *item)
void pushTimelineItem(QWidget *item)
{
item->hide();
scroll_layout_->addWidget(item);
@ -230,7 +195,7 @@ private:
//! Decides whether or not to show or hide the scroll down button.
void toggleScrollDownButton();
void init();
void addTimelineItem(TimelineItem *item,
void addTimelineItem(QWidget *item,
TimelineDirection direction = TimelineDirection::Bottom);
void updateLastSender(const QString &user_id, TimelineDirection direction);
void notifyForLastEvent();
@ -295,8 +260,8 @@ private:
const QDateTime &second = QDateTime::currentDateTime()) const;
// Return nullptr if the event couldn't be parsed.
TimelineItem *parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
TimelineDirection direction);
QWidget *parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
TimelineDirection direction);
QVBoxLayout *top_layout_;
QVBoxLayout *scroll_layout_;

@ -0,0 +1,47 @@
#pragma once
#include <QColor>
#include <QDateTime>
#include <QWidget>
class InfoMessage : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor boxColor WRITE setBoxColor READ boxColor)
public:
explicit InfoMessage(QWidget *parent = nullptr);
InfoMessage(QString msg, QWidget *parent = nullptr);
void setTextColor(QColor color) { textColor_ = color; }
void setBoxColor(QColor color) { boxColor_ = color; }
void saveDatetime(QDateTime datetime) { datetime_ = datetime; }
QColor textColor() const { return textColor_; }
QColor boxColor() const { return boxColor_; }
QDateTime datetime() const { return datetime_; }
protected:
void paintEvent(QPaintEvent *event) override;
int width_;
int height_;
QString msg_;
QFont font_;
QDateTime datetime_;
QColor textColor_ = QColor("black");
QColor boxColor_ = QColor("white");
};
class DateSeparator : public InfoMessage
{
Q_OBJECT
public:
DateSeparator(QDateTime datetime, QWidget *parent = nullptr);
};

@ -23,7 +23,7 @@ QuickSwitcher {
background-color: #202228;
}
DateSeparator {
InfoMessage {
qproperty-textColor: #caccd1;
qproperty-boxColor: rgba(45, 49, 57, 120);
}

@ -23,7 +23,7 @@ QuickSwitcher {
background-color: white;
}
DateSeparator {
InfoMessage {
qproperty-textColor: #333;
qproperty-boxColor: rgba(220, 220, 220, 120);
}

@ -25,7 +25,7 @@ QuickSwitcher {
background-color: palette(window);
}
DateSeparator {
InfoMessage {
qproperty-textColor: palette(text);
qproperty-boxColor: palette(window);
}

@ -23,6 +23,7 @@
#include "ChatPage.h"
#include "Config.h"
#include "FloatingButton.h"
#include "InfoMessage.hpp"
#include "Logging.hpp"
#include "Olm.hpp"
#include "UserSettingsPage.h"
@ -36,55 +37,19 @@
using TimelineEvent = mtx::events::collections::TimelineEvents;
DateSeparator::DateSeparator(QDateTime datetime, QWidget *parent)
: QWidget{parent}
//! Retrieve the timestamp of the event represented by the given widget.
QDateTime
getDate(QWidget *widget)
{
auto now = QDateTime::currentDateTime();
auto days = now.daysTo(datetime);
auto item = qobject_cast<TimelineItem *>(widget);
if (item)
return item->descriptionMessage().datetime;
font_.setWeight(60);
font_.setPixelSize(conf::timeline::fonts::dateSeparator);
auto infoMsg = qobject_cast<InfoMessage *>(widget);
if (infoMsg)
return infoMsg->datetime();
QString fmt;
if (now.date().year() != datetime.date().year())
fmt = QString("ddd d MMMM yy");
else
fmt = QString("ddd d MMMM");
if (days == 0)
msg_ = tr("Today");
else if (std::abs(days) == 1)
msg_ = tr("Yesterday");
else
msg_ = datetime.toString(fmt);
QFontMetrics fm{font_};
width_ = fm.width(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
setFixedHeight(height_ + 2 * HMargin);
}
void
DateSeparator::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setFont(font_);
// Center the box horizontally & vertically.
auto textRegion = QRectF(width() / 2 - width_ / 2, HMargin, width_, height_);
QPainterPath ppath;
ppath.addRoundedRect(textRegion, height_ / 2, height_ / 2);
p.setPen(Qt::NoPen);
p.fillPath(ppath, boxColor());
p.drawPath(ppath);
p.setPen(QPen(textColor()));
p.drawText(textRegion, Qt::AlignCenter, msg_);
return QDateTime();
}
TimelineView::TimelineView(const mtx::responses::Timeline &timeline,
@ -231,7 +196,7 @@ TimelineView::addBackwardsEvents(const mtx::responses::Messages &msgs)
isPaginationInProgress_ = false;
}
TimelineItem *
QWidget *
TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
TimelineDirection direction)
{
@ -255,6 +220,12 @@ TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &
});
return nullptr;
} else if (mpark::holds_alternative<StateEvent<state::Encryption>>(event)) {
auto msg = mpark::get<StateEvent<state::Encryption>>(event);
auto item = new InfoMessage(tr("Encryption is enabled"), this);
item->saveDatetime(QDateTime::fromMSecsSinceEpoch(msg.origin_server_ts));
return item;
} else if (mpark::holds_alternative<RoomEvent<msg::Audio>>(event)) {
auto audio = mpark::get<RoomEvent<msg::Audio>>(event);
return processMessageEvent<AudioEvent, AudioItem>(audio, direction);
@ -280,13 +251,18 @@ TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &
return processMessageEvent<Sticker, StickerItem>(mpark::get<Sticker>(event),
direction);
} else if (mpark::holds_alternative<EncryptedEvent<msg::Encrypted>>(event)) {
auto res = parseEncryptedEvent(mpark::get<EncryptedEvent<msg::Encrypted>>(event));
auto item = parseMessageEvent(res.event, direction);
auto res = parseEncryptedEvent(mpark::get<EncryptedEvent<msg::Encrypted>>(event));
auto widget = parseMessageEvent(res.event, direction);
if (item != nullptr && res.isDecrypted)
if (widget == nullptr)
return nullptr;
auto item = qobject_cast<TimelineItem *>(widget);
if (item && res.isDecrypted)
item->markReceived(true);
return item;
return widget;
}
return nullptr;
@ -374,7 +350,7 @@ TimelineView::renderBottomEvents(const std::vector<TimelineEvent> &events)
int counter = 0;
for (const auto &event : events) {
TimelineItem *item = parseMessageEvent(event, TimelineDirection::Bottom);
QWidget *item = parseMessageEvent(event, TimelineDirection::Bottom);
if (item != nullptr) {
addTimelineItem(item, TimelineDirection::Bottom);
@ -395,7 +371,7 @@ TimelineView::renderBottomEvents(const std::vector<TimelineEvent> &events)
void
TimelineView::renderTopEvents(const std::vector<TimelineEvent> &events)
{
std::vector<TimelineItem *> items;
std::vector<QWidget *> items;
// Reset the sender of the first message in the timeline
// cause we're about to insert a new one.
@ -408,7 +384,7 @@ TimelineView::renderTopEvents(const std::vector<TimelineEvent> &events)
while (ii != 0) {
--ii;
TimelineItem *item = parseMessageEvent(events[ii], TimelineDirection::Top);
auto item = parseMessageEvent(events[ii], TimelineDirection::Top);
if (item != nullptr)
items.push_back(item);
@ -429,9 +405,16 @@ TimelineView::renderTopEvents(const std::vector<TimelineEvent> &events)
// If this batch is the first being rendered (i.e the first and the last
// events originate from this batch), set the last sender.
if (lastSender_.isEmpty() && !items.empty())
saveLastMessageInfo(items.at(0)->descriptionMessage().userid,
items.at(0)->descriptionMessage().datetime);
if (lastSender_.isEmpty() && !items.empty()) {
for (const auto &w : items) {
auto timelineItem = qobject_cast<TimelineItem *>(w);
if (timelineItem) {
saveLastMessageInfo(timelineItem->descriptionMessage().userid,
timelineItem->descriptionMessage().datetime);
break;
}
}
}
}
void
@ -569,17 +552,16 @@ TimelineView::isSenderRendered(const QString &user_id,
}
void
TimelineView::addTimelineItem(TimelineItem *item, TimelineDirection direction)
TimelineView::addTimelineItem(QWidget *item, TimelineDirection direction)
{
const auto newDate = item->descriptionMessage().datetime;
const auto newDate = getDate(item);
if (direction == TimelineDirection::Bottom) {
const auto lastItemPosition = scroll_layout_->count() - 1;
auto lastItem =
qobject_cast<TimelineItem *>(scroll_layout_->itemAt(lastItemPosition)->widget());
const auto lastItem = scroll_layout_->itemAt(lastItemPosition)->widget();
if (lastItem) {
auto oldDate = lastItem->descriptionMessage().datetime;
const auto oldDate = getDate(lastItem);
if (oldDate.daysTo(newDate) != 0) {
auto separator = new DateSeparator(newDate, this);
@ -594,11 +576,10 @@ TimelineView::addTimelineItem(TimelineItem *item, TimelineDirection direction)
// The first item (position 0) is a stretch widget that pushes
// the widgets to the bottom of the page.
if (scroll_layout_->count() > 1) {
auto firstItem =
qobject_cast<TimelineItem *>(scroll_layout_->itemAt(1)->widget());
const auto firstItem = scroll_layout_->itemAt(1)->widget();
if (firstItem) {
auto oldDate = firstItem->descriptionMessage().datetime;
const auto oldDate = getDate(firstItem);
if (newDate.daysTo(oldDate) != 0) {
auto separator = new DateSeparator(oldDate);

@ -0,0 +1,79 @@
#include "Config.h"
#include "InfoMessage.hpp"
#include <QDateTime>
#include <QPainter>
#include <QPen>
constexpr int VPadding = 6;
constexpr int HPadding = 12;
constexpr int HMargin = 20;
InfoMessage::InfoMessage(QWidget *parent)
: QWidget{parent}
{
font_.setWeight(60);
font_.setPixelSize(conf::timeline::fonts::dateSeparator);
}
InfoMessage::InfoMessage(QString msg, QWidget *parent)
: QWidget{parent}
, msg_{msg}
{
font_.setWeight(60);
font_.setPixelSize(conf::timeline::fonts::dateSeparator);
QFontMetrics fm{font_};
width_ = fm.width(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
setFixedHeight(height_ + 2 * HMargin);
}
void
InfoMessage::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setFont(font_);
// Center the box horizontally & vertically.
auto textRegion = QRectF(width() / 2 - width_ / 2, HMargin, width_, height_);
QPainterPath ppath;
ppath.addRoundedRect(textRegion, height_ / 2, height_ / 2);
p.setPen(Qt::NoPen);
p.fillPath(ppath, boxColor());
p.drawPath(ppath);
p.setPen(QPen(textColor()));
p.drawText(textRegion, Qt::AlignCenter, msg_);
}
DateSeparator::DateSeparator(QDateTime datetime, QWidget *parent)
: InfoMessage{parent}
{
auto now = QDateTime::currentDateTime();
auto days = now.daysTo(datetime);
QString fmt;
if (now.date().year() != datetime.date().year())
fmt = QString("ddd d MMMM yy");
else
fmt = QString("ddd d MMMM");
if (days == 0)
msg_ = tr("Today");
else if (std::abs(days) == 1)
msg_ = tr("Yesterday");
else
msg_ = datetime.toString(fmt);
QFontMetrics fm{font_};
width_ = fm.width(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
setFixedHeight(height_ + 2 * HMargin);
}
Loading…
Cancel
Save