From 4b4035eebcc19ea7895a60968bc8925d25045165 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Tue, 25 Apr 2017 14:37:54 +0300 Subject: Rename History to Timeline In order to be compatible with the Matrix terminology --- src/ChatPage.cc | 2 +- src/HistoryView.cc | 190 ------------------------------------------ src/HistoryViewItem.cc | 159 ----------------------------------- src/HistoryViewManager.cc | 201 --------------------------------------------- src/TimelineItem.cc | 159 +++++++++++++++++++++++++++++++++++ src/TimelineView.cc | 190 ++++++++++++++++++++++++++++++++++++++++++ src/TimelineViewManager.cc | 201 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 551 insertions(+), 551 deletions(-) delete mode 100644 src/HistoryView.cc delete mode 100644 src/HistoryViewItem.cc delete mode 100644 src/HistoryViewManager.cc create mode 100644 src/TimelineItem.cc create mode 100644 src/TimelineView.cc create mode 100644 src/TimelineViewManager.cc (limited to 'src') diff --git a/src/ChatPage.cc b/src/ChatPage.cc index 3bae177b..0ddf0f8b 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc @@ -39,7 +39,7 @@ ChatPage::ChatPage(QSharedPointer client, QWidget *parent) top_bar_ = new TopRoomBar(this); ui->topBarLayout->addWidget(top_bar_); - view_manager_ = new HistoryViewManager(client, this); + view_manager_ = new TimelineViewManager(client, this); ui->mainContentLayout->addWidget(view_manager_); text_input_ = new TextInputWidget(this); diff --git a/src/HistoryView.cc b/src/HistoryView.cc deleted file mode 100644 index 2d54caca..00000000 --- a/src/HistoryView.cc +++ /dev/null @@ -1,190 +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 . - */ - -#include -#include -#include -#include -#include - -#include "HistoryView.h" -#include "HistoryViewItem.h" -#include "HistoryViewManager.h" - -HistoryView::HistoryView(const QList &events, QWidget *parent) - : QWidget(parent) -{ - init(); - addEvents(events); -} - -HistoryView::HistoryView(QWidget *parent) - : QWidget(parent) -{ - init(); -} - -void HistoryView::clear() -{ - for (const auto msg : scroll_layout_->children()) - msg->deleteLater(); -} - -void HistoryView::sliderRangeChanged(int min, int max) -{ - Q_UNUSED(min); - scroll_area_->verticalScrollBar()->setValue(max); -} - -int HistoryView::addEvents(const QList &events) -{ - QSettings settings; - auto local_user = settings.value("auth/user_id").toString(); - - int message_count = 0; - - for (const auto &event : events) { - if (event.type() == "m.room.message") { - auto msg_type = event.content().value("msgtype").toString(); - - if (isPendingMessage(event, local_user)) { - removePendingMessage(event); - continue; - } - - if (msg_type == "m.text" || msg_type == "m.notice") { - auto with_sender = last_sender_ != event.sender(); - auto color = HistoryViewManager::getUserColor(event.sender()); - - addHistoryItem(event, color, with_sender); - last_sender_ = event.sender(); - - message_count += 1; - } - } - } - - return message_count; -} - -void HistoryView::init() -{ - top_layout_ = new QVBoxLayout(this); - top_layout_->setSpacing(0); - top_layout_->setMargin(0); - - scroll_area_ = new QScrollArea(this); - scroll_area_->setWidgetResizable(true); - scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - scroll_widget_ = new QWidget(); - - scroll_layout_ = new QVBoxLayout(); - scroll_layout_->addStretch(1); - scroll_layout_->setSpacing(0); - - scroll_widget_->setLayout(scroll_layout_); - - scroll_area_->setWidget(scroll_widget_); - - top_layout_->addWidget(scroll_area_); - - setLayout(top_layout_); - - connect(scroll_area_->verticalScrollBar(), - SIGNAL(rangeChanged(int, int)), - this, - SLOT(sliderRangeChanged(int, int))); -} - -void HistoryView::addHistoryItem(const Event &event, const QString &color, bool with_sender) -{ - HistoryViewItem *item = new HistoryViewItem(event, with_sender, color, scroll_widget_); - scroll_layout_->addWidget(item); -} - -void HistoryView::updatePendingMessage(int txn_id, QString event_id) -{ - for (auto &msg : pending_msgs_) { - if (msg.txn_id == txn_id) { - msg.event_id = event_id; - break; - } - } -} - -bool HistoryView::isPendingMessage(const Event &event, const QString &userid) -{ - if (event.sender() != userid || event.type() != "m.room.message") - return false; - - auto msgtype = event.content().value("msgtype").toString(); - auto body = event.content().value("body").toString(); - - // FIXME: should contain more checks later on for other types of messages. - if (msgtype != "m.text") - return false; - - for (const auto &msg : pending_msgs_) { - if (msg.event_id == event.eventId() || msg.body == body) - return true; - } - - return false; -} - -void HistoryView::removePendingMessage(const Event &event) -{ - auto body = event.content().value("body").toString(); - - for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) { - int index = std::distance(pending_msgs_.begin(), it); - - if (it->event_id == event.eventId() || it->body == body) { - pending_msgs_.removeAt(index); - break; - } - } -} - -void HistoryView::addUserTextMessage(const QString &body, int txn_id) -{ - QSettings settings; - auto user_id = settings.value("auth/user_id").toString(); - - auto with_sender = last_sender_ != user_id; - auto color = HistoryViewManager::getUserColor(user_id); - - HistoryViewItem *view_item; - - if (with_sender) - view_item = new HistoryViewItem(user_id, color, body, scroll_widget_); - else - view_item = new HistoryViewItem(body, scroll_widget_); - - scroll_layout_->addWidget(view_item); - - last_sender_ = user_id; - - PendingMessage message(txn_id, body, "", view_item); - - pending_msgs_.push_back(message); -} - -HistoryView::~HistoryView() -{ -} diff --git a/src/HistoryViewItem.cc b/src/HistoryViewItem.cc deleted file mode 100644 index cde07eb9..00000000 --- a/src/HistoryViewItem.cc +++ /dev/null @@ -1,159 +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 . - */ - -#include -#include - -#include "HistoryViewItem.h" - -HistoryViewItem::HistoryViewItem(const QString &userid, const QString &color, const QString &body, QWidget *parent) - : QWidget(parent) -{ - generateTimestamp(QDateTime::currentDateTime()); - generateBody(userid, color, body); - setupLayout(); -} - -HistoryViewItem::HistoryViewItem(const QString &body, QWidget *parent) - : QWidget(parent) -{ - generateTimestamp(QDateTime::currentDateTime()); - generateBody(body); - setupLayout(); -} - -HistoryViewItem::HistoryViewItem(const Event &event, bool with_sender, const QString &color, QWidget *parent) - : QWidget(parent) -{ - auto body = event.content().value("body").toString().trimmed().toHtmlEscaped(); - auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); - - generateTimestamp(timestamp); - - if (event.content().value("msgtype").toString() == "m.notice") - body = "" + body + ""; - - if (with_sender) - generateBody(event.sender(), color, body); - else - generateBody(body); - - setupLayout(); -} - -void HistoryViewItem::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( - "" - "" - "" - " " - " %1" - " " - "" - ""); - content_label_->setText(content.arg(replaceEmoji(body))); - content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); -} - -void HistoryViewItem::generateBody(const QString &userid, const QString &color, const QString &body) -{ - auto 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( - "" - "" - "" - " " - " %2" - " " - " " - " %3" - " " - "" - ""); - content_label_->setText(content.arg(color).arg(sender).arg(replaceEmoji(body))); - content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); -} - -void HistoryViewItem::generateTimestamp(const QDateTime &time) -{ - auto local_time = time.toString("HH:mm"); - - time_label_ = new QLabel(this); - QString msg( - "" - "" - "" - " " - " %1" - " " - "" - ""); - time_label_->setText(msg.arg(local_time)); - time_label_->setStyleSheet("margin-left: 7px; margin-right: 7px; margin-top: 0;"); - time_label_->setAlignment(Qt::AlignTop); -} - -void HistoryViewItem::setupLayout() -{ - if (time_label_ == nullptr) { - qWarning() << "HistoryViewItem: Time label is not initialized"; - return; - } - - if (content_label_ == nullptr) { - qWarning() << "HistoryViewItem: Content label is not initialized"; - return; - } - - top_layout_ = new QHBoxLayout(); - top_layout_->setMargin(0); - top_layout_->addWidget(time_label_); - top_layout_->addWidget(content_label_, 1); - - setLayout(top_layout_); -} - -QString HistoryViewItem::replaceEmoji(const QString &body) -{ - QString fmtBody = ""; - - for (auto &c : body) { - int code = c.unicode(); - - // TODO: Be more precise here. - if (code > 9000) - fmtBody += "" + QString(c) + ""; - else - fmtBody += c; - } - - return fmtBody; -} - -HistoryViewItem::~HistoryViewItem() -{ -} diff --git a/src/HistoryViewManager.cc b/src/HistoryViewManager.cc deleted file mode 100644 index 5967ac12..00000000 --- a/src/HistoryViewManager.cc +++ /dev/null @@ -1,201 +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 . - */ - -#include - -#include -#include -#include -#include -#include - -#include "HistoryView.h" -#include "HistoryViewManager.h" - -HistoryViewManager::HistoryViewManager(QSharedPointer client, QWidget *parent) - : QStackedWidget(parent) - , client_(client) -{ - setStyleSheet("QWidget { background: #f8fbfe; color: #e8e8e8; border: none;}"); - - connect(client_.data(), - SIGNAL(messageSent(const QString &, const QString &, int)), - this, - SLOT(messageSent(const QString &, const QString &, int))); -} - -HistoryViewManager::~HistoryViewManager() -{ -} - -void HistoryViewManager::messageSent(const QString &event_id, const QString &roomid, int txn_id) -{ - // We save the latest valid transaction ID for later use. - QSettings settings; - settings.setValue("client/transaction_id", txn_id + 1); - - auto view = views_[roomid]; - view->updatePendingMessage(txn_id, event_id); -} - -void HistoryViewManager::sendTextMessage(const QString &msg) -{ - auto room = active_room_; - auto view = views_[room.id()]; - - view->addUserTextMessage(msg, client_->transactionId()); - client_->sendTextMessage(room.id(), msg); -} - -void HistoryViewManager::clearAll() -{ - NICK_COLORS.clear(); - - for (const auto &view : views_) { - view->clear(); - removeWidget(view); - view->deleteLater(); - } - - views_.clear(); -} - -void HistoryViewManager::initialize(const Rooms &rooms) -{ - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { - auto roomid = it.key(); - auto events = it.value().timeline().events(); - - // Create a history view with the room events. - HistoryView *view = new HistoryView(events); - views_.insert(it.key(), view); - - // Add the view in the widget stack. - addWidget(view); - } -} - -void HistoryViewManager::sync(const Rooms &rooms) -{ - for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { - auto roomid = it.key(); - - if (!views_.contains(roomid)) { - qDebug() << "Ignoring event from unknown room"; - continue; - } - - auto view = views_.value(roomid); - auto events = it.value().timeline().events(); - - int msgs_added = view->addEvents(events); - - if (msgs_added > 0) { - // TODO: When window gets active the current - // unread count (if any) should be cleared. - auto isAppActive = QApplication::activeWindow() != nullptr; - - if (roomid != active_room_.id() || !isAppActive) - emit unreadMessages(roomid, msgs_added); - } - } -} - -void HistoryViewManager::setHistoryView(const RoomInfo &info) -{ - if (!views_.contains(info.id())) { - qDebug() << "Room List id is not present in view manager"; - qDebug() << info.name(); - return; - } - - active_room_ = info; - auto widget = views_.value(info.id()); - - setCurrentWidget(widget); -} - -QMap HistoryViewManager::NICK_COLORS; - -QString HistoryViewManager::chooseRandomColor() -{ - std::random_device random_device; - std::mt19937 engine{random_device()}; - std::uniform_real_distribution dist(0, 1); - - float hue = dist(engine); - float saturation = 0.9; - float value = 0.7; - - int hue_i = hue * 6; - - float f = hue * 6 - hue_i; - - float p = value * (1 - saturation); - float q = value * (1 - f * saturation); - float t = value * (1 - (1 - f) * saturation); - - float r = 0; - float g = 0; - float b = 0; - - if (hue_i == 0) { - r = value; - g = t; - b = p; - } else if (hue_i == 1) { - r = q; - g = value; - b = p; - } else if (hue_i == 2) { - r = p; - g = value; - b = t; - } else if (hue_i == 3) { - r = p; - g = q; - b = value; - } else if (hue_i == 4) { - r = t; - g = p; - b = value; - } else if (hue_i == 5) { - r = value; - g = p; - b = q; - } - - int ri = r * 256; - int gi = g * 256; - int bi = b * 256; - - QColor color(ri, gi, bi); - - return color.name(); -} - -QString HistoryViewManager::getUserColor(const QString &userid) -{ - auto color = NICK_COLORS.value(userid); - - if (color.isEmpty()) { - color = chooseRandomColor(); - NICK_COLORS.insert(userid, color); - } - - return color; -} diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc new file mode 100644 index 00000000..607522a3 --- /dev/null +++ b/src/TimelineItem.cc @@ -0,0 +1,159 @@ +/* + * 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 . + */ + +#include +#include + +#include "TimelineItem.h" + +TimelineItem::TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent) + : QWidget(parent) +{ + generateTimestamp(QDateTime::currentDateTime()); + generateBody(userid, color, body); + setupLayout(); +} + +TimelineItem::TimelineItem(const QString &body, QWidget *parent) + : QWidget(parent) +{ + generateTimestamp(QDateTime::currentDateTime()); + generateBody(body); + setupLayout(); +} + +TimelineItem::TimelineItem(const Event &event, bool with_sender, const QString &color, QWidget *parent) + : QWidget(parent) +{ + auto body = event.content().value("body").toString().trimmed().toHtmlEscaped(); + auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp()); + + generateTimestamp(timestamp); + + if (event.content().value("msgtype").toString() == "m.notice") + body = "" + body + ""; + + if (with_sender) + generateBody(event.sender(), color, body); + else + generateBody(body); + + setupLayout(); +} + +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( + "" + "" + "" + " " + " %1" + " " + "" + ""); + content_label_->setText(content.arg(replaceEmoji(body))); + content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); +} + +void TimelineItem::generateBody(const QString &userid, const QString &color, const QString &body) +{ + auto 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( + "" + "" + "" + " " + " %2" + " " + " " + " %3" + " " + "" + ""); + content_label_->setText(content.arg(color).arg(sender).arg(replaceEmoji(body))); + content_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); +} + +void TimelineItem::generateTimestamp(const QDateTime &time) +{ + auto local_time = time.toString("HH:mm"); + + time_label_ = new QLabel(this); + QString msg( + "" + "" + "" + " " + " %1" + " " + "" + ""); + time_label_->setText(msg.arg(local_time)); + time_label_->setStyleSheet("margin-left: 7px; margin-right: 7px; margin-top: 0;"); + time_label_->setAlignment(Qt::AlignTop); +} + +void TimelineItem::setupLayout() +{ + if (time_label_ == nullptr) { + qWarning() << "TimelineItem: Time label is not initialized"; + return; + } + + if (content_label_ == nullptr) { + qWarning() << "TimelineItem: Content label is not initialized"; + return; + } + + top_layout_ = new QHBoxLayout(); + top_layout_->setMargin(0); + top_layout_->addWidget(time_label_); + top_layout_->addWidget(content_label_, 1); + + setLayout(top_layout_); +} + +QString TimelineItem::replaceEmoji(const QString &body) +{ + QString fmtBody = ""; + + for (auto &c : body) { + int code = c.unicode(); + + // TODO: Be more precise here. + if (code > 9000) + fmtBody += "" + QString(c) + ""; + else + fmtBody += c; + } + + return fmtBody; +} + +TimelineItem::~TimelineItem() +{ +} diff --git a/src/TimelineView.cc b/src/TimelineView.cc new file mode 100644 index 00000000..00a42557 --- /dev/null +++ b/src/TimelineView.cc @@ -0,0 +1,190 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include + +#include "TimelineItem.h" +#include "TimelineView.h" +#include "TimelineViewManager.h" + +TimelineView::TimelineView(const QList &events, QWidget *parent) + : QWidget(parent) +{ + init(); + addEvents(events); +} + +TimelineView::TimelineView(QWidget *parent) + : QWidget(parent) +{ + init(); +} + +void TimelineView::clear() +{ + for (const auto msg : scroll_layout_->children()) + msg->deleteLater(); +} + +void TimelineView::sliderRangeChanged(int min, int max) +{ + Q_UNUSED(min); + scroll_area_->verticalScrollBar()->setValue(max); +} + +int TimelineView::addEvents(const QList &events) +{ + QSettings settings; + auto local_user = settings.value("auth/user_id").toString(); + + int message_count = 0; + + for (const auto &event : events) { + if (event.type() == "m.room.message") { + auto msg_type = event.content().value("msgtype").toString(); + + if (isPendingMessage(event, local_user)) { + removePendingMessage(event); + continue; + } + + if (msg_type == "m.text" || msg_type == "m.notice") { + auto with_sender = last_sender_ != event.sender(); + auto color = TimelineViewManager::getUserColor(event.sender()); + + addHistoryItem(event, color, with_sender); + last_sender_ = event.sender(); + + message_count += 1; + } + } + } + + return message_count; +} + +void TimelineView::init() +{ + top_layout_ = new QVBoxLayout(this); + top_layout_->setSpacing(0); + top_layout_->setMargin(0); + + scroll_area_ = new QScrollArea(this); + scroll_area_->setWidgetResizable(true); + scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + scroll_widget_ = new QWidget(); + + scroll_layout_ = new QVBoxLayout(); + scroll_layout_->addStretch(1); + scroll_layout_->setSpacing(0); + + scroll_widget_->setLayout(scroll_layout_); + + scroll_area_->setWidget(scroll_widget_); + + top_layout_->addWidget(scroll_area_); + + setLayout(top_layout_); + + connect(scroll_area_->verticalScrollBar(), + SIGNAL(rangeChanged(int, int)), + this, + SLOT(sliderRangeChanged(int, int))); +} + +void TimelineView::addHistoryItem(const Event &event, const QString &color, bool with_sender) +{ + TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_); + scroll_layout_->addWidget(item); +} + +void TimelineView::updatePendingMessage(int txn_id, QString event_id) +{ + for (auto &msg : pending_msgs_) { + if (msg.txn_id == txn_id) { + msg.event_id = event_id; + break; + } + } +} + +bool TimelineView::isPendingMessage(const Event &event, const QString &userid) +{ + if (event.sender() != userid || event.type() != "m.room.message") + return false; + + auto msgtype = event.content().value("msgtype").toString(); + auto body = event.content().value("body").toString(); + + // FIXME: should contain more checks later on for other types of messages. + if (msgtype != "m.text") + return false; + + for (const auto &msg : pending_msgs_) { + if (msg.event_id == event.eventId() || msg.body == body) + return true; + } + + return false; +} + +void TimelineView::removePendingMessage(const Event &event) +{ + auto body = event.content().value("body").toString(); + + for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) { + int index = std::distance(pending_msgs_.begin(), it); + + if (it->event_id == event.eventId() || it->body == body) { + pending_msgs_.removeAt(index); + break; + } + } +} + +void TimelineView::addUserTextMessage(const QString &body, int txn_id) +{ + QSettings settings; + auto user_id = settings.value("auth/user_id").toString(); + + auto with_sender = last_sender_ != user_id; + auto color = TimelineViewManager::getUserColor(user_id); + + TimelineItem *view_item; + + if (with_sender) + view_item = new TimelineItem(user_id, color, body, scroll_widget_); + else + view_item = new TimelineItem(body, scroll_widget_); + + scroll_layout_->addWidget(view_item); + + last_sender_ = user_id; + + PendingMessage message(txn_id, body, "", view_item); + + pending_msgs_.push_back(message); +} + +TimelineView::~TimelineView() +{ +} diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc new file mode 100644 index 00000000..3783b250 --- /dev/null +++ b/src/TimelineViewManager.cc @@ -0,0 +1,201 @@ +/* + * 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 . + */ + +#include + +#include +#include +#include +#include +#include + +#include "TimelineView.h" +#include "TimelineViewManager.h" + +TimelineViewManager::TimelineViewManager(QSharedPointer client, QWidget *parent) + : QStackedWidget(parent) + , client_(client) +{ + setStyleSheet("QWidget { background: #f8fbfe; color: #e8e8e8; border: none;}"); + + connect(client_.data(), + SIGNAL(messageSent(const QString &, const QString &, int)), + this, + SLOT(messageSent(const QString &, const QString &, int))); +} + +TimelineViewManager::~TimelineViewManager() +{ +} + +void TimelineViewManager::messageSent(const QString &event_id, const QString &roomid, int txn_id) +{ + // We save the latest valid transaction ID for later use. + QSettings settings; + settings.setValue("client/transaction_id", txn_id + 1); + + auto view = views_[roomid]; + view->updatePendingMessage(txn_id, event_id); +} + +void TimelineViewManager::sendTextMessage(const QString &msg) +{ + auto room = active_room_; + auto view = views_[room.id()]; + + view->addUserTextMessage(msg, client_->transactionId()); + client_->sendTextMessage(room.id(), msg); +} + +void TimelineViewManager::clearAll() +{ + NICK_COLORS.clear(); + + for (const auto &view : views_) { + view->clear(); + removeWidget(view); + view->deleteLater(); + } + + views_.clear(); +} + +void TimelineViewManager::initialize(const Rooms &rooms) +{ + for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { + auto roomid = it.key(); + auto events = it.value().timeline().events(); + + // Create a history view with the room events. + TimelineView *view = new TimelineView(events); + views_.insert(it.key(), view); + + // Add the view in the widget stack. + addWidget(view); + } +} + +void TimelineViewManager::sync(const Rooms &rooms) +{ + for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) { + auto roomid = it.key(); + + if (!views_.contains(roomid)) { + qDebug() << "Ignoring event from unknown room"; + continue; + } + + auto view = views_.value(roomid); + auto events = it.value().timeline().events(); + + int msgs_added = view->addEvents(events); + + if (msgs_added > 0) { + // TODO: When window gets active the current + // unread count (if any) should be cleared. + auto isAppActive = QApplication::activeWindow() != nullptr; + + if (roomid != active_room_.id() || !isAppActive) + emit unreadMessages(roomid, msgs_added); + } + } +} + +void TimelineViewManager::setHistoryView(const RoomInfo &info) +{ + if (!views_.contains(info.id())) { + qDebug() << "Room List id is not present in view manager"; + qDebug() << info.name(); + return; + } + + active_room_ = info; + auto widget = views_.value(info.id()); + + setCurrentWidget(widget); +} + +QMap TimelineViewManager::NICK_COLORS; + +QString TimelineViewManager::chooseRandomColor() +{ + std::random_device random_device; + std::mt19937 engine{random_device()}; + std::uniform_real_distribution dist(0, 1); + + float hue = dist(engine); + float saturation = 0.9; + float value = 0.7; + + int hue_i = hue * 6; + + float f = hue * 6 - hue_i; + + float p = value * (1 - saturation); + float q = value * (1 - f * saturation); + float t = value * (1 - (1 - f) * saturation); + + float r = 0; + float g = 0; + float b = 0; + + if (hue_i == 0) { + r = value; + g = t; + b = p; + } else if (hue_i == 1) { + r = q; + g = value; + b = p; + } else if (hue_i == 2) { + r = p; + g = value; + b = t; + } else if (hue_i == 3) { + r = p; + g = q; + b = value; + } else if (hue_i == 4) { + r = t; + g = p; + b = value; + } else if (hue_i == 5) { + r = value; + g = p; + b = q; + } + + int ri = r * 256; + int gi = g * 256; + int bi = b * 256; + + QColor color(ri, gi, bi); + + return color.name(); +} + +QString TimelineViewManager::getUserColor(const QString &userid) +{ + auto color = NICK_COLORS.value(userid); + + if (color.isEmpty()) { + color = chooseRandomColor(); + NICK_COLORS.insert(userid, color); + } + + return color; +} -- cgit 1.5.1