Move all files under src/
This commit is contained in:
parent
96a2c614bf
commit
0e814da91c
145 changed files with 281 additions and 279 deletions
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
namespace AvatarProvider {
|
||||
36
src/AvatarProvider.h
Normal file
36
src/AvatarProvider.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QImage>
|
||||
#include <functional>
|
||||
|
||||
class AvatarProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void avatarDownloaded(const QByteArray &data);
|
||||
};
|
||||
|
||||
using AvatarCallback = std::function<void(QImage)>;
|
||||
|
||||
namespace AvatarProvider {
|
||||
void
|
||||
resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback cb);
|
||||
}
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
#include <variant.hpp>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Utils.h"
|
||||
|
||||
//! Should be changed when a breaking change occurs in the cache format.
|
||||
661
src/Cache.h
Normal file
661
src/Cache.h
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QImage>
|
||||
#include <QString>
|
||||
|
||||
#include <json.hpp>
|
||||
#include <lmdb++.h>
|
||||
#include <mtx/events/join_rules.hpp>
|
||||
#include <mtx/responses.hpp>
|
||||
#include <mtxclient/crypto/client.hpp>
|
||||
#include <mutex>
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
using mtx::events::state::JoinRule;
|
||||
|
||||
struct RoomMember
|
||||
{
|
||||
QString user_id;
|
||||
QString display_name;
|
||||
QImage avatar;
|
||||
};
|
||||
|
||||
struct SearchResult
|
||||
{
|
||||
QString user_id;
|
||||
QString display_name;
|
||||
};
|
||||
|
||||
static int
|
||||
numeric_key_comparison(const MDB_val *a, const MDB_val *b)
|
||||
{
|
||||
auto lhs = std::stoull(std::string((char *)a->mv_data, a->mv_size));
|
||||
auto rhs = std::stoull(std::string((char *)b->mv_data, b->mv_size));
|
||||
|
||||
if (lhs < rhs)
|
||||
return 1;
|
||||
else if (lhs == rhs)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(SearchResult)
|
||||
Q_DECLARE_METATYPE(QVector<SearchResult>)
|
||||
Q_DECLARE_METATYPE(RoomMember)
|
||||
Q_DECLARE_METATYPE(mtx::responses::Timeline)
|
||||
|
||||
//! Used to uniquely identify a list of read receipts.
|
||||
struct ReadReceiptKey
|
||||
{
|
||||
std::string event_id;
|
||||
std::string room_id;
|
||||
};
|
||||
|
||||
inline void
|
||||
to_json(json &j, const ReadReceiptKey &key)
|
||||
{
|
||||
j = json{{"event_id", key.event_id}, {"room_id", key.room_id}};
|
||||
}
|
||||
|
||||
inline void
|
||||
from_json(const json &j, ReadReceiptKey &key)
|
||||
{
|
||||
key.event_id = j.at("event_id").get<std::string>();
|
||||
key.room_id = j.at("room_id").get<std::string>();
|
||||
}
|
||||
|
||||
struct DescInfo
|
||||
{
|
||||
QString username;
|
||||
QString userid;
|
||||
QString body;
|
||||
QString timestamp;
|
||||
QDateTime datetime;
|
||||
};
|
||||
|
||||
//! UI info associated with a room.
|
||||
struct RoomInfo
|
||||
{
|
||||
//! The calculated name of the room.
|
||||
std::string name;
|
||||
//! The topic of the room.
|
||||
std::string topic;
|
||||
//! The calculated avatar url of the room.
|
||||
std::string avatar_url;
|
||||
//! Whether or not the room is an invite.
|
||||
bool is_invite = false;
|
||||
//! Total number of members in the room.
|
||||
int16_t member_count = 0;
|
||||
//! Who can access to the room.
|
||||
JoinRule join_rule = JoinRule::Public;
|
||||
bool guest_access = false;
|
||||
//! Metadata describing the last message in the timeline.
|
||||
DescInfo msgInfo;
|
||||
};
|
||||
|
||||
inline void
|
||||
to_json(json &j, const RoomInfo &info)
|
||||
{
|
||||
j["name"] = info.name;
|
||||
j["topic"] = info.topic;
|
||||
j["avatar_url"] = info.avatar_url;
|
||||
j["is_invite"] = info.is_invite;
|
||||
j["join_rule"] = info.join_rule;
|
||||
j["guest_access"] = info.guest_access;
|
||||
|
||||
if (info.member_count != 0)
|
||||
j["member_count"] = info.member_count;
|
||||
}
|
||||
|
||||
inline void
|
||||
from_json(const json &j, RoomInfo &info)
|
||||
{
|
||||
info.name = j.at("name");
|
||||
info.topic = j.at("topic");
|
||||
info.avatar_url = j.at("avatar_url");
|
||||
info.is_invite = j.at("is_invite");
|
||||
info.join_rule = j.at("join_rule");
|
||||
info.guest_access = j.at("guest_access");
|
||||
|
||||
if (j.count("member_count"))
|
||||
info.member_count = j.at("member_count");
|
||||
}
|
||||
|
||||
//! Basic information per member;
|
||||
struct MemberInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string avatar_url;
|
||||
};
|
||||
|
||||
inline void
|
||||
to_json(json &j, const MemberInfo &info)
|
||||
{
|
||||
j["name"] = info.name;
|
||||
j["avatar_url"] = info.avatar_url;
|
||||
}
|
||||
|
||||
inline void
|
||||
from_json(const json &j, MemberInfo &info)
|
||||
{
|
||||
info.name = j.at("name");
|
||||
info.avatar_url = j.at("avatar_url");
|
||||
}
|
||||
|
||||
struct RoomSearchResult
|
||||
{
|
||||
std::string room_id;
|
||||
RoomInfo info;
|
||||
QImage img;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(RoomSearchResult)
|
||||
Q_DECLARE_METATYPE(RoomInfo)
|
||||
|
||||
// Extra information associated with an outbound megolm session.
|
||||
struct OutboundGroupSessionData
|
||||
{
|
||||
std::string session_id;
|
||||
std::string session_key;
|
||||
uint64_t message_index = 0;
|
||||
};
|
||||
|
||||
inline void
|
||||
to_json(nlohmann::json &obj, const OutboundGroupSessionData &msg)
|
||||
{
|
||||
obj["session_id"] = msg.session_id;
|
||||
obj["session_key"] = msg.session_key;
|
||||
obj["message_index"] = msg.message_index;
|
||||
}
|
||||
|
||||
inline void
|
||||
from_json(const nlohmann::json &obj, OutboundGroupSessionData &msg)
|
||||
{
|
||||
msg.session_id = obj.at("session_id");
|
||||
msg.session_key = obj.at("session_key");
|
||||
msg.message_index = obj.at("message_index");
|
||||
}
|
||||
|
||||
struct OutboundGroupSessionDataRef
|
||||
{
|
||||
OlmOutboundGroupSession *session;
|
||||
OutboundGroupSessionData data;
|
||||
};
|
||||
|
||||
struct DevicePublicKeys
|
||||
{
|
||||
std::string ed25519;
|
||||
std::string curve25519;
|
||||
};
|
||||
|
||||
inline void
|
||||
to_json(nlohmann::json &obj, const DevicePublicKeys &msg)
|
||||
{
|
||||
obj["ed25519"] = msg.ed25519;
|
||||
obj["curve25519"] = msg.curve25519;
|
||||
}
|
||||
|
||||
inline void
|
||||
from_json(const nlohmann::json &obj, DevicePublicKeys &msg)
|
||||
{
|
||||
msg.ed25519 = obj.at("ed25519");
|
||||
msg.curve25519 = obj.at("curve25519");
|
||||
}
|
||||
|
||||
//! Represents a unique megolm session identifier.
|
||||
struct MegolmSessionIndex
|
||||
{
|
||||
//! The room in which this session exists.
|
||||
std::string room_id;
|
||||
//! The session_id of the megolm session.
|
||||
std::string session_id;
|
||||
//! The curve25519 public key of the sender.
|
||||
std::string sender_key;
|
||||
|
||||
//! Representation to be used in a hash map.
|
||||
std::string to_hash() const { return room_id + session_id + sender_key; }
|
||||
};
|
||||
|
||||
struct OlmSessionStorage
|
||||
{
|
||||
// Megolm sessions
|
||||
std::map<std::string, mtx::crypto::InboundGroupSessionPtr> group_inbound_sessions;
|
||||
std::map<std::string, mtx::crypto::OutboundGroupSessionPtr> group_outbound_sessions;
|
||||
std::map<std::string, OutboundGroupSessionData> group_outbound_session_data;
|
||||
|
||||
// Guards for accessing megolm sessions.
|
||||
std::mutex group_outbound_mtx;
|
||||
std::mutex group_inbound_mtx;
|
||||
};
|
||||
|
||||
class Cache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Cache(const QString &userId, QObject *parent = nullptr);
|
||||
|
||||
static QHash<QString, QString> DisplayNames;
|
||||
static QHash<QString, QString> AvatarUrls;
|
||||
|
||||
static std::string displayName(const std::string &room_id, const std::string &user_id);
|
||||
static QString displayName(const QString &room_id, const QString &user_id);
|
||||
static QString avatarUrl(const QString &room_id, const QString &user_id);
|
||||
|
||||
static void removeDisplayName(const QString &room_id, const QString &user_id);
|
||||
static void removeAvatarUrl(const QString &room_id, const QString &user_id);
|
||||
|
||||
static void insertDisplayName(const QString &room_id,
|
||||
const QString &user_id,
|
||||
const QString &display_name);
|
||||
static void insertAvatarUrl(const QString &room_id,
|
||||
const QString &user_id,
|
||||
const QString &avatar_url);
|
||||
|
||||
//! Load saved data for the display names & avatars.
|
||||
void populateMembers();
|
||||
std::vector<std::string> joinedRooms();
|
||||
|
||||
QMap<QString, RoomInfo> roomInfo(bool withInvites = true);
|
||||
std::map<QString, bool> invites();
|
||||
|
||||
//! Calculate & return the name of the room.
|
||||
QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
//! Get room join rules
|
||||
JoinRule getRoomJoinRule(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
bool getRoomGuestAccess(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
//! Retrieve the topic of the room if any.
|
||||
QString getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
//! Retrieve the room avatar's url if any.
|
||||
QString getRoomAvatarUrl(lmdb::txn &txn,
|
||||
lmdb::dbi &statesdb,
|
||||
lmdb::dbi &membersdb,
|
||||
const QString &room_id);
|
||||
|
||||
//! Retrieve member info from a room.
|
||||
std::vector<RoomMember> getMembers(const std::string &room_id,
|
||||
std::size_t startIndex = 0,
|
||||
std::size_t len = 30);
|
||||
|
||||
void saveState(const mtx::responses::Sync &res);
|
||||
bool isInitialized() const;
|
||||
|
||||
std::string nextBatchToken() const;
|
||||
|
||||
void deleteData();
|
||||
|
||||
void removeInvite(lmdb::txn &txn, const std::string &room_id);
|
||||
void removeInvite(const std::string &room_id);
|
||||
void removeRoom(lmdb::txn &txn, const std::string &roomid);
|
||||
void removeRoom(const std::string &roomid);
|
||||
void removeRoom(const QString &roomid) { removeRoom(roomid.toStdString()); };
|
||||
void setup();
|
||||
|
||||
bool isFormatValid();
|
||||
void setCurrentFormat();
|
||||
|
||||
std::map<QString, mtx::responses::Timeline> roomMessages();
|
||||
|
||||
//! Retrieve all the user ids from a room.
|
||||
std::vector<std::string> roomMembers(const std::string &room_id);
|
||||
|
||||
//! Check if the given user has power leve greater than than
|
||||
//! lowest power level of the given events.
|
||||
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
||||
const std::string &room_id,
|
||||
const std::string &user_id);
|
||||
|
||||
//! Retrieves the saved room avatar.
|
||||
QImage getRoomAvatar(const QString &id);
|
||||
QImage getRoomAvatar(const std::string &id);
|
||||
|
||||
//! Adds a user to the read list for the given event.
|
||||
//!
|
||||
//! There should be only one user id present in a receipt list per room.
|
||||
//! The user id should be removed from any other lists.
|
||||
using Receipts = std::map<std::string, std::map<std::string, uint64_t>>;
|
||||
void updateReadReceipt(lmdb::txn &txn,
|
||||
const std::string &room_id,
|
||||
const Receipts &receipts);
|
||||
|
||||
//! Retrieve all the read receipts for the given event id and room.
|
||||
//!
|
||||
//! Returns a map of user ids and the time of the read receipt in milliseconds.
|
||||
using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
|
||||
UserReceipts readReceipts(const QString &event_id, const QString &room_id);
|
||||
|
||||
QByteArray image(const QString &url) const;
|
||||
QByteArray image(lmdb::txn &txn, const std::string &url) const;
|
||||
QByteArray image(const std::string &url) const
|
||||
{
|
||||
return image(QString::fromStdString(url));
|
||||
}
|
||||
void saveImage(const std::string &url, const std::string &data);
|
||||
void saveImage(const QString &url, const QByteArray &data);
|
||||
|
||||
RoomInfo singleRoomInfo(const std::string &room_id);
|
||||
std::vector<std::string> roomsWithStateUpdates(const mtx::responses::Sync &res);
|
||||
std::map<QString, RoomInfo> getRoomInfo(const std::vector<std::string> &rooms);
|
||||
std::map<QString, RoomInfo> roomUpdates(const mtx::responses::Sync &sync)
|
||||
{
|
||||
return getRoomInfo(roomsWithStateUpdates(sync));
|
||||
}
|
||||
|
||||
QVector<SearchResult> searchUsers(const std::string &room_id,
|
||||
const std::string &query,
|
||||
std::uint8_t max_items = 5);
|
||||
std::vector<RoomSearchResult> searchRooms(const std::string &query,
|
||||
std::uint8_t max_items = 5);
|
||||
|
||||
void markSentNotification(const std::string &event_id);
|
||||
//! Removes an event from the sent notifications.
|
||||
void removeReadNotification(const std::string &event_id);
|
||||
//! Check if we have sent a desktop notification for the given event id.
|
||||
bool isNotificationSent(const std::string &event_id);
|
||||
|
||||
//! Mark a room that uses e2e encryption.
|
||||
void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id);
|
||||
bool isRoomEncrypted(const std::string &room_id);
|
||||
|
||||
//! Save the public keys for a device.
|
||||
void saveDeviceKeys(const std::string &device_id);
|
||||
void getDeviceKeys(const std::string &device_id);
|
||||
|
||||
//! Save the device list for a user.
|
||||
void setDeviceList(const std::string &user_id, const std::vector<std::string> &devices);
|
||||
std::vector<std::string> getDeviceList(const std::string &user_id);
|
||||
|
||||
//
|
||||
// Outbound Megolm Sessions
|
||||
//
|
||||
void saveOutboundMegolmSession(const std::string &room_id,
|
||||
const OutboundGroupSessionData &data,
|
||||
mtx::crypto::OutboundGroupSessionPtr session);
|
||||
OutboundGroupSessionDataRef getOutboundMegolmSession(const std::string &room_id);
|
||||
bool outboundMegolmSessionExists(const std::string &room_id) noexcept;
|
||||
void updateOutboundMegolmSession(const std::string &room_id, int message_index);
|
||||
|
||||
//
|
||||
// Inbound Megolm Sessions
|
||||
//
|
||||
void saveInboundMegolmSession(const MegolmSessionIndex &index,
|
||||
mtx::crypto::InboundGroupSessionPtr session);
|
||||
OlmInboundGroupSession *getInboundMegolmSession(const MegolmSessionIndex &index);
|
||||
bool inboundMegolmSessionExists(const MegolmSessionIndex &index) noexcept;
|
||||
|
||||
//
|
||||
// Olm Sessions
|
||||
//
|
||||
void saveOlmSession(const std::string &curve25519, mtx::crypto::OlmSessionPtr session);
|
||||
std::vector<std::string> getOlmSessions(const std::string &curve25519);
|
||||
boost::optional<mtx::crypto::OlmSessionPtr> getOlmSession(const std::string &curve25519,
|
||||
const std::string &session_id);
|
||||
|
||||
void saveOlmAccount(const std::string &pickled);
|
||||
std::string restoreOlmAccount();
|
||||
|
||||
void restoreSessions();
|
||||
|
||||
OlmSessionStorage session_storage;
|
||||
|
||||
private:
|
||||
//! Save an invited room.
|
||||
void saveInvite(lmdb::txn &txn,
|
||||
lmdb::dbi &statesdb,
|
||||
lmdb::dbi &membersdb,
|
||||
const mtx::responses::InvitedRoom &room);
|
||||
|
||||
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||
|
||||
DescInfo getLastMessageInfo(lmdb::txn &txn, const std::string &room_id);
|
||||
void saveTimelineMessages(lmdb::txn &txn,
|
||||
const std::string &room_id,
|
||||
const mtx::responses::Timeline &res);
|
||||
|
||||
mtx::responses::Timeline getTimelineMessages(lmdb::txn &txn, const std::string &room_id);
|
||||
|
||||
//! Remove a room from the cache.
|
||||
// void removeLeftRoom(lmdb::txn &txn, const std::string &room_id);
|
||||
template<class T>
|
||||
void saveStateEvents(lmdb::txn &txn,
|
||||
const lmdb::dbi &statesdb,
|
||||
const lmdb::dbi &membersdb,
|
||||
const std::string &room_id,
|
||||
const std::vector<T> &events)
|
||||
{
|
||||
for (const auto &e : events)
|
||||
saveStateEvent(txn, statesdb, membersdb, room_id, e);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void saveStateEvent(lmdb::txn &txn,
|
||||
const lmdb::dbi &statesdb,
|
||||
const lmdb::dbi &membersdb,
|
||||
const std::string &room_id,
|
||||
const T &event)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
if (mpark::holds_alternative<StateEvent<Member>>(event)) {
|
||||
const auto e = mpark::get<StateEvent<Member>>(event);
|
||||
|
||||
switch (e.content.membership) {
|
||||
//
|
||||
// We only keep users with invite or join membership.
|
||||
//
|
||||
case Membership::Invite:
|
||||
case Membership::Join: {
|
||||
auto display_name = e.content.display_name.empty()
|
||||
? e.state_key
|
||||
: e.content.display_name;
|
||||
|
||||
// Lightweight representation of a member.
|
||||
MemberInfo tmp{display_name, e.content.avatar_url};
|
||||
|
||||
lmdb::dbi_put(txn,
|
||||
membersdb,
|
||||
lmdb::val(e.state_key),
|
||||
lmdb::val(json(tmp).dump()));
|
||||
|
||||
insertDisplayName(QString::fromStdString(room_id),
|
||||
QString::fromStdString(e.state_key),
|
||||
QString::fromStdString(display_name));
|
||||
|
||||
insertAvatarUrl(QString::fromStdString(room_id),
|
||||
QString::fromStdString(e.state_key),
|
||||
QString::fromStdString(e.content.avatar_url));
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lmdb::dbi_del(
|
||||
txn, membersdb, lmdb::val(e.state_key), lmdb::val(""));
|
||||
|
||||
removeDisplayName(QString::fromStdString(room_id),
|
||||
QString::fromStdString(e.state_key));
|
||||
removeAvatarUrl(QString::fromStdString(room_id),
|
||||
QString::fromStdString(e.state_key));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (mpark::holds_alternative<StateEvent<Encryption>>(event)) {
|
||||
setEncryptedRoom(txn, room_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isStateEvent(event))
|
||||
return;
|
||||
|
||||
mpark::visit(
|
||||
[&txn, &statesdb](auto e) {
|
||||
lmdb::dbi_put(
|
||||
txn, statesdb, lmdb::val(to_string(e.type)), lmdb::val(json(e).dump()));
|
||||
},
|
||||
event);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool isStateEvent(const T &e)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
return mpark::holds_alternative<StateEvent<Aliases>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<state::Avatar>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<CanonicalAlias>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Create>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<GuestAccess>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<HistoryVisibility>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<JoinRules>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Name>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Member>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<PowerLevels>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Topic>>(e);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool containsStateUpdates(const T &e)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
return mpark::holds_alternative<StateEvent<state::Avatar>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<CanonicalAlias>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Name>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Member>>(e) ||
|
||||
mpark::holds_alternative<StateEvent<Topic>>(e);
|
||||
}
|
||||
|
||||
bool containsStateUpdates(const mtx::events::collections::StrippedEvents &e)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
using namespace mtx::events::state;
|
||||
|
||||
return mpark::holds_alternative<StrippedEvent<state::Avatar>>(e) ||
|
||||
mpark::holds_alternative<StrippedEvent<CanonicalAlias>>(e) ||
|
||||
mpark::holds_alternative<StrippedEvent<Name>>(e) ||
|
||||
mpark::holds_alternative<StrippedEvent<Member>>(e) ||
|
||||
mpark::holds_alternative<StrippedEvent<Topic>>(e);
|
||||
}
|
||||
|
||||
void saveInvites(lmdb::txn &txn,
|
||||
const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
|
||||
|
||||
//! Sends signals for the rooms that are removed.
|
||||
void removeLeftRooms(lmdb::txn &txn,
|
||||
const std::map<std::string, mtx::responses::LeftRoom> &rooms)
|
||||
{
|
||||
for (const auto &room : rooms) {
|
||||
removeRoom(txn, room.first);
|
||||
|
||||
// Clean up leftover invites.
|
||||
removeInvite(txn, room.first);
|
||||
}
|
||||
}
|
||||
|
||||
lmdb::dbi getMessagesDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
auto db =
|
||||
lmdb::dbi::open(txn, std::string(room_id + "/messages").c_str(), MDB_CREATE);
|
||||
lmdb::dbi_set_compare(txn, db, numeric_key_comparison);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
lmdb::dbi getInviteStatesDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
return lmdb::dbi::open(
|
||||
txn, std::string(room_id + "/invite_state").c_str(), MDB_CREATE);
|
||||
}
|
||||
|
||||
lmdb::dbi getInviteMembersDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
return lmdb::dbi::open(
|
||||
txn, std::string(room_id + "/invite_members").c_str(), MDB_CREATE);
|
||||
}
|
||||
|
||||
lmdb::dbi getStatesDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE);
|
||||
}
|
||||
|
||||
lmdb::dbi getMembersDb(lmdb::txn &txn, const std::string &room_id)
|
||||
{
|
||||
return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), 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.
|
||||
//!
|
||||
//! Each entry is a map from the session_id to the pickled representation of the session.
|
||||
lmdb::dbi getOlmSessionsDb(lmdb::txn &txn, const std::string &curve25519_key)
|
||||
{
|
||||
return lmdb::dbi::open(
|
||||
txn, std::string("olm_sessions/" + curve25519_key).c_str(), MDB_CREATE);
|
||||
}
|
||||
|
||||
QString getDisplayName(const mtx::events::StateEvent<mtx::events::state::Member> &event)
|
||||
{
|
||||
if (!event.content.display_name.empty())
|
||||
return QString::fromStdString(event.content.display_name);
|
||||
|
||||
return QString::fromStdString(event.state_key);
|
||||
}
|
||||
|
||||
void setNextBatchToken(lmdb::txn &txn, const std::string &token);
|
||||
void setNextBatchToken(lmdb::txn &txn, const QString &token);
|
||||
|
||||
lmdb::env env_;
|
||||
lmdb::dbi syncStateDb_;
|
||||
lmdb::dbi roomsDb_;
|
||||
lmdb::dbi invitesDb_;
|
||||
lmdb::dbi mediaDb_;
|
||||
lmdb::dbi readReceiptsDb_;
|
||||
lmdb::dbi notificationsDb_;
|
||||
|
||||
lmdb::dbi devicesDb_;
|
||||
lmdb::dbi deviceKeysDb_;
|
||||
|
||||
lmdb::dbi inboundMegolmSessionDb_;
|
||||
lmdb::dbi outboundMegolmSessionDb_;
|
||||
|
||||
QString localUserId_;
|
||||
QString cacheDirectory_;
|
||||
};
|
||||
|
||||
namespace cache {
|
||||
void
|
||||
init(const QString &user_id);
|
||||
|
||||
Cache *
|
||||
client();
|
||||
}
|
||||
|
|
@ -23,22 +23,22 @@
|
|||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Olm.hpp"
|
||||
#include "OverlayModal.h"
|
||||
#include "Olm.h"
|
||||
#include "QuickSwitcher.h"
|
||||
#include "RoomList.h"
|
||||
#include "SideBarActions.h"
|
||||
#include "Splitter.h"
|
||||
#include "TextInputWidget.h"
|
||||
#include "Theme.h"
|
||||
#include "TopRoomBar.h"
|
||||
#include "TypingDisplay.h"
|
||||
#include "UserInfoWidget.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
#include "notifications/Manager.h"
|
||||
|
||||
268
src/ChatPage.h
Normal file
268
src/ChatPage.h
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "CommunitiesList.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "notifications/Manager.h"
|
||||
|
||||
class OverlayModal;
|
||||
class QuickSwitcher;
|
||||
class RoomList;
|
||||
class SideBarActions;
|
||||
class Splitter;
|
||||
class TextInputWidget;
|
||||
class TimelineViewManager;
|
||||
class TopRoomBar;
|
||||
class TypingDisplay;
|
||||
class UserInfoWidget;
|
||||
class UserSettings;
|
||||
class NotificationsManager;
|
||||
|
||||
namespace dialogs {
|
||||
class ReadReceipts;
|
||||
}
|
||||
|
||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
||||
|
||||
class ChatPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent = 0);
|
||||
|
||||
// Initialize all the components of the UI.
|
||||
void bootstrap(QString userid, QString homeserver, QString token);
|
||||
void showQuickSwitcher();
|
||||
void showReadReceipts(const QString &event_id);
|
||||
QString currentRoom() const { return current_room_; }
|
||||
|
||||
static ChatPage *instance() { return instance_; }
|
||||
|
||||
QSharedPointer<UserSettings> userSettings() { return userSettings_; }
|
||||
void deleteConfigs();
|
||||
|
||||
//! Calculate the width of the message timeline.
|
||||
int timelineWidth();
|
||||
bool isSideBarExpanded();
|
||||
//! Hide the room & group list (if it was visible).
|
||||
void hideSideBars();
|
||||
//! Show the room/group list (if it was visible).
|
||||
void showSideBars();
|
||||
|
||||
public slots:
|
||||
void leaveRoom(const QString &room_id);
|
||||
|
||||
signals:
|
||||
void connectionLost();
|
||||
void connectionRestored();
|
||||
|
||||
void messageReply(const QString &username, const QString &msg);
|
||||
|
||||
void notificationsRetrieved(const mtx::responses::Notifications &);
|
||||
|
||||
void uploadFailed(const QString &msg);
|
||||
void imageUploaded(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
qint64 dsize,
|
||||
const QSize &dimensions);
|
||||
void fileUploaded(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
qint64 dsize);
|
||||
void audioUploaded(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
qint64 dsize);
|
||||
void videoUploaded(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
qint64 dsize);
|
||||
|
||||
void contentLoaded();
|
||||
void closing();
|
||||
void changeWindowTitle(const QString &msg);
|
||||
void unreadMessages(int count);
|
||||
void showNotification(const QString &msg);
|
||||
void showLoginPage(const QString &msg);
|
||||
void showUserSettingsPage();
|
||||
void showOverlayProgressBar();
|
||||
|
||||
void removeTimelineEvent(const QString &room_id, const QString &event_id);
|
||||
|
||||
void ownProfileOk();
|
||||
void setUserDisplayName(const QString &name);
|
||||
void setUserAvatar(const QImage &avatar);
|
||||
void loggedOut();
|
||||
|
||||
void trySyncCb();
|
||||
void tryDelayedSyncCb();
|
||||
void tryInitialSyncCb();
|
||||
void leftRoom(const QString &room_id);
|
||||
|
||||
void initializeRoomList(QMap<QString, RoomInfo>);
|
||||
void initializeViews(const mtx::responses::Rooms &rooms);
|
||||
void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs);
|
||||
void syncUI(const mtx::responses::Rooms &rooms);
|
||||
void syncRoomlist(const std::map<QString, RoomInfo> &updates);
|
||||
void syncTopBar(const std::map<QString, RoomInfo> &updates);
|
||||
void dropToLoginPageCb(const QString &msg);
|
||||
|
||||
void notifyMessage(const QString &roomid,
|
||||
const QString &eventid,
|
||||
const QString &roomname,
|
||||
const QString &sender,
|
||||
const QString &message,
|
||||
const QImage &icon);
|
||||
|
||||
void updateGroupsInfo(const mtx::responses::JoinedGroups &groups);
|
||||
|
||||
private slots:
|
||||
void showUnreadMessageNotification(int count);
|
||||
void updateTopBarAvatar(const QString &roomid, const QPixmap &img);
|
||||
void changeTopRoomInfo(const QString &room_id);
|
||||
void logout();
|
||||
void removeRoom(const QString &room_id);
|
||||
void dropToLoginPage(const QString &msg);
|
||||
|
||||
void joinRoom(const QString &room);
|
||||
void createRoom(const mtx::requests::CreateRoom &req);
|
||||
void sendTypingNotifications();
|
||||
|
||||
private:
|
||||
static ChatPage *instance_;
|
||||
|
||||
//! Handler callback for initial sync. It doesn't run on the main thread so all
|
||||
//! communication with the GUI should be done through signals.
|
||||
void initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err);
|
||||
void tryInitialSync();
|
||||
void trySync();
|
||||
void ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts);
|
||||
void getProfileInfo();
|
||||
|
||||
//! Check if the given room is currently open.
|
||||
bool isRoomActive(const QString &room_id)
|
||||
{
|
||||
return isActiveWindow() && currentRoom() == room_id;
|
||||
}
|
||||
|
||||
using UserID = QString;
|
||||
using Membership = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||
using Memberships = std::map<std::string, Membership>;
|
||||
|
||||
using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>;
|
||||
void removeLeftRooms(const LeftRooms &rooms);
|
||||
|
||||
void updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids);
|
||||
|
||||
void loadStateFromCache();
|
||||
void resetUI();
|
||||
//! Decides whether or not to hide the group's sidebar.
|
||||
void setGroupViewState(bool isEnabled);
|
||||
|
||||
template<class Collection>
|
||||
Memberships getMemberships(const std::vector<Collection> &events) const;
|
||||
|
||||
//! Update the room with the new notification count.
|
||||
void updateRoomNotificationCount(const QString &room_id, uint16_t notification_count);
|
||||
//! Send desktop notification for the received messages.
|
||||
void sendDesktopNotifications(const mtx::responses::Notifications &);
|
||||
|
||||
QStringList generateTypingUsers(const QString &room_id,
|
||||
const std::vector<std::string> &typing_users);
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
Splitter *splitter;
|
||||
|
||||
QWidget *sideBar_;
|
||||
QVBoxLayout *sideBarLayout_;
|
||||
QWidget *sideBarTopWidget_;
|
||||
QVBoxLayout *sideBarTopWidgetLayout_;
|
||||
|
||||
QFrame *content_;
|
||||
QVBoxLayout *contentLayout_;
|
||||
|
||||
CommunitiesList *communitiesList_;
|
||||
RoomList *room_list_;
|
||||
|
||||
TimelineViewManager *view_manager_;
|
||||
SideBarActions *sidebarActions_;
|
||||
|
||||
TopRoomBar *top_bar_;
|
||||
TextInputWidget *text_input_;
|
||||
TypingDisplay *typingDisplay_;
|
||||
|
||||
QTimer connectivityTimer_;
|
||||
std::atomic_bool isConnected_;
|
||||
|
||||
QString current_room_;
|
||||
QString current_community_;
|
||||
|
||||
UserInfoWidget *user_info_widget_;
|
||||
|
||||
// Keeps track of the users currently typing on each room.
|
||||
std::map<QString, QList<QString>> typingUsers_;
|
||||
QTimer *typingRefresher_;
|
||||
|
||||
QSharedPointer<QuickSwitcher> quickSwitcher_;
|
||||
QSharedPointer<OverlayModal> quickSwitcherModal_;
|
||||
|
||||
QSharedPointer<dialogs::ReadReceipts> receiptsDialog_;
|
||||
QSharedPointer<OverlayModal> receiptsModal_;
|
||||
|
||||
// Global user settings.
|
||||
QSharedPointer<UserSettings> userSettings_;
|
||||
|
||||
NotificationsManager notificationsManager;
|
||||
};
|
||||
|
||||
template<class Collection>
|
||||
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>>
|
||||
ChatPage::getMemberships(const std::vector<Collection> &collection) const
|
||||
{
|
||||
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> memberships;
|
||||
|
||||
using Member = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||
|
||||
for (const auto &event : collection) {
|
||||
if (mpark::holds_alternative<Member>(event)) {
|
||||
auto member = mpark::get<Member>(event);
|
||||
memberships.emplace(member.state_key, member);
|
||||
}
|
||||
}
|
||||
|
||||
return memberships;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "CommunitiesList.h"
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
#include <QLabel>
|
||||
50
src/CommunitiesList.h
Normal file
50
src/CommunitiesList.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <QScrollArea>
|
||||
#include <QSharedPointer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "CommunitiesListItem.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
class CommunitiesList : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CommunitiesList(QWidget *parent = nullptr);
|
||||
|
||||
void clear() { communities_.clear(); }
|
||||
|
||||
void addCommunity(const std::string &id);
|
||||
void removeCommunity(const QString &id) { communities_.erase(id); };
|
||||
std::vector<QString> roomList(const QString &id) const;
|
||||
|
||||
signals:
|
||||
void communityChanged(const QString &id);
|
||||
void avatarRetrieved(const QString &id, const QPixmap &img);
|
||||
void groupProfileRetrieved(const QString &group_id, const mtx::responses::GroupProfile &);
|
||||
void groupRoomsRetrieved(const QString &group_id, const std::vector<QString> &res);
|
||||
|
||||
public slots:
|
||||
void updateCommunityAvatar(const QString &id, const QPixmap &img);
|
||||
void highlightSelectedCommunity(const QString &id);
|
||||
void setCommunities(const mtx::responses::JoinedGroups &groups);
|
||||
|
||||
private:
|
||||
void fetchCommunityAvatar(const QString &id, const QString &avatarUrl);
|
||||
void addGlobalItem() { addCommunity("world"); }
|
||||
|
||||
//! Check whether or not a community id is currently managed.
|
||||
bool communityExists(const QString &id) const
|
||||
{
|
||||
return communities_.find(id) != communities_.end();
|
||||
}
|
||||
|
||||
QVBoxLayout *topLayout_;
|
||||
QVBoxLayout *contentsLayout_;
|
||||
QWidget *scrollAreaContents_;
|
||||
QScrollArea *scrollArea_;
|
||||
|
||||
std::map<QString, QSharedPointer<CommunitiesListItem>> communities_;
|
||||
};
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "CommunitiesListItem.h"
|
||||
#include "Painter.h"
|
||||
#include "Ripple.h"
|
||||
#include "RippleOverlay.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Painter.h"
|
||||
#include "ui/Ripple.h"
|
||||
#include "ui/RippleOverlay.h"
|
||||
|
||||
CommunitiesListItem::CommunitiesListItem(QString group_id, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
88
src/CommunitiesListItem.h
Normal file
88
src/CommunitiesListItem.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include <mtx/responses/groups.hpp>
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
class RippleOverlay;
|
||||
|
||||
class CommunitiesListItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
|
||||
setHighlightedBackgroundColor)
|
||||
Q_PROPERTY(
|
||||
QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
|
||||
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
|
||||
|
||||
Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor)
|
||||
Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor)
|
||||
|
||||
public:
|
||||
CommunitiesListItem(QString group_id, QWidget *parent = nullptr);
|
||||
|
||||
void setName(QString name) { name_ = name; }
|
||||
bool isPressed() const { return isPressed_; }
|
||||
void setAvatar(const QImage &img);
|
||||
|
||||
void setRooms(std::vector<QString> room_ids) { room_ids_ = std::move(room_ids); }
|
||||
std::vector<QString> rooms() const { return room_ids_; }
|
||||
|
||||
QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
|
||||
QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
|
||||
QColor backgroundColor() const { return backgroundColor_; }
|
||||
|
||||
QColor avatarFgColor() const { return avatarFgColor_; }
|
||||
QColor avatarBgColor() const { return avatarBgColor_; }
|
||||
|
||||
void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
|
||||
void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
|
||||
void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
|
||||
|
||||
void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; }
|
||||
void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; }
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
return QSize(IconSize + IconSize / 3, IconSize + IconSize / 3);
|
||||
}
|
||||
|
||||
signals:
|
||||
void clicked(const QString &group_id);
|
||||
|
||||
public slots:
|
||||
void setPressedState(bool state);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
const int IconSize = 36;
|
||||
|
||||
QString resolveName() const;
|
||||
|
||||
std::vector<QString> room_ids_;
|
||||
|
||||
QString name_;
|
||||
QString groupId_;
|
||||
QPixmap avatar_;
|
||||
|
||||
QColor highlightedBackgroundColor_;
|
||||
QColor hoverBackgroundColor_;
|
||||
QColor backgroundColor_;
|
||||
|
||||
QColor avatarFgColor_;
|
||||
QColor avatarBgColor_;
|
||||
|
||||
bool isPressed_ = false;
|
||||
|
||||
RippleOverlay *rippleOverlay_;
|
||||
};
|
||||
106
src/Config.h
Normal file
106
src/Config.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
|
||||
// Non-theme app configuration. Layouts, fonts spacing etc.
|
||||
//
|
||||
// Font sizes are in pixels.
|
||||
|
||||
namespace conf {
|
||||
constexpr int sideBarCollapsePoint = 450;
|
||||
// Global settings.
|
||||
constexpr int fontSize = 14;
|
||||
constexpr int textInputFontSize = 14;
|
||||
constexpr int emojiSize = 14;
|
||||
constexpr int headerFontSize = 21;
|
||||
constexpr int typingNotificationFontSize = 11;
|
||||
|
||||
namespace popup {
|
||||
constexpr int font = fontSize;
|
||||
constexpr int avatar = 28;
|
||||
}
|
||||
|
||||
namespace modals {
|
||||
constexpr int errorFont = conf::fontSize - 2;
|
||||
}
|
||||
|
||||
namespace receipts {
|
||||
constexpr int font = 12;
|
||||
}
|
||||
|
||||
namespace dialogs {
|
||||
constexpr int labelSize = 15;
|
||||
}
|
||||
|
||||
namespace strings {
|
||||
const QString url_html = "<a href=\"\\1\">\\1</a>";
|
||||
const QRegExp url_regex(
|
||||
"((www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]\\)\\:])");
|
||||
}
|
||||
|
||||
// Window geometry.
|
||||
namespace window {
|
||||
constexpr int height = 600;
|
||||
constexpr int width = 1066;
|
||||
|
||||
constexpr int minHeight = height;
|
||||
constexpr int minWidth = 950;
|
||||
} // namespace window
|
||||
|
||||
namespace textInput {
|
||||
constexpr int height = 50;
|
||||
}
|
||||
|
||||
namespace sidebarActions {
|
||||
constexpr int height = textInput::height;
|
||||
constexpr int iconSize = 28;
|
||||
}
|
||||
|
||||
// Button settings.
|
||||
namespace btn {
|
||||
constexpr int fontSize = 20;
|
||||
constexpr int cornerRadius = 3;
|
||||
} // namespace btn
|
||||
|
||||
// RoomList specific.
|
||||
namespace roomlist {
|
||||
namespace fonts {
|
||||
constexpr int heading = 13;
|
||||
constexpr int timestamp = heading;
|
||||
constexpr int badge = 10;
|
||||
constexpr int bubble = 20;
|
||||
constexpr int communityBubble = bubble - 4;
|
||||
} // namespace fonts
|
||||
} // namespace roomlist
|
||||
|
||||
namespace userInfoWidget {
|
||||
namespace fonts {
|
||||
constexpr int displayName = 15;
|
||||
constexpr int userid = 13;
|
||||
} // namespace fonts
|
||||
} // namespace userInfoWidget
|
||||
|
||||
namespace topRoomBar {
|
||||
namespace fonts {
|
||||
constexpr int roomName = 15;
|
||||
constexpr int roomDescription = 14;
|
||||
} // namespace fonts
|
||||
} // namespace topRoomBar
|
||||
|
||||
namespace timeline {
|
||||
constexpr int msgAvatarTopMargin = 15;
|
||||
constexpr int msgTopMargin = 2;
|
||||
constexpr int msgLeftMargin = 14;
|
||||
constexpr int avatarSize = 36;
|
||||
constexpr int headerSpacing = 3;
|
||||
constexpr int headerLeftMargin = 15;
|
||||
|
||||
namespace fonts {
|
||||
constexpr int timestamp = 13;
|
||||
constexpr int indicator = timestamp - 2;
|
||||
constexpr int dateSeparator = conf::fontSize;
|
||||
} // namespace fonts
|
||||
} // namespace timeline
|
||||
|
||||
} // namespace conf
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include <QHBoxLayout>
|
||||
|
||||
#include "FlatButton.h"
|
||||
#include "InviteeItem.h"
|
||||
#include "Theme.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
constexpr int SidePadding = 10;
|
||||
constexpr int IconSize = 13;
|
||||
27
src/InviteeItem.h
Normal file
27
src/InviteeItem.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
|
||||
#include "mtx.hpp"
|
||||
|
||||
class FlatButton;
|
||||
|
||||
class InviteeItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InviteeItem(mtx::identifiers::User user, QWidget *parent = nullptr);
|
||||
|
||||
QString userID() { return user_; }
|
||||
|
||||
signals:
|
||||
void removeItem();
|
||||
|
||||
private:
|
||||
QString user_;
|
||||
|
||||
QLabel *name_;
|
||||
FlatButton *removeUserBtn_;
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <spdlog/sinks/file_sinks.h>
|
||||
|
|
|
|||
21
src/Logging.h
Normal file
21
src/Logging.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace nhlog {
|
||||
void
|
||||
init(const std::string &file);
|
||||
|
||||
std::shared_ptr<spdlog::logger>
|
||||
ui();
|
||||
|
||||
std::shared_ptr<spdlog::logger>
|
||||
net();
|
||||
|
||||
std::shared_ptr<spdlog::logger>
|
||||
db();
|
||||
|
||||
std::shared_ptr<spdlog::logger>
|
||||
crypto();
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@
|
|||
#include <mtx/identifiers.hpp>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "LoadingIndicator.h"
|
||||
#include "LoginPage.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "RaisedButton.h"
|
||||
#include "TextField.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/LoadingIndicator.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/RaisedButton.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
using namespace mtx::identifiers;
|
||||
|
||||
124
src/LoginPage.h
Normal file
124
src/LoginPage.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
class FlatButton;
|
||||
class LoadingIndicator;
|
||||
class OverlayModal;
|
||||
class RaisedButton;
|
||||
class TextField;
|
||||
|
||||
namespace mtx {
|
||||
namespace responses {
|
||||
struct Login;
|
||||
}
|
||||
}
|
||||
|
||||
class LoginPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LoginPage(QWidget *parent = 0);
|
||||
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void backButtonClicked();
|
||||
void loggingIn();
|
||||
void errorOccurred();
|
||||
|
||||
//! Used to trigger the corresponding slot outside of the main thread.
|
||||
void versionErrorCb(const QString &err);
|
||||
void loginErrorCb(const QString &err);
|
||||
void versionOkCb();
|
||||
|
||||
void loginOk(const mtx::responses::Login &res);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
public slots:
|
||||
// Displays errors produced during the login.
|
||||
void loginError(const QString &msg) { error_label_->setText(msg); }
|
||||
|
||||
private slots:
|
||||
// Callback for the back button.
|
||||
void onBackButtonClicked();
|
||||
|
||||
// Callback for the login button.
|
||||
void onLoginButtonClicked();
|
||||
|
||||
// Callback for probing the server found in the mxid
|
||||
void onMatrixIdEntered();
|
||||
|
||||
// Callback for probing the manually entered server
|
||||
void onServerAddressEntered();
|
||||
|
||||
// Callback for errors produced during server probing
|
||||
void versionError(const QString &error_message);
|
||||
// Callback for successful server probing
|
||||
void versionOk();
|
||||
|
||||
private:
|
||||
bool isMatrixIdValid();
|
||||
void checkHomeserverVersion();
|
||||
std::string initialDeviceName()
|
||||
{
|
||||
#if defined(Q_OS_MAC)
|
||||
return "nheko on macOS";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return "nheko on Linux";
|
||||
#elif defined(Q_OS_WIN)
|
||||
return "nheko on Windows";
|
||||
#else
|
||||
return "nheko";
|
||||
#endif
|
||||
}
|
||||
|
||||
QVBoxLayout *top_layout_;
|
||||
|
||||
QHBoxLayout *top_bar_layout_;
|
||||
QHBoxLayout *logo_layout_;
|
||||
QHBoxLayout *button_layout_;
|
||||
|
||||
QLabel *logo_;
|
||||
QLabel *error_label_;
|
||||
|
||||
QHBoxLayout *serverLayout_;
|
||||
QHBoxLayout *matrixidLayout_;
|
||||
LoadingIndicator *spinner_;
|
||||
QLabel *errorIcon_;
|
||||
QString inferredServerAddress_;
|
||||
|
||||
FlatButton *back_button_;
|
||||
RaisedButton *login_button_;
|
||||
|
||||
QWidget *form_widget_;
|
||||
QHBoxLayout *form_wrapper_;
|
||||
QVBoxLayout *form_layout_;
|
||||
|
||||
TextField *matrixid_input_;
|
||||
TextField *password_input_;
|
||||
TextField *serverInput_;
|
||||
};
|
||||
|
|
@ -24,25 +24,25 @@
|
|||
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "LoadingIndicator.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "LoginPage.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "RegisterPage.h"
|
||||
#include "SnackBar.h"
|
||||
#include "TrayIcon.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "WelcomePage.h"
|
||||
#include "ui/LoadingIndicator.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/SnackBar.h"
|
||||
|
||||
#include "dialogs/CreateRoom.h"
|
||||
#include "dialogs/InviteUsers.h"
|
||||
#include "dialogs/JoinRoom.h"
|
||||
#include "dialogs/LeaveRoom.h"
|
||||
#include "dialogs/Logout.h"
|
||||
#include "dialogs/MemberList.hpp"
|
||||
#include "dialogs/RoomSettings.hpp"
|
||||
#include "dialogs/MemberList.h"
|
||||
#include "dialogs/RoomSettings.h"
|
||||
|
||||
MainWindow *MainWindow::instance_ = nullptr;
|
||||
|
||||
174
src/MainWindow.h
Normal file
174
src/MainWindow.h
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QSharedPointer>
|
||||
#include <QStackedWidget>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include "LoginPage.h"
|
||||
#include "RegisterPage.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "WelcomePage.h"
|
||||
|
||||
class ChatPage;
|
||||
class LoadingIndicator;
|
||||
class OverlayModal;
|
||||
class SnackBar;
|
||||
class TrayIcon;
|
||||
class UserSettings;
|
||||
|
||||
namespace mtx {
|
||||
namespace requests {
|
||||
struct CreateRoom;
|
||||
}
|
||||
}
|
||||
|
||||
namespace dialogs {
|
||||
class CreateRoom;
|
||||
class InviteUsers;
|
||||
class JoinRoom;
|
||||
class LeaveRoom;
|
||||
class Logout;
|
||||
class MemberList;
|
||||
class ReCaptcha;
|
||||
class RoomSettings;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
|
||||
static MainWindow *instance() { return instance_; };
|
||||
void saveCurrentWindowSize();
|
||||
|
||||
void openLeaveRoomDialog(const QString &room_id = "");
|
||||
void openInviteUsersDialog(std::function<void(const QStringList &invitees)> callback);
|
||||
void openCreateRoomDialog(
|
||||
std::function<void(const mtx::requests::CreateRoom &request)> callback);
|
||||
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
|
||||
void openLogoutDialog(std::function<void()> callback);
|
||||
void openRoomSettings(const QString &room_id = "");
|
||||
void openMemberListDialog(const QString &room_id = "");
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private slots:
|
||||
//! Show or hide the sidebars based on window's size.
|
||||
void adjustSideBars();
|
||||
//! Handle interaction with the tray icon.
|
||||
void iconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
|
||||
//! Show the welcome page in the main window.
|
||||
void showWelcomePage()
|
||||
{
|
||||
removeOverlayProgressBar();
|
||||
pageStack_->addWidget(welcome_page_);
|
||||
pageStack_->setCurrentWidget(welcome_page_);
|
||||
}
|
||||
|
||||
//! Show the login page in the main window.
|
||||
void showLoginPage()
|
||||
{
|
||||
pageStack_->addWidget(login_page_);
|
||||
pageStack_->setCurrentWidget(login_page_);
|
||||
}
|
||||
|
||||
//! Show the register page in the main window.
|
||||
void showRegisterPage()
|
||||
{
|
||||
pageStack_->addWidget(register_page_);
|
||||
pageStack_->setCurrentWidget(register_page_);
|
||||
}
|
||||
|
||||
//! Show user settings page.
|
||||
void showUserSettingsPage() { pageStack_->setCurrentWidget(userSettingsPage_); }
|
||||
|
||||
//! Show the chat page and start communicating with the given access token.
|
||||
void showChatPage();
|
||||
|
||||
void showOverlayProgressBar();
|
||||
void removeOverlayProgressBar();
|
||||
|
||||
private:
|
||||
bool hasActiveUser();
|
||||
void restoreWindowSize();
|
||||
//! Check if there is an open dialog.
|
||||
bool hasActiveDialogs() const;
|
||||
//! Check if the current page supports the "minimize to tray" functionality.
|
||||
bool pageSupportsTray() const;
|
||||
|
||||
static MainWindow *instance_;
|
||||
|
||||
//! The initial welcome screen.
|
||||
WelcomePage *welcome_page_;
|
||||
//! The login screen.
|
||||
LoginPage *login_page_;
|
||||
//! The register page.
|
||||
RegisterPage *register_page_;
|
||||
//! A stacked widget that handles the transitions between widgets.
|
||||
QStackedWidget *pageStack_;
|
||||
//! The main chat area.
|
||||
ChatPage *chat_page_;
|
||||
UserSettingsPage *userSettingsPage_;
|
||||
QSharedPointer<UserSettings> userSettings_;
|
||||
//! Used to hide undefined states between page transitions.
|
||||
QSharedPointer<OverlayModal> progressModal_;
|
||||
QSharedPointer<LoadingIndicator> spinner_;
|
||||
//! Tray icon that shows the unread message count.
|
||||
TrayIcon *trayIcon_;
|
||||
//! Notifications display.
|
||||
QSharedPointer<SnackBar> snackBar_;
|
||||
//! Leave room modal.
|
||||
QSharedPointer<OverlayModal> leaveRoomModal_;
|
||||
//! Leave room dialog.
|
||||
QSharedPointer<dialogs::LeaveRoom> leaveRoomDialog_;
|
||||
//! Invite users modal.
|
||||
QSharedPointer<OverlayModal> inviteUsersModal_;
|
||||
//! Invite users dialog.
|
||||
QSharedPointer<dialogs::InviteUsers> inviteUsersDialog_;
|
||||
//! Join room modal.
|
||||
QSharedPointer<OverlayModal> joinRoomModal_;
|
||||
//! Join room dialog.
|
||||
QSharedPointer<dialogs::JoinRoom> joinRoomDialog_;
|
||||
//! Create room modal.
|
||||
QSharedPointer<OverlayModal> createRoomModal_;
|
||||
//! Create room dialog.
|
||||
QSharedPointer<dialogs::CreateRoom> createRoomDialog_;
|
||||
//! Logout modal.
|
||||
QSharedPointer<OverlayModal> logoutModal_;
|
||||
//! Logout dialog.
|
||||
QSharedPointer<dialogs::Logout> logoutDialog_;
|
||||
//! Room settings modal.
|
||||
QSharedPointer<OverlayModal> roomSettingsModal_;
|
||||
//! Room settings dialog.
|
||||
QSharedPointer<dialogs::RoomSettings> roomSettingsDialog_;
|
||||
//! Member list modal.
|
||||
QSharedPointer<OverlayModal> memberListModal_;
|
||||
//! Member list dialog.
|
||||
QSharedPointer<dialogs::MemberList> memberListDialog_;
|
||||
};
|
||||
30
src/MatrixClient.h
Normal file
30
src/MatrixClient.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
|
||||
#include <mtx/responses.hpp>
|
||||
#include <mtxclient/http/client.hpp>
|
||||
|
||||
Q_DECLARE_METATYPE(mtx::responses::Login)
|
||||
Q_DECLARE_METATYPE(mtx::responses::Messages)
|
||||
Q_DECLARE_METATYPE(mtx::responses::Notifications)
|
||||
Q_DECLARE_METATYPE(mtx::responses::Rooms)
|
||||
Q_DECLARE_METATYPE(mtx::responses::Sync)
|
||||
Q_DECLARE_METATYPE(mtx::responses::JoinedGroups)
|
||||
Q_DECLARE_METATYPE(mtx::responses::GroupProfile)
|
||||
Q_DECLARE_METATYPE(std::string)
|
||||
Q_DECLARE_METATYPE(std::vector<std::string>)
|
||||
Q_DECLARE_METATYPE(std::vector<QString>)
|
||||
|
||||
namespace http {
|
||||
mtx::http::Client *
|
||||
client();
|
||||
|
||||
bool
|
||||
is_logged_in();
|
||||
|
||||
//! Initialize the http module
|
||||
void
|
||||
init();
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "Olm.hpp"
|
||||
#include "Olm.h"
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
using namespace mtx::crypto;
|
||||
|
|
|
|||
86
src/Olm.h
Normal file
86
src/Olm.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <mtx.hpp>
|
||||
#include <mtxclient/crypto/client.hpp>
|
||||
|
||||
constexpr auto OLM_ALGO = "m.olm.v1.curve25519-aes-sha2";
|
||||
|
||||
namespace olm {
|
||||
|
||||
struct OlmMessage
|
||||
{
|
||||
std::string sender_key;
|
||||
std::string sender;
|
||||
|
||||
using RecipientKey = std::string;
|
||||
std::map<RecipientKey, mtx::events::msg::OlmCipherContent> ciphertext;
|
||||
};
|
||||
|
||||
inline void
|
||||
from_json(const nlohmann::json &obj, OlmMessage &msg)
|
||||
{
|
||||
if (obj.at("type") != "m.room.encrypted")
|
||||
throw std::invalid_argument("invalid type for olm message");
|
||||
|
||||
if (obj.at("content").at("algorithm") != OLM_ALGO)
|
||||
throw std::invalid_argument("invalid algorithm for olm message");
|
||||
|
||||
msg.sender = obj.at("sender");
|
||||
msg.sender_key = obj.at("content").at("sender_key");
|
||||
msg.ciphertext = obj.at("content")
|
||||
.at("ciphertext")
|
||||
.get<std::map<std::string, mtx::events::msg::OlmCipherContent>>();
|
||||
}
|
||||
|
||||
mtx::crypto::OlmClient *
|
||||
client();
|
||||
|
||||
void
|
||||
handle_to_device_messages(const std::vector<nlohmann::json> &msgs);
|
||||
|
||||
nlohmann::json
|
||||
try_olm_decryption(const std::string &sender_key,
|
||||
const mtx::events::msg::OlmCipherContent &content);
|
||||
|
||||
void
|
||||
handle_olm_message(const OlmMessage &msg);
|
||||
|
||||
//! Establish a new inbound megolm session with the decrypted payload from olm.
|
||||
void
|
||||
create_inbound_megolm_session(const std::string &sender,
|
||||
const std::string &sender_key,
|
||||
const nlohmann::json &payload);
|
||||
|
||||
void
|
||||
handle_pre_key_olm_message(const std::string &sender,
|
||||
const std::string &sender_key,
|
||||
const mtx::events::msg::OlmCipherContent &content);
|
||||
|
||||
mtx::events::msg::Encrypted
|
||||
encrypt_group_message(const std::string &room_id,
|
||||
const std::string &device_id,
|
||||
const std::string &body);
|
||||
|
||||
void
|
||||
mark_keys_as_published();
|
||||
|
||||
//! Request the encryption keys from sender's device for the given event.
|
||||
void
|
||||
request_keys(const std::string &room_id, const std::string &event_id);
|
||||
|
||||
void
|
||||
send_key_request_for(const std::string &room_id,
|
||||
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &);
|
||||
|
||||
void
|
||||
handle_key_request_message(const mtx::events::msg::KeyRequest &);
|
||||
|
||||
void
|
||||
send_megolm_key_to_device(const std::string &user_id,
|
||||
const std::string &device_id,
|
||||
const json &payload);
|
||||
|
||||
} // namespace olm
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <QtConcurrent>
|
||||
|
||||
#include "QuickSwitcher.h"
|
||||
#include "SuggestionsPopup.h"
|
||||
|
||||
RoomSearchInput::RoomSearchInput(QWidget *parent)
|
||||
: TextField(parent)
|
||||
79
src/QuickSwitcher.h
Normal file
79
src/QuickSwitcher.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QKeyEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "SuggestionsPopup.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
Q_DECLARE_METATYPE(std::vector<RoomSearchResult>)
|
||||
|
||||
class RoomSearchInput : public TextField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RoomSearchInput(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void selectNextCompletion();
|
||||
void selectPreviousCompletion();
|
||||
void hiding();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
bool focusNextPrevChild(bool) override { return false; };
|
||||
};
|
||||
|
||||
class QuickSwitcher : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QuickSwitcher(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void closing();
|
||||
void roomSelected(const QString &roomid);
|
||||
void queryResults(const std::vector<RoomSearchResult> &rooms);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void showEvent(QShowEvent *) override { roomSearch_->setFocus(); }
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void reset()
|
||||
{
|
||||
emit closing();
|
||||
roomSearch_->clear();
|
||||
}
|
||||
|
||||
// Current highlighted selection from the completer.
|
||||
int selection_ = -1;
|
||||
|
||||
QVBoxLayout *topLayout_;
|
||||
RoomSearchInput *roomSearch_;
|
||||
|
||||
//! Autocomplete popup box with the room suggestions.
|
||||
SuggestionsPopup popup_;
|
||||
};
|
||||
|
|
@ -19,15 +19,15 @@
|
|||
#include <QTimer>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "RaisedButton.h"
|
||||
#include "RegisterPage.h"
|
||||
#include "TextField.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/RaisedButton.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
#include "dialogs/ReCaptcha.hpp"
|
||||
#include "dialogs/ReCaptcha.h"
|
||||
|
||||
RegisterPage::RegisterPage(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
84
src/RegisterPage.h
Normal file
84
src/RegisterPage.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QSharedPointer>
|
||||
#include <memory>
|
||||
|
||||
class FlatButton;
|
||||
class RaisedButton;
|
||||
class TextField;
|
||||
|
||||
namespace dialogs {
|
||||
class ReCaptcha;
|
||||
}
|
||||
|
||||
class RegisterPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RegisterPage(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void backButtonClicked();
|
||||
void errorOccurred();
|
||||
void registering();
|
||||
void registerOk();
|
||||
void registerErrorCb(const QString &msg);
|
||||
void registrationFlow(const std::string &user,
|
||||
const std::string &pass,
|
||||
const std::string &session);
|
||||
|
||||
private slots:
|
||||
void onBackButtonClicked();
|
||||
void onRegisterButtonClicked();
|
||||
|
||||
// Display registration specific errors to the user.
|
||||
void registerError(const QString &msg);
|
||||
|
||||
private:
|
||||
QVBoxLayout *top_layout_;
|
||||
|
||||
QHBoxLayout *back_layout_;
|
||||
QHBoxLayout *logo_layout_;
|
||||
QHBoxLayout *button_layout_;
|
||||
|
||||
QLabel *logo_;
|
||||
QLabel *error_label_;
|
||||
|
||||
FlatButton *back_button_;
|
||||
RaisedButton *register_button_;
|
||||
|
||||
QWidget *form_widget_;
|
||||
QHBoxLayout *form_wrapper_;
|
||||
QVBoxLayout *form_layout_;
|
||||
|
||||
TextField *username_input_;
|
||||
TextField *password_input_;
|
||||
TextField *password_confirmation_;
|
||||
TextField *server_input_;
|
||||
|
||||
//! ReCaptcha dialog.
|
||||
std::shared_ptr<dialogs::ReCaptcha> captchaDialog_;
|
||||
};
|
||||
|
|
@ -24,12 +24,12 @@
|
|||
|
||||
#include "Cache.h"
|
||||
#include "Config.h"
|
||||
#include "Menu.h"
|
||||
#include "Ripple.h"
|
||||
#include "RippleOverlay.h"
|
||||
#include "RoomInfoListItem.h"
|
||||
#include "Theme.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Menu.h"
|
||||
#include "ui/Ripple.h"
|
||||
#include "ui/RippleOverlay.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
constexpr int MaxUnreadCountDisplayed = 99;
|
||||
|
||||
204
src/RoomInfoListItem.h
Normal file
204
src/RoomInfoListItem.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QDateTime>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Cache.h"
|
||||
#include <mtx/responses.hpp>
|
||||
|
||||
class Menu;
|
||||
class RippleOverlay;
|
||||
|
||||
class RoomInfoListItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
|
||||
setHighlightedBackgroundColor)
|
||||
Q_PROPERTY(
|
||||
QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
|
||||
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
|
||||
|
||||
Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor)
|
||||
Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor)
|
||||
|
||||
Q_PROPERTY(QColor bubbleBgColor READ bubbleBgColor WRITE setBubbleBgColor)
|
||||
Q_PROPERTY(QColor bubbleFgColor READ bubbleFgColor WRITE setBubbleFgColor)
|
||||
|
||||
Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor)
|
||||
Q_PROPERTY(QColor subtitleColor READ subtitleColor WRITE setSubtitleColor)
|
||||
|
||||
Q_PROPERTY(QColor timestampColor READ timestampColor WRITE setTimestampColor)
|
||||
Q_PROPERTY(QColor highlightedTimestampColor READ highlightedTimestampColor WRITE
|
||||
setHighlightedTimestampColor)
|
||||
|
||||
Q_PROPERTY(
|
||||
QColor highlightedTitleColor READ highlightedTitleColor WRITE setHighlightedTitleColor)
|
||||
Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
|
||||
setHighlightedSubtitleColor)
|
||||
|
||||
Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
|
||||
Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
|
||||
|
||||
public:
|
||||
RoomInfoListItem(QString room_id, RoomInfo info, QWidget *parent = 0);
|
||||
|
||||
void updateUnreadMessageCount(int count);
|
||||
void clearUnreadMessageCount() { updateUnreadMessageCount(0); };
|
||||
|
||||
QString roomId() { return roomId_; }
|
||||
bool isPressed() const { return isPressed_; }
|
||||
int unreadMessageCount() const { return unreadMsgCount_; }
|
||||
|
||||
void setAvatar(const QImage &avatar_image);
|
||||
void setDescriptionMessage(const DescInfo &info);
|
||||
DescInfo lastMessageInfo() const { return lastMsgInfo_; }
|
||||
|
||||
QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
|
||||
QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
|
||||
QColor backgroundColor() const { return backgroundColor_; }
|
||||
QColor avatarBgColor() const { return avatarBgColor_; }
|
||||
QColor avatarFgColor() const { return avatarFgColor_; }
|
||||
|
||||
QColor highlightedTitleColor() const { return highlightedTitleColor_; }
|
||||
QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
|
||||
QColor highlightedTimestampColor() const { return highlightedTimestampColor_; }
|
||||
|
||||
QColor titleColor() const { return titleColor_; }
|
||||
QColor subtitleColor() const { return subtitleColor_; }
|
||||
QColor timestampColor() const { return timestampColor_; }
|
||||
QColor btnColor() const { return btnColor_; }
|
||||
QColor btnTextColor() const { return btnTextColor_; }
|
||||
|
||||
QColor bubbleFgColor() const { return bubbleFgColor_; }
|
||||
QColor bubbleBgColor() const { return bubbleBgColor_; }
|
||||
|
||||
void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
|
||||
void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
|
||||
void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
|
||||
void setTimestampColor(QColor &color) { timestampColor_ = color; }
|
||||
void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; }
|
||||
void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; }
|
||||
|
||||
void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
|
||||
void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
|
||||
void setHighlightedTimestampColor(QColor &color) { highlightedTimestampColor_ = color; }
|
||||
|
||||
void setTitleColor(QColor &color) { titleColor_ = color; }
|
||||
void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
|
||||
|
||||
void setBtnColor(QColor &color) { btnColor_ = color; }
|
||||
void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
|
||||
|
||||
void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; }
|
||||
void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; }
|
||||
|
||||
void setRoomName(const QString &name) { roomName_ = name; }
|
||||
void setRoomType(bool isInvite)
|
||||
{
|
||||
if (isInvite)
|
||||
roomType_ = RoomType::Invited;
|
||||
else
|
||||
roomType_ = RoomType::Joined;
|
||||
}
|
||||
|
||||
bool isInvite() { return roomType_ == RoomType::Invited; }
|
||||
|
||||
signals:
|
||||
void clicked(const QString &room_id);
|
||||
void leaveRoom(const QString &room_id);
|
||||
void acceptInvite(const QString &room_id);
|
||||
void declineInvite(const QString &room_id);
|
||||
|
||||
public slots:
|
||||
void setPressedState(bool state);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
||||
private:
|
||||
void init(QWidget *parent);
|
||||
QString roomName() { return roomName_; }
|
||||
|
||||
RippleOverlay *ripple_overlay_;
|
||||
|
||||
enum class RoomType
|
||||
{
|
||||
Joined,
|
||||
Invited,
|
||||
};
|
||||
|
||||
RoomType roomType_ = RoomType::Joined;
|
||||
|
||||
// State information for the invited rooms.
|
||||
mtx::responses::InvitedRoom invitedRoom_;
|
||||
|
||||
QString roomId_;
|
||||
QString roomName_;
|
||||
|
||||
DescInfo lastMsgInfo_;
|
||||
|
||||
QPixmap roomAvatar_;
|
||||
|
||||
Menu *menu_;
|
||||
QAction *leaveRoom_;
|
||||
|
||||
bool isPressed_ = false;
|
||||
|
||||
int unreadMsgCount_ = 0;
|
||||
|
||||
QColor highlightedBackgroundColor_;
|
||||
QColor hoverBackgroundColor_;
|
||||
QColor backgroundColor_;
|
||||
|
||||
QColor highlightedTitleColor_;
|
||||
QColor highlightedSubtitleColor_;
|
||||
|
||||
QColor titleColor_;
|
||||
QColor subtitleColor_;
|
||||
|
||||
QColor btnColor_;
|
||||
QColor btnTextColor_;
|
||||
|
||||
QRectF acceptBtnRegion_;
|
||||
QRectF declineBtnRegion_;
|
||||
|
||||
// Fonts
|
||||
QFont bubbleFont_;
|
||||
QFont font_;
|
||||
QFont headingFont_;
|
||||
QFont timestampFont_;
|
||||
QFont usernameFont_;
|
||||
QFont unreadCountFont_;
|
||||
int bubbleDiameter_;
|
||||
|
||||
QColor timestampColor_;
|
||||
QColor highlightedTimestampColor_;
|
||||
|
||||
QColor avatarBgColor_;
|
||||
QColor avatarFgColor_;
|
||||
|
||||
QColor bubbleBgColor_;
|
||||
QColor bubbleFgColor_;
|
||||
};
|
||||
|
|
@ -21,14 +21,14 @@
|
|||
#include <QTimer>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "RoomInfoListItem.h"
|
||||
#include "RoomList.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
|
||||
RoomList::RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
108
src/RoomList.h
Normal file
108
src/RoomList.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QSharedPointer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include <mtx.hpp>
|
||||
|
||||
class LeaveRoomDialog;
|
||||
class OverlayModal;
|
||||
class RoomInfoListItem;
|
||||
class Sync;
|
||||
class UserSettings;
|
||||
struct DescInfo;
|
||||
struct RoomInfo;
|
||||
|
||||
class RoomList : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent = 0);
|
||||
|
||||
void initialize(const QMap<QString, RoomInfo> &info);
|
||||
void sync(const std::map<QString, RoomInfo> &info);
|
||||
|
||||
void clear() { rooms_.clear(); };
|
||||
void updateAvatar(const QString &room_id, const QString &url);
|
||||
|
||||
void addRoom(const QString &room_id, const RoomInfo &info);
|
||||
void addInvitedRoom(const QString &room_id, const RoomInfo &info);
|
||||
void removeRoom(const QString &room_id, bool reset);
|
||||
void setFilterRooms(bool filterRooms);
|
||||
void setRoomFilter(std::vector<QString> room_ids);
|
||||
void updateRoom(const QString &room_id, const RoomInfo &info);
|
||||
void cleanupInvites(const std::map<QString, bool> &invites);
|
||||
|
||||
signals:
|
||||
void roomChanged(const QString &room_id);
|
||||
void totalUnreadMessageCountUpdated(int count);
|
||||
void acceptInvite(const QString &room_id);
|
||||
void declineInvite(const QString &room_id);
|
||||
void roomAvatarChanged(const QString &room_id, const QPixmap &img);
|
||||
void joinRoom(const QString &room_id);
|
||||
void updateRoomAvatarCb(const QString &room_id, const QPixmap &img);
|
||||
|
||||
public slots:
|
||||
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
|
||||
void highlightSelectedRoom(const QString &room_id);
|
||||
void updateUnreadMessageCount(const QString &roomid, int count);
|
||||
void updateRoomDescription(const QString &roomid, const DescInfo &info);
|
||||
void closeJoinRoomDialog(bool isJoining, QString roomAlias);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void sortRoomsByLastMessage();
|
||||
|
||||
private:
|
||||
//! Return the first non-null room.
|
||||
std::pair<QString, QSharedPointer<RoomInfoListItem>> firstRoom() const;
|
||||
void calculateUnreadMessageCount();
|
||||
bool roomExists(const QString &room_id) { return rooms_.find(room_id) != rooms_.end(); }
|
||||
bool filterItemExists(const QString &id)
|
||||
{
|
||||
return std::find(roomFilter_.begin(), roomFilter_.end(), id) != roomFilter_.end();
|
||||
}
|
||||
|
||||
QVBoxLayout *topLayout_;
|
||||
QVBoxLayout *contentsLayout_;
|
||||
QScrollArea *scrollArea_;
|
||||
QWidget *scrollAreaContents_;
|
||||
|
||||
QPushButton *joinRoomButton_;
|
||||
|
||||
OverlayModal *joinRoomModal_;
|
||||
|
||||
std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_;
|
||||
QString selectedRoom_;
|
||||
|
||||
//! Which rooms to include in the room list.
|
||||
std::vector<QString> roomFilter_;
|
||||
|
||||
QSharedPointer<UserSettings> userSettings_;
|
||||
|
||||
bool isSortPending_ = false;
|
||||
};
|
||||
31
src/RunGuard.h
Normal file
31
src/RunGuard.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
//
|
||||
// Taken from
|
||||
// https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection
|
||||
//
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedMemory>
|
||||
#include <QSystemSemaphore>
|
||||
|
||||
class RunGuard
|
||||
{
|
||||
public:
|
||||
RunGuard(const QString &key);
|
||||
~RunGuard();
|
||||
|
||||
bool isAnotherRunning();
|
||||
bool tryToRun();
|
||||
void release();
|
||||
|
||||
private:
|
||||
const QString key;
|
||||
const QString memLockKey;
|
||||
const QString sharedmemKey;
|
||||
|
||||
QSharedMemory sharedMem;
|
||||
QSystemSemaphore memLock;
|
||||
|
||||
Q_DISABLE_COPY(RunGuard)
|
||||
};
|
||||
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
#include "Config.h"
|
||||
#include "MainWindow.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "SideBarActions.h"
|
||||
#include "Theme.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Menu.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
SideBarActions::SideBarActions(QWidget *parent)
|
||||
: QWidget{parent}
|
||||
50
src/SideBarActions.h
Normal file
50
src/SideBarActions.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QHBoxLayout>
|
||||
#include <QResizeEvent>
|
||||
#include <QWidget>
|
||||
|
||||
namespace mtx {
|
||||
namespace requests {
|
||||
struct CreateRoom;
|
||||
}
|
||||
}
|
||||
|
||||
class Menu;
|
||||
class FlatButton;
|
||||
|
||||
class SideBarActions : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
|
||||
|
||||
public:
|
||||
SideBarActions(QWidget *parent = nullptr);
|
||||
|
||||
QColor borderColor() const { return borderColor_; }
|
||||
void setBorderColor(QColor &color) { borderColor_ = color; }
|
||||
|
||||
signals:
|
||||
void showSettings();
|
||||
void joinRoom(const QString &room);
|
||||
void createRoom(const mtx::requests::CreateRoom &request);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout_;
|
||||
|
||||
Menu *addMenu_;
|
||||
QAction *createRoomAction_;
|
||||
QAction *joinRoomAction_;
|
||||
|
||||
FlatButton *settingsBtn_;
|
||||
FlatButton *createRoomBtn_;
|
||||
FlatButton *joinRoomBtn_;
|
||||
|
||||
QColor borderColor_;
|
||||
};
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include "Config.h"
|
||||
#include "Splitter.h"
|
||||
#include "Theme.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
constexpr auto MaxWidth = (1 << 24) - 1;
|
||||
|
||||
46
src/Splitter.h
Normal file
46
src/Splitter.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSplitter>
|
||||
|
||||
class Splitter : public QSplitter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Splitter(QWidget *parent = nullptr);
|
||||
~Splitter();
|
||||
|
||||
void restoreSizes(int fallback);
|
||||
|
||||
public slots:
|
||||
void hideSidebar();
|
||||
void showFullRoomList();
|
||||
void showChatView();
|
||||
|
||||
signals:
|
||||
void hiddenSidebar();
|
||||
|
||||
private:
|
||||
void onSplitterMoved(int pos, int index);
|
||||
|
||||
int moveEventLimit_ = 50;
|
||||
|
||||
int leftMoveCount_ = 0;
|
||||
int rightMoveCount_ = 0;
|
||||
};
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
#include "Avatar.h"
|
||||
#include "AvatarProvider.h"
|
||||
#include "Config.h"
|
||||
#include "DropShadow.h"
|
||||
#include "SuggestionsPopup.hpp"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
#include "Config.h"
|
||||
#include "SuggestionsPopup.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/DropShadow.h"
|
||||
|
||||
constexpr int PopupHMargin = 4;
|
||||
constexpr int PopupItemMargin = 3;
|
||||
|
||||
|
|
|
|||
147
src/SuggestionsPopup.h
Normal file
147
src/SuggestionsPopup.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#pragma once
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPoint>
|
||||
#include <QWidget>
|
||||
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
|
||||
class Avatar;
|
||||
struct SearchResult;
|
||||
|
||||
class PopupItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor)
|
||||
Q_PROPERTY(bool hovering READ hovering WRITE setHovering)
|
||||
|
||||
public:
|
||||
PopupItem(QWidget *parent);
|
||||
|
||||
QString selectedText() const { return QString(); }
|
||||
QColor hoverColor() const { return hoverColor_; }
|
||||
void setHoverColor(QColor &color) { hoverColor_ = color; }
|
||||
|
||||
bool hovering() const { return hovering_; }
|
||||
void setHovering(const bool hover) { hovering_ = hover; };
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void clicked(const QString &text);
|
||||
|
||||
protected:
|
||||
QHBoxLayout *topLayout_;
|
||||
Avatar *avatar_;
|
||||
QColor hoverColor_;
|
||||
|
||||
//! Set if the item is currently being
|
||||
//! hovered during tab completion (cycling).
|
||||
bool hovering_;
|
||||
};
|
||||
|
||||
class UserItem : public PopupItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserItem(QWidget *parent, const QString &user_id);
|
||||
QString selectedText() const { return userId_; }
|
||||
void updateItem(const QString &user_id);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
void resolveAvatar(const QString &user_id);
|
||||
|
||||
QLabel *userName_;
|
||||
QString userId_;
|
||||
};
|
||||
|
||||
class RoomItem : public PopupItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RoomItem(QWidget *parent, const RoomSearchResult &res);
|
||||
QString selectedText() const { return roomId_; }
|
||||
void updateItem(const RoomSearchResult &res);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
QLabel *roomName_;
|
||||
QString roomId_;
|
||||
RoomSearchResult info_;
|
||||
};
|
||||
|
||||
class SuggestionsPopup : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SuggestionsPopup(QWidget *parent = nullptr);
|
||||
|
||||
template<class Item>
|
||||
void selectHoveredSuggestion()
|
||||
{
|
||||
const auto item = layout_->itemAt(selectedItem_);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
const auto &widget = qobject_cast<Item *>(item->widget());
|
||||
emit itemSelected(
|
||||
Cache::displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
|
||||
|
||||
resetSelection();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void addUsers(const QVector<SearchResult> &users);
|
||||
void addRooms(const std::vector<RoomSearchResult> &rooms);
|
||||
|
||||
//! Move to the next available suggestion item.
|
||||
void selectNextSuggestion();
|
||||
//! Move to the previous available suggestion item.
|
||||
void selectPreviousSuggestion();
|
||||
//! Remove hovering from all items.
|
||||
void resetHovering();
|
||||
//! Set hovering to the item in the given layout position.
|
||||
void setHovering(int pos);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void itemSelected(const QString &user);
|
||||
|
||||
private:
|
||||
void hoverSelection();
|
||||
void resetSelection() { selectedItem_ = -1; }
|
||||
void selectFirstItem() { selectedItem_ = 0; }
|
||||
void selectLastItem() { selectedItem_ = layout_->count() - 1; }
|
||||
void removeLayoutItemsAfter(size_t startingPos)
|
||||
{
|
||||
size_t posToRemove = layout_->count() - 1;
|
||||
|
||||
QLayoutItem *item;
|
||||
while (startingPos <= posToRemove && (item = layout_->takeAt(posToRemove)) != 0) {
|
||||
delete item->widget();
|
||||
delete item;
|
||||
|
||||
posToRemove = layout_->count() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
QVBoxLayout *layout_;
|
||||
|
||||
//! Counter for tab completion (cycling).
|
||||
int selectedItem_ = -1;
|
||||
};
|
||||
|
|
@ -36,6 +36,8 @@
|
|||
#include "Config.h"
|
||||
#include "TextInputWidget.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/LoadingIndicator.h"
|
||||
|
||||
static constexpr size_t INPUT_HISTORY_SIZE = 127;
|
||||
static constexpr int MAX_TEXTINPUT_HEIGHT = 120;
|
||||
183
src/TextInputWidget.h
Normal file
183
src/TextInputWidget.h
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPaintEvent>
|
||||
#include <QTextEdit>
|
||||
#include <QWidget>
|
||||
|
||||
#include "SuggestionsPopup.h"
|
||||
#include "dialogs/PreviewUploadOverlay.h"
|
||||
#include "emoji/PickButton.h"
|
||||
|
||||
namespace dialogs {
|
||||
class PreviewUploadOverlay;
|
||||
}
|
||||
|
||||
struct SearchResult;
|
||||
|
||||
class FlatButton;
|
||||
class LoadingIndicator;
|
||||
|
||||
class FilteredTextEdit : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilteredTextEdit(QWidget *parent = nullptr);
|
||||
|
||||
void stopTyping();
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
void submit();
|
||||
|
||||
signals:
|
||||
void heightChanged(int height);
|
||||
void startedTyping();
|
||||
void stoppedTyping();
|
||||
void startedUpload();
|
||||
void message(QString);
|
||||
void command(QString name, QString args);
|
||||
void image(QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void audio(QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void video(QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void file(QSharedPointer<QIODevice> data, const QString &filename);
|
||||
|
||||
//! Trigger the suggestion popup.
|
||||
void showSuggestions(const QString &query);
|
||||
void resultsRetrieved(const QVector<SearchResult> &results);
|
||||
void selectNextSuggestion();
|
||||
void selectPreviousSuggestion();
|
||||
void selectHoveredSuggestion();
|
||||
|
||||
public slots:
|
||||
void showResults(const QVector<SearchResult> &results);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
bool canInsertFromMimeData(const QMimeData *source) const override;
|
||||
void insertFromMimeData(const QMimeData *source) override;
|
||||
void focusOutEvent(QFocusEvent *event) override
|
||||
{
|
||||
popup_.hide();
|
||||
QTextEdit::focusOutEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
std::deque<QString> true_history_, working_history_;
|
||||
size_t history_index_;
|
||||
QTimer *typingTimer_;
|
||||
|
||||
SuggestionsPopup popup_;
|
||||
|
||||
void closeSuggestions() { popup_.hide(); }
|
||||
void resetAnchor() { atTriggerPosition_ = -1; }
|
||||
|
||||
QString query()
|
||||
{
|
||||
auto cursor = textCursor();
|
||||
cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
|
||||
return cursor.selectedText();
|
||||
}
|
||||
|
||||
dialogs::PreviewUploadOverlay previewDialog_;
|
||||
|
||||
//! Latest position of the '@' character that triggers the username completer.
|
||||
int atTriggerPosition_ = -1;
|
||||
|
||||
void textChanged();
|
||||
void uploadData(const QByteArray data, const QString &media, const QString &filename);
|
||||
void afterCompletion(int);
|
||||
void showPreview(const QMimeData *source, const QStringList &formats);
|
||||
};
|
||||
|
||||
class TextInputWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
|
||||
|
||||
public:
|
||||
TextInputWidget(QWidget *parent = 0);
|
||||
|
||||
void stopTyping();
|
||||
|
||||
QColor borderColor() const { return borderColor_; }
|
||||
void setBorderColor(QColor &color) { borderColor_ = color; }
|
||||
void disableInput()
|
||||
{
|
||||
input_->setEnabled(false);
|
||||
input_->setPlaceholderText(tr("Connection lost. Nheko is trying to re-connect..."));
|
||||
}
|
||||
void enableInput()
|
||||
{
|
||||
input_->setEnabled(true);
|
||||
input_->setPlaceholderText(tr("Write a message..."));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void openFileSelection();
|
||||
void hideUploadSpinner();
|
||||
void focusLineEdit() { input_->setFocus(); }
|
||||
void addReply(const QString &username, const QString &msg);
|
||||
|
||||
private slots:
|
||||
void addSelectedEmoji(const QString &emoji);
|
||||
|
||||
signals:
|
||||
void sendTextMessage(QString msg);
|
||||
void sendEmoteMessage(QString msg);
|
||||
|
||||
void uploadImage(const QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void uploadFile(const QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void uploadAudio(const QSharedPointer<QIODevice> data, const QString &filename);
|
||||
void uploadVideo(const QSharedPointer<QIODevice> data, const QString &filename);
|
||||
|
||||
void sendJoinRoomRequest(const QString &room);
|
||||
|
||||
void startedTyping();
|
||||
void stoppedTyping();
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *event) override;
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
void showUploadSpinner();
|
||||
void command(QString name, QString args);
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
FilteredTextEdit *input_;
|
||||
|
||||
LoadingIndicator *spinner_;
|
||||
|
||||
FlatButton *sendFileBtn_;
|
||||
FlatButton *sendMessageBtn_;
|
||||
emoji::PickButton *emojiBtn_;
|
||||
|
||||
QColor borderColor_;
|
||||
};
|
||||
|
|
@ -18,14 +18,14 @@
|
|||
#include <QDebug>
|
||||
#include <QStyleOption>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "TopRoomBar.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Menu.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
|
||||
TopRoomBar::TopRoomBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
107
src/TopRoomBar.h
Normal file
107
src/TopRoomBar.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QLabel>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QSharedPointer>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class Avatar;
|
||||
class FlatButton;
|
||||
class Menu;
|
||||
class OverlayModal;
|
||||
|
||||
class TopRoomBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
|
||||
|
||||
public:
|
||||
TopRoomBar(QWidget *parent = 0);
|
||||
|
||||
void updateRoomAvatar(const QImage &avatar_image);
|
||||
void updateRoomAvatar(const QIcon &icon);
|
||||
void updateRoomName(const QString &name);
|
||||
void updateRoomTopic(QString topic);
|
||||
void updateRoomAvatarFromName(const QString &name);
|
||||
|
||||
void reset();
|
||||
|
||||
QColor borderColor() const { return borderColor_; }
|
||||
void setBorderColor(QColor &color) { borderColor_ = color; }
|
||||
|
||||
public slots:
|
||||
//! Add a "back-arrow" button that can switch to roomlist only view.
|
||||
void enableBackButton();
|
||||
//! Replace the "back-arrow" button with the avatar of the room.
|
||||
void disableBackButton();
|
||||
|
||||
signals:
|
||||
void inviteUsers(QStringList users);
|
||||
void showRoomList();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *) override
|
||||
{
|
||||
if (roomSettings_ != nullptr)
|
||||
roomSettings_->trigger();
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *) override
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
|
||||
p.setPen(QPen(borderColor()));
|
||||
p.drawLine(QPointF(0, height() - p.pen().widthF()),
|
||||
QPointF(width(), height() - p.pen().widthF()));
|
||||
}
|
||||
|
||||
private:
|
||||
QHBoxLayout *topLayout_ = nullptr;
|
||||
QVBoxLayout *textLayout_ = nullptr;
|
||||
|
||||
QLabel *nameLabel_ = nullptr;
|
||||
QLabel *topicLabel_ = nullptr;
|
||||
|
||||
Menu *menu_;
|
||||
QAction *leaveRoom_ = nullptr;
|
||||
QAction *roomMembers_ = nullptr;
|
||||
QAction *roomSettings_ = nullptr;
|
||||
QAction *inviteUsers_ = nullptr;
|
||||
|
||||
FlatButton *settingsBtn_;
|
||||
FlatButton *backBtn_;
|
||||
|
||||
Avatar *avatar_;
|
||||
|
||||
int buttonSize_;
|
||||
|
||||
QColor borderColor_;
|
||||
};
|
||||
59
src/TrayIcon.h
Normal file
59
src/TrayIcon.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
#include <QIconEngine>
|
||||
#include <QPainter>
|
||||
#include <QRect>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
class MsgCountComposedIcon : public QIconEngine
|
||||
{
|
||||
public:
|
||||
MsgCountComposedIcon(const QString &filename);
|
||||
|
||||
virtual void paint(QPainter *p, const QRect &rect, QIcon::Mode mode, QIcon::State state);
|
||||
virtual QIconEngine *clone() const;
|
||||
virtual QList<QSize> availableSizes(QIcon::Mode mode, QIcon::State state) const;
|
||||
virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
|
||||
|
||||
int msgCount = 0;
|
||||
|
||||
private:
|
||||
const int BubbleDiameter = 17;
|
||||
|
||||
QIcon icon_;
|
||||
};
|
||||
|
||||
class TrayIcon : public QSystemTrayIcon
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TrayIcon(const QString &filename, QWidget *parent);
|
||||
|
||||
public slots:
|
||||
void setUnreadCount(int count);
|
||||
|
||||
private:
|
||||
QAction *viewAction_;
|
||||
QAction *quitAction_;
|
||||
|
||||
MsgCountComposedIcon *icon_;
|
||||
};
|
||||
21
src/TypingDisplay.h
Normal file
21
src/TypingDisplay.h
Normal 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_;
|
||||
};
|
||||
|
|
@ -17,12 +17,12 @@
|
|||
|
||||
#include <QTimer>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "MainWindow.h"
|
||||
#include "OverlayModal.h"
|
||||
#include "UserInfoWidget.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
|
||||
UserInfoWidget::UserInfoWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
73
src/UserInfoWidget.h
Normal file
73
src/UserInfoWidget.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
|
||||
class Avatar;
|
||||
class FlatButton;
|
||||
class OverlayModal;
|
||||
|
||||
class UserInfoWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
|
||||
|
||||
public:
|
||||
UserInfoWidget(QWidget *parent = 0);
|
||||
|
||||
void setAvatar(const QImage &img);
|
||||
void setDisplayName(const QString &name);
|
||||
void setUserId(const QString &userid);
|
||||
|
||||
void reset();
|
||||
|
||||
QColor borderColor() const { return borderColor_; }
|
||||
void setBorderColor(QColor &color) { borderColor_ = color; }
|
||||
|
||||
signals:
|
||||
void logout();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
Avatar *userAvatar_;
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
QHBoxLayout *avatarLayout_;
|
||||
QVBoxLayout *textLayout_;
|
||||
QHBoxLayout *buttonLayout_;
|
||||
|
||||
FlatButton *logoutButton_;
|
||||
|
||||
QLabel *displayNameLabel_;
|
||||
QLabel *userIdLabel_;
|
||||
|
||||
QString display_name_;
|
||||
QString user_id_;
|
||||
|
||||
QImage avatar_image_;
|
||||
|
||||
int logoutButtonSize_;
|
||||
|
||||
QColor borderColor_;
|
||||
};
|
||||
|
|
@ -24,11 +24,11 @@
|
|||
#include <QSettings>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include <ToggleButton.h>
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/ToggleButton.h"
|
||||
|
||||
#include "version.hpp"
|
||||
#include "version.h"
|
||||
|
||||
UserSettings::UserSettings() { load(); }
|
||||
|
||||
148
src/UserSettingsPage.h
Normal file
148
src/UserSettingsPage.h
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QFrame>
|
||||
#include <QLayout>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
class Toggle;
|
||||
|
||||
constexpr int OptionMargin = 6;
|
||||
constexpr int LayoutTopMargin = 50;
|
||||
constexpr int LayoutBottomMargin = LayoutTopMargin;
|
||||
|
||||
class UserSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserSettings();
|
||||
|
||||
void save();
|
||||
void load();
|
||||
void applyTheme();
|
||||
void setTheme(QString theme);
|
||||
void setTray(bool state)
|
||||
{
|
||||
isTrayEnabled_ = state;
|
||||
save();
|
||||
};
|
||||
|
||||
void setStartInTray(bool state)
|
||||
{
|
||||
isStartInTrayEnabled_ = state;
|
||||
save();
|
||||
};
|
||||
|
||||
void setRoomOrdering(bool state)
|
||||
{
|
||||
isOrderingEnabled_ = state;
|
||||
save();
|
||||
};
|
||||
|
||||
void setGroupView(bool state)
|
||||
{
|
||||
if (isGroupViewEnabled_ != state)
|
||||
emit groupViewStateChanged(state);
|
||||
|
||||
isGroupViewEnabled_ = state;
|
||||
save();
|
||||
};
|
||||
|
||||
void setReadReceipts(bool state)
|
||||
{
|
||||
isReadReceiptsEnabled_ = state;
|
||||
save();
|
||||
}
|
||||
|
||||
void setTypingNotifications(bool state)
|
||||
{
|
||||
isTypingNotificationsEnabled_ = state;
|
||||
save();
|
||||
};
|
||||
|
||||
QString theme() const { return !theme_.isEmpty() ? theme_ : "light"; }
|
||||
bool isTrayEnabled() const { return isTrayEnabled_; }
|
||||
bool isStartInTrayEnabled() const { return isStartInTrayEnabled_; }
|
||||
bool isOrderingEnabled() const { return isOrderingEnabled_; }
|
||||
bool isGroupViewEnabled() const { return isGroupViewEnabled_; }
|
||||
bool isTypingNotificationsEnabled() const { return isTypingNotificationsEnabled_; }
|
||||
bool isReadReceiptsEnabled() const { return isReadReceiptsEnabled_; }
|
||||
|
||||
signals:
|
||||
void groupViewStateChanged(bool state);
|
||||
|
||||
private:
|
||||
QString theme_;
|
||||
bool isTrayEnabled_;
|
||||
bool isStartInTrayEnabled_;
|
||||
bool isOrderingEnabled_;
|
||||
bool isGroupViewEnabled_;
|
||||
bool isTypingNotificationsEnabled_;
|
||||
bool isReadReceiptsEnabled_;
|
||||
};
|
||||
|
||||
class HorizontalLine : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HorizontalLine(QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
class UserSettingsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserSettingsPage(QSharedPointer<UserSettings> settings, QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void moveBack();
|
||||
void trayOptionChanged(bool value);
|
||||
|
||||
private:
|
||||
void restoreThemeCombo() const;
|
||||
|
||||
// Layouts
|
||||
QVBoxLayout *topLayout_;
|
||||
QVBoxLayout *mainLayout_;
|
||||
QHBoxLayout *topBarLayout_;
|
||||
|
||||
// Shared settings object.
|
||||
QSharedPointer<UserSettings> settings_;
|
||||
|
||||
Toggle *trayToggle_;
|
||||
Toggle *startInTrayToggle_;
|
||||
Toggle *roomOrderToggle_;
|
||||
Toggle *groupViewToggle_;
|
||||
Toggle *typingNotifications_;
|
||||
Toggle *readReceipts_;
|
||||
|
||||
QComboBox *themeCombo_;
|
||||
|
||||
int sideMargin_ = 0;
|
||||
};
|
||||
194
src/Utils.h
Normal file
194
src/Utils.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
#pragma once
|
||||
|
||||
#include "Cache.h"
|
||||
#include "RoomInfoListItem.h"
|
||||
#include "timeline/widgets/AudioItem.h"
|
||||
#include "timeline/widgets/FileItem.h"
|
||||
#include "timeline/widgets/ImageItem.h"
|
||||
#include "timeline/widgets/VideoItem.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QPixmap>
|
||||
#include <mtx/events/collections.hpp>
|
||||
|
||||
namespace utils {
|
||||
|
||||
using TimelineEvent = mtx::events::collections::TimelineEvents;
|
||||
|
||||
//! Human friendly timestamp representation.
|
||||
QString
|
||||
descriptiveTime(const QDateTime &then);
|
||||
|
||||
//! Generate a message description from the event to be displayed
|
||||
//! in the RoomList.
|
||||
DescInfo
|
||||
getMessageDescription(const TimelineEvent &event, const QString &localUser, const QString &room_id);
|
||||
|
||||
//! Get the first character of a string, taking into account that
|
||||
//! surrogate pairs might be in use.
|
||||
QString
|
||||
firstChar(const QString &input);
|
||||
|
||||
//! Get a human readable file size with the appropriate units attached.
|
||||
QString
|
||||
humanReadableFileSize(uint64_t bytes);
|
||||
|
||||
QString
|
||||
event_body(const mtx::events::collections::TimelineEvents &event);
|
||||
|
||||
//! Match widgets/events with a description message.
|
||||
template<class T>
|
||||
QString
|
||||
messageDescription(const QString &username = "", const QString &body = "")
|
||||
{
|
||||
using Audio = mtx::events::RoomEvent<mtx::events::msg::Audio>;
|
||||
using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>;
|
||||
using File = mtx::events::RoomEvent<mtx::events::msg::File>;
|
||||
using Image = mtx::events::RoomEvent<mtx::events::msg::Image>;
|
||||
using Notice = mtx::events::RoomEvent<mtx::events::msg::Notice>;
|
||||
using Sticker = mtx::events::Sticker;
|
||||
using Text = mtx::events::RoomEvent<mtx::events::msg::Text>;
|
||||
using Video = mtx::events::RoomEvent<mtx::events::msg::Video>;
|
||||
using Encrypted = mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>;
|
||||
|
||||
if (std::is_same<T, AudioItem>::value || std::is_same<T, Audio>::value)
|
||||
return QString("sent an audio clip");
|
||||
else if (std::is_same<T, ImageItem>::value || std::is_same<T, Image>::value)
|
||||
return QString("sent an image");
|
||||
else if (std::is_same<T, FileItem>::value || std::is_same<T, File>::value)
|
||||
return QString("sent a file");
|
||||
else if (std::is_same<T, VideoItem>::value || std::is_same<T, Video>::value)
|
||||
return QString("sent a video clip");
|
||||
else if (std::is_same<T, StickerItem>::value || std::is_same<T, Sticker>::value)
|
||||
return QString("sent a sticker");
|
||||
else if (std::is_same<T, Notice>::value)
|
||||
return QString("sent a notification");
|
||||
else if (std::is_same<T, Text>::value)
|
||||
return QString(": %1").arg(body);
|
||||
else if (std::is_same<T, Emote>::value)
|
||||
return QString("* %1 %2").arg(username).arg(body);
|
||||
else if (std::is_same<T, Encrypted>::value)
|
||||
return QString("sent an encrypted message");
|
||||
}
|
||||
|
||||
template<class T, class Event>
|
||||
DescInfo
|
||||
createDescriptionInfo(const Event &event, const QString &localUser, const QString &room_id)
|
||||
{
|
||||
using Text = mtx::events::RoomEvent<mtx::events::msg::Text>;
|
||||
using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>;
|
||||
|
||||
const auto msg = mpark::get<T>(event);
|
||||
const auto sender = QString::fromStdString(msg.sender);
|
||||
|
||||
const auto username = Cache::displayName(room_id, sender);
|
||||
const auto ts = QDateTime::fromMSecsSinceEpoch(msg.origin_server_ts);
|
||||
|
||||
bool isText = std::is_same<T, Text>::value;
|
||||
bool isEmote = std::is_same<T, Emote>::value;
|
||||
|
||||
return DescInfo{
|
||||
isEmote ? "" : (sender == localUser ? "You" : username),
|
||||
sender,
|
||||
(isText || isEmote)
|
||||
? messageDescription<T>(username, QString::fromStdString(msg.content.body).trimmed())
|
||||
: QString(" %1").arg(messageDescription<T>()),
|
||||
utils::descriptiveTime(ts),
|
||||
ts};
|
||||
}
|
||||
|
||||
//! Scale down an image to fit to the given width & height limitations.
|
||||
template<class ImageType>
|
||||
ImageType
|
||||
scaleDown(uint64_t max_width, uint64_t max_height, const ImageType &source)
|
||||
{
|
||||
if (source.isNull())
|
||||
return QPixmap();
|
||||
|
||||
auto width_ratio = (double)max_width / (double)source.width();
|
||||
auto height_ratio = (double)max_height / (double)source.height();
|
||||
|
||||
auto min_aspect_ratio = std::min(width_ratio, height_ratio);
|
||||
|
||||
int final_width = 0;
|
||||
int final_height = 0;
|
||||
|
||||
if (min_aspect_ratio > 1) {
|
||||
final_width = source.width();
|
||||
final_height = source.height();
|
||||
} else {
|
||||
final_width = source.width() * min_aspect_ratio;
|
||||
final_height = source.height() * min_aspect_ratio;
|
||||
}
|
||||
|
||||
return source.scaled(
|
||||
final_width, final_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
//! Delete items in a container based on a predicate.
|
||||
template<typename ContainerT, typename PredicateT>
|
||||
void
|
||||
erase_if(ContainerT &items, const PredicateT &predicate)
|
||||
{
|
||||
for (auto it = items.begin(); it != items.end();) {
|
||||
if (predicate(*it))
|
||||
it = items.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t
|
||||
event_timestamp(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return mpark::visit([](auto msg) { return msg.origin_server_ts; }, event);
|
||||
}
|
||||
|
||||
inline nlohmann::json
|
||||
serialize_event(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return mpark::visit([](auto msg) { return json(msg); }, event);
|
||||
}
|
||||
|
||||
inline mtx::events::EventType
|
||||
event_type(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return mpark::visit([](auto msg) { return msg.type; }, event);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
event_id(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return mpark::visit([](auto msg) { return msg.event_id; }, event);
|
||||
}
|
||||
|
||||
inline QString
|
||||
eventId(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return QString::fromStdString(event_id(event));
|
||||
}
|
||||
|
||||
inline QString
|
||||
event_sender(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return mpark::visit([](auto msg) { return QString::fromStdString(msg.sender); }, event);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QString
|
||||
message_body(const mtx::events::collections::TimelineEvents &event)
|
||||
{
|
||||
return QString::fromStdString(mpark::get<T>(event).content.body);
|
||||
}
|
||||
|
||||
//! Calculate the Levenshtein distance between two strings with character skipping.
|
||||
int
|
||||
levenshtein_distance(const std::string &s1, const std::string &s2);
|
||||
|
||||
QPixmap
|
||||
scaleImageToPixmap(const QImage &img, int size);
|
||||
|
||||
//! Convert a Content Matrix URI to an HTTP link.
|
||||
QString
|
||||
mxcToHttp(const QUrl &url, const QString &server, int port);
|
||||
}
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
#include <QStyleOption>
|
||||
|
||||
#include "Config.h"
|
||||
#include "RaisedButton.h"
|
||||
#include "WelcomePage.h"
|
||||
#include "ui/RaisedButton.h"
|
||||
|
||||
WelcomePage::WelcomePage(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
44
src/WelcomePage.h
Normal file
44
src/WelcomePage.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class RaisedButton;
|
||||
|
||||
class WelcomePage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WelcomePage(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
// Notify that the user wants to login in.
|
||||
void userLogin();
|
||||
|
||||
// Notify that the user wants to register.
|
||||
void userRegister();
|
||||
|
||||
private:
|
||||
RaisedButton *registerBtn_;
|
||||
RaisedButton *loginBtn_;
|
||||
};
|
||||
|
|
@ -3,14 +3,14 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "TextField.h"
|
||||
#include "Theme.h"
|
||||
#include "ToggleButton.h"
|
||||
|
||||
#include "dialogs/CreateRoom.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/TextField.h"
|
||||
#include "ui/Theme.h"
|
||||
#include "ui/ToggleButton.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
CreateRoom::CreateRoom(QWidget *parent)
|
||||
45
src/dialogs/CreateRoom.h
Normal file
45
src/dialogs/CreateRoom.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
#include <mtx.hpp>
|
||||
|
||||
class FlatButton;
|
||||
class TextField;
|
||||
class QComboBox;
|
||||
class Toggle;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class CreateRoom : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CreateRoom(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void closing(bool isCreating, const mtx::requests::CreateRoom &request);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
void clearFields();
|
||||
|
||||
QComboBox *visibilityCombo_;
|
||||
QComboBox *presetCombo_;
|
||||
|
||||
Toggle *directToggle_;
|
||||
|
||||
FlatButton *confirmBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
|
||||
TextField *nameInput_;
|
||||
TextField *topicInput_;
|
||||
TextField *aliasInput_;
|
||||
|
||||
mtx::requests::CreateRoom request_;
|
||||
};
|
||||
|
||||
} // dialogs
|
||||
|
|
@ -19,9 +19,10 @@
|
|||
#include <QDesktopWidget>
|
||||
#include <QPainter>
|
||||
|
||||
#include "Utils.h"
|
||||
#include "dialogs/ImageOverlay.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
ImageOverlay::ImageOverlay(QPixmap image, QWidget *parent)
|
||||
47
src/dialogs/ImageOverlay.h
Normal file
47
src/dialogs/ImageOverlay.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMouseEvent>
|
||||
#include <QPixmap>
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class ImageOverlay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImageOverlay(QPixmap image, QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closing();
|
||||
|
||||
private:
|
||||
QPixmap originalImage_;
|
||||
QPixmap image_;
|
||||
|
||||
QRect content_;
|
||||
QRect close_button_;
|
||||
QRect screen_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -6,13 +6,13 @@
|
|||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "TextField.h"
|
||||
|
||||
#include "InviteeItem.h"
|
||||
#include "dialogs/InviteUsers.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "InviteeItem.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
#include "mtx.hpp"
|
||||
|
||||
using namespace dialogs;
|
||||
42
src/dialogs/InviteUsers.h
Normal file
42
src/dialogs/InviteUsers.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QListWidgetItem>
|
||||
#include <QStringList>
|
||||
|
||||
class FlatButton;
|
||||
class TextField;
|
||||
class QListWidget;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class InviteUsers : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InviteUsers(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closing(bool isLeaving, QStringList invitees);
|
||||
|
||||
private slots:
|
||||
void removeInvitee(QListWidgetItem *item);
|
||||
|
||||
private:
|
||||
void addUser();
|
||||
QStringList invitedUsers() const;
|
||||
|
||||
FlatButton *confirmBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
|
||||
TextField *inviteeInput_;
|
||||
QLabel *errorLabel_;
|
||||
|
||||
QListWidget *inviteeList_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "TextField.h"
|
||||
#include "Theme.h"
|
||||
|
||||
#include "dialogs/JoinRoom.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/TextField.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
JoinRoom::JoinRoom(QWidget *parent)
|
||||
30
src/dialogs/JoinRoom.h
Normal file
30
src/dialogs/JoinRoom.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class FlatButton;
|
||||
class TextField;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class JoinRoom : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
JoinRoom(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void closing(bool isJoining, const QString &room);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
FlatButton *confirmBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
|
||||
TextField *roomInput_;
|
||||
};
|
||||
|
||||
} // dialogs
|
||||
|
|
@ -2,12 +2,12 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "Theme.h"
|
||||
|
||||
#include "dialogs/LeaveRoom.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
LeaveRoom::LeaveRoom(QWidget *parent)
|
||||
25
src/dialogs/LeaveRoom.h
Normal file
25
src/dialogs/LeaveRoom.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class FlatButton;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class LeaveRoom : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LeaveRoom(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closing(bool isLeaving);
|
||||
|
||||
private:
|
||||
FlatButton *confirmBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -20,12 +20,12 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "Theme.h"
|
||||
|
||||
#include "dialogs/Logout.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
Logout::Logout(QWidget *parent)
|
||||
42
src/dialogs/Logout.h
Normal file
42
src/dialogs/Logout.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class FlatButton;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class Logout : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Logout(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closing(bool isLoggingOut);
|
||||
|
||||
private:
|
||||
FlatButton *confirmBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -3,15 +3,15 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/MemberList.h"
|
||||
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "Cache.h"
|
||||
#include "dialogs/MemberList.hpp"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/FlatButton.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
|
|
|
|||
61
src/dialogs/MemberList.h
Normal file
61
src/dialogs/MemberList.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QListWidget>
|
||||
|
||||
class Avatar;
|
||||
class FlatButton;
|
||||
class QHBoxLayout;
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
|
||||
struct RoomMember;
|
||||
|
||||
template<class T>
|
||||
class QSharedPointer;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class MemberItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MemberItem(const RoomMember &member, QWidget *parent);
|
||||
|
||||
private:
|
||||
QHBoxLayout *topLayout_;
|
||||
QVBoxLayout *textLayout_;
|
||||
|
||||
Avatar *avatar_;
|
||||
|
||||
QLabel *userName_;
|
||||
QLabel *userId_;
|
||||
};
|
||||
|
||||
class MemberList : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MemberList(const QString &room_id, QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addUsers(const std::vector<RoomMember> &users);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override
|
||||
{
|
||||
list_->clear();
|
||||
QFrame::hideEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
void moveButtonToBottom();
|
||||
|
||||
QString room_id_;
|
||||
QLabel *topLabel_;
|
||||
QListWidget *list_;
|
||||
FlatButton *moreBtn_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -23,13 +23,13 @@
|
|||
#include <QMimeDatabase>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/PreviewUploadOverlay.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "dialogs/PreviewUploadOverlay.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
constexpr const char *DEFAULT = "Upload %1?";
|
||||
61
src/dialogs/PreviewUploadOverlay.h
Normal file
61
src/dialogs/PreviewUploadOverlay.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPixmap>
|
||||
#include <QWidget>
|
||||
|
||||
#include "ui/FlatButton.h"
|
||||
|
||||
class QMimeData;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class PreviewUploadOverlay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PreviewUploadOverlay(QWidget *parent = nullptr);
|
||||
|
||||
void setPreview(const QByteArray data, const QString &mime);
|
||||
void setPreview(const QString &path);
|
||||
|
||||
signals:
|
||||
void confirmUpload(const QByteArray data, const QString &media, const QString &filename);
|
||||
|
||||
private:
|
||||
void init();
|
||||
void setLabels(const QString &type, const QString &mime, uint64_t upload_size);
|
||||
|
||||
bool isImage_;
|
||||
QPixmap image_;
|
||||
|
||||
QByteArray data_;
|
||||
QString filePath_;
|
||||
QString mediaType_;
|
||||
|
||||
QLabel titleLabel_;
|
||||
QLabel infoLabel_;
|
||||
QLineEdit fileName_;
|
||||
|
||||
FlatButton upload_;
|
||||
FlatButton cancel_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -4,13 +4,13 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "RaisedButton.h"
|
||||
#include "Theme.h"
|
||||
#include "dialogs/ReCaptcha.h"
|
||||
|
||||
#include "dialogs/ReCaptcha.hpp"
|
||||
#include "Config.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/RaisedButton.h"
|
||||
#include "ui/Theme.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
|
|
|
|||
28
src/dialogs/ReCaptcha.h
Normal file
28
src/dialogs/ReCaptcha.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class FlatButton;
|
||||
class RaisedButton;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class ReCaptcha : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ReCaptcha(const QString &session, QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closing();
|
||||
|
||||
private:
|
||||
FlatButton *openCaptchaBtn_;
|
||||
RaisedButton *confirmBtn_;
|
||||
RaisedButton *cancelBtn_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -6,14 +6,14 @@
|
|||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/ReadReceipts.h"
|
||||
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "dialogs/ReadReceipts.h"
|
||||
#include "ui/Avatar.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
58
src/dialogs/ReadReceipts.h
Normal file
58
src/dialogs/ReadReceipts.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class Avatar;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class ReceiptItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ReceiptItem(QWidget *parent,
|
||||
const QString &user_id,
|
||||
uint64_t timestamp,
|
||||
const QString &room_id);
|
||||
|
||||
private:
|
||||
QString dateFormat(const QDateTime &then) const;
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
QVBoxLayout *textLayout_;
|
||||
|
||||
Avatar *avatar_;
|
||||
|
||||
QLabel *userName_;
|
||||
QLabel *timestamp_;
|
||||
};
|
||||
|
||||
class ReadReceipts : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReadReceipts(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addUsers(const std::multimap<uint64_t, std::string, std::greater<uint64_t>> &users);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override
|
||||
{
|
||||
userList_->clear();
|
||||
QFrame::hideEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
QLabel *topLabel_;
|
||||
|
||||
QListWidget *userList_;
|
||||
};
|
||||
} // dialogs
|
||||
|
|
@ -1,16 +1,3 @@
|
|||
#include "Avatar.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "Logging.hpp"
|
||||
#include "MatrixClient.h"
|
||||
#include "Painter.h"
|
||||
#include "TextField.h"
|
||||
#include "Theme.h"
|
||||
#include "Utils.h"
|
||||
#include "dialogs/RoomSettings.hpp"
|
||||
#include "ui/ToggleButton.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
|
|
@ -22,6 +9,20 @@
|
|||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/RoomSettings.h"
|
||||
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Painter.h"
|
||||
#include "ui/TextField.h"
|
||||
#include "ui/Theme.h"
|
||||
#include "ui/ToggleButton.h"
|
||||
|
||||
using namespace dialogs;
|
||||
using namespace mtx::events;
|
||||
|
||||
|
|
|
|||
126
src/dialogs/RoomSettings.h
Normal file
126
src/dialogs/RoomSettings.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QImage>
|
||||
|
||||
#include "Cache.h"
|
||||
|
||||
class Avatar;
|
||||
class FlatButton;
|
||||
class QComboBox;
|
||||
class QHBoxLayout;
|
||||
class QLabel;
|
||||
class QLabel;
|
||||
class QLayout;
|
||||
class QPixmap;
|
||||
class TextField;
|
||||
class TextField;
|
||||
class Toggle;
|
||||
|
||||
template<class T>
|
||||
class QSharedPointer;
|
||||
|
||||
class EditModal : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditModal(const QString &roomId, QWidget *parent = nullptr);
|
||||
|
||||
void setFields(const QString &roomName, const QString &roomTopic);
|
||||
|
||||
signals:
|
||||
void nameChanged(const QString &roomName);
|
||||
void nameEventSentCb(const QString &newName);
|
||||
void topicEventSentCb();
|
||||
void stateEventErrorCb(const QString &msg);
|
||||
|
||||
private:
|
||||
QString roomId_;
|
||||
QString initialName_;
|
||||
QString initialTopic_;
|
||||
|
||||
QLabel *errorField_;
|
||||
|
||||
TextField *nameInput_;
|
||||
TextField *topicInput_;
|
||||
|
||||
FlatButton *applyBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
};
|
||||
|
||||
class TopSection : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
|
||||
|
||||
public:
|
||||
TopSection(const RoomInfo &info, const QImage &img, QWidget *parent = nullptr);
|
||||
QSize sizeHint() const override;
|
||||
void setRoomName(const QString &name);
|
||||
|
||||
QColor textColor() const { return textColor_; }
|
||||
void setTextColor(QColor &color) { textColor_ = color; }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
static constexpr int AvatarSize = 72;
|
||||
static constexpr int Padding = 5;
|
||||
|
||||
RoomInfo info_;
|
||||
QPixmap avatar_;
|
||||
QColor textColor_;
|
||||
};
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class RoomSettings : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RoomSettings(const QString &room_id, QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void closing();
|
||||
void enableEncryptionError(const QString &msg);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void saveSettings();
|
||||
|
||||
private:
|
||||
static constexpr int AvatarSize = 64;
|
||||
|
||||
void setAvatar(const QImage &img) { avatarImg_ = img; }
|
||||
void setupEditButton();
|
||||
//! Retrieve the current room information from cache.
|
||||
void retrieveRoomInfo();
|
||||
void enableEncryption();
|
||||
|
||||
//! Whether the user would be able to change the name or the topic of the room.
|
||||
bool hasEditRights_ = true;
|
||||
bool usesEncryption_ = false;
|
||||
QHBoxLayout *editLayout_;
|
||||
|
||||
// Button section
|
||||
FlatButton *okBtn_;
|
||||
FlatButton *cancelBtn_;
|
||||
|
||||
FlatButton *editFieldsBtn_;
|
||||
|
||||
RoomInfo info_;
|
||||
QString room_id_;
|
||||
QImage avatarImg_;
|
||||
|
||||
TopSection *topSection_;
|
||||
|
||||
QComboBox *accessCombo;
|
||||
Toggle *encryptionToggle_;
|
||||
};
|
||||
|
||||
} // dialogs
|
||||
59
src/emoji/Category.h
Normal file
59
src/emoji/Category.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QListView>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "ItemDelegate.h"
|
||||
|
||||
namespace emoji {
|
||||
|
||||
class Category : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Category(QString category, std::vector<Emoji> emoji, QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void emojiSelected(const QString &emoji);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void clickIndex(const QModelIndex &index)
|
||||
{
|
||||
emit emojiSelected(index.data(Qt::UserRole).toString());
|
||||
};
|
||||
|
||||
private:
|
||||
QVBoxLayout *mainLayout_;
|
||||
|
||||
QStandardItemModel *itemModel_;
|
||||
QListView *emojiListView_;
|
||||
|
||||
emoji::Emoji *data_;
|
||||
emoji::ItemDelegate *delegate_;
|
||||
|
||||
QLabel *category_;
|
||||
};
|
||||
} // namespace emoji
|
||||
43
src/emoji/ItemDelegate.h
Normal file
43
src/emoji/ItemDelegate.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QStandardItemModel>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include "Provider.h"
|
||||
|
||||
namespace emoji {
|
||||
|
||||
class ItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ItemDelegate(QObject *parent = nullptr);
|
||||
~ItemDelegate();
|
||||
|
||||
void paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
private:
|
||||
Emoji *data_;
|
||||
};
|
||||
} // namespace emoji
|
||||
|
|
@ -19,8 +19,8 @@
|
|||
#include <QScrollBar>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "DropShadow.h"
|
||||
#include "FlatButton.h"
|
||||
#include "ui/DropShadow.h"
|
||||
#include "ui/FlatButton.h"
|
||||
|
||||
#include "emoji/Category.h"
|
||||
#include "emoji/Panel.h"
|
||||
66
src/emoji/Panel.h
Normal file
66
src/emoji/Panel.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "Provider.h"
|
||||
|
||||
namespace emoji {
|
||||
|
||||
class Category;
|
||||
|
||||
class Panel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Panel(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void mouseLeft();
|
||||
void emojiSelected(const QString &emoji);
|
||||
|
||||
protected:
|
||||
void leaveEvent(QEvent *event) override
|
||||
{
|
||||
emit leaving();
|
||||
QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
signals:
|
||||
void leaving();
|
||||
|
||||
private:
|
||||
void showCategory(const Category *category);
|
||||
|
||||
Provider emoji_provider_;
|
||||
|
||||
QScrollArea *scrollArea_;
|
||||
|
||||
int shadowMargin_;
|
||||
|
||||
// Panel dimensions.
|
||||
int width_;
|
||||
int height_;
|
||||
|
||||
int categoryIconSize_;
|
||||
};
|
||||
} // namespace emoji
|
||||
53
src/emoji/PickButton.h
Normal file
53
src/emoji/PickButton.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "ui/FlatButton.h"
|
||||
|
||||
namespace emoji {
|
||||
|
||||
class Panel;
|
||||
|
||||
class PickButton : public FlatButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PickButton(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void emojiSelected(const QString &emoji);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
|
||||
private:
|
||||
// Vertical distance from panel's bottom.
|
||||
int vertical_distance_ = 10;
|
||||
|
||||
// Horizontal distance from panel's bottom right corner.
|
||||
int horizontal_distance_ = 70;
|
||||
|
||||
QSharedPointer<Panel> panel_;
|
||||
QTimer hideTimer_;
|
||||
};
|
||||
} // namespace emoji
|
||||
45
src/emoji/Provider.h
Normal file
45
src/emoji/Provider.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
namespace emoji {
|
||||
|
||||
struct Emoji
|
||||
{
|
||||
// Unicode code.
|
||||
QString unicode;
|
||||
// Keyboard shortcut e.g :emoji:
|
||||
QString shortname;
|
||||
};
|
||||
|
||||
class Provider
|
||||
{
|
||||
public:
|
||||
static const std::vector<Emoji> people;
|
||||
static const std::vector<Emoji> nature;
|
||||
static const std::vector<Emoji> food;
|
||||
static const std::vector<Emoji> activity;
|
||||
static const std::vector<Emoji> travel;
|
||||
static const std::vector<Emoji> objects;
|
||||
static const std::vector<Emoji> symbols;
|
||||
static const std::vector<Emoji> flags;
|
||||
};
|
||||
} // namespace emoji
|
||||
|
|
@ -32,12 +32,12 @@
|
|||
#include <QTranslator>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "RaisedButton.h"
|
||||
#include "RunGuard.h"
|
||||
#include "version.hpp"
|
||||
#include "ui/RaisedButton.h"
|
||||
#include "version.h"
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <boost/stacktrace.hpp>
|
||||
55
src/notifications/Manager.h
Normal file
55
src/notifications/Manager.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <QImage>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <QtDBus/QDBusArgument>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#endif
|
||||
|
||||
struct roomEventId
|
||||
{
|
||||
QString roomId;
|
||||
QString eventId;
|
||||
};
|
||||
|
||||
class NotificationsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NotificationsManager(QObject *parent = nullptr);
|
||||
|
||||
void postNotification(const QString &roomId,
|
||||
const QString &eventId,
|
||||
const QString &roomName,
|
||||
const QString &senderName,
|
||||
const QString &text,
|
||||
const QImage &icon);
|
||||
|
||||
signals:
|
||||
void notificationClicked(const QString roomId, const QString eventId);
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
private:
|
||||
QDBusInterface dbus;
|
||||
uint showNotification(const QString summary, const QString text, const QImage image);
|
||||
|
||||
// notification ID to (room ID, event ID)
|
||||
QMap<uint, roomEventId> notificationIds;
|
||||
#endif
|
||||
|
||||
// these slots are platform specific (D-Bus only)
|
||||
// but Qt slot declarations can not be inside an ifdef!
|
||||
private slots:
|
||||
void actionInvoked(uint id, QString action);
|
||||
void notificationClosed(uint id, uint reason);
|
||||
};
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
QDBusArgument &
|
||||
operator<<(QDBusArgument &arg, const QImage &image);
|
||||
const QDBusArgument &
|
||||
operator>>(const QDBusArgument &arg, QImage &);
|
||||
#endif
|
||||
|
|
@ -20,12 +20,12 @@
|
|||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Olm.hpp"
|
||||
#include "Painter.h"
|
||||
#include "Logging.h"
|
||||
#include "Olm.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/Painter.h"
|
||||
|
||||
#include "timeline/TimelineItem.h"
|
||||
#include "timeline/widgets/AudioItem.h"
|
||||
380
src/timeline/TimelineItem.h
Normal file
380
src/timeline/TimelineItem.h
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QSettings>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QTextBrowser>
|
||||
#include <QTimer>
|
||||
|
||||
#include "AvatarProvider.h"
|
||||
#include "RoomInfoListItem.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "Cache.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
class ImageItem;
|
||||
class StickerItem;
|
||||
class AudioItem;
|
||||
class VideoItem;
|
||||
class FileItem;
|
||||
class Avatar;
|
||||
|
||||
enum class StatusIndicatorState
|
||||
{
|
||||
//! The encrypted message was received by the server.
|
||||
Encrypted,
|
||||
//! The plaintext message was received by the server.
|
||||
Received,
|
||||
//! The client sent the message. Not yet received.
|
||||
Sent,
|
||||
//! When the message is loaded from cache or backfill.
|
||||
Empty,
|
||||
};
|
||||
|
||||
//!
|
||||
//! Used to notify the user about the status of a message.
|
||||
//!
|
||||
class StatusIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StatusIndicator(QWidget *parent);
|
||||
void setState(StatusIndicatorState state);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void paintIcon(QPainter &p, QIcon &icon);
|
||||
|
||||
QIcon lockIcon_;
|
||||
QIcon clockIcon_;
|
||||
QIcon checkmarkIcon_;
|
||||
|
||||
QColor iconColor_ = QColor("#999");
|
||||
|
||||
StatusIndicatorState state_ = StatusIndicatorState::Empty;
|
||||
|
||||
static constexpr int MaxWidth = 24;
|
||||
};
|
||||
|
||||
class TextLabel : public QTextBrowser
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TextLabel(const QString &text, QWidget *parent = 0)
|
||||
: QTextBrowser(parent)
|
||||
{
|
||||
setText(text);
|
||||
setOpenExternalLinks(true);
|
||||
|
||||
// Make it look and feel like an ordinary label.
|
||||
setReadOnly(true);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
QPalette pal = palette();
|
||||
pal.setColor(QPalette::Base, Qt::transparent);
|
||||
setPalette(pal);
|
||||
|
||||
// Wrap anywhere but prefer words, adjust minimum height on the fly.
|
||||
setLineWrapMode(QTextEdit::WidgetWidth);
|
||||
setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||
connect(document()->documentLayout(),
|
||||
&QAbstractTextDocumentLayout::documentSizeChanged,
|
||||
this,
|
||||
&TextLabel::adjustHeight);
|
||||
document()->setDocumentMargin(0);
|
||||
|
||||
setFixedHeight(20);
|
||||
}
|
||||
|
||||
void wheelEvent(QWheelEvent *event) override { event->ignore(); }
|
||||
|
||||
private slots:
|
||||
void adjustHeight(const QSizeF &size) { setFixedHeight(size.height()); }
|
||||
};
|
||||
|
||||
class UserProfileFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UserProfileFilter(const QString &user_id, QLabel *parent)
|
||||
: QObject(parent)
|
||||
, user_id_{user_id}
|
||||
{}
|
||||
|
||||
signals:
|
||||
void hoverOff();
|
||||
void hoverOn();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonRelease) {
|
||||
// QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
// TODO: Open user profile
|
||||
return true;
|
||||
} else if (event->type() == QEvent::HoverLeave) {
|
||||
emit hoverOff();
|
||||
return true;
|
||||
} else if (event->type() == QEvent::HoverEnter) {
|
||||
emit hoverOn();
|
||||
return true;
|
||||
}
|
||||
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
private:
|
||||
QString user_id_;
|
||||
};
|
||||
|
||||
class TimelineItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
|
||||
// For local messages.
|
||||
// m.text & m.emote
|
||||
TimelineItem(mtx::events::MessageType ty,
|
||||
const QString &userid,
|
||||
QString body,
|
||||
bool withSender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
// m.image
|
||||
TimelineItem(ImageItem *item,
|
||||
const QString &userid,
|
||||
bool withSender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineItem(FileItem *item,
|
||||
const QString &userid,
|
||||
bool withSender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineItem(AudioItem *item,
|
||||
const QString &userid,
|
||||
bool withSender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineItem(VideoItem *item,
|
||||
const QString &userid,
|
||||
bool withSender,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
|
||||
TimelineItem(ImageItem *img,
|
||||
const mtx::events::RoomEvent<mtx::events::msg::Image> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent);
|
||||
TimelineItem(StickerItem *img,
|
||||
const mtx::events::Sticker &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent);
|
||||
TimelineItem(FileItem *file,
|
||||
const mtx::events::RoomEvent<mtx::events::msg::File> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent);
|
||||
TimelineItem(AudioItem *audio,
|
||||
const mtx::events::RoomEvent<mtx::events::msg::Audio> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent);
|
||||
TimelineItem(VideoItem *video,
|
||||
const mtx::events::RoomEvent<mtx::events::msg::Video> &e,
|
||||
bool with_sender,
|
||||
const QString &room_id,
|
||||
QWidget *parent);
|
||||
|
||||
void setUserAvatar(const QImage &pixmap);
|
||||
DescInfo descriptionMessage() const { return descriptionMsg_; }
|
||||
QString eventId() const { return event_id_; }
|
||||
void setEventId(const QString &event_id) { event_id_ = event_id; }
|
||||
void markReceived(bool isEncrypted);
|
||||
void markSent();
|
||||
bool isReceived() { return isReceived_; };
|
||||
void setRoomId(QString room_id) { room_id_ = room_id; }
|
||||
void sendReadReceipt() const;
|
||||
|
||||
//! Add a user avatar for this event.
|
||||
void addAvatar();
|
||||
void addKeyRequestAction();
|
||||
|
||||
signals:
|
||||
void eventRedacted(const QString &event_id);
|
||||
void redactionFailed(const QString &msg);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
//! Add a context menu option to save the image of the timeline item.
|
||||
void addSaveImageAction(ImageItem *image);
|
||||
//! Add the reply action in the context menu for widgets that support it.
|
||||
void addReplyAction();
|
||||
|
||||
template<class Widget>
|
||||
void setupLocalWidgetLayout(Widget *widget, const QString &userid, bool withSender);
|
||||
|
||||
template<class Event, class Widget>
|
||||
void setupWidgetLayout(Widget *widget, const Event &event, bool withSender);
|
||||
|
||||
void generateBody(const QString &body);
|
||||
void generateBody(const QString &user_id, const QString &displayname, const QString &body);
|
||||
void generateTimestamp(const QDateTime &time);
|
||||
|
||||
void setupAvatarLayout(const QString &userName);
|
||||
void setupSimpleLayout();
|
||||
|
||||
void adjustMessageLayout();
|
||||
void adjustMessageLayoutForWidget();
|
||||
|
||||
//! Whether or not the event associated with the widget
|
||||
//! has been acknowledged by the server.
|
||||
bool isReceived_ = false;
|
||||
|
||||
QString replaceEmoji(const QString &body);
|
||||
QString event_id_;
|
||||
QString room_id_;
|
||||
|
||||
DescInfo descriptionMsg_;
|
||||
|
||||
QMenu *contextMenu_;
|
||||
QAction *showReadReceipts_;
|
||||
QAction *markAsRead_;
|
||||
QAction *redactMsg_;
|
||||
QAction *replyMsg_;
|
||||
|
||||
QHBoxLayout *topLayout_ = nullptr;
|
||||
QHBoxLayout *messageLayout_ = nullptr;
|
||||
QVBoxLayout *mainLayout_ = nullptr;
|
||||
QHBoxLayout *widgetLayout_ = nullptr;
|
||||
|
||||
Avatar *userAvatar_;
|
||||
|
||||
QFont font_;
|
||||
QFont usernameFont_;
|
||||
|
||||
StatusIndicator *statusIndicator_;
|
||||
|
||||
QLabel *timestamp_;
|
||||
QLabel *userName_;
|
||||
TextLabel *body_;
|
||||
};
|
||||
|
||||
template<class Widget>
|
||||
void
|
||||
TimelineItem::setupLocalWidgetLayout(Widget *widget, const QString &userid, bool withSender)
|
||||
{
|
||||
auto displayName = Cache::displayName(room_id_, userid);
|
||||
auto timestamp = QDateTime::currentDateTime();
|
||||
|
||||
descriptionMsg_ = {"You",
|
||||
userid,
|
||||
QString(" %1").arg(utils::messageDescription<Widget>()),
|
||||
utils::descriptiveTime(timestamp),
|
||||
timestamp};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
widgetLayout_ = new QHBoxLayout;
|
||||
widgetLayout_->setContentsMargins(0, 2, 0, 2);
|
||||
widgetLayout_->addWidget(widget);
|
||||
widgetLayout_->addStretch(1);
|
||||
|
||||
if (withSender) {
|
||||
generateBody(userid, displayName, "");
|
||||
setupAvatarLayout(displayName);
|
||||
|
||||
AvatarProvider::resolve(
|
||||
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
|
||||
} else {
|
||||
setupSimpleLayout();
|
||||
}
|
||||
|
||||
adjustMessageLayoutForWidget();
|
||||
}
|
||||
|
||||
template<class Event, class Widget>
|
||||
void
|
||||
TimelineItem::setupWidgetLayout(Widget *widget, const Event &event, bool withSender)
|
||||
{
|
||||
init();
|
||||
|
||||
event_id_ = QString::fromStdString(event.event_id);
|
||||
const auto sender = QString::fromStdString(event.sender);
|
||||
|
||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
|
||||
auto displayName = Cache::displayName(room_id_, sender);
|
||||
|
||||
QSettings settings;
|
||||
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||
sender,
|
||||
QString(" %1").arg(utils::messageDescription<Widget>()),
|
||||
utils::descriptiveTime(timestamp),
|
||||
timestamp};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
widgetLayout_ = new QHBoxLayout();
|
||||
widgetLayout_->setContentsMargins(0, 2, 0, 2);
|
||||
widgetLayout_->addWidget(widget);
|
||||
widgetLayout_->addStretch(1);
|
||||
|
||||
if (withSender) {
|
||||
generateBody(sender, displayName, "");
|
||||
setupAvatarLayout(displayName);
|
||||
|
||||
AvatarProvider::resolve(
|
||||
room_id_, sender, this, [this](const QImage &img) { setUserAvatar(img); });
|
||||
} else {
|
||||
setupSimpleLayout();
|
||||
}
|
||||
|
||||
adjustMessageLayoutForWidget();
|
||||
}
|
||||
|
|
@ -22,12 +22,12 @@
|
|||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "FloatingButton.h"
|
||||
#include "InfoMessage.hpp"
|
||||
#include "Logging.hpp"
|
||||
#include "Olm.hpp"
|
||||
#include "Logging.h"
|
||||
#include "Olm.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/FloatingButton.h"
|
||||
#include "ui/InfoMessage.h"
|
||||
|
||||
#include "timeline/TimelineView.h"
|
||||
#include "timeline/widgets/AudioItem.h"
|
||||
426
src/timeline/TimelineView.h
Normal file
426
src/timeline/TimelineView.h
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QLayout>
|
||||
#include <QList>
|
||||
#include <QQueue>
|
||||
#include <QScrollArea>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QTimer>
|
||||
|
||||
#include <mtx/events.hpp>
|
||||
#include <mtx/responses/messages.hpp>
|
||||
|
||||
#include "MatrixClient.h"
|
||||
#include "timeline/TimelineItem.h"
|
||||
#include "ui/ScrollBar.h"
|
||||
|
||||
class StateKeeper
|
||||
{
|
||||
public:
|
||||
StateKeeper(std::function<void()> &&fn)
|
||||
: fn_(std::move(fn))
|
||||
{}
|
||||
|
||||
~StateKeeper() { fn_(); }
|
||||
|
||||
private:
|
||||
std::function<void()> fn_;
|
||||
};
|
||||
|
||||
struct DecryptionResult
|
||||
{
|
||||
//! The decrypted content as a normal plaintext event.
|
||||
utils::TimelineEvent event;
|
||||
//! Whether or not the decryption was successful.
|
||||
bool isDecrypted = false;
|
||||
};
|
||||
|
||||
class FloatingButton;
|
||||
struct DescInfo;
|
||||
|
||||
// Contains info about a message shown in the history view
|
||||
// but not yet confirmed by the homeserver through sync.
|
||||
struct PendingMessage
|
||||
{
|
||||
mtx::events::MessageType ty;
|
||||
std::string txn_id;
|
||||
QString body;
|
||||
QString filename;
|
||||
QString mime;
|
||||
uint64_t media_size;
|
||||
QString event_id;
|
||||
TimelineItem *widget;
|
||||
QSize dimensions;
|
||||
bool is_encrypted = false;
|
||||
};
|
||||
|
||||
template<class MessageT>
|
||||
MessageT
|
||||
toRoomMessage(const PendingMessage &) = delete;
|
||||
|
||||
template<>
|
||||
mtx::events::msg::Audio
|
||||
toRoomMessage<mtx::events::msg::Audio>(const PendingMessage &m);
|
||||
|
||||
template<>
|
||||
mtx::events::msg::Emote
|
||||
toRoomMessage<mtx::events::msg::Emote>(const PendingMessage &m);
|
||||
|
||||
template<>
|
||||
mtx::events::msg::File
|
||||
toRoomMessage<mtx::events::msg::File>(const PendingMessage &);
|
||||
|
||||
template<>
|
||||
mtx::events::msg::Image
|
||||
toRoomMessage<mtx::events::msg::Image>(const PendingMessage &m);
|
||||
|
||||
template<>
|
||||
mtx::events::msg::Text
|
||||
toRoomMessage<mtx::events::msg::Text>(const PendingMessage &);
|
||||
|
||||
template<>
|
||||
mtx::events::msg::Video
|
||||
toRoomMessage<mtx::events::msg::Video>(const PendingMessage &m);
|
||||
|
||||
// In which place new TimelineItems should be inserted.
|
||||
enum class TimelineDirection
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
};
|
||||
|
||||
class TimelineView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TimelineView(const mtx::responses::Timeline &timeline,
|
||||
const QString &room_id,
|
||||
QWidget *parent = 0);
|
||||
TimelineView(const QString &room_id, QWidget *parent = 0);
|
||||
|
||||
// Add new events at the end of the timeline.
|
||||
void addEvents(const mtx::responses::Timeline &timeline);
|
||||
void addUserMessage(mtx::events::MessageType ty, const QString &msg);
|
||||
|
||||
template<class Widget, mtx::events::MessageType MsgType>
|
||||
void addUserMessage(const QString &url,
|
||||
const QString &filename,
|
||||
const QString &mime,
|
||||
uint64_t size,
|
||||
const QSize &dimensions = QSize());
|
||||
void updatePendingMessage(const std::string &txn_id, const QString &event_id);
|
||||
void scrollDown();
|
||||
|
||||
//! Remove an item from the timeline with the given Event ID.
|
||||
void removeEvent(const QString &event_id);
|
||||
void setPrevBatchToken(const QString &token) { prev_batch_token_ = token; }
|
||||
|
||||
public slots:
|
||||
void sliderRangeChanged(int min, int max);
|
||||
void sliderMoved(int position);
|
||||
void fetchHistory();
|
||||
|
||||
// Add old events at the top of the timeline.
|
||||
void addBackwardsEvents(const mtx::responses::Messages &msgs);
|
||||
|
||||
// Whether or not the initial batch has been loaded.
|
||||
bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; }
|
||||
|
||||
void handleFailedMessage(const std::string &txn_id);
|
||||
|
||||
private slots:
|
||||
void sendNextPendingMessage();
|
||||
|
||||
signals:
|
||||
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
|
||||
void messagesRetrieved(const mtx::responses::Messages &res);
|
||||
void messageFailed(const std::string &txn_id);
|
||||
void messageSent(const std::string &txn_id, const QString &event_id);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
private:
|
||||
using TimelineEvent = mtx::events::collections::TimelineEvents;
|
||||
|
||||
QWidget *relativeWidget(QWidget *item, int dt) const;
|
||||
|
||||
DecryptionResult parseEncryptedEvent(
|
||||
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e);
|
||||
|
||||
void handleClaimedKeys(std::shared_ptr<StateKeeper> keeper,
|
||||
const std::map<std::string, std::string> &room_key,
|
||||
const std::map<std::string, DevicePublicKeys> &pks,
|
||||
const std::string &user_id,
|
||||
const mtx::responses::ClaimKeys &res,
|
||||
mtx::http::RequestErr err);
|
||||
|
||||
//! Callback for all message sending.
|
||||
void sendRoomMessageHandler(const std::string &txn_id,
|
||||
const mtx::responses::EventId &res,
|
||||
mtx::http::RequestErr err);
|
||||
void prepareEncryptedMessage(const PendingMessage &msg);
|
||||
|
||||
//! Call the /messages endpoint to fill the timeline.
|
||||
void getMessages();
|
||||
//! HACK: Fixing layout flickering when adding to the bottom
|
||||
//! of the timeline.
|
||||
void pushTimelineItem(QWidget *item)
|
||||
{
|
||||
item->hide();
|
||||
scroll_layout_->addWidget(item);
|
||||
QTimer::singleShot(0, this, [item]() { item->show(); });
|
||||
};
|
||||
|
||||
//! Decides whether or not to show or hide the scroll down button.
|
||||
void toggleScrollDownButton();
|
||||
void init();
|
||||
void addTimelineItem(QWidget *item,
|
||||
TimelineDirection direction = TimelineDirection::Bottom);
|
||||
void updateLastSender(const QString &user_id, TimelineDirection direction);
|
||||
void notifyForLastEvent();
|
||||
void notifyForLastEvent(const TimelineEvent &event);
|
||||
//! Keep track of the sender and the timestamp of the current message.
|
||||
void saveLastMessageInfo(const QString &sender, const QDateTime &datetime)
|
||||
{
|
||||
lastSender_ = sender;
|
||||
lastMsgTimestamp_ = datetime;
|
||||
}
|
||||
void saveFirstMessageInfo(const QString &sender, const QDateTime &datetime)
|
||||
{
|
||||
firstSender_ = sender;
|
||||
firstMsgTimestamp_ = datetime;
|
||||
}
|
||||
//! Keep track of the sender and the timestamp of the current message.
|
||||
void saveMessageInfo(const QString &sender,
|
||||
uint64_t origin_server_ts,
|
||||
TimelineDirection direction);
|
||||
|
||||
TimelineEvent findFirstViewableEvent(const std::vector<TimelineEvent> &events);
|
||||
TimelineEvent findLastViewableEvent(const std::vector<TimelineEvent> &events);
|
||||
|
||||
//! Mark the last event as read.
|
||||
void readLastEvent() const;
|
||||
//! Whether or not the scrollbar is visible (non-zero height).
|
||||
bool isScrollbarActivated() { return scroll_area_->verticalScrollBar()->value() != 0; }
|
||||
//! Retrieve the event id of the last item.
|
||||
QString getLastEventId() const;
|
||||
|
||||
template<class Event, class Widget>
|
||||
TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction);
|
||||
|
||||
// TODO: Remove this eventually.
|
||||
template<class Event>
|
||||
TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction);
|
||||
|
||||
// For events with custom display widgets.
|
||||
template<class Event, class Widget>
|
||||
TimelineItem *createTimelineItem(const Event &event, bool withSender);
|
||||
|
||||
// For events without custom display widgets.
|
||||
// TODO: All events should have custom widgets.
|
||||
template<class Event>
|
||||
TimelineItem *createTimelineItem(const Event &event, bool withSender);
|
||||
|
||||
// Used to determine whether or not we should prefix a message with the
|
||||
// sender's name.
|
||||
bool isSenderRendered(const QString &user_id,
|
||||
uint64_t origin_server_ts,
|
||||
TimelineDirection direction);
|
||||
|
||||
bool isPendingMessage(const std::string &txn_id,
|
||||
const QString &sender,
|
||||
const QString &userid);
|
||||
void removePendingMessage(const std::string &txn_id);
|
||||
|
||||
bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); }
|
||||
|
||||
void handleNewUserMessage(PendingMessage msg);
|
||||
bool isDateDifference(const QDateTime &first,
|
||||
const QDateTime &second = QDateTime::currentDateTime()) const;
|
||||
|
||||
// Return nullptr if the event couldn't be parsed.
|
||||
QWidget *parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
|
||||
TimelineDirection direction);
|
||||
|
||||
//! Store the event id associated with the given widget.
|
||||
void saveEventId(QWidget *widget);
|
||||
|
||||
QVBoxLayout *top_layout_;
|
||||
QVBoxLayout *scroll_layout_;
|
||||
|
||||
QScrollArea *scroll_area_;
|
||||
ScrollBar *scrollbar_;
|
||||
QWidget *scroll_widget_;
|
||||
|
||||
QString firstSender_;
|
||||
QDateTime firstMsgTimestamp_;
|
||||
QString lastSender_;
|
||||
QDateTime lastMsgTimestamp_;
|
||||
|
||||
QString room_id_;
|
||||
QString prev_batch_token_;
|
||||
QString local_user_;
|
||||
|
||||
bool isPaginationInProgress_ = false;
|
||||
|
||||
// Keeps track whether or not the user has visited the view.
|
||||
bool isInitialized = false;
|
||||
bool isTimelineFinished = false;
|
||||
bool isInitialSync = true;
|
||||
|
||||
const int SCROLL_BAR_GAP = 200;
|
||||
|
||||
QTimer *paginationTimer_;
|
||||
|
||||
int scroll_height_ = 0;
|
||||
int previous_max_height_ = 0;
|
||||
|
||||
int oldPosition_;
|
||||
int oldHeight_;
|
||||
|
||||
FloatingButton *scrollDownBtn_;
|
||||
|
||||
TimelineDirection lastMessageDirection_;
|
||||
|
||||
//! Messages received by sync not added to the timeline.
|
||||
std::vector<TimelineEvent> bottomMessages_;
|
||||
//! Messages received by /messages not added to the timeline.
|
||||
std::vector<TimelineEvent> topMessages_;
|
||||
|
||||
//! Render the given timeline events to the bottom of the timeline.
|
||||
void renderBottomEvents(const std::vector<TimelineEvent> &events);
|
||||
//! Render the given timeline events to the top of the timeline.
|
||||
void renderTopEvents(const std::vector<TimelineEvent> &events);
|
||||
|
||||
// The events currently rendered. Used for duplicate detection.
|
||||
QMap<QString, QWidget *> eventIds_;
|
||||
QQueue<PendingMessage> pending_msgs_;
|
||||
QList<PendingMessage> pending_sent_msgs_;
|
||||
};
|
||||
|
||||
template<class Widget, mtx::events::MessageType MsgType>
|
||||
void
|
||||
TimelineView::addUserMessage(const QString &url,
|
||||
const QString &filename,
|
||||
const QString &mime,
|
||||
uint64_t size,
|
||||
const QSize &dimensions)
|
||||
{
|
||||
auto with_sender = (lastSender_ != local_user_) || isDateDifference(lastMsgTimestamp_);
|
||||
auto trimmed = QFileInfo{filename}.fileName(); // Trim file path.
|
||||
|
||||
auto widget = new Widget(url, trimmed, size, this);
|
||||
|
||||
TimelineItem *view_item =
|
||||
new TimelineItem(widget, local_user_, with_sender, room_id_, scroll_widget_);
|
||||
|
||||
addTimelineItem(view_item);
|
||||
|
||||
lastMessageDirection_ = TimelineDirection::Bottom;
|
||||
|
||||
// Keep track of the sender and the timestamp of the current message.
|
||||
saveLastMessageInfo(local_user_, QDateTime::currentDateTime());
|
||||
|
||||
PendingMessage message;
|
||||
message.ty = MsgType;
|
||||
message.txn_id = http::client()->generate_txn_id();
|
||||
message.body = url;
|
||||
message.filename = trimmed;
|
||||
message.mime = mime;
|
||||
message.media_size = size;
|
||||
message.widget = view_item;
|
||||
message.dimensions = dimensions;
|
||||
|
||||
handleNewUserMessage(message);
|
||||
}
|
||||
|
||||
template<class Event>
|
||||
TimelineItem *
|
||||
TimelineView::createTimelineItem(const Event &event, bool withSender)
|
||||
{
|
||||
TimelineItem *item = new TimelineItem(event, withSender, room_id_, scroll_widget_);
|
||||
return item;
|
||||
}
|
||||
|
||||
template<class Event, class Widget>
|
||||
TimelineItem *
|
||||
TimelineView::createTimelineItem(const Event &event, bool withSender)
|
||||
{
|
||||
auto eventWidget = new Widget(event);
|
||||
auto item = new TimelineItem(eventWidget, event, withSender, room_id_, scroll_widget_);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
template<class Event>
|
||||
TimelineItem *
|
||||
TimelineView::processMessageEvent(const Event &event, TimelineDirection direction)
|
||||
{
|
||||
const auto event_id = QString::fromStdString(event.event_id);
|
||||
const auto sender = QString::fromStdString(event.sender);
|
||||
|
||||
const auto txn_id = event.unsigned_data.transaction_id;
|
||||
if ((!txn_id.empty() && isPendingMessage(txn_id, sender, local_user_)) ||
|
||||
isDuplicate(event_id)) {
|
||||
removePendingMessage(txn_id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto with_sender = isSenderRendered(sender, event.origin_server_ts, direction);
|
||||
|
||||
saveMessageInfo(sender, event.origin_server_ts, direction);
|
||||
|
||||
auto item = createTimelineItem<Event>(event, with_sender);
|
||||
|
||||
eventIds_[event_id] = item;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
template<class Event, class Widget>
|
||||
TimelineItem *
|
||||
TimelineView::processMessageEvent(const Event &event, TimelineDirection direction)
|
||||
{
|
||||
const auto event_id = QString::fromStdString(event.event_id);
|
||||
const auto sender = QString::fromStdString(event.sender);
|
||||
|
||||
const auto txn_id = event.unsigned_data.transaction_id;
|
||||
if ((!txn_id.empty() && isPendingMessage(txn_id, sender, local_user_)) ||
|
||||
isDuplicate(event_id)) {
|
||||
removePendingMessage(txn_id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto with_sender = isSenderRendered(sender, event.origin_server_ts, direction);
|
||||
|
||||
saveMessageInfo(sender, event.origin_server_ts, direction);
|
||||
|
||||
auto item = createTimelineItem<Event, Widget>(event, with_sender);
|
||||
|
||||
eventIds_[event_id] = item;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#include <QSettings>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "timeline/TimelineView.h"
|
||||
#include "timeline/TimelineViewManager.h"
|
||||
#include "timeline/widgets/AudioItem.h"
|
||||
94
src/timeline/TimelineViewManager.h
Normal file
94
src/timeline/TimelineViewManager.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include <mtx.hpp>
|
||||
|
||||
class QFile;
|
||||
|
||||
class RoomInfoListItem;
|
||||
class TimelineView;
|
||||
struct DescInfo;
|
||||
struct SavedMessages;
|
||||
|
||||
class TimelineViewManager : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TimelineViewManager(QWidget *parent);
|
||||
|
||||
// Initialize with timeline events.
|
||||
void initialize(const mtx::responses::Rooms &rooms);
|
||||
// Empty initialization.
|
||||
void initialize(const std::vector<std::string> &rooms);
|
||||
|
||||
void addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id);
|
||||
void addRoom(const QString &room_id);
|
||||
|
||||
void sync(const mtx::responses::Rooms &rooms);
|
||||
void clearAll() { views_.clear(); }
|
||||
|
||||
// Check if all the timelines have been loaded.
|
||||
bool hasLoaded() const;
|
||||
|
||||
static QString chooseRandomColor();
|
||||
|
||||
signals:
|
||||
void clearRoomMessageCount(QString roomid);
|
||||
void updateRoomsLastMessage(const QString &user, const DescInfo &info);
|
||||
|
||||
public slots:
|
||||
void removeTimelineEvent(const QString &room_id, const QString &event_id);
|
||||
void initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs);
|
||||
|
||||
void setHistoryView(const QString &room_id);
|
||||
void queueTextMessage(const QString &msg);
|
||||
void queueEmoteMessage(const QString &msg);
|
||||
void queueImageMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
uint64_t dsize,
|
||||
const QSize &dimensions);
|
||||
void queueFileMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
uint64_t dsize);
|
||||
void queueAudioMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
uint64_t dsize);
|
||||
void queueVideoMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url,
|
||||
const QString &mime,
|
||||
uint64_t dsize);
|
||||
|
||||
private:
|
||||
//! Check if the given room id is managed by a TimelineView.
|
||||
bool timelineViewExists(const QString &id) { return views_.find(id) != views_.end(); }
|
||||
|
||||
QString active_room_;
|
||||
std::map<QString, QSharedPointer<TimelineView>> views_;
|
||||
};
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Utils.h"
|
||||
|
||||
107
src/timeline/widgets/AudioItem.h
Normal file
107
src/timeline/widgets/AudioItem.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
#include <QIcon>
|
||||
#include <QMediaPlayer>
|
||||
#include <QMouseEvent>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include <mtx.hpp>
|
||||
|
||||
class AudioItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
|
||||
Q_PROPERTY(QColor iconColor WRITE setIconColor READ iconColor)
|
||||
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
|
||||
|
||||
Q_PROPERTY(QColor durationBackgroundColor WRITE setDurationBackgroundColor READ
|
||||
durationBackgroundColor)
|
||||
Q_PROPERTY(QColor durationForegroundColor WRITE setDurationForegroundColor READ
|
||||
durationForegroundColor)
|
||||
|
||||
public:
|
||||
AudioItem(const mtx::events::RoomEvent<mtx::events::msg::Audio> &event,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
AudioItem(const QString &url,
|
||||
const QString &filename,
|
||||
uint64_t size,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
void setTextColor(const QColor &color) { textColor_ = color; }
|
||||
void setIconColor(const QColor &color) { iconColor_ = color; }
|
||||
void setBackgroundColor(const QColor &color) { backgroundColor_ = color; }
|
||||
|
||||
void setDurationBackgroundColor(const QColor &color) { durationBgColor_ = color; }
|
||||
void setDurationForegroundColor(const QColor &color) { durationFgColor_ = color; }
|
||||
|
||||
QColor textColor() const { return textColor_; }
|
||||
QColor iconColor() const { return iconColor_; }
|
||||
QColor backgroundColor() const { return backgroundColor_; }
|
||||
|
||||
QColor durationBackgroundColor() const { return durationBgColor_; }
|
||||
QColor durationForegroundColor() const { return durationFgColor_; }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
signals:
|
||||
void fileDownloadedCb(const QByteArray &data);
|
||||
|
||||
private slots:
|
||||
void fileDownloaded(const QByteArray &data);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
enum class AudioState
|
||||
{
|
||||
Play,
|
||||
Pause,
|
||||
};
|
||||
|
||||
AudioState state_ = AudioState::Play;
|
||||
|
||||
QUrl url_;
|
||||
QString text_;
|
||||
QString readableFileSize_;
|
||||
QString filenameToSave_;
|
||||
|
||||
mtx::events::RoomEvent<mtx::events::msg::Audio> event_;
|
||||
|
||||
QMediaPlayer *player_;
|
||||
|
||||
QIcon playIcon_;
|
||||
QIcon pauseIcon_;
|
||||
|
||||
QColor textColor_ = QColor("white");
|
||||
QColor iconColor_ = QColor("#38A3D8");
|
||||
QColor backgroundColor_ = QColor("#333");
|
||||
|
||||
QColor durationBgColor_ = QColor("black");
|
||||
QColor durationFgColor_ = QColor("blue");
|
||||
};
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "Logging.hpp"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Utils.h"
|
||||
|
||||
82
src/timeline/widgets/FileItem.h
Normal file
82
src/timeline/widgets/FileItem.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
#include <QIcon>
|
||||
#include <QMouseEvent>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include <mtx.hpp>
|
||||
|
||||
class FileItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
|
||||
Q_PROPERTY(QColor iconColor WRITE setIconColor READ iconColor)
|
||||
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
|
||||
|
||||
public:
|
||||
FileItem(const mtx::events::RoomEvent<mtx::events::msg::File> &event,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
FileItem(const QString &url,
|
||||
const QString &filename,
|
||||
uint64_t size,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
void setTextColor(const QColor &color) { textColor_ = color; }
|
||||
void setIconColor(const QColor &color) { iconColor_ = color; }
|
||||
void setBackgroundColor(const QColor &color) { backgroundColor_ = color; }
|
||||
|
||||
QColor textColor() const { return textColor_; }
|
||||
QColor iconColor() const { return iconColor_; }
|
||||
QColor backgroundColor() const { return backgroundColor_; }
|
||||
|
||||
signals:
|
||||
void fileDownloadedCb(const QByteArray &data);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void fileDownloaded(const QByteArray &data);
|
||||
|
||||
private:
|
||||
void openUrl();
|
||||
void init();
|
||||
|
||||
QUrl url_;
|
||||
QString text_;
|
||||
QString readableFileSize_;
|
||||
QString filenameToSave_;
|
||||
|
||||
mtx::events::RoomEvent<mtx::events::msg::File> event_;
|
||||
|
||||
QIcon icon_;
|
||||
|
||||
QColor textColor_ = QColor("white");
|
||||
QColor iconColor_ = QColor("#38A3D8");
|
||||
QColor backgroundColor_ = QColor("#333");
|
||||
};
|
||||
|
|
@ -24,11 +24,11 @@
|
|||
#include <QUuid>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Logging.hpp"
|
||||
#include "ImageItem.h"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "Utils.h"
|
||||
#include "dialogs/ImageOverlay.h"
|
||||
#include "timeline/widgets/ImageItem.h"
|
||||
|
||||
void
|
||||
ImageItem::downloadMedia(const QUrl &url)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue