mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-30 17:40:47 +03:00
Show presence and set custom status messages
This commit is contained in:
parent
e5a55ab1b9
commit
96f4169be9
11 changed files with 191 additions and 1 deletions
|
@ -9,6 +9,7 @@ Rectangle {
|
|||
radius: settings.avatarCircles ? height/2 : 3
|
||||
|
||||
property alias url: img.source
|
||||
property string userid
|
||||
property string displayName
|
||||
|
||||
Label {
|
||||
|
@ -42,6 +43,23 @@ Rectangle {
|
|||
radius: settings.avatarCircles ? height/2 : 3
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: avatar.bottom
|
||||
anchors.right: avatar.right
|
||||
|
||||
height: avatar.height / 6
|
||||
width: height
|
||||
radius: settings.avatarCircles ? height / 2 : height / 4
|
||||
color: switch (timelineManager.userPresence(userid)) {
|
||||
case "online": return "#00cc66"
|
||||
case "unavailable": return "#ff9933"
|
||||
case "offline": return "#a82353"
|
||||
default: "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
color: colors.base
|
||||
}
|
||||
|
|
|
@ -152,6 +152,8 @@ Page {
|
|||
|
||||
onCountChanged: if (atYEnd) model.currentIndex = 0 // Mark last event as read, since we are at the bottom
|
||||
|
||||
property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32)
|
||||
|
||||
delegate: Rectangle {
|
||||
// This would normally be previousSection, but our model's order is inverted.
|
||||
property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1
|
||||
|
@ -159,7 +161,7 @@ Page {
|
|||
id: wrapper
|
||||
property Item section
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32)
|
||||
width: chat.delegateMaxWidth
|
||||
height: section ? section.height + timelinerow.height : timelinerow.height
|
||||
color: "transparent"
|
||||
|
||||
|
@ -236,6 +238,7 @@ Page {
|
|||
height: avatarSize
|
||||
url: chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/")
|
||||
displayName: modelData.userName
|
||||
userid: modelData.userId
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
@ -258,6 +261,15 @@ Page {
|
|||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
color: colors.buttonText
|
||||
text: timelineManager.userStatus(modelData.userId)
|
||||
textFormat: Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
width: chat.delegateMaxWidth - parent.spacing*2 - userName.implicitWidth - avatarSize
|
||||
font.italic: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -952,6 +952,8 @@ Cache::saveState(const mtx::responses::Sync &res)
|
|||
|
||||
saveInvites(txn, res.rooms.invite);
|
||||
|
||||
savePresence(txn, res.presence);
|
||||
|
||||
removeLeftRooms(txn, res.rooms.leave);
|
||||
|
||||
txn.commit();
|
||||
|
@ -1037,6 +1039,21 @@ Cache::saveInvite(lmdb::txn &txn,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cache::savePresence(
|
||||
lmdb::txn &txn,
|
||||
const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presenceUpdates)
|
||||
{
|
||||
for (const auto &update : presenceUpdates) {
|
||||
auto presenceDb = getPresenceDb(txn);
|
||||
|
||||
lmdb::dbi_put(txn,
|
||||
presenceDb,
|
||||
lmdb::val(update.sender),
|
||||
lmdb::val(json(update.content).dump()));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Cache::roomsWithStateUpdates(const mtx::responses::Sync &res)
|
||||
{
|
||||
|
@ -2254,6 +2271,50 @@ Cache::removeAvatarUrl(const QString &room_id, const QString &user_id)
|
|||
AvatarUrls.remove(fmt);
|
||||
}
|
||||
|
||||
mtx::presence::PresenceState
|
||||
Cache::presenceState(const std::string &user_id)
|
||||
{
|
||||
lmdb::val presenceVal;
|
||||
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
auto db = getPresenceDb(txn);
|
||||
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), presenceVal);
|
||||
|
||||
mtx::presence::PresenceState state = mtx::presence::offline;
|
||||
|
||||
if (res) {
|
||||
mtx::events::presence::Presence presence =
|
||||
json::parse(std::string(presenceVal.data(), presenceVal.size()));
|
||||
state = presence.presence;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
std::string
|
||||
Cache::statusMessage(const std::string &user_id)
|
||||
{
|
||||
lmdb::val presenceVal;
|
||||
|
||||
auto txn = lmdb::txn::begin(env_);
|
||||
auto db = getPresenceDb(txn);
|
||||
auto res = lmdb::dbi_get(txn, db, lmdb::val(user_id), presenceVal);
|
||||
|
||||
std::string status_msg;
|
||||
|
||||
if (res) {
|
||||
mtx::events::presence::Presence presence =
|
||||
json::parse(std::string(presenceVal.data(), presenceVal.size()));
|
||||
status_msg = presence.status_msg;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
|
||||
return status_msg;
|
||||
}
|
||||
|
||||
void
|
||||
to_json(json &j, const RoomInfo &info)
|
||||
{
|
||||
|
@ -2425,6 +2486,17 @@ insertAvatarUrl(const QString &room_id, const QString &user_id, const QString &a
|
|||
instance_->insertAvatarUrl(room_id, user_id, avatar_url);
|
||||
}
|
||||
|
||||
mtx::presence::PresenceState
|
||||
presenceState(const std::string &user_id)
|
||||
{
|
||||
return instance_->presenceState(user_id);
|
||||
}
|
||||
std::string
|
||||
statusMessage(const std::string &user_id)
|
||||
{
|
||||
return instance_->statusMessage(user_id);
|
||||
}
|
||||
|
||||
//! Load saved data for the display names & avatars.
|
||||
void
|
||||
populateMembers()
|
||||
|
|
|
@ -54,6 +54,12 @@ insertDisplayName(const QString &room_id, const QString &user_id, const QString
|
|||
void
|
||||
insertAvatarUrl(const QString &room_id, const QString &user_id, const QString &avatar_url);
|
||||
|
||||
// presence
|
||||
mtx::presence::PresenceState
|
||||
presenceState(const std::string &user_id);
|
||||
std::string
|
||||
statusMessage(const std::string &user_id);
|
||||
|
||||
//! Load saved data for the display names & avatars.
|
||||
void
|
||||
populateMembers();
|
||||
|
|
|
@ -52,6 +52,10 @@ public:
|
|||
static QString displayName(const QString &room_id, const QString &user_id);
|
||||
static QString avatarUrl(const QString &room_id, const QString &user_id);
|
||||
|
||||
// presence
|
||||
mtx::presence::PresenceState presenceState(const std::string &user_id);
|
||||
std::string statusMessage(const std::string &user_id);
|
||||
|
||||
static void removeDisplayName(const QString &room_id, const QString &user_id);
|
||||
static void removeAvatarUrl(const QString &room_id, const QString &user_id);
|
||||
|
||||
|
@ -377,6 +381,10 @@ private:
|
|||
void saveInvites(lmdb::txn &txn,
|
||||
const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
|
||||
|
||||
void savePresence(
|
||||
lmdb::txn &txn,
|
||||
const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presenceUpdates);
|
||||
|
||||
//! Sends signals for the rooms that are removed.
|
||||
void removeLeftRooms(lmdb::txn &txn,
|
||||
const std::map<std::string, mtx::responses::LeftRoom> &rooms)
|
||||
|
@ -430,6 +438,11 @@ private:
|
|||
return lmdb::dbi::open(txn, std::string(room_id + "/mentions").c_str(), MDB_CREATE);
|
||||
}
|
||||
|
||||
lmdb::dbi getPresenceDb(lmdb::txn &txn)
|
||||
{
|
||||
return lmdb::dbi::open(txn, "presence", MDB_CREATE);
|
||||
}
|
||||
|
||||
//! Retrieves or creates the database that stores the open OLM sessions between our device
|
||||
//! and the given curve25519 key which represents another device.
|
||||
//!
|
||||
|
|
|
@ -61,6 +61,7 @@ constexpr size_t MAX_ONETIME_KEYS = 50;
|
|||
|
||||
Q_DECLARE_METATYPE(std::optional<mtx::crypto::EncryptedFile>)
|
||||
Q_DECLARE_METATYPE(std::optional<RelatedInfo>)
|
||||
Q_DECLARE_METATYPE(mtx::presence::PresenceState)
|
||||
|
||||
ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
|
@ -72,6 +73,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
|
||||
qRegisterMetaType<std::optional<mtx::crypto::EncryptedFile>>();
|
||||
qRegisterMetaType<std::optional<RelatedInfo>>();
|
||||
qRegisterMetaType<mtx::presence::PresenceState>();
|
||||
|
||||
topLayout_ = new QHBoxLayout(this);
|
||||
topLayout_->setSpacing(0);
|
||||
|
@ -1221,6 +1223,24 @@ ChatPage::sendTypingNotifications()
|
|||
});
|
||||
}
|
||||
|
||||
QString
|
||||
ChatPage::status() const
|
||||
{
|
||||
return QString::fromStdString(cache::statusMessage(utils::localUser().toStdString()));
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::setStatus(const QString &status)
|
||||
{
|
||||
http::client()->put_presence_status(
|
||||
currentPresence(), status.toStdString(), [](mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
nhlog::net()->warn("failed to set presence status_msg: {}",
|
||||
err->matrix_error.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
|
||||
{
|
||||
|
|
|
@ -89,6 +89,11 @@ public:
|
|||
void initiateLogout();
|
||||
void focusMessageInput();
|
||||
|
||||
QString status() const;
|
||||
void setStatus(const QString &status);
|
||||
|
||||
mtx::presence::PresenceState currentPresence() const { return mtx::presence::online; }
|
||||
|
||||
public slots:
|
||||
void leaveRoom(const QString &room_id);
|
||||
void createRoom(const mtx::requests::CreateRoom &req);
|
||||
|
@ -154,6 +159,7 @@ signals:
|
|||
const QImage &icon);
|
||||
|
||||
void updateGroupsInfo(const mtx::responses::JoinedGroups &groups);
|
||||
void retrievedPresence(const QString &statusMsg, mtx::presence::PresenceState state);
|
||||
void themeChanged();
|
||||
void decryptSidebarChanged();
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
|
@ -24,6 +26,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Splitter.h"
|
||||
|
@ -105,6 +108,27 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
|
|||
connect(logoutButton_, &QPushButton::clicked, this, []() {
|
||||
MainWindow::instance()->openLogoutDialog();
|
||||
});
|
||||
|
||||
menu = new QMenu(this);
|
||||
|
||||
auto setStatusAction = menu->addAction(tr("Set custom status message"));
|
||||
connect(setStatusAction, &QAction::triggered, this, [this]() {
|
||||
bool ok = false;
|
||||
QString text = QInputDialog::getText(this,
|
||||
tr("Custom status message"),
|
||||
tr("Status:"),
|
||||
QLineEdit::Normal,
|
||||
ChatPage::instance()->status(),
|
||||
&ok);
|
||||
if (ok && !text.isEmpty())
|
||||
ChatPage::instance()->setStatus(text);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
UserInfoWidget::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
menu->popup(event->globalPos());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -26,6 +26,7 @@ class OverlayModal;
|
|||
class QLabel;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class QMenu;
|
||||
|
||||
class UserInfoWidget : public QWidget
|
||||
{
|
||||
|
@ -48,6 +49,7 @@ public:
|
|||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *) override;
|
||||
|
||||
private:
|
||||
Avatar *userAvatar_;
|
||||
|
@ -70,4 +72,6 @@ private:
|
|||
int logoutButtonSize_;
|
||||
|
||||
QColor borderColor_;
|
||||
|
||||
QMenu *menu = nullptr;
|
||||
};
|
||||
|
|
|
@ -57,6 +57,18 @@ TimelineViewManager::userColor(QString id, QColor background)
|
|||
return userColors.value(id);
|
||||
}
|
||||
|
||||
QString
|
||||
TimelineViewManager::userPresence(QString id) const
|
||||
{
|
||||
return QString::fromStdString(
|
||||
mtx::presence::to_string(cache::presenceState(id.toStdString())));
|
||||
}
|
||||
QString
|
||||
TimelineViewManager::userStatus(QString id) const
|
||||
{
|
||||
return QString::fromStdString(cache::statusMessage(id.toStdString()));
|
||||
}
|
||||
|
||||
TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||
: imgProvider(new MxcImageProvider())
|
||||
, colorImgProvider(new ColorImageProvider())
|
||||
|
|
|
@ -41,6 +41,9 @@ public:
|
|||
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
|
||||
Q_INVOKABLE QColor userColor(QString id, QColor background);
|
||||
|
||||
Q_INVOKABLE QString userPresence(QString id) const;
|
||||
Q_INVOKABLE QString userStatus(QString id) const;
|
||||
|
||||
signals:
|
||||
void clearRoomMessageCount(QString roomid);
|
||||
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
|
||||
|
|
Loading…
Reference in a new issue