Implemented sending of typing notifications (#105)
This commit is contained in:
parent
91b8427795
commit
287b5aa4c0
|
@ -47,6 +47,7 @@ class LeftRoom;
|
||||||
|
|
||||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||||
|
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
||||||
|
|
||||||
class ChatPage : public QWidget
|
class ChatPage : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -141,6 +142,7 @@ private:
|
||||||
|
|
||||||
// Keeps track of the users currently typing on each room.
|
// Keeps track of the users currently typing on each room.
|
||||||
QMap<QString, QList<QString>> typingUsers_;
|
QMap<QString, QList<QString>> typingUsers_;
|
||||||
|
QTimer *typingRefresher_;
|
||||||
|
|
||||||
QSharedPointer<QuickSwitcher> quickSwitcher_;
|
QSharedPointer<QuickSwitcher> quickSwitcher_;
|
||||||
QSharedPointer<OverlayModal> quickSwitcherModal_;
|
QSharedPointer<OverlayModal> quickSwitcherModal_;
|
||||||
|
|
|
@ -56,6 +56,8 @@ public:
|
||||||
void uploadImage(const QString &roomid, const QString &filename);
|
void uploadImage(const QString &roomid, const QString &filename);
|
||||||
void joinRoom(const QString &roomIdOrAlias);
|
void joinRoom(const QString &roomIdOrAlias);
|
||||||
void leaveRoom(const QString &roomId);
|
void leaveRoom(const QString &roomId);
|
||||||
|
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
|
||||||
|
void removeTypingNotification(const QString &roomid);
|
||||||
|
|
||||||
QUrl getHomeServer() { return server_; };
|
QUrl getHomeServer() { return server_; };
|
||||||
int transactionId() { return txn_id_; };
|
int transactionId() { return txn_id_; };
|
||||||
|
|
|
@ -35,12 +35,20 @@ static const QString JOIN_COMMAND("/join ");
|
||||||
class FilteredTextEdit : public QTextEdit
|
class FilteredTextEdit : public QTextEdit
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer *typingTimer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FilteredTextEdit(QWidget *parent = nullptr);
|
explicit FilteredTextEdit(QWidget *parent = nullptr);
|
||||||
void keyPressEvent(QKeyEvent *event);
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
|
||||||
|
void stopTyping();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enterPressed();
|
void enterPressed();
|
||||||
|
void startedTyping();
|
||||||
|
void stoppedTyping();
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextInputWidget : public QFrame
|
class TextInputWidget : public QFrame
|
||||||
|
@ -51,6 +59,8 @@ public:
|
||||||
TextInputWidget(QWidget *parent = 0);
|
TextInputWidget(QWidget *parent = 0);
|
||||||
~TextInputWidget();
|
~TextInputWidget();
|
||||||
|
|
||||||
|
void stopTyping();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onSendButtonClicked();
|
void onSendButtonClicked();
|
||||||
void openFileSelection();
|
void openFileSelection();
|
||||||
|
@ -66,6 +76,9 @@ signals:
|
||||||
void uploadImage(QString filename);
|
void uploadImage(QString filename);
|
||||||
void sendJoinRoomRequest(const QString &room);
|
void sendJoinRoomRequest(const QString &room);
|
||||||
|
|
||||||
|
void startedTyping();
|
||||||
|
void stoppedTyping();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showUploadSpinner();
|
void showUploadSpinner();
|
||||||
QString parseEmoteCommand(const QString &cmd);
|
QString parseEmoteCommand(const QString &cmd);
|
||||||
|
|
|
@ -122,6 +122,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
contentLayout_->addWidget(typingDisplay_);
|
contentLayout_->addWidget(typingDisplay_);
|
||||||
contentLayout_->addWidget(text_input_);
|
contentLayout_->addWidget(text_input_);
|
||||||
|
|
||||||
|
typingRefresher_ = new QTimer(this);
|
||||||
|
typingRefresher_->setInterval(TYPING_REFRESH_TIMEOUT);
|
||||||
|
|
||||||
user_info_widget_ = new UserInfoWidget(sideBarTopWidget_);
|
user_info_widget_ = new UserInfoWidget(sideBarTopWidget_);
|
||||||
sideBarTopWidgetLayout_->addWidget(user_info_widget_);
|
sideBarTopWidgetLayout_->addWidget(user_info_widget_);
|
||||||
|
|
||||||
|
@ -139,6 +142,7 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
|
|
||||||
typingDisplay_->setUsers(users);
|
typingDisplay_->setUsers(users);
|
||||||
});
|
});
|
||||||
|
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::stopTyping);
|
||||||
|
|
||||||
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
||||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
|
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
|
||||||
|
@ -159,6 +163,20 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
room_list_->updateUnreadMessageCount(roomid, count);
|
room_list_->updateUnreadMessageCount(roomid, count);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(text_input_, &TextInputWidget::startedTyping, this, [=]() {
|
||||||
|
typingRefresher_->start();
|
||||||
|
client_->sendTypingNotification(current_room_);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(text_input_, &TextInputWidget::stoppedTyping, this, [=]() {
|
||||||
|
typingRefresher_->stop();
|
||||||
|
client_->removeTypingNotification(current_room_);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(typingRefresher_, &QTimer::timeout, this, [=]() {
|
||||||
|
client_->sendTypingNotification(current_room_);
|
||||||
|
});
|
||||||
|
|
||||||
connect(view_manager_,
|
connect(view_manager_,
|
||||||
&TimelineViewManager::updateRoomsLastMessage,
|
&TimelineViewManager::updateRoomsLastMessage,
|
||||||
room_list_,
|
room_list_,
|
||||||
|
@ -600,13 +618,20 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_id
|
||||||
{
|
{
|
||||||
QStringList users;
|
QStringList users;
|
||||||
|
|
||||||
for (const auto uid : user_ids)
|
QSettings settings;
|
||||||
|
QString user_id = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
|
for (const auto uid : user_ids) {
|
||||||
|
if (uid == user_id)
|
||||||
|
continue;
|
||||||
users.append(TimelineViewManager::displayName(uid));
|
users.append(TimelineViewManager::displayName(uid));
|
||||||
|
}
|
||||||
|
|
||||||
users.sort();
|
users.sort();
|
||||||
|
|
||||||
if (current_room_ == roomid)
|
if (current_room_ == roomid) {
|
||||||
typingDisplay_->setUsers(users);
|
typingDisplay_->setUsers(users);
|
||||||
|
}
|
||||||
|
|
||||||
typingUsers_.insert(roomid, users);
|
typingUsers_.insert(roomid, users);
|
||||||
}
|
}
|
||||||
|
|
|
@ -794,3 +794,53 @@ MatrixClient::leaveRoom(const QString &roomId)
|
||||||
emit leftRoom(roomId);
|
emit leftRoom(roomId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatrixClient::sendTypingNotification(const QString &roomid, int timeoutInMillis)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
QString user_id = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
|
QUrlQuery query;
|
||||||
|
query.addQueryItem("access_token", token_);
|
||||||
|
|
||||||
|
QUrl endpoint(server_);
|
||||||
|
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/typing/%2").arg(roomid).arg(user_id));
|
||||||
|
|
||||||
|
endpoint.setQuery(query);
|
||||||
|
|
||||||
|
QString msgType("");
|
||||||
|
QJsonObject body;
|
||||||
|
|
||||||
|
body = { { "typing", true }, { "timeout", timeoutInMillis } };
|
||||||
|
|
||||||
|
QNetworkRequest request(QString(endpoint.toEncoded()));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatrixClient::removeTypingNotification(const QString &roomid)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
QString user_id = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
|
QUrlQuery query;
|
||||||
|
query.addQueryItem("access_token", token_);
|
||||||
|
|
||||||
|
QUrl endpoint(server_);
|
||||||
|
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/typing/%2").arg(roomid).arg(user_id));
|
||||||
|
|
||||||
|
endpoint.setQuery(query);
|
||||||
|
|
||||||
|
QString msgType("");
|
||||||
|
QJsonObject body;
|
||||||
|
|
||||||
|
body = { { "typing", false } };
|
||||||
|
|
||||||
|
QNetworkRequest request(QString(endpoint.toEncoded()));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
|
||||||
|
}
|
||||||
|
|
|
@ -29,15 +29,37 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent)
|
||||||
: QTextEdit(parent)
|
: QTextEdit(parent)
|
||||||
{
|
{
|
||||||
setAcceptRichText(false);
|
setAcceptRichText(false);
|
||||||
|
|
||||||
|
typingTimer_ = new QTimer(this);
|
||||||
|
typingTimer_->setInterval(1000);
|
||||||
|
typingTimer_->setSingleShot(true);
|
||||||
|
|
||||||
|
connect(typingTimer_, &QTimer::timeout, this, &FilteredTextEdit::stopTyping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FilteredTextEdit::keyPressEvent(QKeyEvent *event)
|
FilteredTextEdit::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
|
if (!typingTimer_->isActive()) {
|
||||||
|
emit startedTyping();
|
||||||
|
}
|
||||||
|
|
||||||
|
typingTimer_->start();
|
||||||
|
|
||||||
|
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
|
||||||
|
stopTyping();
|
||||||
|
|
||||||
emit enterPressed();
|
emit enterPressed();
|
||||||
else
|
} else {
|
||||||
QTextEdit::keyPressEvent(event);
|
QTextEdit::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FilteredTextEdit::stopTyping()
|
||||||
|
{
|
||||||
|
typingTimer_->stop();
|
||||||
|
emit stoppedTyping();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextInputWidget::TextInputWidget(QWidget *parent)
|
TextInputWidget::TextInputWidget(QWidget *parent)
|
||||||
|
@ -104,6 +126,10 @@ TextInputWidget::TextInputWidget(QWidget *parent)
|
||||||
SIGNAL(emojiSelected(const QString &)),
|
SIGNAL(emojiSelected(const QString &)),
|
||||||
this,
|
this,
|
||||||
SLOT(addSelectedEmoji(const QString &)));
|
SLOT(addSelectedEmoji(const QString &)));
|
||||||
|
|
||||||
|
connect(input_, &FilteredTextEdit::startedTyping, this, &TextInputWidget::startedTyping);
|
||||||
|
|
||||||
|
connect(input_, &FilteredTextEdit::stoppedTyping, this, &TextInputWidget::stoppedTyping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -227,3 +253,9 @@ TextInputWidget::hideUploadSpinner()
|
||||||
}
|
}
|
||||||
|
|
||||||
TextInputWidget::~TextInputWidget() {}
|
TextInputWidget::~TextInputWidget() {}
|
||||||
|
|
||||||
|
void
|
||||||
|
TextInputWidget::stopTyping()
|
||||||
|
{
|
||||||
|
input_->stopTyping();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue