Receive typing notifications (#88)

This commit is contained in:
Konstantinos Sideris 2017-10-04 11:33:34 +03:00
parent 88349eae90
commit d60c2b76e3
10 changed files with 171 additions and 32 deletions

View File

@ -125,8 +125,8 @@ endif()
#
set(SRC_FILES
src/AvatarProvider.cc
src/ChatPage.cc
src/Cache.cc
src/ChatPage.cc
src/Deserializable.cc
src/EmojiCategory.cc
src/EmojiItemDelegate.cc
@ -135,9 +135,6 @@ set(SRC_FILES
src/EmojiProvider.cc
src/ImageItem.cc
src/ImageOverlayDialog.cc
src/TimelineItem.cc
src/TimelineView.cc
src/TimelineViewManager.cc
src/InputValidator.cc
src/JoinRoomDialog.cc
src/LeaveRoomDialog.cc
@ -147,21 +144,25 @@ set(SRC_FILES
src/MainWindow.cc
src/MatrixClient.cc
src/Profile.cc
src/RoomInfoListItem.cc
src/RoomMessages.cc
src/RoomList.cc
src/RoomState.cc
src/QuickSwitcher.cc
src/Register.cc
src/RegisterPage.cc
src/RoomInfoListItem.cc
src/RoomList.cc
src/RoomMessages.cc
src/RoomState.cc
src/Splitter.cc
src/Sync.cc
src/TextInputWidget.cc
src/TrayIcon.cc
src/TimelineItem.cc
src/TimelineView.cc
src/TimelineViewManager.cc
src/TopRoomBar.cc
src/TrayIcon.cc
src/TypingDisplay.cc
src/UserInfoWidget.cc
src/Versions.cc
src/WelcomePage.cc
src/QuickSwitcher.cc
src/main.cc
src/ui/Avatar.cc
@ -222,23 +223,24 @@ qt5_wrap_cpp(MOC_HEADERS
include/ImageItem.h
include/ImageOverlayDialog.h
include/JoinRoomDialog.h
include/TimelineItem.h
include/TimelineView.h
include/TimelineViewManager.h
include/LeaveRoomDialog.h
include/LoginPage.h
include/LogoutDialog.h
include/MainWindow.h
include/MatrixClient.h
include/QuickSwitcher.h
include/RegisterPage.h
include/RoomInfoListItem.h
include/RoomList.h
include/Splitter.h
include/UserInfoWidget.h
include/TextInputWidget.h
include/TimelineItem.h
include/TimelineView.h
include/TimelineViewManager.h
include/TopRoomBar.h
include/TrayIcon.h
include/TextInputWidget.h
include/QuickSwitcher.h
include/TypingDisplay.h
include/UserInfoWidget.h
include/WelcomePage.h
include/ui/Avatar.h

View File

@ -31,6 +31,7 @@
#include "TextInputWidget.h"
#include "TimelineViewManager.h"
#include "TopRoomBar.h"
#include "TypingDisplay.h"
#include "UserInfoWidget.h"
class ChatPage : public QWidget
@ -68,6 +69,7 @@ protected:
void keyPressEvent(QKeyEvent *event) override;
private:
void updateTypingUsers(const QString &roomid, const QList<QString> &user_ids);
void updateDisplayNames(const RoomState &state);
void loadStateFromCache();
void showQuickSwitcher();
@ -92,6 +94,7 @@ private:
TopRoomBar *top_bar_;
TextInputWidget *text_input_;
TypingDisplay *typingDisplay_;
QTimer *sync_timer_;
int sync_interval_;
@ -104,6 +107,9 @@ private:
QMap<QString, RoomState> state_manager_;
QMap<QString, QSharedPointer<RoomSettings>> settingsManager_;
// Keeps track of the users currently typing on each room.
QMap<QString, QList<QString>> typingUsers_;
QuickSwitcher *quickSwitcher_ = nullptr;
OverlayModal *quickSwitcherModal_ = nullptr;

View File

@ -7,9 +7,10 @@
namespace conf
{
// Global settings.
static const int fontSize = 12;
static const int emojiSize = 14;
static const int headerFontSize = 21;
static const int fontSize = 12;
static const int emojiSize = 14;
static const int headerFontSize = 21;
static const int typingNotificationFontSize = 11;
// Window geometry.
namespace window

View File

@ -142,23 +142,30 @@ Timeline::limited() const
return limited_;
}
// TODO: Add support for ehpmeral, account_data, undread_notifications
// TODO: Add support for account_data, undread_notifications
class JoinedRoom : public Deserializable
{
public:
inline State state() const;
inline Timeline timeline() const;
inline QList<QString> typingUserIDs() const;
void deserialize(const QJsonValue &data) override;
private:
State state_;
Timeline timeline_;
/* Ephemeral ephemeral_; */
QList<QString> typingUserIDs_;
/* AccountData account_data_; */
/* UnreadNotifications unread_notifications_; */
};
inline QList<QString>
JoinedRoom::typingUserIDs() const
{
return typingUserIDs_;
}
inline State
JoinedRoom::state() const
{

21
include/TypingDisplay.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <QPaintEvent>
#include <QWidget>
class TypingDisplay : public QWidget
{
Q_OBJECT
public:
TypingDisplay(QWidget *parent = nullptr);
void setUsers(const QStringList &user_ids);
protected:
void paintEvent(QPaintEvent *event) override;
private:
QString text_;
int leftPadding_;
};

View File

@ -101,8 +101,10 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
view_manager_ = new TimelineViewManager(client, this);
mainContentLayout_->addWidget(view_manager_);
text_input_ = new TextInputWidget(this);
text_input_ = new TextInputWidget(this);
typingDisplay_ = new TypingDisplay(this);
contentLayout_->addWidget(text_input_);
contentLayout_->addWidget(typingDisplay_);
user_info_widget_ = new UserInfoWidget(sideBarTopWidget_);
sideBarTopWidgetLayout_->addWidget(user_info_widget_);
@ -117,6 +119,15 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect(
top_bar_, &TopRoomBar::leaveRoom, this, [=]() { client_->leaveRoom(current_room_); });
connect(room_list_, &RoomList::roomChanged, this, [=](const QString &roomid) {
QStringList users;
if (typingUsers_.contains(roomid))
users = typingUsers_[roomid];
typingDisplay_->setUsers(users);
});
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
connect(
@ -308,6 +319,8 @@ ChatPage::syncCompleted(const SyncResponse &response)
auto joined = response.rooms().join();
for (auto it = joined.constBegin(); it != joined.constEnd(); it++) {
updateTypingUsers(it.key(), it.value().typingUserIDs());
RoomState room_state;
// Merge the new updates for rooms that we are tracking.
@ -620,6 +633,22 @@ ChatPage::removeRoom(const QString &room_id)
room_list_->removeRoom(room_id, room_id == current_room_);
}
void
ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_ids)
{
QStringList users;
for (const auto uid : user_ids)
users.append(TimelineViewManager::displayName(uid));
users.sort();
if (current_room_ == roomid)
typingDisplay_->setUsers(users);
typingUsers_.insert(roomid, users);
}
ChatPage::~ChatPage()
{
sync_timer_->stop();

View File

@ -611,8 +611,9 @@ void
MatrixClient::sync() noexcept
{
QJsonObject filter{ { "room",
QJsonObject{ { "include_leave", true },
{ "ephemeral", QJsonObject{ { "limit", 0 } } } } },
QJsonObject{
{ "include_leave", true },
} },
{ "presence", QJsonObject{ { "limit", 0 } } } };
QUrlQuery query;

View File

@ -168,7 +168,21 @@ JoinedRoom::deserialize(const QJsonValue &data)
if (!ephemeral.value("events").isArray())
qWarning() << "join/ephemeral/events should be an array";
// TODO: Implement ephemeral handling
auto ephemeralEvents = ephemeral.value("events").toArray();
for (const auto e : ephemeralEvents) {
auto obj = e.toObject();
if (obj.contains("type") && obj.value("type") == "m.typing") {
auto ids = obj.value("content")
.toObject()
.value("user_ids")
.toArray();
for (const auto uid : ids)
typingUserIDs_.push_back(uid.toString());
}
}
}
}

View File

@ -45,13 +45,14 @@ TextInputWidget::TextInputWidget(QWidget *parent)
{
setFont(QFont("Emoji One"));
setFixedHeight(45);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setCursor(Qt::ArrowCursor);
setStyleSheet("background-color: #fff; height: 45px;");
setStyleSheet("background-color: #fff;");
topLayout_ = new QHBoxLayout();
topLayout_->setSpacing(2);
topLayout_->setMargin(4);
topLayout_->setSpacing(0);
topLayout_->setContentsMargins(5, 15, 0, 5);
QIcon send_file_icon;
send_file_icon.addFile(":/icons/icons/clip-dark.png", QSize(), QIcon::Normal, QIcon::Off);
@ -63,18 +64,19 @@ TextInputWidget::TextInputWidget(QWidget *parent)
spinner_ = new LoadingIndicator(this);
spinner_->setColor("#acc7dc");
spinner_->setFixedHeight(40);
spinner_->setFixedWidth(40);
spinner_->setFixedHeight(32);
spinner_->setFixedWidth(32);
spinner_->hide();
QFont font;
font.setPixelSize(conf::fontSize);
input_ = new FilteredTextEdit(this);
input_->setFixedHeight(45);
input_->setFixedHeight(32);
input_->setFont(font);
input_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
input_->setPlaceholderText(tr("Write a message..."));
input_->setStyleSheet("color: #333333; border-radius: 0; padding-top: 10px;");
input_->setStyleSheet("color: #333333; border: none; margin: 0 5px");
sendMessageBtn_ = new FlatButton(this);
sendMessageBtn_->setForegroundColor(QColor("#acc7dc"));

56
src/TypingDisplay.cc Normal file
View File

@ -0,0 +1,56 @@
#include <QDebug>
#include <QPainter>
#include <QPoint>
#include "Config.h"
#include "TypingDisplay.h"
TypingDisplay::TypingDisplay(QWidget *parent)
: QWidget(parent)
, leftPadding_{ 57 }
{
QFont font;
font.setPixelSize(conf::typingNotificationFontSize);
setFixedHeight(QFontMetrics(font).height() + 2);
}
void
TypingDisplay::setUsers(const QStringList &uid)
{
if (uid.isEmpty())
text_.clear();
else
text_ = uid.join(", ");
if (uid.size() == 1)
text_ += tr(" is typing ...");
else if (uid.size() > 1)
text_ += tr(" are typing ...");
update();
}
void
TypingDisplay::paintEvent(QPaintEvent *)
{
QPen pen(QColor("#333"));
QFont font;
font.setPixelSize(conf::typingNotificationFontSize);
font.setWeight(40);
font.setItalic(true);
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setFont(font);
p.setPen(pen);
QRect region = rect();
region.translate(leftPadding_, 0);
QFontMetrics fm(font);
text_ = fm.elidedText(text_, Qt::ElideRight, width() - 3 * leftPadding_);
p.drawText(region, Qt::AlignTop, text_);
}