diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 9f983b9f..52468f64 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -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();
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index bd43efd8..265b51ce 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -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;
diff --git a/src/Sync.cc b/src/Sync.cc
index 90314352..39d84acb 100644
--- a/src/Sync.cc
+++ b/src/Sync.cc
@@ -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());
+ }
+ }
}
}
diff --git a/src/TextInputWidget.cc b/src/TextInputWidget.cc
index 5f06d992..4d5f4d5f 100644
--- a/src/TextInputWidget.cc
+++ b/src/TextInputWidget.cc
@@ -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"));
diff --git a/src/TypingDisplay.cc b/src/TypingDisplay.cc
new file mode 100644
index 00000000..619b70cb
--- /dev/null
+++ b/src/TypingDisplay.cc
@@ -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_);
+}
|