Style change again

This commit is contained in:
Konstantinos Sideris 2017-09-10 12:59:21 +03:00
parent ed36bdb037
commit 1bfe48de75
130 changed files with 6039 additions and 5940 deletions

View File

@ -27,21 +27,21 @@
class AvatarProvider : public QObject class AvatarProvider : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static void init(QSharedPointer<MatrixClient> client); static void init(QSharedPointer<MatrixClient> client);
static void resolve(const QString &userId, TimelineItem *item); static void resolve(const QString &userId, TimelineItem *item);
static void setAvatarUrl(const QString &userId, const QUrl &url); static void setAvatarUrl(const QString &userId, const QUrl &url);
static void clear(); static void clear();
private: private:
static void updateAvatar(const QString &uid, const QImage &img); static void updateAvatar(const QString &uid, const QImage &img);
static QSharedPointer<MatrixClient> client_; static QSharedPointer<MatrixClient> client_;
static QMap<QString, QList<TimelineItem *>> toBeResolved_; static QMap<QString, QList<TimelineItem *>> toBeResolved_;
static QMap<QString, QImage> userAvatars_; static QMap<QString, QImage> userAvatars_;
static QMap<QString, QUrl> avatarUrls_; static QMap<QString, QUrl> avatarUrls_;
}; };

View File

@ -7,24 +7,24 @@
namespace conf namespace conf
{ {
// Global settings. // Global settings.
static const int fontSize = 12; static const int fontSize = 12;
static const int emojiSize = 14; static const int emojiSize = 14;
static const int headerFontSize = 21; static const int headerFontSize = 21;
// Window geometry. // Window geometry.
namespace window namespace window
{ {
static const int height = 600; static const int height = 600;
static const int width = 1066; static const int width = 1066;
static const int minHeight = 600; static const int minHeight = 600;
static const int minWidth = 950; static const int minWidth = 950;
} }
// Button settings. // Button settings.
namespace btn namespace btn
{ {
static const int fontSize = 20; static const int fontSize = 20;
static const int cornerRadius = 3; static const int cornerRadius = 3;
} }
@ -34,8 +34,8 @@ namespace roomlist
namespace fonts namespace fonts
{ {
static const int heading = 13; static const int heading = 13;
static const int badge = 10; static const int badge = 10;
static const int bubble = 20; static const int bubble = 20;
} // namespace fonts } // namespace fonts
} // namespace roomlist } // namespace roomlist
@ -44,7 +44,7 @@ namespace userInfoWidget
namespace fonts namespace fonts
{ {
static const int displayName = 16; static const int displayName = 16;
static const int userid = 14; static const int userid = 14;
} // namespace fonts } // namespace fonts
} // namespace userInfoWidget } // namespace userInfoWidget
@ -52,16 +52,16 @@ namespace topRoomBar
{ {
namespace fonts namespace fonts
{ {
static const int roomName = 15; static const int roomName = 15;
static const int roomDescription = 13; static const int roomDescription = 13;
} // namespace fonts } // namespace fonts
} // namespace topRoomBar } // namespace topRoomBar
namespace timeline namespace timeline
{ {
static const int msgMargin = 11; static const int msgMargin = 11;
static const int avatarSize = 36; static const int avatarSize = 36;
static const int headerSpacing = 5; static const int headerSpacing = 5;
static const int headerLeftMargin = 15; static const int headerLeftMargin = 15;
namespace fonts namespace fonts

View File

@ -26,36 +26,36 @@
class DeserializationException : public std::exception class DeserializationException : public std::exception
{ {
public: public:
explicit DeserializationException(const std::string &msg); explicit DeserializationException(const std::string &msg);
virtual const char *what() const noexcept; virtual const char *what() const noexcept;
private: private:
std::string msg_; std::string msg_;
}; };
// JSON response structs need to implement the interface. // JSON response structs need to implement the interface.
class Deserializable class Deserializable
{ {
public: public:
virtual void deserialize(const QJsonValue &) virtual void deserialize(const QJsonValue &)
{ {
} }
virtual void deserialize(const QJsonObject &) virtual void deserialize(const QJsonObject &)
{ {
} }
virtual void deserialize(const QJsonDocument &) virtual void deserialize(const QJsonDocument &)
{ {
} }
virtual ~Deserializable() virtual ~Deserializable()
{ {
} }
}; };
class Serializable class Serializable
{ {
public: public:
virtual QJsonObject serialize() const = 0; virtual QJsonObject serialize() const = 0;
virtual ~Serializable() virtual ~Serializable()
{ {
} }
}; };

View File

@ -29,32 +29,32 @@
class EmojiCategory : public QWidget class EmojiCategory : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent = nullptr); EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent = nullptr);
~EmojiCategory(); ~EmojiCategory();
signals: signals:
void emojiSelected(const QString &emoji); void emojiSelected(const QString &emoji);
private slots: private slots:
inline void clickIndex(const QModelIndex &); inline void clickIndex(const QModelIndex &);
private: private:
QVBoxLayout *mainLayout_; QVBoxLayout *mainLayout_;
QStandardItemModel *itemModel_; QStandardItemModel *itemModel_;
QListView *emojiListView_; QListView *emojiListView_;
Emoji *data_; Emoji *data_;
EmojiItemDelegate *delegate_; EmojiItemDelegate *delegate_;
QLabel *category_; QLabel *category_;
}; };
inline void inline void
EmojiCategory::clickIndex(const QModelIndex &index) EmojiCategory::clickIndex(const QModelIndex &index)
{ {
emit emojiSelected(index.data(Qt::UserRole).toString()); emit emojiSelected(index.data(Qt::UserRole).toString());
} }

View File

@ -25,14 +25,16 @@
class EmojiItemDelegate : public QStyledItemDelegate class EmojiItemDelegate : public QStyledItemDelegate
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EmojiItemDelegate(QObject *parent = nullptr); explicit EmojiItemDelegate(QObject *parent = nullptr);
~EmojiItemDelegate(); ~EmojiItemDelegate();
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
private: private:
Emoji *data_; Emoji *data_;
}; };

View File

@ -27,38 +27,38 @@
class EmojiPanel : public QWidget class EmojiPanel : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
EmojiPanel(QWidget *parent = nullptr); EmojiPanel(QWidget *parent = nullptr);
void fadeOut(); void fadeOut();
void fadeIn(); void fadeIn();
signals: signals:
void mouseLeft(); void mouseLeft();
void emojiSelected(const QString &emoji); void emojiSelected(const QString &emoji);
protected: protected:
void leaveEvent(QEvent *event); void leaveEvent(QEvent *event);
void paintEvent(QPaintEvent *event); void paintEvent(QPaintEvent *event);
private: private:
void showEmojiCategory(const EmojiCategory *category); void showEmojiCategory(const EmojiCategory *category);
QPropertyAnimation *animation_; QPropertyAnimation *animation_;
QGraphicsOpacityEffect *opacity_; QGraphicsOpacityEffect *opacity_;
EmojiProvider emoji_provider_; EmojiProvider emoji_provider_;
QScrollArea *scrollArea_; QScrollArea *scrollArea_;
int shadowMargin_; int shadowMargin_;
// Panel dimensions. // Panel dimensions.
int width_; int width_;
int height_; int height_;
int animationDuration_; int animationDuration_;
int categoryIconSize_; int categoryIconSize_;
}; };

View File

@ -25,23 +25,23 @@
class EmojiPickButton : public FlatButton class EmojiPickButton : public FlatButton
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EmojiPickButton(QWidget *parent = nullptr); explicit EmojiPickButton(QWidget *parent = nullptr);
signals: signals:
void emojiSelected(const QString &emoji); void emojiSelected(const QString &emoji);
protected: protected:
void enterEvent(QEvent *e) override; void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
private: private:
// Vertical distance from panel's bottom. // Vertical distance from panel's bottom.
int vertical_distance_ = 10; int vertical_distance_ = 10;
// Horizontal distance from panel's bottom right corner. // Horizontal distance from panel's bottom right corner.
int horizontal_distance_ = 70; int horizontal_distance_ = 70;
EmojiPanel *panel_; EmojiPanel *panel_;
}; };

View File

@ -22,21 +22,21 @@
#include <QMap> #include <QMap>
struct Emoji { struct Emoji {
// Unicode code. // Unicode code.
QString unicode; QString unicode;
// Keyboard shortcut e.g :emoji: // Keyboard shortcut e.g :emoji:
QString shortname; QString shortname;
}; };
class EmojiProvider class EmojiProvider
{ {
public: public:
static const QList<Emoji> people; static const QList<Emoji> people;
static const QList<Emoji> nature; static const QList<Emoji> nature;
static const QList<Emoji> food; static const QList<Emoji> food;
static const QList<Emoji> activity; static const QList<Emoji> activity;
static const QList<Emoji> travel; static const QList<Emoji> travel;
static const QList<Emoji> objects; static const QList<Emoji> objects;
static const QList<Emoji> symbols; static const QList<Emoji> symbols;
static const QList<Emoji> flags; static const QList<Emoji> flags;
}; };

View File

@ -26,47 +26,47 @@
#include "MatrixClient.h" #include "MatrixClient.h"
namespace events = matrix::events; namespace events = matrix::events;
namespace msgs = matrix::events::messages; namespace msgs = matrix::events::messages;
class ImageItem : public QWidget class ImageItem : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
ImageItem(QSharedPointer<MatrixClient> client, ImageItem(QSharedPointer<MatrixClient> client,
const events::MessageEvent<msgs::Image> &event, const events::MessageEvent<msgs::Image> &event,
QWidget *parent = nullptr); QWidget *parent = nullptr);
void setImage(const QPixmap &image); void setImage(const QPixmap &image);
QSize sizeHint() const override; QSize sizeHint() const override;
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
private slots: private slots:
void imageDownloaded(const QString &event_id, const QPixmap &img); void imageDownloaded(const QString &event_id, const QPixmap &img);
private: private:
void scaleImage(); void scaleImage();
void openUrl(); void openUrl();
int max_width_ = 500; int max_width_ = 500;
int max_height_ = 300; int max_height_ = 300;
int width_; int width_;
int height_; int height_;
QPixmap scaled_image_; QPixmap scaled_image_;
QPixmap image_; QPixmap image_;
QUrl url_; QUrl url_;
QString text_; QString text_;
int bottom_height_ = 30; int bottom_height_ = 30;
events::MessageEvent<msgs::Image> event_; events::MessageEvent<msgs::Image> event_;
QSharedPointer<MatrixClient> client_; QSharedPointer<MatrixClient> client_;
}; };

View File

@ -23,24 +23,24 @@
class ImageOverlayDialog : public QWidget class ImageOverlayDialog : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
ImageOverlayDialog(QPixmap image, QWidget *parent = nullptr); ImageOverlayDialog(QPixmap image, QWidget *parent = nullptr);
protected: protected:
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
signals: signals:
void closing(); void closing();
private: private:
void scaleImage(int width, int height); void scaleImage(int width, int height);
QPixmap originalImage_; QPixmap originalImage_;
QPixmap image_; QPixmap image_;
QRect content_; QRect content_;
QRect close_button_; QRect close_button_;
QRect screen_; QRect screen_;
}; };

View File

@ -23,9 +23,9 @@
class InputValidator class InputValidator
{ {
public: public:
// Validators for the different types of input. // Validators for the different types of input.
static QRegExpValidator Id; static QRegExpValidator Id;
static QRegExpValidator Localpart; static QRegExpValidator Localpart;
static QRegExpValidator Password; static QRegExpValidator Password;
static QRegExpValidator Domain; static QRegExpValidator Domain;
}; };

View File

@ -24,60 +24,60 @@
class LoginRequest class LoginRequest
{ {
public: public:
LoginRequest(); LoginRequest();
LoginRequest(QString username, QString password); LoginRequest(QString username, QString password);
QByteArray serialize() noexcept; QByteArray serialize() noexcept;
inline void setPassword(QString password); inline void setPassword(QString password);
inline void setUser(QString username); inline void setUser(QString username);
private: private:
QString user_; QString user_;
QString password_; QString password_;
}; };
inline void inline void
LoginRequest::setPassword(QString password) LoginRequest::setPassword(QString password)
{ {
password_ = password; password_ = password;
} }
inline void inline void
LoginRequest::setUser(QString username) LoginRequest::setUser(QString username)
{ {
user_ = username; user_ = username;
} }
class LoginResponse : public Deserializable class LoginResponse : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
inline QString getAccessToken(); inline QString getAccessToken();
inline QString getHomeServer(); inline QString getHomeServer();
inline QString getUserId(); inline QString getUserId();
private: private:
QString access_token_; QString access_token_;
QString home_server_; QString home_server_;
QString user_id_; QString user_id_;
}; };
inline QString inline QString
LoginResponse::getAccessToken() LoginResponse::getAccessToken()
{ {
return access_token_; return access_token_;
} }
inline QString inline QString
LoginResponse::getHomeServer() LoginResponse::getHomeServer()
{ {
return home_server_; return home_server_;
} }
inline QString inline QString
LoginResponse::getUserId() LoginResponse::getUserId()
{ {
return user_id_; return user_id_;
} }

View File

@ -32,68 +32,68 @@
class LoginPage : public QWidget class LoginPage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0); LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~LoginPage(); ~LoginPage();
void reset(); void reset();
signals: signals:
void backButtonClicked(); void backButtonClicked();
private slots: private slots:
// Callback for the back button. // Callback for the back button.
void onBackButtonClicked(); void onBackButtonClicked();
// Callback for the login button. // Callback for the login button.
void onLoginButtonClicked(); void onLoginButtonClicked();
// Callback for probing the server found in the mxid // Callback for probing the server found in the mxid
void onMatrixIdEntered(); void onMatrixIdEntered();
// Callback for probing the manually entered server // Callback for probing the manually entered server
void onServerAddressEntered(); void onServerAddressEntered();
// Displays errors produced during the login. // Displays errors produced during the login.
void loginError(QString error_message); void loginError(QString error_message);
// Callback for errors produced during server probing // Callback for errors produced during server probing
void versionError(QString error_message); void versionError(QString error_message);
// Callback for successful server probing // Callback for successful server probing
void versionSuccess(); void versionSuccess();
private: private:
bool isMatrixIdValid(); bool isMatrixIdValid();
QVBoxLayout *top_layout_; QVBoxLayout *top_layout_;
QHBoxLayout *top_bar_layout_; QHBoxLayout *top_bar_layout_;
QHBoxLayout *logo_layout_; QHBoxLayout *logo_layout_;
QHBoxLayout *button_layout_; QHBoxLayout *button_layout_;
QLabel *logo_; QLabel *logo_;
QLabel *error_label_; QLabel *error_label_;
QHBoxLayout *serverLayout_; QHBoxLayout *serverLayout_;
QHBoxLayout *matrixidLayout_; QHBoxLayout *matrixidLayout_;
CircularProgress *spinner_; CircularProgress *spinner_;
QLabel *errorIcon_; QLabel *errorIcon_;
QString inferredServerAddress_; QString inferredServerAddress_;
FlatButton *back_button_; FlatButton *back_button_;
RaisedButton *login_button_; RaisedButton *login_button_;
QWidget *form_widget_; QWidget *form_widget_;
QHBoxLayout *form_wrapper_; QHBoxLayout *form_wrapper_;
QVBoxLayout *form_layout_; QVBoxLayout *form_layout_;
TextField *matrixid_input_; TextField *matrixid_input_;
TextField *password_input_; TextField *password_input_;
TextField *serverInput_; TextField *serverInput_;
// Matrix client API provider. // Matrix client API provider.
QSharedPointer<MatrixClient> client_; QSharedPointer<MatrixClient> client_;
}; };

View File

@ -23,14 +23,14 @@
class LogoutDialog : public QFrame class LogoutDialog : public QFrame
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit LogoutDialog(QWidget *parent = nullptr); explicit LogoutDialog(QWidget *parent = nullptr);
signals: signals:
void closing(bool isLoggingOut); void closing(bool isLoggingOut);
private: private:
FlatButton *confirmBtn_; FlatButton *confirmBtn_;
FlatButton *cancelBtn_; FlatButton *cancelBtn_;
}; };

View File

@ -32,64 +32,64 @@
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = 0);
~MainWindow(); ~MainWindow();
static MainWindow *instance(); static MainWindow *instance();
void saveCurrentWindowSize(); void saveCurrentWindowSize();
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
private slots: private slots:
// Handle interaction with the tray icon. // Handle interaction with the tray icon.
void iconActivated(QSystemTrayIcon::ActivationReason reason); void iconActivated(QSystemTrayIcon::ActivationReason reason);
// Show the welcome page in the main window. // Show the welcome page in the main window.
void showWelcomePage(); void showWelcomePage();
// Show the login page in the main window. // Show the login page in the main window.
void showLoginPage(); void showLoginPage();
// Show the register page in the main window. // Show the register page in the main window.
void showRegisterPage(); void showRegisterPage();
// Show the chat page and start communicating with the given access token. // Show the chat page and start communicating with the given access token.
void showChatPage(QString user_id, QString home_server, QString token); void showChatPage(QString user_id, QString home_server, QString token);
void removeOverlayProgressBar(); void removeOverlayProgressBar();
private: private:
bool hasActiveUser(); bool hasActiveUser();
void restoreWindowSize(); void restoreWindowSize();
static MainWindow *instance_; static MainWindow *instance_;
// The initial welcome screen. // The initial welcome screen.
WelcomePage *welcome_page_; WelcomePage *welcome_page_;
// The login screen. // The login screen.
LoginPage *login_page_; LoginPage *login_page_;
// The register page. // The register page.
RegisterPage *register_page_; RegisterPage *register_page_;
// A stacked widget that handles the transitions between widgets. // A stacked widget that handles the transitions between widgets.
SlidingStackWidget *sliding_stack_; SlidingStackWidget *sliding_stack_;
// The main chat area. // The main chat area.
ChatPage *chat_page_; ChatPage *chat_page_;
// Used to hide undefined states between page transitions. // Used to hide undefined states between page transitions.
OverlayModal *progress_modal_; OverlayModal *progress_modal_;
CircularProgress *spinner_; CircularProgress *spinner_;
// Matrix Client API provider. // Matrix Client API provider.
QSharedPointer<MatrixClient> client_; QSharedPointer<MatrixClient> client_;
// Tray icon that shows the unread message count. // Tray icon that shows the unread message count.
TrayIcon *trayIcon_; TrayIcon *trayIcon_;
}; };

View File

@ -25,24 +25,24 @@
class ProfileResponse : public Deserializable class ProfileResponse : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
inline QUrl getAvatarUrl(); inline QUrl getAvatarUrl();
inline QString getDisplayName(); inline QString getDisplayName();
private: private:
QUrl avatar_url_; QUrl avatar_url_;
QString display_name_; QString display_name_;
}; };
inline QUrl inline QUrl
ProfileResponse::getAvatarUrl() ProfileResponse::getAvatarUrl()
{ {
return avatar_url_; return avatar_url_;
} }
inline QString inline QString
ProfileResponse::getDisplayName() ProfileResponse::getDisplayName()
{ {
return display_name_; return display_name_;
} }

View File

@ -26,44 +26,44 @@
class RoomSearchInput : public TextField class RoomSearchInput : public TextField
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RoomSearchInput(QWidget *parent = nullptr); explicit RoomSearchInput(QWidget *parent = nullptr);
signals: signals:
void selectNextCompletion(); void selectNextCompletion();
void selectPreviousCompletion(); void selectPreviousCompletion();
void hiding(); void hiding();
protected: protected:
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
void hideEvent(QHideEvent *event) override; void hideEvent(QHideEvent *event) override;
bool focusNextPrevChild(bool next) override; bool focusNextPrevChild(bool next) override;
}; };
class QuickSwitcher : public QFrame class QuickSwitcher : public QFrame
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit QuickSwitcher(QWidget *parent = nullptr); explicit QuickSwitcher(QWidget *parent = nullptr);
void setRoomList(const QMap<QString, QString> &rooms); void setRoomList(const QMap<QString, QString> &rooms);
signals: signals:
void closing(); void closing();
void roomSelected(const QString &roomid); void roomSelected(const QString &roomid);
protected: protected:
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
void showEvent(QShowEvent *event) override; void showEvent(QShowEvent *event) override;
private: private:
// Current highlighted selection from the completer. // Current highlighted selection from the completer.
int selection_ = -1; int selection_ = -1;
QVBoxLayout *topLayout_; QVBoxLayout *topLayout_;
RoomSearchInput *roomSearch_; RoomSearchInput *roomSearch_;
QCompleter *completer_; QCompleter *completer_;
QMap<QString, QString> rooms_; QMap<QString, QString> rooms_;
}; };

View File

@ -24,60 +24,60 @@
class RegisterRequest class RegisterRequest
{ {
public: public:
RegisterRequest(); RegisterRequest();
RegisterRequest(const QString &username, const QString &password); RegisterRequest(const QString &username, const QString &password);
QByteArray serialize() noexcept; QByteArray serialize() noexcept;
inline void setPassword(QString password); inline void setPassword(QString password);
inline void setUser(QString username); inline void setUser(QString username);
private: private:
QString user_; QString user_;
QString password_; QString password_;
}; };
inline void inline void
RegisterRequest::setPassword(QString password) RegisterRequest::setPassword(QString password)
{ {
password_ = password; password_ = password;
} }
inline void inline void
RegisterRequest::setUser(QString username) RegisterRequest::setUser(QString username)
{ {
user_ = username; user_ = username;
} }
class RegisterResponse : public Deserializable class RegisterResponse : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
inline QString getAccessToken(); inline QString getAccessToken();
inline QString getHomeServer(); inline QString getHomeServer();
inline QString getUserId(); inline QString getUserId();
private: private:
QString access_token_; QString access_token_;
QString home_server_; QString home_server_;
QString user_id_; QString user_id_;
}; };
inline QString inline QString
RegisterResponse::getAccessToken() RegisterResponse::getAccessToken()
{ {
return access_token_; return access_token_;
} }
inline QString inline QString
RegisterResponse::getHomeServer() RegisterResponse::getHomeServer()
{ {
return home_server_; return home_server_;
} }
inline QString inline QString
RegisterResponse::getUserId() RegisterResponse::getUserId()
{ {
return user_id_; return user_id_;
} }

View File

@ -31,44 +31,44 @@
class RegisterPage : public QWidget class RegisterPage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
RegisterPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0); RegisterPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~RegisterPage(); ~RegisterPage();
signals: signals:
void backButtonClicked(); void backButtonClicked();
private slots: private slots:
void onBackButtonClicked(); void onBackButtonClicked();
void onRegisterButtonClicked(); void onRegisterButtonClicked();
// Display registration specific errors to the user. // Display registration specific errors to the user.
void registerError(const QString &msg); void registerError(const QString &msg);
private: private:
QVBoxLayout *top_layout_; QVBoxLayout *top_layout_;
QHBoxLayout *back_layout_; QHBoxLayout *back_layout_;
QHBoxLayout *logo_layout_; QHBoxLayout *logo_layout_;
QHBoxLayout *button_layout_; QHBoxLayout *button_layout_;
Avatar *logo_; Avatar *logo_;
QLabel *error_label_; QLabel *error_label_;
FlatButton *back_button_; FlatButton *back_button_;
RaisedButton *register_button_; RaisedButton *register_button_;
QWidget *form_widget_; QWidget *form_widget_;
QHBoxLayout *form_wrapper_; QHBoxLayout *form_wrapper_;
QVBoxLayout *form_layout_; QVBoxLayout *form_layout_;
TextField *username_input_; TextField *username_input_;
TextField *password_input_; TextField *password_input_;
TextField *password_confirmation_; TextField *password_confirmation_;
TextField *server_input_; TextField *server_input_;
// Matrix client API provider. // Matrix client API provider.
QSharedPointer<MatrixClient> client_; QSharedPointer<MatrixClient> client_;
}; };

View File

@ -27,99 +27,102 @@
#include "RoomState.h" #include "RoomState.h"
struct DescInfo { struct DescInfo {
QString username; QString username;
QString userid; QString userid;
QString body; QString body;
QString timestamp; QString timestamp;
}; };
class RoomInfoListItem : public QWidget class RoomInfoListItem : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
RoomInfoListItem(QSharedPointer<RoomSettings> settings, RoomState state, QString room_id, QWidget *parent = 0); RoomInfoListItem(QSharedPointer<RoomSettings> settings,
RoomState state,
QString room_id,
QWidget *parent = 0);
~RoomInfoListItem(); ~RoomInfoListItem();
void updateUnreadMessageCount(int count); void updateUnreadMessageCount(int count);
void clearUnreadMessageCount(); void clearUnreadMessageCount();
void setState(const RoomState &state); void setState(const RoomState &state);
inline bool isPressed() const; inline bool isPressed() const;
inline RoomState state() const; inline RoomState state() const;
inline void setAvatar(const QImage &avatar_image); inline void setAvatar(const QImage &avatar_image);
inline int unreadMessageCount() const; inline int unreadMessageCount() const;
inline void setDescriptionMessage(const DescInfo &info); inline void setDescriptionMessage(const DescInfo &info);
signals: signals:
void clicked(const QString &room_id); void clicked(const QString &room_id);
public slots: public slots:
void setPressedState(bool state); void setPressedState(bool state);
protected: protected:
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override;
private: private:
QString notificationText(); QString notificationText();
const int Padding = 7; const int Padding = 7;
const int IconSize = 48; const int IconSize = 48;
RippleOverlay *ripple_overlay_; RippleOverlay *ripple_overlay_;
RoomState state_; RoomState state_;
QString roomId_; QString roomId_;
QString roomName_; QString roomName_;
DescInfo lastMsgInfo_; DescInfo lastMsgInfo_;
QPixmap roomAvatar_; QPixmap roomAvatar_;
Menu *menu_; Menu *menu_;
QAction *toggleNotifications_; QAction *toggleNotifications_;
QSharedPointer<RoomSettings> roomSettings_; QSharedPointer<RoomSettings> roomSettings_;
bool isPressed_ = false; bool isPressed_ = false;
int maxHeight_; int maxHeight_;
int unreadMsgCount_ = 0; int unreadMsgCount_ = 0;
}; };
inline int inline int
RoomInfoListItem::unreadMessageCount() const RoomInfoListItem::unreadMessageCount() const
{ {
return unreadMsgCount_; return unreadMsgCount_;
} }
inline bool inline bool
RoomInfoListItem::isPressed() const RoomInfoListItem::isPressed() const
{ {
return isPressed_; return isPressed_;
} }
inline RoomState inline RoomState
RoomInfoListItem::state() const RoomInfoListItem::state() const
{ {
return state_; return state_;
} }
inline void inline void
RoomInfoListItem::setAvatar(const QImage &img) RoomInfoListItem::setAvatar(const QImage &img)
{ {
roomAvatar_ = roomAvatar_ = QPixmap::fromImage(
QPixmap::fromImage(img.scaled(IconSize, IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); img.scaled(IconSize, IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
update(); update();
} }
inline void inline void
RoomInfoListItem::setDescriptionMessage(const DescInfo &info) RoomInfoListItem::setDescriptionMessage(const DescInfo &info)
{ {
lastMsgInfo_ = info; lastMsgInfo_ = info;
} }

View File

@ -29,37 +29,37 @@
class RoomList : public QWidget class RoomList : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0); RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~RoomList(); ~RoomList();
void setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &settings, void setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
const QMap<QString, RoomState> &states); const QMap<QString, RoomState> &states);
void sync(const QMap<QString, RoomState> &states); void sync(const QMap<QString, RoomState> &states);
void clear(); void clear();
signals: signals:
void roomChanged(const QString &room_id); void roomChanged(const QString &room_id);
void totalUnreadMessageCountUpdated(int count); void totalUnreadMessageCountUpdated(int count);
public slots: public slots:
void updateRoomAvatar(const QString &roomid, const QPixmap &img); void updateRoomAvatar(const QString &roomid, const QPixmap &img);
void highlightSelectedRoom(const QString &room_id); void highlightSelectedRoom(const QString &room_id);
void updateUnreadMessageCount(const QString &roomid, int count); void updateUnreadMessageCount(const QString &roomid, int count);
void updateRoomDescription(const QString &roomid, const DescInfo &info); void updateRoomDescription(const QString &roomid, const DescInfo &info);
private: private:
void calculateUnreadMessageCount(); void calculateUnreadMessageCount();
QVBoxLayout *topLayout_; QVBoxLayout *topLayout_;
QVBoxLayout *contentsLayout_; QVBoxLayout *contentsLayout_;
QScrollArea *scrollArea_; QScrollArea *scrollArea_;
QWidget *scrollAreaContents_; QWidget *scrollAreaContents_;
QMap<QString, QSharedPointer<RoomInfoListItem>> rooms_; QMap<QString, QSharedPointer<RoomInfoListItem>> rooms_;
QSharedPointer<MatrixClient> client_; QSharedPointer<MatrixClient> client_;
}; };

View File

@ -25,32 +25,32 @@
class RoomMessages : public Deserializable class RoomMessages : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
inline QString start() const; inline QString start() const;
inline QString end() const; inline QString end() const;
inline QJsonArray chunk() const; inline QJsonArray chunk() const;
private: private:
QString start_; QString start_;
QString end_; QString end_;
QJsonArray chunk_; QJsonArray chunk_;
}; };
inline QString inline QString
RoomMessages::start() const RoomMessages::start() const
{ {
return start_; return start_;
} }
inline QString inline QString
RoomMessages::end() const RoomMessages::end() const
{ {
return end_; return end_;
} }
inline QJsonArray inline QJsonArray
RoomMessages::chunk() const RoomMessages::chunk() const
{ {
return chunk_; return chunk_;
} }

View File

@ -22,34 +22,34 @@
class RoomSettings class RoomSettings
{ {
public: public:
RoomSettings(QString room_id) RoomSettings(QString room_id)
{ {
path_ = QString("notifications/%1").arg(room_id); path_ = QString("notifications/%1").arg(room_id);
isNotificationsEnabled_ = true; isNotificationsEnabled_ = true;
QSettings settings; QSettings settings;
if (settings.contains(path_)) if (settings.contains(path_))
isNotificationsEnabled_ = settings.value(path_).toBool(); isNotificationsEnabled_ = settings.value(path_).toBool();
else else
settings.setValue(path_, isNotificationsEnabled_); settings.setValue(path_, isNotificationsEnabled_);
}; };
bool isNotificationsEnabled() bool isNotificationsEnabled()
{ {
return isNotificationsEnabled_; return isNotificationsEnabled_;
}; };
void toggleNotifications() void toggleNotifications()
{ {
isNotificationsEnabled_ = !isNotificationsEnabled_; isNotificationsEnabled_ = !isNotificationsEnabled_;
QSettings settings; QSettings settings;
settings.setValue(path_, isNotificationsEnabled_); settings.setValue(path_, isNotificationsEnabled_);
} }
private: private:
QString path_; QString path_;
bool isNotificationsEnabled_; bool isNotificationsEnabled_;
}; };

View File

@ -32,56 +32,57 @@
class SlidingStackWidget : public QStackedWidget class SlidingStackWidget : public QStackedWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
// Defines the animation direction. // Defines the animation direction.
enum class AnimationDirection { LEFT_TO_RIGHT, RIGHT_TO_LEFT, AUTOMATIC }; enum class AnimationDirection { LEFT_TO_RIGHT, RIGHT_TO_LEFT, AUTOMATIC };
SlidingStackWidget(QWidget *parent); SlidingStackWidget(QWidget *parent);
~SlidingStackWidget(); ~SlidingStackWidget();
public slots: public slots:
// Move to the next widget. // Move to the next widget.
void slideInNext(); void slideInNext();
// Move to the previous widget. // Move to the previous widget.
void slideInPrevious(); void slideInPrevious();
// Move to a widget by index. // Move to a widget by index.
void slideInIndex(int index, AnimationDirection direction = AnimationDirection::AUTOMATIC); void slideInIndex(int index, AnimationDirection direction = AnimationDirection::AUTOMATIC);
int getWidgetIndex(QWidget *widget); int getWidgetIndex(QWidget *widget);
signals: signals:
// Internal signal to alert the engine for the animation's end. // Internal signal to alert the engine for the animation's end.
void animationFinished(); void animationFinished();
protected slots: protected slots:
// Internal slot to handle the end of the animation. // Internal slot to handle the end of the animation.
void onAnimationFinished(); void onAnimationFinished();
protected: protected:
// The method that does the main work for the widget transition. // The method that does the main work for the widget transition.
void slideInWidget(QWidget *widget, AnimationDirection direction = AnimationDirection::AUTOMATIC); void slideInWidget(QWidget *widget,
AnimationDirection direction = AnimationDirection::AUTOMATIC);
// Indicates whether or not the animation is active. // Indicates whether or not the animation is active.
bool active_; bool active_;
// The widget currently displayed. // The widget currently displayed.
QWidget *window_; QWidget *window_;
// The speed of the animation in milliseconds. // The speed of the animation in milliseconds.
int speed_; int speed_;
// The animation type. // The animation type.
QEasingCurve::Type animation_type_; QEasingCurve::Type animation_type_;
// Current widget's index. // Current widget's index.
int now_; int now_;
// Reference point. // Reference point.
QPoint current_position_; QPoint current_position_;
// Next widget's to show index. // Next widget's to show index.
int next_; int next_;
}; };

View File

@ -21,15 +21,15 @@
class Splitter : public QSplitter class Splitter : public QSplitter
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Splitter(QWidget *parent = nullptr); explicit Splitter(QWidget *parent = nullptr);
private: private:
void onSplitterMoved(int pos, int index); void onSplitterMoved(int pos, int index);
int moveEventLimit_ = 50; int moveEventLimit_ = 50;
int leftMoveCount_ = 0; int leftMoveCount_ = 0;
int rightMoveCount_ = 0; int rightMoveCount_ = 0;
}; };

View File

@ -27,187 +27,187 @@
class Event : public Deserializable class Event : public Deserializable
{ {
public: public:
inline QJsonObject content() const; inline QJsonObject content() const;
inline QJsonObject unsigned_content() const; inline QJsonObject unsigned_content() const;
inline QString sender() const; inline QString sender() const;
inline QString state_key() const; inline QString state_key() const;
inline QString type() const; inline QString type() const;
inline QString eventId() const; inline QString eventId() const;
inline uint64_t timestamp() const; inline uint64_t timestamp() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
private: private:
QJsonObject content_; QJsonObject content_;
QJsonObject unsigned_; QJsonObject unsigned_;
QString sender_; QString sender_;
QString state_key_; QString state_key_;
QString type_; QString type_;
QString event_id_; QString event_id_;
uint64_t origin_server_ts_; uint64_t origin_server_ts_;
}; };
inline QJsonObject inline QJsonObject
Event::content() const Event::content() const
{ {
return content_; return content_;
} }
inline QJsonObject inline QJsonObject
Event::unsigned_content() const Event::unsigned_content() const
{ {
return unsigned_; return unsigned_;
} }
inline QString inline QString
Event::sender() const Event::sender() const
{ {
return sender_; return sender_;
} }
inline QString inline QString
Event::state_key() const Event::state_key() const
{ {
return state_key_; return state_key_;
} }
inline QString inline QString
Event::type() const Event::type() const
{ {
return type_; return type_;
} }
inline QString inline QString
Event::eventId() const Event::eventId() const
{ {
return event_id_; return event_id_;
} }
inline uint64_t inline uint64_t
Event::timestamp() const Event::timestamp() const
{ {
return origin_server_ts_; return origin_server_ts_;
} }
class State : public Deserializable class State : public Deserializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
inline QJsonArray events() const; inline QJsonArray events() const;
private: private:
QJsonArray events_; QJsonArray events_;
}; };
inline QJsonArray inline QJsonArray
State::events() const State::events() const
{ {
return events_; return events_;
} }
class Timeline : public Deserializable class Timeline : public Deserializable
{ {
public: public:
inline QJsonArray events() const; inline QJsonArray events() const;
inline QString previousBatch() const; inline QString previousBatch() const;
inline bool limited() const; inline bool limited() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
private: private:
QJsonArray events_; QJsonArray events_;
QString prev_batch_; QString prev_batch_;
bool limited_; bool limited_;
}; };
inline QJsonArray inline QJsonArray
Timeline::events() const Timeline::events() const
{ {
return events_; return events_;
} }
inline QString inline QString
Timeline::previousBatch() const Timeline::previousBatch() const
{ {
return prev_batch_; return prev_batch_;
} }
inline bool inline bool
Timeline::limited() const Timeline::limited() const
{ {
return limited_; return limited_;
} }
// TODO: Add support for ehpmeral, account_data, undread_notifications // TODO: Add support for ehpmeral, account_data, undread_notifications
class JoinedRoom : public Deserializable class JoinedRoom : public Deserializable
{ {
public: public:
inline State state() const; inline State state() const;
inline Timeline timeline() const; inline Timeline timeline() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
private: private:
State state_; State state_;
Timeline timeline_; Timeline timeline_;
/* Ephemeral ephemeral_; */ /* Ephemeral ephemeral_; */
/* AccountData account_data_; */ /* AccountData account_data_; */
/* UnreadNotifications unread_notifications_; */ /* UnreadNotifications unread_notifications_; */
}; };
inline State inline State
JoinedRoom::state() const JoinedRoom::state() const
{ {
return state_; return state_;
} }
inline Timeline inline Timeline
JoinedRoom::timeline() const JoinedRoom::timeline() const
{ {
return timeline_; return timeline_;
} }
// TODO: Add support for invited and left rooms. // TODO: Add support for invited and left rooms.
class Rooms : public Deserializable class Rooms : public Deserializable
{ {
public: public:
inline QMap<QString, JoinedRoom> join() const; inline QMap<QString, JoinedRoom> join() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
private: private:
QMap<QString, JoinedRoom> join_; QMap<QString, JoinedRoom> join_;
}; };
inline QMap<QString, JoinedRoom> inline QMap<QString, JoinedRoom>
Rooms::join() const Rooms::join() const
{ {
return join_; return join_;
} }
class SyncResponse : public Deserializable class SyncResponse : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
inline QString nextBatch() const; inline QString nextBatch() const;
inline Rooms rooms() const; inline Rooms rooms() const;
private: private:
QString next_batch_; QString next_batch_;
Rooms rooms_; Rooms rooms_;
}; };
inline Rooms inline Rooms
SyncResponse::rooms() const SyncResponse::rooms() const
{ {
return rooms_; return rooms_;
} }
inline QString inline QString
SyncResponse::nextBatch() const SyncResponse::nextBatch() const
{ {
return next_batch_; return next_batch_;
} }

View File

@ -28,31 +28,31 @@
class MsgCountComposedIcon : public QIconEngine class MsgCountComposedIcon : public QIconEngine
{ {
public: public:
MsgCountComposedIcon(const QString &filename); MsgCountComposedIcon(const QString &filename);
virtual void paint(QPainter *p, const QRect &rect, QIcon::Mode mode, QIcon::State state); virtual void paint(QPainter *p, const QRect &rect, QIcon::Mode mode, QIcon::State state);
virtual QIconEngine *clone() const; virtual QIconEngine *clone() const;
int msgCount = 0; int msgCount = 0;
private: private:
const int BubbleDiameter = 17; const int BubbleDiameter = 17;
QIcon icon_; QIcon icon_;
}; };
class TrayIcon : public QSystemTrayIcon class TrayIcon : public QSystemTrayIcon
{ {
Q_OBJECT Q_OBJECT
public: public:
TrayIcon(const QString &filename, QWidget *parent); TrayIcon(const QString &filename, QWidget *parent);
public slots: public slots:
void setUnreadCount(int count); void setUnreadCount(int count);
private: private:
QAction *viewAction_; QAction *viewAction_;
QAction *quitAction_; QAction *quitAction_;
MsgCountComposedIcon *icon_; MsgCountComposedIcon *icon_;
}; };

View File

@ -29,47 +29,47 @@
class UserInfoWidget : public QWidget class UserInfoWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
UserInfoWidget(QWidget *parent = 0); UserInfoWidget(QWidget *parent = 0);
~UserInfoWidget(); ~UserInfoWidget();
void setAvatar(const QImage &img); void setAvatar(const QImage &img);
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setUserId(const QString &userid); void setUserId(const QString &userid);
void reset(); void reset();
signals: signals:
void logout(); void logout();
protected: protected:
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
private slots: private slots:
void closeLogoutDialog(bool isLoggingOut); void closeLogoutDialog(bool isLoggingOut);
private: private:
Avatar *userAvatar_; Avatar *userAvatar_;
QHBoxLayout *topLayout_; QHBoxLayout *topLayout_;
QHBoxLayout *avatarLayout_; QHBoxLayout *avatarLayout_;
QVBoxLayout *textLayout_; QVBoxLayout *textLayout_;
QHBoxLayout *buttonLayout_; QHBoxLayout *buttonLayout_;
FlatButton *logoutButton_; FlatButton *logoutButton_;
QLabel *displayNameLabel_; QLabel *displayNameLabel_;
QLabel *userIdLabel_; QLabel *userIdLabel_;
QString display_name_; QString display_name_;
QString user_id_; QString user_id_;
QImage avatar_image_; QImage avatar_image_;
OverlayModal *logoutModal_; OverlayModal *logoutModal_;
LogoutDialog *logoutDialog_; LogoutDialog *logoutDialog_;
int logoutButtonSize_; int logoutButtonSize_;
}; };

View File

@ -25,16 +25,16 @@
class VersionsResponse : public Deserializable class VersionsResponse : public Deserializable
{ {
public: public:
void deserialize(const QJsonDocument &data) override; void deserialize(const QJsonDocument &data) override;
bool isVersionSupported(unsigned int major, unsigned int minor, unsigned int patch); bool isVersionSupported(unsigned int major, unsigned int minor, unsigned int patch);
private: private:
struct Version_ { struct Version_ {
unsigned int major_; unsigned int major_;
unsigned int minor_; unsigned int minor_;
unsigned int patch_; unsigned int patch_;
}; };
QVector<Version_> supported_versions_; QVector<Version_> supported_versions_;
}; };

View File

@ -27,32 +27,32 @@
class WelcomePage : public QWidget class WelcomePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit WelcomePage(QWidget *parent = 0); explicit WelcomePage(QWidget *parent = 0);
~WelcomePage(); ~WelcomePage();
signals: signals:
// Notify that the user wants to login in. // Notify that the user wants to login in.
void userLogin(); void userLogin();
// Notify that the user wants to register. // Notify that the user wants to register.
void userRegister(); void userRegister();
private slots: private slots:
void onLoginButtonClicked(); void onLoginButtonClicked();
void onRegisterButtonClicked(); void onRegisterButtonClicked();
private: private:
QVBoxLayout *top_layout_; QVBoxLayout *top_layout_;
QHBoxLayout *button_layout_; QHBoxLayout *button_layout_;
QLabel *intro_banner_; QLabel *intro_banner_;
QLabel *intro_text_; QLabel *intro_text_;
QSpacerItem *button_spacer_; QSpacerItem *button_spacer_;
RaisedButton *register_button_; RaisedButton *register_button_;
RaisedButton *login_button_; RaisedButton *login_button_;
}; };

View File

@ -31,19 +31,19 @@ class AliasesEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QList<QString> aliases() const; inline QList<QString> aliases() const;
private: private:
QList<QString> aliases_; QList<QString> aliases_;
}; };
inline QList<QString> inline QList<QString>
AliasesEventContent::aliases() const AliasesEventContent::aliases() const
{ {
return aliases_; return aliases_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -35,19 +35,19 @@ class AvatarEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QUrl url() const; inline QUrl url() const;
private: private:
QUrl url_; QUrl url_;
}; };
inline QUrl inline QUrl
AvatarEventContent::url() const AvatarEventContent::url() const
{ {
return url_; return url_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -37,19 +37,19 @@ class CanonicalAliasEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QString alias() const; inline QString alias() const;
private: private:
QString alias_; QString alias_;
}; };
inline QString inline QString
CanonicalAliasEventContent::alias() const CanonicalAliasEventContent::alias() const
{ {
return alias_; return alias_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -34,20 +34,20 @@ class CreateEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QString creator() const; inline QString creator() const;
private: private:
// The user_id of the room creator. This is set by the homeserver. // The user_id of the room creator. This is set by the homeserver.
QString creator_; QString creator_;
}; };
inline QString inline QString
CreateEventContent::creator() const CreateEventContent::creator() const
{ {
return creator_; return creator_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -27,30 +27,30 @@ namespace matrix
namespace events namespace events
{ {
enum class EventType { enum class EventType {
/// m.room.aliases /// m.room.aliases
RoomAliases, RoomAliases,
/// m.room.avatar /// m.room.avatar
RoomAvatar, RoomAvatar,
/// m.room.canonical_alias /// m.room.canonical_alias
RoomCanonicalAlias, RoomCanonicalAlias,
/// m.room.create /// m.room.create
RoomCreate, RoomCreate,
/// m.room.history_visibility /// m.room.history_visibility
RoomHistoryVisibility, RoomHistoryVisibility,
/// m.room.join_rules /// m.room.join_rules
RoomJoinRules, RoomJoinRules,
/// m.room.member /// m.room.member
RoomMember, RoomMember,
/// m.room.message /// m.room.message
RoomMessage, RoomMessage,
/// m.room.name /// m.room.name
RoomName, RoomName,
/// m.room.power_levels /// m.room.power_levels
RoomPowerLevels, RoomPowerLevels,
/// m.room.topic /// m.room.topic
RoomTopic, RoomTopic,
// Unsupported event // Unsupported event
Unsupported, Unsupported,
}; };
EventType EventType
@ -67,92 +67,92 @@ class Event
, public Serializable , public Serializable
{ {
public: public:
inline Content content() const; inline Content content() const;
inline EventType eventType() const; inline EventType eventType() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
private: private:
Content content_; Content content_;
EventType type_; EventType type_;
}; };
template<class Content> template<class Content>
inline Content inline Content
Event<Content>::content() const Event<Content>::content() const
{ {
return content_; return content_;
} }
template<class Content> template<class Content>
inline EventType inline EventType
Event<Content>::eventType() const Event<Content>::eventType() const
{ {
return type_; return type_;
} }
template<class Content> template<class Content>
void void
Event<Content>::deserialize(const QJsonValue &data) Event<Content>::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Event is not a JSON object"); throw DeserializationException("Event is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
content_.deserialize(object.value("content")); content_.deserialize(object.value("content"));
type_ = extractEventType(object); type_ = extractEventType(object);
} }
template<class Content> template<class Content>
QJsonObject QJsonObject
Event<Content>::serialize() const Event<Content>::serialize() const
{ {
QJsonObject object; QJsonObject object;
switch (type_) { switch (type_) {
case EventType::RoomAliases: case EventType::RoomAliases:
object["type"] = "m.room.aliases"; object["type"] = "m.room.aliases";
break; break;
case EventType::RoomAvatar: case EventType::RoomAvatar:
object["type"] = "m.room.avatar"; object["type"] = "m.room.avatar";
break; break;
case EventType::RoomCanonicalAlias: case EventType::RoomCanonicalAlias:
object["type"] = "m.room.canonical_alias"; object["type"] = "m.room.canonical_alias";
break; break;
case EventType::RoomCreate: case EventType::RoomCreate:
object["type"] = "m.room.create"; object["type"] = "m.room.create";
break; break;
case EventType::RoomHistoryVisibility: case EventType::RoomHistoryVisibility:
object["type"] = "m.room.history_visibility"; object["type"] = "m.room.history_visibility";
break; break;
case EventType::RoomJoinRules: case EventType::RoomJoinRules:
object["type"] = "m.room.join_rules"; object["type"] = "m.room.join_rules";
break; break;
case EventType::RoomMember: case EventType::RoomMember:
object["type"] = "m.room.member"; object["type"] = "m.room.member";
break; break;
case EventType::RoomMessage: case EventType::RoomMessage:
object["type"] = "m.room.message"; object["type"] = "m.room.message";
break; break;
case EventType::RoomName: case EventType::RoomName:
object["type"] = "m.room.name"; object["type"] = "m.room.name";
break; break;
case EventType::RoomPowerLevels: case EventType::RoomPowerLevels:
object["type"] = "m.room.power_levels"; object["type"] = "m.room.power_levels";
break; break;
case EventType::RoomTopic: case EventType::RoomTopic:
object["type"] = "m.room.topic"; object["type"] = "m.room.topic";
break; break;
case EventType::Unsupported: case EventType::Unsupported:
qWarning() << "Unsupported type to serialize"; qWarning() << "Unsupported type to serialize";
break; break;
} }
object["content"] = content_.serialize(); object["content"] = content_.serialize();
return object; return object;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -26,10 +26,10 @@ namespace matrix
namespace events namespace events
{ {
enum class HistoryVisibility { enum class HistoryVisibility {
Invited, Invited,
Joined, Joined,
Shared, Shared,
WorldReadable, WorldReadable,
}; };
class HistoryVisibilityEventContent class HistoryVisibilityEventContent
@ -37,19 +37,19 @@ class HistoryVisibilityEventContent
, public Serializable , public Serializable
{ {
public: public:
inline HistoryVisibility historyVisibility() const; inline HistoryVisibility historyVisibility() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
private: private:
HistoryVisibility history_visibility_; HistoryVisibility history_visibility_;
}; };
inline HistoryVisibility inline HistoryVisibility
HistoryVisibilityEventContent::historyVisibility() const HistoryVisibilityEventContent::historyVisibility() const
{ {
return history_visibility_; return history_visibility_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -26,18 +26,18 @@ namespace matrix
namespace events namespace events
{ {
enum class JoinRule { enum class JoinRule {
// A user who wishes to join the room must first receive // A user who wishes to join the room must first receive
// an invite to the room from someone already inside of the room. // an invite to the room from someone already inside of the room.
Invite, Invite,
// Reserved but not yet implemented by the Matrix specification. // Reserved but not yet implemented by the Matrix specification.
Knock, Knock,
// Reserved but not yet implemented by the Matrix specification. // Reserved but not yet implemented by the Matrix specification.
Private, Private,
/// Anyone can join the room without any prior action. /// Anyone can join the room without any prior action.
Public, Public,
}; };
/* /*
@ -49,19 +49,19 @@ class JoinRulesEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline JoinRule joinRule() const; inline JoinRule joinRule() const;
private: private:
JoinRule join_rule_; JoinRule join_rule_;
}; };
inline JoinRule inline JoinRule
JoinRulesEventContent::joinRule() const JoinRulesEventContent::joinRule() const
{ {
return join_rule_; return join_rule_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -27,20 +27,20 @@ namespace matrix
namespace events namespace events
{ {
enum class Membership { enum class Membership {
// The user is banned. // The user is banned.
Ban, Ban,
// The user has been invited. // The user has been invited.
Invite, Invite,
// The user has joined. // The user has joined.
Join, Join,
// The user has requested to join. // The user has requested to join.
Knock, Knock,
// The user has left. // The user has left.
Leave, Leave,
}; };
/* /*
@ -52,35 +52,35 @@ class MemberEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QUrl avatarUrl() const; inline QUrl avatarUrl() const;
inline QString displayName() const; inline QString displayName() const;
inline Membership membershipState() const; inline Membership membershipState() const;
private: private:
QUrl avatar_url_; QUrl avatar_url_;
QString display_name_; QString display_name_;
Membership membership_state_; Membership membership_state_;
}; };
inline QUrl inline QUrl
MemberEventContent::avatarUrl() const MemberEventContent::avatarUrl() const
{ {
return avatar_url_; return avatar_url_;
} }
inline QString inline QString
MemberEventContent::displayName() const MemberEventContent::displayName() const
{ {
return display_name_; return display_name_;
} }
inline Membership inline Membership
MemberEventContent::membershipState() const MemberEventContent::membershipState() const
{ {
return membership_state_; return membership_state_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -28,38 +28,38 @@ template<class MsgContent>
class MessageEvent : public RoomEvent<MessageEventContent> class MessageEvent : public RoomEvent<MessageEventContent>
{ {
public: public:
inline MsgContent msgContent() const; inline MsgContent msgContent() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
private: private:
MsgContent msg_content_; MsgContent msg_content_;
}; };
template<class MsgContent> template<class MsgContent>
inline MsgContent inline MsgContent
MessageEvent<MsgContent>::msgContent() const MessageEvent<MsgContent>::msgContent() const
{ {
return msg_content_; return msg_content_;
} }
template<class MsgContent> template<class MsgContent>
void void
MessageEvent<MsgContent>::deserialize(const QJsonValue &data) MessageEvent<MsgContent>::deserialize(const QJsonValue &data)
{ {
RoomEvent<MessageEventContent>::deserialize(data); RoomEvent<MessageEventContent>::deserialize(data);
msg_content_.deserialize(data.toObject().value("content").toObject()); msg_content_.deserialize(data.toObject().value("content").toObject());
} }
namespace messages namespace messages
{ {
struct ThumbnailInfo { struct ThumbnailInfo {
int h; int h;
int w; int w;
int size; int size;
QString mimetype; QString mimetype;
}; };
} // namespace messages } // namespace messages
} // namespace events } // namespace events

View File

@ -26,32 +26,32 @@ namespace matrix
namespace events namespace events
{ {
enum class MessageEventType { enum class MessageEventType {
// m.audio // m.audio
Audio, Audio,
// m.emote // m.emote
Emote, Emote,
// m.file // m.file
File, File,
// m.image // m.image
Image, Image,
// m.location // m.location
Location, Location,
// m.notice // m.notice
Notice, Notice,
// m.text // m.text
Text, Text,
// m.video // m.video
Video, Video,
// Unrecognized message type // Unrecognized message type
Unknown, Unknown,
}; };
MessageEventType MessageEventType
@ -62,19 +62,19 @@ class MessageEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QString body() const; inline QString body() const;
private: private:
QString body_; QString body_;
}; };
inline QString inline QString
MessageEventContent::body() const MessageEventContent::body() const
{ {
return body_; return body_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -34,19 +34,19 @@ class NameEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QString name() const; inline QString name() const;
private: private:
QString name_; QString name_;
}; };
inline QString inline QString
NameEventContent::name() const NameEventContent::name() const
{ {
return name_; return name_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -27,9 +27,9 @@ namespace matrix
namespace events namespace events
{ {
enum class PowerLevels { enum class PowerLevels {
User = 0, User = 0,
Moderator = 50, Moderator = 50,
Admin = 100, Admin = 100,
}; };
/* /*
@ -41,75 +41,75 @@ class PowerLevelsEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline int banLevel() const; inline int banLevel() const;
inline int inviteLevel() const; inline int inviteLevel() const;
inline int kickLevel() const; inline int kickLevel() const;
inline int redactLevel() const; inline int redactLevel() const;
inline int eventsDefaultLevel() const; inline int eventsDefaultLevel() const;
inline int stateDefaultLevel() const; inline int stateDefaultLevel() const;
inline int usersDefaultLevel() const; inline int usersDefaultLevel() const;
int eventLevel(QString event_type) const; int eventLevel(QString event_type) const;
int userLevel(QString user_id) const; int userLevel(QString user_id) const;
private: private:
int ban_ = static_cast<int>(PowerLevels::Moderator); int ban_ = static_cast<int>(PowerLevels::Moderator);
int invite_ = static_cast<int>(PowerLevels::Moderator); int invite_ = static_cast<int>(PowerLevels::Moderator);
int kick_ = static_cast<int>(PowerLevels::Moderator); int kick_ = static_cast<int>(PowerLevels::Moderator);
int redact_ = static_cast<int>(PowerLevels::Moderator); int redact_ = static_cast<int>(PowerLevels::Moderator);
int events_default_ = static_cast<int>(PowerLevels::User); int events_default_ = static_cast<int>(PowerLevels::User);
int state_default_ = static_cast<int>(PowerLevels::Moderator); int state_default_ = static_cast<int>(PowerLevels::Moderator);
int users_default_ = static_cast<int>(PowerLevels::User); int users_default_ = static_cast<int>(PowerLevels::User);
QMap<QString, int> events_; QMap<QString, int> events_;
QMap<QString, int> users_; QMap<QString, int> users_;
}; };
inline int inline int
PowerLevelsEventContent::banLevel() const PowerLevelsEventContent::banLevel() const
{ {
return ban_; return ban_;
} }
inline int inline int
PowerLevelsEventContent::inviteLevel() const PowerLevelsEventContent::inviteLevel() const
{ {
return invite_; return invite_;
} }
inline int inline int
PowerLevelsEventContent::kickLevel() const PowerLevelsEventContent::kickLevel() const
{ {
return kick_; return kick_;
} }
inline int inline int
PowerLevelsEventContent::redactLevel() const PowerLevelsEventContent::redactLevel() const
{ {
return redact_; return redact_;
} }
inline int inline int
PowerLevelsEventContent::eventsDefaultLevel() const PowerLevelsEventContent::eventsDefaultLevel() const
{ {
return events_default_; return events_default_;
} }
inline int inline int
PowerLevelsEventContent::stateDefaultLevel() const PowerLevelsEventContent::stateDefaultLevel() const
{ {
return state_default_; return state_default_;
} }
inline int inline int
PowerLevelsEventContent::usersDefaultLevel() const PowerLevelsEventContent::usersDefaultLevel() const
{ {
return users_default_; return users_default_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -30,89 +30,89 @@ template<class Content>
class RoomEvent : public Event<Content> class RoomEvent : public Event<Content>
{ {
public: public:
inline QString eventId() const; inline QString eventId() const;
inline QString roomId() const; inline QString roomId() const;
inline QString sender() const; inline QString sender() const;
inline uint64_t timestamp() const; inline uint64_t timestamp() const;
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
private: private:
QString event_id_; QString event_id_;
QString room_id_; QString room_id_;
QString sender_; QString sender_;
uint64_t origin_server_ts_; uint64_t origin_server_ts_;
}; };
template<class Content> template<class Content>
inline QString inline QString
RoomEvent<Content>::eventId() const RoomEvent<Content>::eventId() const
{ {
return event_id_; return event_id_;
} }
template<class Content> template<class Content>
inline QString inline QString
RoomEvent<Content>::roomId() const RoomEvent<Content>::roomId() const
{ {
return room_id_; return room_id_;
} }
template<class Content> template<class Content>
inline QString inline QString
RoomEvent<Content>::sender() const RoomEvent<Content>::sender() const
{ {
return sender_; return sender_;
} }
template<class Content> template<class Content>
inline uint64_t inline uint64_t
RoomEvent<Content>::timestamp() const RoomEvent<Content>::timestamp() const
{ {
return origin_server_ts_; return origin_server_ts_;
} }
template<class Content> template<class Content>
void void
RoomEvent<Content>::deserialize(const QJsonValue &data) RoomEvent<Content>::deserialize(const QJsonValue &data)
{ {
Event<Content>::deserialize(data); Event<Content>::deserialize(data);
auto object = data.toObject(); auto object = data.toObject();
if (!object.contains("event_id")) if (!object.contains("event_id"))
throw DeserializationException("event_id key is missing"); throw DeserializationException("event_id key is missing");
if (!object.contains("origin_server_ts")) if (!object.contains("origin_server_ts"))
throw DeserializationException("origin_server_ts key is missing"); throw DeserializationException("origin_server_ts key is missing");
// FIXME: Synapse doesn't include room id?! // FIXME: Synapse doesn't include room id?!
/* if (!object.contains("room_id")) */ /* if (!object.contains("room_id")) */
/* throw DeserializationException("room_id key is missing"); */ /* throw DeserializationException("room_id key is missing"); */
if (!object.contains("sender")) if (!object.contains("sender"))
throw DeserializationException("sender key is missing"); throw DeserializationException("sender key is missing");
event_id_ = object.value("event_id").toString(); event_id_ = object.value("event_id").toString();
room_id_ = object.value("room_id").toString(); room_id_ = object.value("room_id").toString();
sender_ = object.value("sender").toString(); sender_ = object.value("sender").toString();
origin_server_ts_ = object.value("origin_server_ts").toDouble(); origin_server_ts_ = object.value("origin_server_ts").toDouble();
} }
template<class Content> template<class Content>
QJsonObject QJsonObject
RoomEvent<Content>::serialize() const RoomEvent<Content>::serialize() const
{ {
QJsonObject object = Event<Content>::serialize(); QJsonObject object = Event<Content>::serialize();
object["event_id"] = event_id_; object["event_id"] = event_id_;
object["room_id"] = room_id_; object["room_id"] = room_id_;
object["sender"] = sender_; object["sender"] = sender_;
object["origin_server_ts"] = QJsonValue(static_cast<qint64>(origin_server_ts_)); object["origin_server_ts"] = QJsonValue(static_cast<qint64>(origin_server_ts_));
return object; return object;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -29,62 +29,62 @@ template<class Content>
class StateEvent : public RoomEvent<Content> class StateEvent : public RoomEvent<Content>
{ {
public: public:
inline QString stateKey() const; inline QString stateKey() const;
inline Content previousContent() const; inline Content previousContent() const;
void deserialize(const QJsonValue &data); void deserialize(const QJsonValue &data);
QJsonObject serialize() const; QJsonObject serialize() const;
private: private:
QString state_key_; QString state_key_;
Content prev_content_; Content prev_content_;
}; };
template<class Content> template<class Content>
inline QString inline QString
StateEvent<Content>::stateKey() const StateEvent<Content>::stateKey() const
{ {
return state_key_; return state_key_;
} }
template<class Content> template<class Content>
inline Content inline Content
StateEvent<Content>::previousContent() const StateEvent<Content>::previousContent() const
{ {
return prev_content_; return prev_content_;
} }
template<class Content> template<class Content>
void void
StateEvent<Content>::deserialize(const QJsonValue &data) StateEvent<Content>::deserialize(const QJsonValue &data)
{ {
RoomEvent<Content>::deserialize(data); RoomEvent<Content>::deserialize(data);
auto object = data.toObject(); auto object = data.toObject();
if (!object.contains("state_key")) if (!object.contains("state_key"))
throw DeserializationException("state_key key is missing"); throw DeserializationException("state_key key is missing");
state_key_ = object.value("state_key").toString(); state_key_ = object.value("state_key").toString();
if (object.contains("prev_content")) if (object.contains("prev_content"))
prev_content_.deserialize(object.value("prev_content")); prev_content_.deserialize(object.value("prev_content"));
} }
template<class Content> template<class Content>
QJsonObject QJsonObject
StateEvent<Content>::serialize() const StateEvent<Content>::serialize() const
{ {
QJsonObject object = RoomEvent<Content>::serialize(); QJsonObject object = RoomEvent<Content>::serialize();
object["state_key"] = state_key_; object["state_key"] = state_key_;
auto prev = prev_content_.serialize(); auto prev = prev_content_.serialize();
if (!prev.isEmpty()) if (!prev.isEmpty())
object["prev_content"] = prev; object["prev_content"] = prev;
return object; return object;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -34,19 +34,19 @@ class TopicEventContent
, public Serializable , public Serializable
{ {
public: public:
void deserialize(const QJsonValue &data) override; void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override; QJsonObject serialize() const override;
inline QString topic() const; inline QString topic() const;
private: private:
QString topic_; QString topic_;
}; };
inline QString inline QString
TopicEventContent::topic() const TopicEventContent::topic() const
{ {
return topic_; return topic_;
} }
} // namespace events } // namespace events
} // namespace matrix } // namespace matrix

View File

@ -28,35 +28,35 @@ namespace events
namespace messages namespace messages
{ {
struct AudioInfo { struct AudioInfo {
uint64_t duration; uint64_t duration;
int size; int size;
QString mimetype; QString mimetype;
}; };
class Audio : public Deserializable class Audio : public Deserializable
{ {
public: public:
inline QString url() const; inline QString url() const;
inline AudioInfo info() const; inline AudioInfo info() const;
void deserialize(const QJsonObject &object) override; void deserialize(const QJsonObject &object) override;
private: private:
QString url_; QString url_;
AudioInfo info_; AudioInfo info_;
}; };
inline QString inline QString
Audio::url() const Audio::url() const
{ {
return url_; return url_;
} }
inline AudioInfo inline AudioInfo
Audio::info() const Audio::info() const
{ {
return info_; return info_;
} }
} // namespace messages } // namespace messages

View File

@ -30,7 +30,7 @@ namespace messages
class Emote : public Deserializable class Emote : public Deserializable
{ {
public: public:
void deserialize(const QJsonObject &obj) override; void deserialize(const QJsonObject &obj) override;
}; };
} // namespace messages } // namespace messages
} // namespace events } // namespace events

View File

@ -29,46 +29,46 @@ namespace events
namespace messages namespace messages
{ {
struct FileInfo { struct FileInfo {
int size; int size;
QString mimetype; QString mimetype;
QString thumbnail_url; QString thumbnail_url;
ThumbnailInfo thumbnail_info; ThumbnailInfo thumbnail_info;
}; };
class File : public Deserializable class File : public Deserializable
{ {
public: public:
inline QString url() const; inline QString url() const;
inline QString filename() const; inline QString filename() const;
inline FileInfo info() const; inline FileInfo info() const;
void deserialize(const QJsonObject &object) override; void deserialize(const QJsonObject &object) override;
private: private:
QString url_; QString url_;
QString filename_; QString filename_;
FileInfo info_; FileInfo info_;
}; };
inline QString inline QString
File::filename() const File::filename() const
{ {
return filename_; return filename_;
} }
inline QString inline QString
File::url() const File::url() const
{ {
return url_; return url_;
} }
inline FileInfo inline FileInfo
File::info() const File::info() const
{ {
return info_; return info_;
} }
} // namespace messages } // namespace messages

View File

@ -29,38 +29,38 @@ namespace events
namespace messages namespace messages
{ {
struct ImageInfo { struct ImageInfo {
int h; int h;
int w; int w;
int size; int size;
QString mimetype; QString mimetype;
QString thumbnail_url; QString thumbnail_url;
ThumbnailInfo thumbnail_info; ThumbnailInfo thumbnail_info;
}; };
class Image : public Deserializable class Image : public Deserializable
{ {
public: public:
inline QString url() const; inline QString url() const;
inline ImageInfo info() const; inline ImageInfo info() const;
void deserialize(const QJsonObject &object) override; void deserialize(const QJsonObject &object) override;
private: private:
QString url_; QString url_;
ImageInfo info_; ImageInfo info_;
}; };
inline QString inline QString
Image::url() const Image::url() const
{ {
return url_; return url_;
} }
inline ImageInfo inline ImageInfo
Image::info() const Image::info() const
{ {
return info_; return info_;
} }
} // namespace messages } // namespace messages

View File

@ -29,34 +29,34 @@ namespace events
namespace messages namespace messages
{ {
struct LocationInfo { struct LocationInfo {
QString thumbnail_url; QString thumbnail_url;
ThumbnailInfo thumbnail_info; ThumbnailInfo thumbnail_info;
}; };
class Location : public Deserializable class Location : public Deserializable
{ {
public: public:
inline QString geoUri() const; inline QString geoUri() const;
inline LocationInfo info() const; inline LocationInfo info() const;
void deserialize(const QJsonObject &object) override; void deserialize(const QJsonObject &object) override;
private: private:
QString geo_uri_; QString geo_uri_;
LocationInfo info_; LocationInfo info_;
}; };
inline QString inline QString
Location::geoUri() const Location::geoUri() const
{ {
return geo_uri_; return geo_uri_;
} }
inline LocationInfo inline LocationInfo
Location::info() const Location::info() const
{ {
return info_; return info_;
} }
} // namespace messages } // namespace messages

View File

@ -30,7 +30,7 @@ namespace messages
class Notice : public Deserializable class Notice : public Deserializable
{ {
public: public:
void deserialize(const QJsonObject &obj) override; void deserialize(const QJsonObject &obj) override;
}; };
} // namespace messages } // namespace messages
} // namespace events } // namespace events

View File

@ -30,7 +30,7 @@ namespace messages
class Text : public Deserializable class Text : public Deserializable
{ {
public: public:
void deserialize(const QJsonObject &obj) override; void deserialize(const QJsonObject &obj) override;
}; };
} // namespace messages } // namespace messages
} // namespace events } // namespace events

View File

@ -29,39 +29,39 @@ namespace events
namespace messages namespace messages
{ {
struct VideoInfo { struct VideoInfo {
int h; int h;
int w; int w;
int size; int size;
int duration; int duration;
QString mimetype; QString mimetype;
QString thumbnail_url; QString thumbnail_url;
ThumbnailInfo thumbnail_info; ThumbnailInfo thumbnail_info;
}; };
class Video : public Deserializable class Video : public Deserializable
{ {
public: public:
inline QString url() const; inline QString url() const;
inline VideoInfo info() const; inline VideoInfo info() const;
void deserialize(const QJsonObject &object) override; void deserialize(const QJsonObject &object) override;
private: private:
QString url_; QString url_;
VideoInfo info_; VideoInfo info_;
}; };
inline QString inline QString
Video::url() const Video::url() const
{ {
return url_; return url_;
} }
inline VideoInfo inline VideoInfo
Video::info() const Video::info() const
{ {
return info_; return info_;
} }
} // namespace messages } // namespace messages

View File

@ -9,40 +9,40 @@
class Avatar : public QWidget class Avatar : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor) Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
public: public:
explicit Avatar(QWidget *parent = 0); explicit Avatar(QWidget *parent = 0);
~Avatar(); ~Avatar();
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);
void setImage(const QImage &image); void setImage(const QImage &image);
void setLetter(const QChar &letter); void setLetter(const QChar &letter);
void setSize(int size); void setSize(int size);
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
QColor backgroundColor() const; QColor backgroundColor() const;
QColor textColor() const; QColor textColor() const;
int size() const; int size() const;
QSize sizeHint() const override; QSize sizeHint() const override;
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
void init(); void init();
ui::AvatarType type_; ui::AvatarType type_;
QChar letter_; QChar letter_;
QColor background_color_; QColor background_color_;
QColor text_color_; QColor text_color_;
QIcon icon_; QIcon icon_;
QImage image_; QImage image_;
QPixmap pixmap_; QPixmap pixmap_;
int size_; int size_;
}; };

View File

@ -9,55 +9,55 @@
class Badge : public OverlayWidget class Badge : public OverlayWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor) Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QPointF relativePosition WRITE setRelativePosition READ relativePosition) Q_PROPERTY(QPointF relativePosition WRITE setRelativePosition READ relativePosition)
public: public:
explicit Badge(QWidget *parent = 0); explicit Badge(QWidget *parent = 0);
explicit Badge(const QIcon &icon, QWidget *parent = 0); explicit Badge(const QIcon &icon, QWidget *parent = 0);
explicit Badge(const QString &text, QWidget *parent = 0); explicit Badge(const QString &text, QWidget *parent = 0);
~Badge(); ~Badge();
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
void setIcon(const QIcon &icon); void setIcon(const QIcon &icon);
void setRelativePosition(const QPointF &pos); void setRelativePosition(const QPointF &pos);
void setRelativePosition(qreal x, qreal y); void setRelativePosition(qreal x, qreal y);
void setRelativeXPosition(qreal x); void setRelativeXPosition(qreal x);
void setRelativeYPosition(qreal y); void setRelativeYPosition(qreal y);
void setText(const QString &text); void setText(const QString &text);
void setDiameter(int diameter); void setDiameter(int diameter);
QIcon icon() const; QIcon icon() const;
QString text() const; QString text() const;
QColor backgroundColor() const; QColor backgroundColor() const;
QColor textColor() const; QColor textColor() const;
QPointF relativePosition() const; QPointF relativePosition() const;
QSize sizeHint() const override; QSize sizeHint() const override;
qreal relativeXPosition() const; qreal relativeXPosition() const;
qreal relativeYPosition() const; qreal relativeYPosition() const;
int diameter() const; int diameter() const;
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
void init(); void init();
QColor background_color_; QColor background_color_;
QColor text_color_; QColor text_color_;
QIcon icon_; QIcon icon_;
QSize size_; QSize size_;
QString text_; QString text_;
int padding_; int padding_;
int diameter_; int diameter_;
qreal x_; qreal x_;
qreal y_; qreal y_;
}; };

View File

@ -9,112 +9,112 @@ class CircularProgressDelegate;
class CircularProgress : public QProgressBar class CircularProgress : public QProgressBar
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal lineWidth WRITE setLineWidth READ lineWidth) Q_PROPERTY(qreal lineWidth WRITE setLineWidth READ lineWidth)
Q_PROPERTY(qreal size WRITE setSize READ size) Q_PROPERTY(qreal size WRITE setSize READ size)
Q_PROPERTY(QColor color WRITE setColor READ color) Q_PROPERTY(QColor color WRITE setColor READ color)
public: public:
explicit CircularProgress(QWidget *parent = nullptr); explicit CircularProgress(QWidget *parent = nullptr);
~CircularProgress(); ~CircularProgress();
void setProgressType(ui::ProgressType type); void setProgressType(ui::ProgressType type);
void setLineWidth(qreal width); void setLineWidth(qreal width);
void setSize(int size); void setSize(int size);
void setColor(const QColor &color); void setColor(const QColor &color);
ui::ProgressType progressType() const; ui::ProgressType progressType() const;
qreal lineWidth() const; qreal lineWidth() const;
int size() const; int size() const;
QColor color() const; QColor color() const;
QSize sizeHint() const override; QSize sizeHint() const override;
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
CircularProgressDelegate *delegate_; CircularProgressDelegate *delegate_;
ui::ProgressType progress_type_; ui::ProgressType progress_type_;
QColor color_; QColor color_;
// Circle width. // Circle width.
qreal width_; qreal width_;
// Circle radius. // Circle radius.
int size_; int size_;
// Animation duration. // Animation duration.
int duration_; int duration_;
}; };
class CircularProgressDelegate : public QObject class CircularProgressDelegate : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal dashOffset WRITE setDashOffset READ dashOffset) Q_PROPERTY(qreal dashOffset WRITE setDashOffset READ dashOffset)
Q_PROPERTY(qreal dashLength WRITE setDashLength READ dashLength) Q_PROPERTY(qreal dashLength WRITE setDashLength READ dashLength)
Q_PROPERTY(int angle WRITE setAngle READ angle) Q_PROPERTY(int angle WRITE setAngle READ angle)
public: public:
explicit CircularProgressDelegate(CircularProgress *parent); explicit CircularProgressDelegate(CircularProgress *parent);
~CircularProgressDelegate(); ~CircularProgressDelegate();
inline void setDashOffset(qreal offset); inline void setDashOffset(qreal offset);
inline void setDashLength(qreal length); inline void setDashLength(qreal length);
inline void setAngle(int angle); inline void setAngle(int angle);
inline qreal dashOffset() const; inline qreal dashOffset() const;
inline qreal dashLength() const; inline qreal dashLength() const;
inline int angle() const; inline int angle() const;
private: private:
CircularProgress *const progress_; CircularProgress *const progress_;
qreal dash_offset_; qreal dash_offset_;
qreal dash_length_; qreal dash_length_;
int angle_; int angle_;
}; };
inline void inline void
CircularProgressDelegate::setDashOffset(qreal offset) CircularProgressDelegate::setDashOffset(qreal offset)
{ {
dash_offset_ = offset; dash_offset_ = offset;
progress_->update(); progress_->update();
} }
inline void inline void
CircularProgressDelegate::setDashLength(qreal length) CircularProgressDelegate::setDashLength(qreal length)
{ {
dash_length_ = length; dash_length_ = length;
progress_->update(); progress_->update();
} }
inline void inline void
CircularProgressDelegate::setAngle(int angle) CircularProgressDelegate::setAngle(int angle)
{ {
angle_ = angle; angle_ = angle;
progress_->update(); progress_->update();
} }
inline qreal inline qreal
CircularProgressDelegate::dashOffset() const CircularProgressDelegate::dashOffset() const
{ {
return dash_offset_; return dash_offset_;
} }
inline qreal inline qreal
CircularProgressDelegate::dashLength() const CircularProgressDelegate::dashLength() const
{ {
return dash_length_; return dash_length_;
} }
inline int inline int
CircularProgressDelegate::angle() const CircularProgressDelegate::angle() const
{ {
return angle_; return angle_;
} }

View File

@ -7,97 +7,105 @@
class DropShadow class DropShadow
{ {
public: public:
static void draw(QPainter &painter, static void draw(QPainter &painter,
qint16 margin, qint16 margin,
qreal radius, qreal radius,
QColor start, QColor start,
QColor end, QColor end,
qreal startPosition, qreal startPosition,
qreal endPosition0, qreal endPosition0,
qreal endPosition1, qreal endPosition1,
qreal width, qreal width,
qreal height) qreal height)
{ {
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
QLinearGradient gradient; QLinearGradient gradient;
gradient.setColorAt(startPosition, start); gradient.setColorAt(startPosition, start);
gradient.setColorAt(endPosition0, end); gradient.setColorAt(endPosition0, end);
// Right // Right
QPointF right0(width - margin, height / 2); QPointF right0(width - margin, height / 2);
QPointF right1(width, height / 2); QPointF right1(width, height / 2);
gradient.setStart(right0); gradient.setStart(right0);
gradient.setFinalStop(right1); gradient.setFinalStop(right1);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect( painter.drawRoundRect(
QRectF(QPointF(width - margin * radius, margin), QPointF(width, height - margin)), 0.0, 0.0); QRectF(QPointF(width - margin * radius, margin), QPointF(width, height - margin)),
0.0,
0.0);
// Left // Left
QPointF left0(margin, height / 2); QPointF left0(margin, height / 2);
QPointF left1(0, height / 2); QPointF left1(0, height / 2);
gradient.setStart(left0); gradient.setStart(left0);
gradient.setFinalStop(left1); gradient.setFinalStop(left1);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(QPointF(margin * radius, margin), QPointF(0, height - margin)), 0.0, 0.0); painter.drawRoundRect(
QRectF(QPointF(margin * radius, margin), QPointF(0, height - margin)), 0.0, 0.0);
// Top // Top
QPointF top0(width / 2, margin); QPointF top0(width / 2, margin);
QPointF top1(width / 2, 0); QPointF top1(width / 2, 0);
gradient.setStart(top0); gradient.setStart(top0);
gradient.setFinalStop(top1); gradient.setFinalStop(top1);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(QPointF(width - margin, 0), QPointF(margin, margin)), 0.0, 0.0); painter.drawRoundRect(
QRectF(QPointF(width - margin, 0), QPointF(margin, margin)), 0.0, 0.0);
// Bottom // Bottom
QPointF bottom0(width / 2, height - margin); QPointF bottom0(width / 2, height - margin);
QPointF bottom1(width / 2, height); QPointF bottom1(width / 2, height);
gradient.setStart(bottom0); gradient.setStart(bottom0);
gradient.setFinalStop(bottom1); gradient.setFinalStop(bottom1);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect( painter.drawRoundRect(
QRectF(QPointF(margin, height - margin), QPointF(width - margin, height)), 0.0, 0.0); QRectF(QPointF(margin, height - margin), QPointF(width - margin, height)),
0.0,
0.0);
// BottomRight // BottomRight
QPointF bottomright0(width - margin, height - margin); QPointF bottomright0(width - margin, height - margin);
QPointF bottomright1(width, height); QPointF bottomright1(width, height);
gradient.setStart(bottomright0); gradient.setStart(bottomright0);
gradient.setFinalStop(bottomright1); gradient.setFinalStop(bottomright1);
gradient.setColorAt(endPosition1, end); gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(bottomright0, bottomright1), 0.0, 0.0); painter.drawRoundRect(QRectF(bottomright0, bottomright1), 0.0, 0.0);
// BottomLeft // BottomLeft
QPointF bottomleft0(margin, height - margin); QPointF bottomleft0(margin, height - margin);
QPointF bottomleft1(0, height); QPointF bottomleft1(0, height);
gradient.setStart(bottomleft0); gradient.setStart(bottomleft0);
gradient.setFinalStop(bottomleft1); gradient.setFinalStop(bottomleft1);
gradient.setColorAt(endPosition1, end); gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(bottomleft0, bottomleft1), 0.0, 0.0); painter.drawRoundRect(QRectF(bottomleft0, bottomleft1), 0.0, 0.0);
// TopLeft // TopLeft
QPointF topleft0(margin, margin); QPointF topleft0(margin, margin);
QPointF topleft1(0, 0); QPointF topleft1(0, 0);
gradient.setStart(topleft0); gradient.setStart(topleft0);
gradient.setFinalStop(topleft1); gradient.setFinalStop(topleft1);
gradient.setColorAt(endPosition1, end); gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(topleft0, topleft1), 0.0, 0.0); painter.drawRoundRect(QRectF(topleft0, topleft1), 0.0, 0.0);
// TopRight // TopRight
QPointF topright0(width - margin, margin); QPointF topright0(width - margin, margin);
QPointF topright1(width, 0); QPointF topright1(width, 0);
gradient.setStart(topright0); gradient.setStart(topright0);
gradient.setFinalStop(topright1); gradient.setFinalStop(topright1);
gradient.setColorAt(endPosition1, end); gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient)); painter.setBrush(QBrush(gradient));
painter.drawRoundRect(QRectF(topright0, topright1), 0.0, 0.0); painter.drawRoundRect(QRectF(topright0, topright1), 0.0, 0.0);
// Widget // Widget
painter.setBrush(QBrush("#FFFFFF")); painter.setBrush(QBrush("#FFFFFF"));
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
painter.drawRoundRect( painter.drawRoundRect(
QRectF(QPointF(margin, margin), QPointF(width - margin, height - margin)), radius, radius); QRectF(QPointF(margin, margin), QPointF(width - margin, height - margin)),
} radius,
radius);
}
}; };

View File

@ -12,167 +12,174 @@ class FlatButton;
class FlatButtonStateMachine : public QStateMachine class FlatButtonStateMachine : public QStateMachine
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal overlayOpacity WRITE setOverlayOpacity READ overlayOpacity) Q_PROPERTY(qreal overlayOpacity WRITE setOverlayOpacity READ overlayOpacity)
Q_PROPERTY(qreal checkedOverlayProgress WRITE setCheckedOverlayProgress READ checkedOverlayProgress) Q_PROPERTY(
qreal checkedOverlayProgress WRITE setCheckedOverlayProgress READ checkedOverlayProgress)
public: public:
explicit FlatButtonStateMachine(FlatButton *parent); explicit FlatButtonStateMachine(FlatButton *parent);
~FlatButtonStateMachine(); ~FlatButtonStateMachine();
void setOverlayOpacity(qreal opacity); void setOverlayOpacity(qreal opacity);
void setCheckedOverlayProgress(qreal opacity); void setCheckedOverlayProgress(qreal opacity);
inline qreal overlayOpacity() const; inline qreal overlayOpacity() const;
inline qreal checkedOverlayProgress() const; inline qreal checkedOverlayProgress() const;
void startAnimations(); void startAnimations();
void setupProperties(); void setupProperties();
void updateCheckedStatus(); void updateCheckedStatus();
signals: signals:
void buttonPressed(); void buttonPressed();
void buttonChecked(); void buttonChecked();
void buttonUnchecked(); void buttonUnchecked();
protected: protected:
bool eventFilter(QObject *watched, QEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override;
private: private:
void addTransition(QObject *object, const char *signal, QState *fromState, QState *toState); void addTransition(QObject *object, const char *signal, QState *fromState, QState *toState);
void addTransition(QObject *object, QEvent::Type eventType, QState *fromState, QState *toState); void addTransition(QObject *object,
void addTransition(QAbstractTransition *transition, QState *fromState, QState *toState); QEvent::Type eventType,
QState *fromState,
QState *toState);
void addTransition(QAbstractTransition *transition, QState *fromState, QState *toState);
FlatButton *const button_; FlatButton *const button_;
QState *const top_level_state_; QState *const top_level_state_;
QState *const config_state_; QState *const config_state_;
QState *const checkable_state_; QState *const checkable_state_;
QState *const checked_state_; QState *const checked_state_;
QState *const unchecked_state_; QState *const unchecked_state_;
QState *const neutral_state_; QState *const neutral_state_;
QState *const neutral_focused_state_; QState *const neutral_focused_state_;
QState *const hovered_state_; QState *const hovered_state_;
QState *const hovered_focused_state_; QState *const hovered_focused_state_;
QState *const pressed_state_; QState *const pressed_state_;
qreal overlay_opacity_; qreal overlay_opacity_;
qreal checked_overlay_progress_; qreal checked_overlay_progress_;
bool was_checked_; bool was_checked_;
}; };
inline qreal inline qreal
FlatButtonStateMachine::overlayOpacity() const FlatButtonStateMachine::overlayOpacity() const
{ {
return overlay_opacity_; return overlay_opacity_;
} }
inline qreal inline qreal
FlatButtonStateMachine::checkedOverlayProgress() const FlatButtonStateMachine::checkedOverlayProgress() const
{ {
return checked_overlay_progress_; return checked_overlay_progress_;
} }
class FlatButton : public QPushButton class FlatButton : public QPushButton
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor foregroundColor WRITE setForegroundColor READ foregroundColor) Q_PROPERTY(QColor foregroundColor WRITE setForegroundColor READ foregroundColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QColor overlayColor WRITE setOverlayColor READ overlayColor) Q_PROPERTY(QColor overlayColor WRITE setOverlayColor READ overlayColor)
Q_PROPERTY(QColor disabledForegroundColor WRITE setDisabledForegroundColor READ disabledForegroundColor) Q_PROPERTY(QColor disabledForegroundColor WRITE setDisabledForegroundColor READ
Q_PROPERTY(QColor disabledBackgroundColor WRITE setDisabledBackgroundColor READ disabledBackgroundColor) disabledForegroundColor)
Q_PROPERTY(qreal fontSize WRITE setFontSize READ fontSize) Q_PROPERTY(QColor disabledBackgroundColor WRITE setDisabledBackgroundColor READ
disabledBackgroundColor)
Q_PROPERTY(qreal fontSize WRITE setFontSize READ fontSize)
public: public:
explicit FlatButton(QWidget *parent = 0, ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset); explicit FlatButton(QWidget *parent = 0,
explicit FlatButton(const QString &text, ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
QWidget *parent = 0, explicit FlatButton(const QString &text,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset); QWidget *parent = 0,
FlatButton(const QString &text, ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
ui::Role role, FlatButton(const QString &text,
QWidget *parent = 0, ui::Role role,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset); QWidget *parent = 0,
~FlatButton(); ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
~FlatButton();
void applyPreset(ui::ButtonPreset preset); void applyPreset(ui::ButtonPreset preset);
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setBackgroundMode(Qt::BGMode mode); void setBackgroundMode(Qt::BGMode mode);
void setBaseOpacity(qreal opacity); void setBaseOpacity(qreal opacity);
void setCheckable(bool value); void setCheckable(bool value);
void setCornerRadius(qreal radius); void setCornerRadius(qreal radius);
void setDisabledBackgroundColor(const QColor &color); void setDisabledBackgroundColor(const QColor &color);
void setDisabledForegroundColor(const QColor &color); void setDisabledForegroundColor(const QColor &color);
void setFixedRippleRadius(qreal radius); void setFixedRippleRadius(qreal radius);
void setFontSize(qreal size); void setFontSize(qreal size);
void setForegroundColor(const QColor &color); void setForegroundColor(const QColor &color);
void setHasFixedRippleRadius(bool value); void setHasFixedRippleRadius(bool value);
void setIconPlacement(ui::ButtonIconPlacement placement); void setIconPlacement(ui::ButtonIconPlacement placement);
void setOverlayColor(const QColor &color); void setOverlayColor(const QColor &color);
void setOverlayStyle(ui::OverlayStyle style); void setOverlayStyle(ui::OverlayStyle style);
void setRippleStyle(ui::RippleStyle style); void setRippleStyle(ui::RippleStyle style);
void setRole(ui::Role role); void setRole(ui::Role role);
QColor foregroundColor() const; QColor foregroundColor() const;
QColor backgroundColor() const; QColor backgroundColor() const;
QColor overlayColor() const; QColor overlayColor() const;
QColor disabledForegroundColor() const; QColor disabledForegroundColor() const;
QColor disabledBackgroundColor() const; QColor disabledBackgroundColor() const;
qreal fontSize() const; qreal fontSize() const;
qreal cornerRadius() const; qreal cornerRadius() const;
qreal baseOpacity() const; qreal baseOpacity() const;
bool hasFixedRippleRadius() const; bool hasFixedRippleRadius() const;
ui::Role role() const; ui::Role role() const;
ui::OverlayStyle overlayStyle() const; ui::OverlayStyle overlayStyle() const;
ui::RippleStyle rippleStyle() const; ui::RippleStyle rippleStyle() const;
ui::ButtonIconPlacement iconPlacement() const; ui::ButtonIconPlacement iconPlacement() const;
Qt::BGMode backgroundMode() const; Qt::BGMode backgroundMode() const;
QSize sizeHint() const override; QSize sizeHint() const override;
protected: protected:
int IconPadding = 0; int IconPadding = 0;
void checkStateSet() override; void checkStateSet() override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
virtual void paintBackground(QPainter *painter); virtual void paintBackground(QPainter *painter);
virtual void paintForeground(QPainter *painter); virtual void paintForeground(QPainter *painter);
virtual void updateClipPath(); virtual void updateClipPath();
void init(); void init();
private: private:
RippleOverlay *ripple_overlay_; RippleOverlay *ripple_overlay_;
FlatButtonStateMachine *state_machine_; FlatButtonStateMachine *state_machine_;
ui::Role role_; ui::Role role_;
ui::RippleStyle ripple_style_; ui::RippleStyle ripple_style_;
ui::ButtonIconPlacement icon_placement_; ui::ButtonIconPlacement icon_placement_;
ui::OverlayStyle overlay_style_; ui::OverlayStyle overlay_style_;
Qt::BGMode bg_mode_; Qt::BGMode bg_mode_;
QColor background_color_; QColor background_color_;
QColor foreground_color_; QColor foreground_color_;
QColor overlay_color_; QColor overlay_color_;
QColor disabled_color_; QColor disabled_color_;
QColor disabled_background_color_; QColor disabled_background_color_;
qreal fixed_ripple_radius_; qreal fixed_ripple_radius_;
qreal corner_radius_; qreal corner_radius_;
qreal base_opacity_; qreal base_opacity_;
qreal font_size_; qreal font_size_;
bool use_fixed_ripple_radius_; bool use_fixed_ripple_radius_;
}; };

View File

@ -7,24 +7,26 @@
class Menu : public QMenu class Menu : public QMenu
{ {
public: public:
Menu(QWidget *parent = nullptr) Menu(QWidget *parent = nullptr)
: QMenu(parent) : QMenu(parent)
{ {
QFont font; QFont font;
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
setFont(font); setFont(font);
setStyleSheet("QMenu { color: black; background-color: white; margin: 0px;}" setStyleSheet(
"QMenu::item { color: black; padding: 7px 20px; border: 1px solid transparent; margin: " "QMenu { color: black; background-color: white; margin: 0px;}"
"2px 0px; }" "QMenu::item { color: black; padding: 7px 20px; border: 1px solid transparent; "
"QMenu::item:selected { color: black; background: rgba(180, 180, 180, 100); }"); "margin: "
}; "2px 0px; }"
"QMenu::item:selected { color: black; background: rgba(180, 180, 180, 100); }");
};
protected: protected:
void leaveEvent(QEvent *e) void leaveEvent(QEvent *e)
{ {
Q_UNUSED(e); Q_UNUSED(e);
hide(); hide();
} }
}; };

View File

@ -26,35 +26,35 @@
class OverlayModal : public OverlayWidget class OverlayModal : public OverlayWidget
{ {
public: public:
explicit OverlayModal(QWidget *parent, QWidget *content); explicit OverlayModal(QWidget *parent, QWidget *content);
void fadeIn(); void fadeIn();
void fadeOut(); void fadeOut();
public: public:
inline void setDuration(int duration); inline void setDuration(int duration);
inline void setColor(QColor color); inline void setColor(QColor color);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
int duration_; int duration_;
QColor color_; QColor color_;
QGraphicsOpacityEffect *opacity_; QGraphicsOpacityEffect *opacity_;
QPropertyAnimation *animation_; QPropertyAnimation *animation_;
}; };
inline void inline void
OverlayModal::setDuration(int duration) OverlayModal::setDuration(int duration)
{ {
duration_ = duration; duration_ = duration;
animation_->setDuration(duration_); animation_->setDuration(duration_);
} }
inline void inline void
OverlayModal::setColor(QColor color) OverlayModal::setColor(QColor color)
{ {
color_ = color; color_ = color;
} }

View File

@ -5,14 +5,14 @@
class OverlayWidget : public QWidget class OverlayWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit OverlayWidget(QWidget *parent = nullptr); explicit OverlayWidget(QWidget *parent = nullptr);
protected: protected:
bool event(QEvent *event) override; bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
QRect overlayGeometry() const; QRect overlayGeometry() const;
}; };

View File

@ -8,21 +8,21 @@
class RaisedButton : public FlatButton class RaisedButton : public FlatButton
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RaisedButton(QWidget *parent = 0); explicit RaisedButton(QWidget *parent = 0);
explicit RaisedButton(const QString &text, QWidget *parent = 0); explicit RaisedButton(const QString &text, QWidget *parent = 0);
~RaisedButton(); ~RaisedButton();
protected: protected:
bool event(QEvent *event) override; bool event(QEvent *event) override;
private: private:
void init(); void init();
QStateMachine *shadow_state_machine_; QStateMachine *shadow_state_machine_;
QState *normal_state_; QState *normal_state_;
QState *pressed_state_; QState *pressed_state_;
QGraphicsDropShadowEffect *effect_; QGraphicsDropShadowEffect *effect_;
}; };

View File

@ -10,137 +10,137 @@ class RippleOverlay;
class Ripple : public QParallelAnimationGroup class Ripple : public QParallelAnimationGroup
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal radius WRITE setRadius READ radius) Q_PROPERTY(qreal radius WRITE setRadius READ radius)
Q_PROPERTY(qreal opacity WRITE setOpacity READ opacity) Q_PROPERTY(qreal opacity WRITE setOpacity READ opacity)
public: public:
explicit Ripple(const QPoint &center, QObject *parent = 0); explicit Ripple(const QPoint &center, QObject *parent = 0);
Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent = 0); Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent = 0);
~Ripple(); ~Ripple();
inline void setOverlay(RippleOverlay *overlay); inline void setOverlay(RippleOverlay *overlay);
void setRadius(qreal radius); void setRadius(qreal radius);
void setOpacity(qreal opacity); void setOpacity(qreal opacity);
void setColor(const QColor &color); void setColor(const QColor &color);
void setBrush(const QBrush &brush); void setBrush(const QBrush &brush);
inline qreal radius() const; inline qreal radius() const;
inline qreal opacity() const; inline qreal opacity() const;
inline QColor color() const; inline QColor color() const;
inline QBrush brush() const; inline QBrush brush() const;
inline QPoint center() const; inline QPoint center() const;
inline QPropertyAnimation *radiusAnimation() const; inline QPropertyAnimation *radiusAnimation() const;
inline QPropertyAnimation *opacityAnimation() const; inline QPropertyAnimation *opacityAnimation() const;
inline void setOpacityStartValue(qreal value); inline void setOpacityStartValue(qreal value);
inline void setOpacityEndValue(qreal value); inline void setOpacityEndValue(qreal value);
inline void setRadiusStartValue(qreal value); inline void setRadiusStartValue(qreal value);
inline void setRadiusEndValue(qreal value); inline void setRadiusEndValue(qreal value);
inline void setDuration(int msecs); inline void setDuration(int msecs);
protected slots: protected slots:
void destroy(); void destroy();
private: private:
Q_DISABLE_COPY(Ripple) Q_DISABLE_COPY(Ripple)
QPropertyAnimation *animate(const QByteArray &property, QPropertyAnimation *animate(const QByteArray &property,
const QEasingCurve &easing = QEasingCurve::OutQuad, const QEasingCurve &easing = QEasingCurve::OutQuad,
int duration = 800); int duration = 800);
void init(); void init();
RippleOverlay *overlay_; RippleOverlay *overlay_;
QPropertyAnimation *const radius_anim_; QPropertyAnimation *const radius_anim_;
QPropertyAnimation *const opacity_anim_; QPropertyAnimation *const opacity_anim_;
qreal radius_; qreal radius_;
qreal opacity_; qreal opacity_;
QPoint center_; QPoint center_;
QBrush brush_; QBrush brush_;
}; };
inline void inline void
Ripple::setOverlay(RippleOverlay *overlay) Ripple::setOverlay(RippleOverlay *overlay)
{ {
overlay_ = overlay; overlay_ = overlay;
} }
inline qreal inline qreal
Ripple::radius() const Ripple::radius() const
{ {
return radius_; return radius_;
} }
inline qreal inline qreal
Ripple::opacity() const Ripple::opacity() const
{ {
return opacity_; return opacity_;
} }
inline QColor inline QColor
Ripple::color() const Ripple::color() const
{ {
return brush_.color(); return brush_.color();
} }
inline QBrush inline QBrush
Ripple::brush() const Ripple::brush() const
{ {
return brush_; return brush_;
} }
inline QPoint inline QPoint
Ripple::center() const Ripple::center() const
{ {
return center_; return center_;
} }
inline QPropertyAnimation * inline QPropertyAnimation *
Ripple::radiusAnimation() const Ripple::radiusAnimation() const
{ {
return radius_anim_; return radius_anim_;
} }
inline QPropertyAnimation * inline QPropertyAnimation *
Ripple::opacityAnimation() const Ripple::opacityAnimation() const
{ {
return opacity_anim_; return opacity_anim_;
} }
inline void inline void
Ripple::setOpacityStartValue(qreal value) Ripple::setOpacityStartValue(qreal value)
{ {
opacity_anim_->setStartValue(value); opacity_anim_->setStartValue(value);
} }
inline void inline void
Ripple::setOpacityEndValue(qreal value) Ripple::setOpacityEndValue(qreal value)
{ {
opacity_anim_->setEndValue(value); opacity_anim_->setEndValue(value);
} }
inline void inline void
Ripple::setRadiusStartValue(qreal value) Ripple::setRadiusStartValue(qreal value)
{ {
radius_anim_->setStartValue(value); radius_anim_->setStartValue(value);
} }
inline void inline void
Ripple::setRadiusEndValue(qreal value) Ripple::setRadiusEndValue(qreal value)
{ {
radius_anim_->setEndValue(value); radius_anim_->setEndValue(value);
} }
inline void inline void
Ripple::setDuration(int msecs) Ripple::setDuration(int msecs)
{ {
radius_anim_->setDuration(msecs); radius_anim_->setDuration(msecs);
opacity_anim_->setDuration(msecs); opacity_anim_->setDuration(msecs);
} }

View File

@ -8,51 +8,51 @@ class Ripple;
class RippleOverlay : public OverlayWidget class RippleOverlay : public OverlayWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RippleOverlay(QWidget *parent = 0); explicit RippleOverlay(QWidget *parent = 0);
~RippleOverlay(); ~RippleOverlay();
void addRipple(Ripple *ripple); void addRipple(Ripple *ripple);
void addRipple(const QPoint &position, qreal radius = 300); void addRipple(const QPoint &position, qreal radius = 300);
void removeRipple(Ripple *ripple); void removeRipple(Ripple *ripple);
inline void setClipping(bool enable); inline void setClipping(bool enable);
inline bool hasClipping() const; inline bool hasClipping() const;
inline void setClipPath(const QPainterPath &path); inline void setClipPath(const QPainterPath &path);
protected: protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private: private:
Q_DISABLE_COPY(RippleOverlay) Q_DISABLE_COPY(RippleOverlay)
void paintRipple(QPainter *painter, Ripple *ripple); void paintRipple(QPainter *painter, Ripple *ripple);
QList<Ripple *> ripples_; QList<Ripple *> ripples_;
QPainterPath clip_path_; QPainterPath clip_path_;
bool use_clip_; bool use_clip_;
}; };
inline void inline void
RippleOverlay::setClipping(bool enable) RippleOverlay::setClipping(bool enable)
{ {
use_clip_ = enable; use_clip_ = enable;
update(); update();
} }
inline bool inline bool
RippleOverlay::hasClipping() const RippleOverlay::hasClipping() const
{ {
return use_clip_; return use_clip_;
} }
inline void inline void
RippleOverlay::setClipPath(const QPainterPath &path) RippleOverlay::setClipPath(const QPainterPath &path)
{ {
clip_path_ = path; clip_path_ = path;
update(); update();
} }

View File

@ -25,29 +25,29 @@
class ScrollBar : public QScrollBar class ScrollBar : public QScrollBar
{ {
Q_OBJECT Q_OBJECT
public: public:
ScrollBar(QScrollArea *area, QWidget *parent = nullptr); ScrollBar(QScrollArea *area, QWidget *parent = nullptr);
void fadeIn(); void fadeIn();
void fadeOut(); void fadeOut();
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void sliderChange(SliderChange change) override; void sliderChange(SliderChange change) override;
private: private:
int roundRadius_ = 4; int roundRadius_ = 4;
int handleWidth_ = 7; int handleWidth_ = 7;
int minHandleHeight_ = 20; int minHandleHeight_ = 20;
bool isActive; bool isActive;
const int AnimationDuration = 300; const int AnimationDuration = 300;
const int Padding = 4; const int Padding = 4;
QGraphicsOpacityEffect *eff; QGraphicsOpacityEffect *eff;
QTimer hideTimer_; QTimer hideTimer_;
QScrollArea *area_; QScrollArea *area_;
QRect handle_; QRect handle_;
}; };

View File

@ -13,163 +13,163 @@ class TextFieldStateMachine;
class TextField : public QLineEdit class TextField : public QLineEdit
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor) Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor inkColor WRITE setInkColor READ inkColor) Q_PROPERTY(QColor inkColor WRITE setInkColor READ inkColor)
Q_PROPERTY(QColor underlineColor WRITE setUnderlineColor READ underlineColor) Q_PROPERTY(QColor underlineColor WRITE setUnderlineColor READ underlineColor)
public: public:
explicit TextField(QWidget *parent = 0); explicit TextField(QWidget *parent = 0);
~TextField(); ~TextField();
void setInkColor(const QColor &color); void setInkColor(const QColor &color);
void setBackgroundColor(const QColor &color); void setBackgroundColor(const QColor &color);
void setLabel(const QString &label); void setLabel(const QString &label);
void setLabelColor(const QColor &color); void setLabelColor(const QColor &color);
void setLabelFontSize(qreal size); void setLabelFontSize(qreal size);
void setShowLabel(bool value); void setShowLabel(bool value);
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
void setUnderlineColor(const QColor &color); void setUnderlineColor(const QColor &color);
QColor inkColor() const; QColor inkColor() const;
QColor labelColor() const; QColor labelColor() const;
QColor textColor() const; QColor textColor() const;
QColor underlineColor() const; QColor underlineColor() const;
QColor backgroundColor() const; QColor backgroundColor() const;
QString label() const; QString label() const;
bool hasLabel() const; bool hasLabel() const;
qreal labelFontSize() const; qreal labelFontSize() const;
protected: protected:
bool event(QEvent *event) override; bool event(QEvent *event) override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
void init(); void init();
QColor ink_color_; QColor ink_color_;
QColor background_color_; QColor background_color_;
QColor label_color_; QColor label_color_;
QColor text_color_; QColor text_color_;
QColor underline_color_; QColor underline_color_;
QString label_text_; QString label_text_;
TextFieldLabel *label_; TextFieldLabel *label_;
TextFieldStateMachine *state_machine_; TextFieldStateMachine *state_machine_;
bool show_label_; bool show_label_;
qreal label_font_size_; qreal label_font_size_;
}; };
class TextFieldLabel : public QWidget class TextFieldLabel : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal scale WRITE setScale READ scale) Q_PROPERTY(qreal scale WRITE setScale READ scale)
Q_PROPERTY(QPointF offset WRITE setOffset READ offset) Q_PROPERTY(QPointF offset WRITE setOffset READ offset)
Q_PROPERTY(QColor color WRITE setColor READ color) Q_PROPERTY(QColor color WRITE setColor READ color)
public: public:
TextFieldLabel(TextField *parent); TextFieldLabel(TextField *parent);
~TextFieldLabel(); ~TextFieldLabel();
inline void setColor(const QColor &color); inline void setColor(const QColor &color);
inline void setOffset(const QPointF &pos); inline void setOffset(const QPointF &pos);
inline void setScale(qreal scale); inline void setScale(qreal scale);
inline QColor color() const; inline QColor color() const;
inline QPointF offset() const; inline QPointF offset() const;
inline qreal scale() const; inline qreal scale() const;
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
TextField *const text_field_; TextField *const text_field_;
QColor color_; QColor color_;
qreal scale_; qreal scale_;
qreal x_; qreal x_;
qreal y_; qreal y_;
}; };
inline void inline void
TextFieldLabel::setColor(const QColor &color) TextFieldLabel::setColor(const QColor &color)
{ {
color_ = color; color_ = color;
update(); update();
} }
inline void inline void
TextFieldLabel::setOffset(const QPointF &pos) TextFieldLabel::setOffset(const QPointF &pos)
{ {
x_ = pos.x(); x_ = pos.x();
y_ = pos.y(); y_ = pos.y();
update(); update();
} }
inline void inline void
TextFieldLabel::setScale(qreal scale) TextFieldLabel::setScale(qreal scale)
{ {
scale_ = scale; scale_ = scale;
update(); update();
} }
inline QPointF inline QPointF
TextFieldLabel::offset() const TextFieldLabel::offset() const
{ {
return QPointF(x_, y_); return QPointF(x_, y_);
} }
inline qreal inline qreal
TextFieldLabel::scale() const TextFieldLabel::scale() const
{ {
return scale_; return scale_;
} }
inline QColor inline QColor
TextFieldLabel::color() const TextFieldLabel::color() const
{ {
return color_; return color_;
} }
class TextFieldStateMachine : public QStateMachine class TextFieldStateMachine : public QStateMachine
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal progress WRITE setProgress READ progress) Q_PROPERTY(qreal progress WRITE setProgress READ progress)
public: public:
TextFieldStateMachine(TextField *parent); TextFieldStateMachine(TextField *parent);
~TextFieldStateMachine(); ~TextFieldStateMachine();
inline void setProgress(qreal progress); inline void setProgress(qreal progress);
void setLabel(TextFieldLabel *label); void setLabel(TextFieldLabel *label);
inline qreal progress() const; inline qreal progress() const;
public slots: public slots:
void setupProperties(); void setupProperties();
private: private:
QPropertyAnimation *color_anim_; QPropertyAnimation *color_anim_;
QPropertyAnimation *offset_anim_; QPropertyAnimation *offset_anim_;
QState *focused_state_; QState *focused_state_;
QState *normal_state_; QState *normal_state_;
TextField *text_field_; TextField *text_field_;
TextFieldLabel *label_; TextFieldLabel *label_;
qreal progress_; qreal progress_;
}; };
inline void inline void
TextFieldStateMachine::setProgress(qreal progress) TextFieldStateMachine::setProgress(qreal progress)
{ {
progress_ = progress; progress_ = progress;
text_field_->update(); text_field_->update();
} }
inline qreal inline qreal
TextFieldStateMachine::progress() const TextFieldStateMachine::progress() const
{ {
return progress_; return progress_;
} }

View File

@ -10,7 +10,7 @@ enum class AvatarType { Icon, Image, Letter };
namespace sidebar namespace sidebar
{ {
static const int SmallSize = 60; static const int SmallSize = 60;
static const int NormalSize = 300; static const int NormalSize = 300;
} }
// Default font size. // Default font size.
@ -32,35 +32,35 @@ enum class ButtonIconPlacement { LeftIcon, RightIcon };
enum class ProgressType { DeterminateProgress, IndeterminateProgress }; enum class ProgressType { DeterminateProgress, IndeterminateProgress };
enum class Color { enum class Color {
Black, Black,
BrightWhite, BrightWhite,
FadedWhite, FadedWhite,
MediumWhite, MediumWhite,
DarkGreen, DarkGreen,
LightGreen, LightGreen,
BrightGreen, BrightGreen,
Gray, Gray,
Red, Red,
Blue, Blue,
Transparent Transparent
}; };
} // namespace ui } // namespace ui
class Theme : public QObject class Theme : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Theme(QObject *parent = 0); explicit Theme(QObject *parent = 0);
~Theme(); ~Theme();
QColor getColor(const QString &key) const; QColor getColor(const QString &key) const;
void setColor(const QString &key, const QColor &color); void setColor(const QString &key, const QColor &color);
void setColor(const QString &key, ui::Color color); void setColor(const QString &key, ui::Color color);
private: private:
QColor rgba(int r, int g, int b, qreal a) const; QColor rgba(int r, int g, int b, qreal a) const;
QHash<QString, QColor> colors_; QHash<QString, QColor> colors_;
}; };

View File

@ -6,26 +6,26 @@
class ThemeManager : public QCommonStyle class ThemeManager : public QCommonStyle
{ {
Q_OBJECT Q_OBJECT
public: public:
inline static ThemeManager &instance(); inline static ThemeManager &instance();
void setTheme(Theme *theme); void setTheme(Theme *theme);
QColor themeColor(const QString &key) const; QColor themeColor(const QString &key) const;
private: private:
ThemeManager(); ThemeManager();
ThemeManager(ThemeManager const &); ThemeManager(ThemeManager const &);
void operator=(ThemeManager const &); void operator=(ThemeManager const &);
Theme *theme_; Theme *theme_;
}; };
inline ThemeManager & inline ThemeManager &
ThemeManager::instance() ThemeManager::instance()
{ {
static ThemeManager instance; static ThemeManager instance;
return instance; return instance;
} }

View File

@ -26,63 +26,63 @@ QMap<QString, QList<TimelineItem *>> AvatarProvider::toBeResolved_;
void void
AvatarProvider::init(QSharedPointer<MatrixClient> client) AvatarProvider::init(QSharedPointer<MatrixClient> client)
{ {
client_ = client; client_ = client;
connect(client_.data(), &MatrixClient::userAvatarRetrieved, &AvatarProvider::updateAvatar); connect(client_.data(), &MatrixClient::userAvatarRetrieved, &AvatarProvider::updateAvatar);
} }
void void
AvatarProvider::updateAvatar(const QString &uid, const QImage &img) AvatarProvider::updateAvatar(const QString &uid, const QImage &img)
{ {
if (toBeResolved_.contains(uid)) { if (toBeResolved_.contains(uid)) {
auto items = toBeResolved_[uid]; auto items = toBeResolved_[uid];
// Update all the timeline items with the resolved avatar. // Update all the timeline items with the resolved avatar.
for (const auto item : items) for (const auto item : items)
item->setUserAvatar(img); item->setUserAvatar(img);
toBeResolved_.remove(uid); toBeResolved_.remove(uid);
} }
userAvatars_.insert(uid, img); userAvatars_.insert(uid, img);
} }
void void
AvatarProvider::resolve(const QString &userId, TimelineItem *item) AvatarProvider::resolve(const QString &userId, TimelineItem *item)
{ {
if (userAvatars_.contains(userId)) { if (userAvatars_.contains(userId)) {
auto img = userAvatars_[userId]; auto img = userAvatars_[userId];
item->setUserAvatar(img); item->setUserAvatar(img);
return; return;
} }
if (avatarUrls_.contains(userId)) { if (avatarUrls_.contains(userId)) {
// Add the current timeline item to the waiting list for this avatar. // Add the current timeline item to the waiting list for this avatar.
if (!toBeResolved_.contains(userId)) { if (!toBeResolved_.contains(userId)) {
client_->fetchUserAvatar(userId, avatarUrls_[userId]); client_->fetchUserAvatar(userId, avatarUrls_[userId]);
QList<TimelineItem *> timelineItems; QList<TimelineItem *> timelineItems;
timelineItems.push_back(item); timelineItems.push_back(item);
toBeResolved_.insert(userId, timelineItems); toBeResolved_.insert(userId, timelineItems);
} else { } else {
toBeResolved_[userId].push_back(item); toBeResolved_[userId].push_back(item);
} }
} }
} }
void void
AvatarProvider::setAvatarUrl(const QString &userId, const QUrl &url) AvatarProvider::setAvatarUrl(const QString &userId, const QUrl &url)
{ {
avatarUrls_.insert(userId, url); avatarUrls_.insert(userId, url);
} }
void void
AvatarProvider::clear() AvatarProvider::clear()
{ {
userAvatars_.clear(); userAvatars_.clear();
avatarUrls_.clear(); avatarUrls_.clear();
toBeResolved_.clear(); toBeResolved_.clear();
} }

View File

@ -29,5 +29,5 @@ DeserializationException::DeserializationException(const std::string &msg)
const char * const char *
DeserializationException::what() const noexcept DeserializationException::what() const noexcept
{ {
return msg_.c_str(); return msg_.c_str();
} }

View File

@ -24,60 +24,60 @@
EmojiCategory::EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent) EmojiCategory::EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
mainLayout_ = new QVBoxLayout(this); mainLayout_ = new QVBoxLayout(this);
mainLayout_->setMargin(0); mainLayout_->setMargin(0);
emojiListView_ = new QListView(); emojiListView_ = new QListView();
itemModel_ = new QStandardItemModel(this); itemModel_ = new QStandardItemModel(this);
delegate_ = new EmojiItemDelegate(this); delegate_ = new EmojiItemDelegate(this);
data_ = new Emoji; data_ = new Emoji;
emojiListView_->setItemDelegate(delegate_); emojiListView_->setItemDelegate(delegate_);
emojiListView_->setSpacing(5); emojiListView_->setSpacing(5);
emojiListView_->setModel(itemModel_); emojiListView_->setModel(itemModel_);
emojiListView_->setViewMode(QListView::IconMode); emojiListView_->setViewMode(QListView::IconMode);
emojiListView_->setFlow(QListView::LeftToRight); emojiListView_->setFlow(QListView::LeftToRight);
emojiListView_->setResizeMode(QListView::Adjust); emojiListView_->setResizeMode(QListView::Adjust);
emojiListView_->verticalScrollBar()->setEnabled(false); emojiListView_->verticalScrollBar()->setEnabled(false);
emojiListView_->horizontalScrollBar()->setEnabled(false); emojiListView_->horizontalScrollBar()->setEnabled(false);
const int cols = 7; const int cols = 7;
const int rows = emoji.size() / 7; const int rows = emoji.size() / 7;
// TODO: Be precise here. Take the parent into consideration. // TODO: Be precise here. Take the parent into consideration.
emojiListView_->setFixedSize(cols * 50 + 20, rows * 50 + 20); emojiListView_->setFixedSize(cols * 50 + 20, rows * 50 + 20);
emojiListView_->setGridSize(QSize(50, 50)); emojiListView_->setGridSize(QSize(50, 50));
emojiListView_->setDragEnabled(false); emojiListView_->setDragEnabled(false);
emojiListView_->setEditTriggers(QAbstractItemView::NoEditTriggers); emojiListView_->setEditTriggers(QAbstractItemView::NoEditTriggers);
for (const auto &e : emoji) { for (const auto &e : emoji) {
data_->unicode = e.unicode; data_->unicode = e.unicode;
auto item = new QStandardItem; auto item = new QStandardItem;
item->setSizeHint(QSize(24, 24)); item->setSizeHint(QSize(24, 24));
QVariant unicode(data_->unicode); QVariant unicode(data_->unicode);
item->setData(unicode.toString(), Qt::UserRole); item->setData(unicode.toString(), Qt::UserRole);
itemModel_->appendRow(item); itemModel_->appendRow(item);
} }
QFont font("Open Sans SemiBold"); QFont font("Open Sans SemiBold");
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
category_ = new QLabel(category, this); category_ = new QLabel(category, this);
category_->setFont(font); category_->setFont(font);
category_->setStyleSheet("color: #ccc; margin: 20px 0px 15px 8px;"); category_->setStyleSheet("color: #ccc; margin: 20px 0px 15px 8px;");
auto labelLayout_ = new QHBoxLayout(); auto labelLayout_ = new QHBoxLayout();
labelLayout_->addWidget(category_); labelLayout_->addWidget(category_);
labelLayout_->addStretch(1); labelLayout_->addStretch(1);
mainLayout_->addLayout(labelLayout_); mainLayout_->addLayout(labelLayout_);
mainLayout_->addWidget(emojiListView_); mainLayout_->addWidget(emojiListView_);
connect(emojiListView_, &QListView::clicked, this, &EmojiCategory::clickIndex); connect(emojiListView_, &QListView::clicked, this, &EmojiCategory::clickIndex);
} }
EmojiCategory::~EmojiCategory() EmojiCategory::~EmojiCategory()

View File

@ -23,26 +23,28 @@
EmojiItemDelegate::EmojiItemDelegate(QObject *parent) EmojiItemDelegate::EmojiItemDelegate(QObject *parent)
: QStyledItemDelegate(parent) : QStyledItemDelegate(parent)
{ {
data_ = new Emoji; data_ = new Emoji;
} }
EmojiItemDelegate::~EmojiItemDelegate() EmojiItemDelegate::~EmojiItemDelegate()
{ {
delete data_; delete data_;
} }
void void
EmojiItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const EmojiItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{ {
Q_UNUSED(index); Q_UNUSED(index);
QStyleOptionViewItem viewOption(option); QStyleOptionViewItem viewOption(option);
auto emoji = index.data(Qt::UserRole).toString(); auto emoji = index.data(Qt::UserRole).toString();
QFont font("Emoji One"); QFont font("Emoji One");
font.setPixelSize(19); font.setPixelSize(19);
painter->setFont(font); painter->setFont(font);
painter->drawText(viewOption.rect, Qt::AlignCenter, emoji); painter->drawText(viewOption.rect, Qt::AlignCenter, emoji);
} }

View File

@ -34,225 +34,238 @@ EmojiPanel::EmojiPanel(QWidget *parent)
, animationDuration_{ 100 } , animationDuration_{ 100 }
, categoryIconSize_{ 20 } , categoryIconSize_{ 20 }
{ {
setStyleSheet("QWidget {background: #f8fbfe; color: #e8e8e8; border: none;}" setStyleSheet(
"QScrollBar:vertical { background-color: #f8fbfe; width: 8px; margin: 0px 2px 0 2px; }" "QWidget {background: #f8fbfe; color: #e8e8e8; border: none;}"
"QScrollBar::handle:vertical { background-color: #d6dde3; min-height: 20px; }" "QScrollBar:vertical { background-color: #f8fbfe; width: 8px; margin: 0px 2px 0 2px; }"
"QScrollBar::add-line:vertical { border: none; background: none; }" "QScrollBar::handle:vertical { background-color: #d6dde3; min-height: 20px; }"
"QScrollBar::sub-line:vertical { border: none; background: none; }"); "QScrollBar::add-line:vertical { border: none; background: none; }"
"QScrollBar::sub-line:vertical { border: none; background: none; }");
setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_TranslucentBackground, true);
setAttribute(Qt::WA_ShowWithoutActivating, true); setAttribute(Qt::WA_ShowWithoutActivating, true);
setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip); setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);
auto mainWidget = new QWidget(this); auto mainWidget = new QWidget(this);
mainWidget->setMaximumSize(width_, height_); mainWidget->setMaximumSize(width_, height_);
auto topLayout = new QVBoxLayout(this); auto topLayout = new QVBoxLayout(this);
topLayout->addWidget(mainWidget); topLayout->addWidget(mainWidget);
topLayout->setMargin(shadowMargin_); topLayout->setMargin(shadowMargin_);
auto contentLayout = new QVBoxLayout(mainWidget); auto contentLayout = new QVBoxLayout(mainWidget);
contentLayout->setMargin(0); contentLayout->setMargin(0);
auto emojiCategories = new QFrame(mainWidget); auto emojiCategories = new QFrame(mainWidget);
emojiCategories->setStyleSheet("background-color: #f2f2f2"); emojiCategories->setStyleSheet("background-color: #f2f2f2");
auto categoriesLayout = new QHBoxLayout(emojiCategories); auto categoriesLayout = new QHBoxLayout(emojiCategories);
categoriesLayout->setSpacing(6); categoriesLayout->setSpacing(6);
categoriesLayout->setMargin(5); categoriesLayout->setMargin(5);
auto peopleCategory = new FlatButton(emojiCategories); auto peopleCategory = new FlatButton(emojiCategories);
peopleCategory->setIcon(QIcon(":/icons/icons/emoji-categories/people.png")); peopleCategory->setIcon(QIcon(":/icons/icons/emoji-categories/people.png"));
peopleCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); peopleCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
peopleCategory->setForegroundColor("gray"); peopleCategory->setForegroundColor("gray");
auto natureCategory_ = new FlatButton(emojiCategories); auto natureCategory_ = new FlatButton(emojiCategories);
natureCategory_->setIcon(QIcon(":/icons/icons/emoji-categories/nature.png")); natureCategory_->setIcon(QIcon(":/icons/icons/emoji-categories/nature.png"));
natureCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); natureCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
natureCategory_->setForegroundColor("gray"); natureCategory_->setForegroundColor("gray");
auto foodCategory_ = new FlatButton(emojiCategories); auto foodCategory_ = new FlatButton(emojiCategories);
foodCategory_->setIcon(QIcon(":/icons/icons/emoji-categories/foods.png")); foodCategory_->setIcon(QIcon(":/icons/icons/emoji-categories/foods.png"));
foodCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); foodCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
foodCategory_->setForegroundColor("gray"); foodCategory_->setForegroundColor("gray");
auto activityCategory = new FlatButton(emojiCategories); auto activityCategory = new FlatButton(emojiCategories);
activityCategory->setIcon(QIcon(":/icons/icons/emoji-categories/activity.png")); activityCategory->setIcon(QIcon(":/icons/icons/emoji-categories/activity.png"));
activityCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); activityCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
activityCategory->setForegroundColor("gray"); activityCategory->setForegroundColor("gray");
auto travelCategory = new FlatButton(emojiCategories); auto travelCategory = new FlatButton(emojiCategories);
travelCategory->setIcon(QIcon(":/icons/icons/emoji-categories/travel.png")); travelCategory->setIcon(QIcon(":/icons/icons/emoji-categories/travel.png"));
travelCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); travelCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
travelCategory->setForegroundColor("gray"); travelCategory->setForegroundColor("gray");
auto objectsCategory = new FlatButton(emojiCategories); auto objectsCategory = new FlatButton(emojiCategories);
objectsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/objects.png")); objectsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/objects.png"));
objectsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); objectsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
objectsCategory->setForegroundColor("gray"); objectsCategory->setForegroundColor("gray");
auto symbolsCategory = new FlatButton(emojiCategories); auto symbolsCategory = new FlatButton(emojiCategories);
symbolsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/symbols.png")); symbolsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/symbols.png"));
symbolsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); symbolsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
symbolsCategory->setForegroundColor("gray"); symbolsCategory->setForegroundColor("gray");
auto flagsCategory = new FlatButton(emojiCategories); auto flagsCategory = new FlatButton(emojiCategories);
flagsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/flags.png")); flagsCategory->setIcon(QIcon(":/icons/icons/emoji-categories/flags.png"));
flagsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); flagsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_));
flagsCategory->setForegroundColor("gray"); flagsCategory->setForegroundColor("gray");
categoriesLayout->addWidget(peopleCategory); categoriesLayout->addWidget(peopleCategory);
categoriesLayout->addWidget(natureCategory_); categoriesLayout->addWidget(natureCategory_);
categoriesLayout->addWidget(foodCategory_); categoriesLayout->addWidget(foodCategory_);
categoriesLayout->addWidget(activityCategory); categoriesLayout->addWidget(activityCategory);
categoriesLayout->addWidget(travelCategory); categoriesLayout->addWidget(travelCategory);
categoriesLayout->addWidget(objectsCategory); categoriesLayout->addWidget(objectsCategory);
categoriesLayout->addWidget(symbolsCategory); categoriesLayout->addWidget(symbolsCategory);
categoriesLayout->addWidget(flagsCategory); categoriesLayout->addWidget(flagsCategory);
scrollArea_ = new QScrollArea(this); scrollArea_ = new QScrollArea(this);
scrollArea_->setWidgetResizable(true); scrollArea_->setWidgetResizable(true);
scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
auto scrollWidget = new QWidget(this); auto scrollWidget = new QWidget(this);
auto scrollLayout = new QVBoxLayout(scrollWidget); auto scrollLayout = new QVBoxLayout(scrollWidget);
scrollLayout->setMargin(0); scrollLayout->setMargin(0);
scrollArea_->setWidget(scrollWidget); scrollArea_->setWidget(scrollWidget);
auto peopleEmoji = new EmojiCategory(tr("Smileys & People"), emoji_provider_.people, scrollWidget); auto peopleEmoji =
scrollLayout->addWidget(peopleEmoji); new EmojiCategory(tr("Smileys & People"), emoji_provider_.people, scrollWidget);
scrollLayout->addWidget(peopleEmoji);
auto natureEmoji = new EmojiCategory(tr("Animals & Nature"), emoji_provider_.nature, scrollWidget); auto natureEmoji =
scrollLayout->addWidget(natureEmoji); new EmojiCategory(tr("Animals & Nature"), emoji_provider_.nature, scrollWidget);
scrollLayout->addWidget(natureEmoji);
auto foodEmoji = new EmojiCategory(tr("Food & Drink"), emoji_provider_.food, scrollWidget); auto foodEmoji = new EmojiCategory(tr("Food & Drink"), emoji_provider_.food, scrollWidget);
scrollLayout->addWidget(foodEmoji); scrollLayout->addWidget(foodEmoji);
auto activityEmoji = new EmojiCategory(tr("Activity"), emoji_provider_.activity, scrollWidget); auto activityEmoji =
scrollLayout->addWidget(activityEmoji); new EmojiCategory(tr("Activity"), emoji_provider_.activity, scrollWidget);
scrollLayout->addWidget(activityEmoji);
auto travelEmoji = new EmojiCategory(tr("Travel & Places"), emoji_provider_.travel, scrollWidget); auto travelEmoji =
scrollLayout->addWidget(travelEmoji); new EmojiCategory(tr("Travel & Places"), emoji_provider_.travel, scrollWidget);
scrollLayout->addWidget(travelEmoji);
auto objectsEmoji = new EmojiCategory(tr("Objects"), emoji_provider_.objects, scrollWidget); auto objectsEmoji = new EmojiCategory(tr("Objects"), emoji_provider_.objects, scrollWidget);
scrollLayout->addWidget(objectsEmoji); scrollLayout->addWidget(objectsEmoji);
auto symbolsEmoji = new EmojiCategory(tr("Symbols"), emoji_provider_.symbols, scrollWidget); auto symbolsEmoji = new EmojiCategory(tr("Symbols"), emoji_provider_.symbols, scrollWidget);
scrollLayout->addWidget(symbolsEmoji); scrollLayout->addWidget(symbolsEmoji);
auto flagsEmoji = new EmojiCategory(tr("Flags"), emoji_provider_.flags, scrollWidget); auto flagsEmoji = new EmojiCategory(tr("Flags"), emoji_provider_.flags, scrollWidget);
scrollLayout->addWidget(flagsEmoji); scrollLayout->addWidget(flagsEmoji);
contentLayout->addStretch(1); contentLayout->addStretch(1);
contentLayout->addWidget(scrollArea_); contentLayout->addWidget(scrollArea_);
contentLayout->addWidget(emojiCategories); contentLayout->addWidget(emojiCategories);
opacity_ = new QGraphicsOpacityEffect(this); opacity_ = new QGraphicsOpacityEffect(this);
opacity_->setOpacity(1.0); opacity_->setOpacity(1.0);
setGraphicsEffect(opacity_); setGraphicsEffect(opacity_);
animation_ = new QPropertyAnimation(opacity_, "opacity", this); animation_ = new QPropertyAnimation(opacity_, "opacity", this);
animation_->setDuration(animationDuration_); animation_->setDuration(animationDuration_);
animation_->setStartValue(1); animation_->setStartValue(1);
animation_->setEndValue(0); animation_->setEndValue(0);
connect(peopleEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(peopleEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(peopleCategory, &QPushButton::clicked, [this, peopleEmoji]() { this->showEmojiCategory(peopleEmoji); }); connect(peopleCategory, &QPushButton::clicked, [this, peopleEmoji]() {
this->showEmojiCategory(peopleEmoji);
});
connect(natureEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(natureEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(natureCategory_, &QPushButton::clicked, [this, natureEmoji]() { connect(natureCategory_, &QPushButton::clicked, [this, natureEmoji]() {
this->showEmojiCategory(natureEmoji); this->showEmojiCategory(natureEmoji);
}); });
connect(foodEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(foodEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(foodCategory_, &QPushButton::clicked, [this, foodEmoji]() { this->showEmojiCategory(foodEmoji); }); connect(foodCategory_, &QPushButton::clicked, [this, foodEmoji]() {
this->showEmojiCategory(foodEmoji);
});
connect(activityEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(activityEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(activityCategory, &QPushButton::clicked, [this, activityEmoji]() { connect(activityCategory, &QPushButton::clicked, [this, activityEmoji]() {
this->showEmojiCategory(activityEmoji); this->showEmojiCategory(activityEmoji);
}); });
connect(travelEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(travelEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(travelCategory, &QPushButton::clicked, [this, travelEmoji]() { this->showEmojiCategory(travelEmoji); }); connect(travelCategory, &QPushButton::clicked, [this, travelEmoji]() {
this->showEmojiCategory(travelEmoji);
});
connect(objectsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(objectsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(objectsCategory, &QPushButton::clicked, [this, objectsEmoji]() { connect(objectsCategory, &QPushButton::clicked, [this, objectsEmoji]() {
this->showEmojiCategory(objectsEmoji); this->showEmojiCategory(objectsEmoji);
}); });
connect(symbolsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(symbolsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(symbolsCategory, &QPushButton::clicked, [this, symbolsEmoji]() { connect(symbolsCategory, &QPushButton::clicked, [this, symbolsEmoji]() {
this->showEmojiCategory(symbolsEmoji); this->showEmojiCategory(symbolsEmoji);
}); });
connect(flagsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected); connect(flagsEmoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(flagsCategory, &QPushButton::clicked, [this, flagsEmoji]() { this->showEmojiCategory(flagsEmoji); }); connect(flagsCategory, &QPushButton::clicked, [this, flagsEmoji]() {
this->showEmojiCategory(flagsEmoji);
});
connect(animation_, &QAbstractAnimation::finished, [this]() { connect(animation_, &QAbstractAnimation::finished, [this]() {
if (animation_->direction() == QAbstractAnimation::Forward) if (animation_->direction() == QAbstractAnimation::Forward)
this->hide(); this->hide();
}); });
} }
void void
EmojiPanel::showEmojiCategory(const EmojiCategory *category) EmojiPanel::showEmojiCategory(const EmojiCategory *category)
{ {
auto posToGo = category->mapToParent(QPoint()).y(); auto posToGo = category->mapToParent(QPoint()).y();
auto current = scrollArea_->verticalScrollBar()->value(); auto current = scrollArea_->verticalScrollBar()->value();
if (current == posToGo) if (current == posToGo)
return; return;
// HACK // HACK
// If we want to go to a previous category and position the label at the top // If we want to go to a previous category and position the label at the top
// the 6*50 offset won't work because not all the categories have the same height. // the 6*50 offset won't work because not all the categories have the same height.
// To ensure the category is at the top, we move to the top // To ensure the category is at the top, we move to the top
// and go as normal to the next category. // and go as normal to the next category.
if (current > posToGo) if (current > posToGo)
this->scrollArea_->ensureVisible(0, 0, 0, 0); this->scrollArea_->ensureVisible(0, 0, 0, 0);
posToGo += 6 * 50; posToGo += 6 * 50;
this->scrollArea_->ensureVisible(0, posToGo, 0, 0); this->scrollArea_->ensureVisible(0, posToGo, 0, 0);
} }
void void
EmojiPanel::leaveEvent(QEvent *event) EmojiPanel::leaveEvent(QEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
fadeOut(); fadeOut();
} }
void void
EmojiPanel::paintEvent(QPaintEvent *event) EmojiPanel::paintEvent(QPaintEvent *event)
{ {
QPainter p(this); QPainter p(this);
DropShadow::draw(p, DropShadow::draw(p,
shadowMargin_, shadowMargin_,
4.0, 4.0,
QColor(120, 120, 120, 92), QColor(120, 120, 120, 92),
QColor(255, 255, 255, 0), QColor(255, 255, 255, 0),
0.0, 0.0,
1.0, 1.0,
0.6, 0.6,
width(), width(),
height()); height());
QWidget::paintEvent(event); QWidget::paintEvent(event);
} }
void void
EmojiPanel::fadeOut() EmojiPanel::fadeOut()
{ {
animation_->setDirection(QAbstractAnimation::Forward); animation_->setDirection(QAbstractAnimation::Forward);
animation_->start(); animation_->start();
} }
void void
EmojiPanel::fadeIn() EmojiPanel::fadeIn()
{ {
animation_->setDirection(QAbstractAnimation::Backward); animation_->setDirection(QAbstractAnimation::Backward);
animation_->start(); animation_->start();
} }

View File

@ -28,40 +28,40 @@ EmojiPickButton::EmojiPickButton(QWidget *parent)
void void
EmojiPickButton::enterEvent(QEvent *e) EmojiPickButton::enterEvent(QEvent *e)
{ {
Q_UNUSED(e); Q_UNUSED(e);
if (panel_ == nullptr) { if (panel_ == nullptr) {
panel_ = new EmojiPanel(this); panel_ = new EmojiPanel(this);
connect(panel_, &EmojiPanel::emojiSelected, this, &EmojiPickButton::emojiSelected); connect(panel_, &EmojiPanel::emojiSelected, this, &EmojiPickButton::emojiSelected);
} }
QPoint pos(rect().x(), rect().y()); QPoint pos(rect().x(), rect().y());
pos = this->mapToGlobal(pos); pos = this->mapToGlobal(pos);
auto panel_size = panel_->sizeHint(); auto panel_size = panel_->sizeHint();
auto x = pos.x() - panel_size.width() + horizontal_distance_; auto x = pos.x() - panel_size.width() + horizontal_distance_;
auto y = pos.y() - panel_size.height() - vertical_distance_; auto y = pos.y() - panel_size.height() - vertical_distance_;
panel_->move(x, y); panel_->move(x, y);
panel_->fadeIn(); panel_->fadeIn();
panel_->show(); panel_->show();
} }
void void
EmojiPickButton::leaveEvent(QEvent *e) EmojiPickButton::leaveEvent(QEvent *e)
{ {
Q_UNUSED(e); Q_UNUSED(e);
if (panel_->underMouse()) if (panel_->underMouse())
return; return;
auto pos = QCursor::pos(); auto pos = QCursor::pos();
auto panel_geometry = panel_->geometry(); auto panel_geometry = panel_->geometry();
panel_geometry.adjust(0, 0, 0, vertical_distance_); panel_geometry.adjust(0, 0, 0, vertical_distance_);
if (panel_geometry.contains(pos)) if (panel_geometry.contains(pos))
return; return;
panel_->fadeOut(); panel_->fadeOut();
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,169 +26,171 @@
#include "ImageOverlayDialog.h" #include "ImageOverlayDialog.h"
namespace events = matrix::events; namespace events = matrix::events;
namespace msgs = matrix::events::messages; namespace msgs = matrix::events::messages;
ImageItem::ImageItem(QSharedPointer<MatrixClient> client, ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
const events::MessageEvent<msgs::Image> &event, const events::MessageEvent<msgs::Image> &event,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, event_{ event } , event_{ event }
, client_{ client } , client_{ client }
{ {
setMouseTracking(true); setMouseTracking(true);
setCursor(Qt::PointingHandCursor); setCursor(Qt::PointingHandCursor);
setAttribute(Qt::WA_Hover, true); setAttribute(Qt::WA_Hover, true);
url_ = event.msgContent().url(); url_ = event.msgContent().url();
text_ = event.content().body(); text_ = event.content().body();
QList<QString> url_parts = url_.toString().split("mxc://"); QList<QString> url_parts = url_.toString().split("mxc://");
if (url_parts.size() != 2) { if (url_parts.size() != 2) {
qDebug() << "Invalid format for image" << url_.toString(); qDebug() << "Invalid format for image" << url_.toString();
return; return;
} }
QString media_params = url_parts[1]; QString media_params = url_parts[1];
url_ = QString("%1/_matrix/media/r0/download/%2").arg(client_.data()->getHomeServer().toString(), media_params); url_ = QString("%1/_matrix/media/r0/download/%2")
.arg(client_.data()->getHomeServer().toString(), media_params);
client_.data()->downloadImage(event.eventId(), url_); client_.data()->downloadImage(event.eventId(), url_);
connect(client_.data(), connect(client_.data(),
SIGNAL(imageDownloaded(const QString &, const QPixmap &)), SIGNAL(imageDownloaded(const QString &, const QPixmap &)),
this, this,
SLOT(imageDownloaded(const QString &, const QPixmap &))); SLOT(imageDownloaded(const QString &, const QPixmap &)));
} }
void void
ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img) ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img)
{ {
if (event_id != event_.eventId()) if (event_id != event_.eventId())
return; return;
setImage(img); setImage(img);
} }
void void
ImageItem::openUrl() ImageItem::openUrl()
{ {
if (url_.toString().isEmpty()) if (url_.toString().isEmpty())
return; return;
if (!QDesktopServices::openUrl(url_)) if (!QDesktopServices::openUrl(url_))
qWarning() << "Could not open url" << url_.toString(); qWarning() << "Could not open url" << url_.toString();
} }
void void
ImageItem::scaleImage() ImageItem::scaleImage()
{ {
if (image_.isNull()) if (image_.isNull())
return; return;
auto width_ratio = (double)max_width_ / (double)image_.width(); auto width_ratio = (double)max_width_ / (double)image_.width();
auto height_ratio = (double)max_height_ / (double)image_.height(); auto height_ratio = (double)max_height_ / (double)image_.height();
auto min_aspect_ratio = std::min(width_ratio, height_ratio); auto min_aspect_ratio = std::min(width_ratio, height_ratio);
if (min_aspect_ratio > 1) { if (min_aspect_ratio > 1) {
width_ = image_.width(); width_ = image_.width();
height_ = image_.height(); height_ = image_.height();
} else { } else {
width_ = image_.width() * min_aspect_ratio; width_ = image_.width() * min_aspect_ratio;
height_ = image_.height() * min_aspect_ratio; height_ = image_.height() * min_aspect_ratio;
} }
setFixedSize(width_, height_); setFixedSize(width_, height_);
scaled_image_ = image_.scaled(width_, height_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); scaled_image_ =
image_.scaled(width_, height_, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
} }
QSize QSize
ImageItem::sizeHint() const ImageItem::sizeHint() const
{ {
if (image_.isNull()) if (image_.isNull())
return QSize(max_width_, bottom_height_); return QSize(max_width_, bottom_height_);
return QSize(width_, height_); return QSize(width_, height_);
} }
void void
ImageItem::setImage(const QPixmap &image) ImageItem::setImage(const QPixmap &image)
{ {
image_ = image; image_ = image;
scaleImage(); scaleImage();
update(); update();
} }
void void
ImageItem::mousePressEvent(QMouseEvent *event) ImageItem::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() != Qt::LeftButton) if (event->button() != Qt::LeftButton)
return; return;
if (image_.isNull()) { if (image_.isNull()) {
openUrl(); openUrl();
return; return;
} }
auto point = event->pos(); auto point = event->pos();
// Click on the text box. // Click on the text box.
if (QRect(0, height_ - bottom_height_, width_, bottom_height_).contains(point)) { if (QRect(0, height_ - bottom_height_, width_, bottom_height_).contains(point)) {
openUrl(); openUrl();
} else { } else {
auto image_dialog = new ImageOverlayDialog(image_, this); auto image_dialog = new ImageOverlayDialog(image_, this);
image_dialog->show(); image_dialog->show();
} }
} }
void void
ImageItem::resizeEvent(QResizeEvent *event) ImageItem::resizeEvent(QResizeEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
scaleImage(); scaleImage();
} }
void void
ImageItem::paintEvent(QPaintEvent *event) ImageItem::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
QFont font("Open Sans"); QFont font("Open Sans");
font.setPixelSize(12); font.setPixelSize(12);
QFontMetrics metrics(font); QFontMetrics metrics(font);
int fontHeight = metrics.height(); int fontHeight = metrics.height();
if (image_.isNull()) { if (image_.isNull()) {
int height = fontHeight + 10; int height = fontHeight + 10;
QString elidedText = metrics.elidedText(text_, Qt::ElideRight, max_width_ - 10); QString elidedText = metrics.elidedText(text_, Qt::ElideRight, max_width_ - 10);
setFixedSize(metrics.width(elidedText), fontHeight + 10); setFixedSize(metrics.width(elidedText), fontHeight + 10);
painter.setFont(font); painter.setFont(font);
painter.setPen(QPen(QColor(66, 133, 244))); painter.setPen(QPen(QColor(66, 133, 244)));
painter.drawText(QPoint(0, height / 2 + 2), elidedText); painter.drawText(QPoint(0, height / 2 + 2), elidedText);
return; return;
} }
painter.fillRect(QRect(0, 0, width_, height_), scaled_image_); painter.fillRect(QRect(0, 0, width_, height_), scaled_image_);
if (underMouse()) { if (underMouse()) {
// Bottom text section // Bottom text section
painter.fillRect(QRect(0, height_ - bottom_height_, width_, bottom_height_), painter.fillRect(QRect(0, height_ - bottom_height_, width_, bottom_height_),
QBrush(QColor(33, 33, 33, 128))); QBrush(QColor(33, 33, 33, 128)));
QString elidedText = metrics.elidedText(text_, Qt::ElideRight, width_ - 10); QString elidedText = metrics.elidedText(text_, Qt::ElideRight, width_ - 10);
font.setWeight(500); font.setWeight(500);
painter.setFont(font); painter.setFont(font);
painter.setPen(QPen(QColor("white"))); painter.setPen(QPen(QColor("white")));
painter.drawText(QPoint(5, height_ - fontHeight / 2), elidedText); painter.drawText(QPoint(5, height_ - fontHeight / 2), elidedText);
} }
} }

View File

@ -28,103 +28,105 @@ ImageOverlayDialog::ImageOverlayDialog(QPixmap image, QWidget *parent)
: QWidget{ parent } : QWidget{ parent }
, originalImage_{ image } , originalImage_{ image }
{ {
setMouseTracking(true); setMouseTracking(true);
setParent(0); setParent(0);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint); setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_TranslucentBackground, true);
setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, true);
setWindowState(Qt::WindowFullScreen); setWindowState(Qt::WindowFullScreen);
screen_ = QApplication::desktop()->availableGeometry(); screen_ = QApplication::desktop()->availableGeometry();
move(QApplication::desktop()->mapToGlobal(screen_.topLeft())); move(QApplication::desktop()->mapToGlobal(screen_.topLeft()));
resize(screen_.size()); resize(screen_.size());
connect(this, SIGNAL(closing()), this, SLOT(close())); connect(this, SIGNAL(closing()), this, SLOT(close()));
raise(); raise();
} }
// TODO: Move this into Utils // TODO: Move this into Utils
void void
ImageOverlayDialog::scaleImage(int max_width, int max_height) ImageOverlayDialog::scaleImage(int max_width, int max_height)
{ {
if (originalImage_.isNull()) if (originalImage_.isNull())
return; return;
auto width_ratio = (double)max_width / (double)originalImage_.width(); auto width_ratio = (double)max_width / (double)originalImage_.width();
auto height_ratio = (double)max_height / (double)originalImage_.height(); auto height_ratio = (double)max_height / (double)originalImage_.height();
auto min_aspect_ratio = std::min(width_ratio, height_ratio); auto min_aspect_ratio = std::min(width_ratio, height_ratio);
int final_width = 0; int final_width = 0;
int final_height = 0; int final_height = 0;
if (min_aspect_ratio > 1) { if (min_aspect_ratio > 1) {
final_width = originalImage_.width(); final_width = originalImage_.width();
final_height = originalImage_.height(); final_height = originalImage_.height();
} else { } else {
final_width = originalImage_.width() * min_aspect_ratio; final_width = originalImage_.width() * min_aspect_ratio;
final_height = originalImage_.height() * min_aspect_ratio; final_height = originalImage_.height() * min_aspect_ratio;
} }
image_ = originalImage_.scaled(final_width, final_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image_ = originalImage_.scaled(
final_width, final_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
} }
void void
ImageOverlayDialog::paintEvent(QPaintEvent *event) ImageOverlayDialog::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
// Full screen overlay. // Full screen overlay.
painter.fillRect(QRect(0, 0, screen_.width(), screen_.height()), QColor(55, 55, 55, 170)); painter.fillRect(QRect(0, 0, screen_.width(), screen_.height()), QColor(55, 55, 55, 170));
// Left and Right margins // Left and Right margins
int outer_margin = screen_.width() * 0.12; int outer_margin = screen_.width() * 0.12;
int buttonSize = 36; int buttonSize = 36;
int margin = outer_margin * 0.1; int margin = outer_margin * 0.1;
int max_width = screen_.width() - 2 * outer_margin; int max_width = screen_.width() - 2 * outer_margin;
int max_height = screen_.height(); int max_height = screen_.height();
scaleImage(max_width, max_height); scaleImage(max_width, max_height);
int diff_x = max_width - image_.width(); int diff_x = max_width - image_.width();
int diff_y = max_height - image_.height(); int diff_y = max_height - image_.height();
content_ = QRect(outer_margin + diff_x / 2, diff_y / 2, image_.width(), image_.height()); content_ = QRect(outer_margin + diff_x / 2, diff_y / 2, image_.width(), image_.height());
close_button_ = QRect(screen_.width() - margin - buttonSize, margin, buttonSize, buttonSize); close_button_ =
QRect(screen_.width() - margin - buttonSize, margin, buttonSize, buttonSize);
// Draw main content_. // Draw main content_.
painter.drawPixmap(content_, image_); painter.drawPixmap(content_, image_);
// Draw top right corner X. // Draw top right corner X.
QPen pen; QPen pen;
pen.setCapStyle(Qt::RoundCap); pen.setCapStyle(Qt::RoundCap);
pen.setWidthF(5); pen.setWidthF(5);
pen.setColor("gray"); pen.setColor("gray");
auto center = close_button_.center(); auto center = close_button_.center();
painter.setPen(pen); painter.setPen(pen);
painter.drawLine(center - QPointF(15, 15), center + QPointF(15, 15)); painter.drawLine(center - QPointF(15, 15), center + QPointF(15, 15));
painter.drawLine(center + QPointF(15, -15), center - QPointF(15, -15)); painter.drawLine(center + QPointF(15, -15), center - QPointF(15, -15));
} }
void void
ImageOverlayDialog::mousePressEvent(QMouseEvent *event) ImageOverlayDialog::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() != Qt::LeftButton) if (event->button() != Qt::LeftButton)
return; return;
if (close_button_.contains(event->pos())) if (close_button_.contains(event->pos()))
emit closing(); emit closing();
else if (!content_.contains(event->pos())) else if (!content_.contains(event->pos()))
emit closing(); emit closing();
} }

View File

@ -20,7 +20,8 @@
const QRegExp MXID_REGEX("@[A-Za-z0-9._%+-]+:[A-Za-z0-9.-]{1,126}\\.[A-Za-z]{1,63}"); const QRegExp MXID_REGEX("@[A-Za-z0-9._%+-]+:[A-Za-z0-9.-]{1,126}\\.[A-Za-z]{1,63}");
const QRegExp LOCALPART_REGEX("[A-za-z0-9._%+-]{3,}"); const QRegExp LOCALPART_REGEX("[A-za-z0-9._%+-]{3,}");
const QRegExp PASSWORD_REGEX(".{8,}"); const QRegExp PASSWORD_REGEX(".{8,}");
const QRegExp DOMAIN_REGEX("(?!\\-)(?:[a-zA-Z\\d\\-]{0,62}[a-zA-Z\\d]\\.){1,126}(?!\\d+)[a-zA-Z\\d]{1,63}"); const QRegExp DOMAIN_REGEX(
"(?!\\-)(?:[a-zA-Z\\d\\-]{0,62}[a-zA-Z\\d]\\.){1,126}(?!\\d+)[a-zA-Z\\d]{1,63}");
QRegExpValidator InputValidator::Id(MXID_REGEX); QRegExpValidator InputValidator::Id(MXID_REGEX);
QRegExpValidator InputValidator::Localpart(LOCALPART_REGEX); QRegExpValidator InputValidator::Localpart(LOCALPART_REGEX);

View File

@ -36,43 +36,43 @@ QByteArray
LoginRequest::serialize() noexcept LoginRequest::serialize() noexcept
{ {
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
QString initialDeviceName("nheko on Mac OS"); QString initialDeviceName("nheko on Mac OS");
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
QString initialDeviceName("nheko on Linux"); QString initialDeviceName("nheko on Linux");
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
QString initialDeviceName("nheko on Windows"); QString initialDeviceName("nheko on Windows");
#else #else
QString initialDeviceName("nheko"); QString initialDeviceName("nheko");
#endif #endif
QJsonObject body{ QJsonObject body{
{ "type", "m.login.password" }, { "type", "m.login.password" },
{ "user", user_ }, { "user", user_ },
{ "password", password_ }, { "password", password_ },
{ "initial_device_display_name", initialDeviceName }, { "initial_device_display_name", initialDeviceName },
}; };
return QJsonDocument(body).toJson(QJsonDocument::Compact); return QJsonDocument(body).toJson(QJsonDocument::Compact);
} }
void void
LoginResponse::deserialize(const QJsonDocument &data) LoginResponse::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Login response is not a JSON object"); throw DeserializationException("Login response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (object.value("access_token") == QJsonValue::Undefined) if (object.value("access_token") == QJsonValue::Undefined)
throw DeserializationException("Login: missing access_token param"); throw DeserializationException("Login: missing access_token param");
if (object.value("home_server") == QJsonValue::Undefined) if (object.value("home_server") == QJsonValue::Undefined)
throw DeserializationException("Login: missing home_server param"); throw DeserializationException("Login: missing home_server param");
if (object.value("user_id") == QJsonValue::Undefined) if (object.value("user_id") == QJsonValue::Undefined)
throw DeserializationException("Login: missing user_id param"); throw DeserializationException("Login: missing user_id param");
access_token_ = object.value("access_token").toString(); access_token_ = object.value("access_token").toString();
home_server_ = object.value("home_server").toString(); home_server_ = object.value("home_server").toString();
user_id_ = object.value("user_id").toString(); user_id_ = object.value("user_id").toString();
} }

View File

@ -26,274 +26,275 @@ LoginPage::LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent)
, inferredServerAddress_() , inferredServerAddress_()
, client_{ client } , client_{ client }
{ {
setStyleSheet("background-color: #f9f9f9"); setStyleSheet("background-color: #f9f9f9");
top_layout_ = new QVBoxLayout(); top_layout_ = new QVBoxLayout();
top_bar_layout_ = new QHBoxLayout(); top_bar_layout_ = new QHBoxLayout();
top_bar_layout_->setSpacing(0); top_bar_layout_->setSpacing(0);
top_bar_layout_->setMargin(0); top_bar_layout_->setMargin(0);
back_button_ = new FlatButton(this); back_button_ = new FlatButton(this);
back_button_->setMinimumSize(QSize(30, 30)); back_button_->setMinimumSize(QSize(30, 30));
back_button_->setForegroundColor("#333333"); back_button_->setForegroundColor("#333333");
top_bar_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter); top_bar_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter);
top_bar_layout_->addStretch(1); top_bar_layout_->addStretch(1);
QIcon icon; QIcon icon;
icon.addFile(":/icons/icons/left-angle.png", QSize(), QIcon::Normal, QIcon::Off); icon.addFile(":/icons/icons/left-angle.png", QSize(), QIcon::Normal, QIcon::Off);
back_button_->setIcon(icon); back_button_->setIcon(icon);
back_button_->setIconSize(QSize(24, 24)); back_button_->setIconSize(QSize(24, 24));
QIcon advanced_settings_icon; QIcon advanced_settings_icon;
advanced_settings_icon.addFile(":/icons/icons/cog.png", QSize(), QIcon::Normal, QIcon::Off); advanced_settings_icon.addFile(":/icons/icons/cog.png", QSize(), QIcon::Normal, QIcon::Off);
logo_ = new QLabel(this); logo_ = new QLabel(this);
logo_->setPixmap(QPixmap(":/logos/nheko-128.png")); logo_->setPixmap(QPixmap(":/logos/nheko-128.png"));
logo_layout_ = new QHBoxLayout(); logo_layout_ = new QHBoxLayout();
logo_layout_->setContentsMargins(0, 0, 0, 20); logo_layout_->setContentsMargins(0, 0, 0, 20);
logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter); logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter);
form_wrapper_ = new QHBoxLayout(); form_wrapper_ = new QHBoxLayout();
form_widget_ = new QWidget(); form_widget_ = new QWidget();
form_widget_->setMinimumSize(QSize(350, 200)); form_widget_->setMinimumSize(QSize(350, 200));
form_layout_ = new QVBoxLayout(); form_layout_ = new QVBoxLayout();
form_layout_->setSpacing(20); form_layout_->setSpacing(20);
form_layout_->setContentsMargins(0, 0, 0, 30); form_layout_->setContentsMargins(0, 0, 0, 30);
form_widget_->setLayout(form_layout_); form_widget_->setLayout(form_layout_);
form_wrapper_->addStretch(1); form_wrapper_->addStretch(1);
form_wrapper_->addWidget(form_widget_); form_wrapper_->addWidget(form_widget_);
form_wrapper_->addStretch(1); form_wrapper_->addStretch(1);
matrixid_input_ = new TextField(this); matrixid_input_ = new TextField(this);
matrixid_input_->setTextColor("#333333"); matrixid_input_->setTextColor("#333333");
matrixid_input_->setLabel(tr("Matrix ID")); matrixid_input_->setLabel(tr("Matrix ID"));
matrixid_input_->setInkColor("#555459"); matrixid_input_->setInkColor("#555459");
matrixid_input_->setBackgroundColor("#f9f9f9"); matrixid_input_->setBackgroundColor("#f9f9f9");
matrixid_input_->setPlaceholderText(tr("e.g @joe:matrix.org")); matrixid_input_->setPlaceholderText(tr("e.g @joe:matrix.org"));
spinner_ = new CircularProgress(this); spinner_ = new CircularProgress(this);
spinner_->setColor("#acc7dc"); spinner_->setColor("#acc7dc");
spinner_->setSize(32); spinner_->setSize(32);
spinner_->setMaximumWidth(spinner_->width()); spinner_->setMaximumWidth(spinner_->width());
spinner_->hide(); spinner_->hide();
errorIcon_ = new QLabel(this); errorIcon_ = new QLabel(this);
errorIcon_->setPixmap(QPixmap(":/icons/icons/error.png")); errorIcon_->setPixmap(QPixmap(":/icons/icons/error.png"));
errorIcon_->hide(); errorIcon_->hide();
matrixidLayout_ = new QHBoxLayout(); matrixidLayout_ = new QHBoxLayout();
matrixidLayout_->addWidget(matrixid_input_, 0, Qt::AlignVCenter); matrixidLayout_->addWidget(matrixid_input_, 0, Qt::AlignVCenter);
password_input_ = new TextField(this); password_input_ = new TextField(this);
password_input_->setTextColor("#333333"); password_input_->setTextColor("#333333");
password_input_->setLabel(tr("Password")); password_input_->setLabel(tr("Password"));
password_input_->setInkColor("#555459"); password_input_->setInkColor("#555459");
password_input_->setBackgroundColor("#f9f9f9"); password_input_->setBackgroundColor("#f9f9f9");
password_input_->setEchoMode(QLineEdit::Password); password_input_->setEchoMode(QLineEdit::Password);
serverInput_ = new TextField(this); serverInput_ = new TextField(this);
serverInput_->setTextColor("#333333"); serverInput_->setTextColor("#333333");
serverInput_->setLabel("Homeserver address"); serverInput_->setLabel("Homeserver address");
serverInput_->setInkColor("#555459"); serverInput_->setInkColor("#555459");
serverInput_->setBackgroundColor("#f9f9f9"); serverInput_->setBackgroundColor("#f9f9f9");
serverInput_->setPlaceholderText("matrix.org"); serverInput_->setPlaceholderText("matrix.org");
serverInput_->hide(); serverInput_->hide();
serverLayout_ = new QHBoxLayout(); serverLayout_ = new QHBoxLayout();
serverLayout_->addWidget(serverInput_, 0, Qt::AlignVCenter); serverLayout_->addWidget(serverInput_, 0, Qt::AlignVCenter);
form_layout_->addLayout(matrixidLayout_); form_layout_->addLayout(matrixidLayout_);
form_layout_->addWidget(password_input_, Qt::AlignHCenter, 0); form_layout_->addWidget(password_input_, Qt::AlignHCenter, 0);
form_layout_->addLayout(serverLayout_); form_layout_->addLayout(serverLayout_);
button_layout_ = new QHBoxLayout(); button_layout_ = new QHBoxLayout();
button_layout_->setSpacing(0); button_layout_->setSpacing(0);
button_layout_->setContentsMargins(0, 0, 0, 30); button_layout_->setContentsMargins(0, 0, 0, 30);
login_button_ = new RaisedButton(tr("LOGIN"), this); login_button_ = new RaisedButton(tr("LOGIN"), this);
login_button_->setBackgroundColor(QColor("#333333")); login_button_->setBackgroundColor(QColor("#333333"));
login_button_->setForegroundColor(QColor("white")); login_button_->setForegroundColor(QColor("white"));
login_button_->setMinimumSize(350, 65); login_button_->setMinimumSize(350, 65);
login_button_->setFontSize(20); login_button_->setFontSize(20);
login_button_->setCornerRadius(3); login_button_->setCornerRadius(3);
button_layout_->addStretch(1); button_layout_->addStretch(1);
button_layout_->addWidget(login_button_); button_layout_->addWidget(login_button_);
button_layout_->addStretch(1); button_layout_->addStretch(1);
QFont font; QFont font;
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
error_label_ = new QLabel(this); error_label_ = new QLabel(this);
error_label_->setFont(font); error_label_->setFont(font);
error_label_->setStyleSheet("color: #E22826"); error_label_->setStyleSheet("color: #E22826");
top_layout_->addLayout(top_bar_layout_); top_layout_->addLayout(top_bar_layout_);
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addLayout(logo_layout_); top_layout_->addLayout(logo_layout_);
top_layout_->addLayout(form_wrapper_); top_layout_->addLayout(form_wrapper_);
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addLayout(button_layout_); top_layout_->addLayout(button_layout_);
top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter); top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter);
top_layout_->addStretch(1); top_layout_->addStretch(1);
setLayout(top_layout_); setLayout(top_layout_);
connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked())); connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked()));
connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked())); connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked()));
connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(serverInput_, SIGNAL(returnPressed()), login_button_, SLOT(click())); connect(serverInput_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(client_.data(), SIGNAL(loginError(QString)), this, SLOT(loginError(QString))); connect(client_.data(), SIGNAL(loginError(QString)), this, SLOT(loginError(QString)));
connect(matrixid_input_, SIGNAL(editingFinished()), this, SLOT(onMatrixIdEntered())); connect(matrixid_input_, SIGNAL(editingFinished()), this, SLOT(onMatrixIdEntered()));
connect(client_.data(), SIGNAL(versionError(QString)), this, SLOT(versionError(QString))); connect(client_.data(), SIGNAL(versionError(QString)), this, SLOT(versionError(QString)));
connect(client_.data(), SIGNAL(versionSuccess()), this, SLOT(versionSuccess())); connect(client_.data(), SIGNAL(versionSuccess()), this, SLOT(versionSuccess()));
connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered())); connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered()));
} }
void void
LoginPage::loginError(QString error) LoginPage::loginError(QString error)
{ {
error_label_->setText(error); error_label_->setText(error);
} }
bool bool
LoginPage::isMatrixIdValid() LoginPage::isMatrixIdValid()
{ {
int pos = 0; int pos = 0;
auto matrix_id = matrixid_input_->text(); auto matrix_id = matrixid_input_->text();
return InputValidator::Id.validate(matrix_id, pos) == QValidator::Acceptable; return InputValidator::Id.validate(matrix_id, pos) == QValidator::Acceptable;
} }
void void
LoginPage::onMatrixIdEntered() LoginPage::onMatrixIdEntered()
{ {
error_label_->setText(""); error_label_->setText("");
if (!isMatrixIdValid()) { if (!isMatrixIdValid()) {
loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org"); loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org");
return; return;
} else if (password_input_->text().isEmpty()) { } else if (password_input_->text().isEmpty()) {
loginError(tr("Empty password")); loginError(tr("Empty password"));
} }
QString homeServer = matrixid_input_->text().split(":").at(1); QString homeServer = matrixid_input_->text().split(":").at(1);
if (homeServer != inferredServerAddress_) { if (homeServer != inferredServerAddress_) {
serverInput_->hide(); serverInput_->hide();
serverLayout_->removeWidget(errorIcon_); serverLayout_->removeWidget(errorIcon_);
errorIcon_->hide(); errorIcon_->hide();
if (serverInput_->isVisible()) { if (serverInput_->isVisible()) {
matrixidLayout_->removeWidget(spinner_); matrixidLayout_->removeWidget(spinner_);
serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
spinner_->show(); spinner_->show();
} else { } else {
serverLayout_->removeWidget(spinner_); serverLayout_->removeWidget(spinner_);
matrixidLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); matrixidLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
spinner_->show(); spinner_->show();
} }
inferredServerAddress_ = homeServer; inferredServerAddress_ = homeServer;
serverInput_->setText(homeServer); serverInput_->setText(homeServer);
client_->setServer(homeServer); client_->setServer(homeServer);
client_->versions(); client_->versions();
} }
} }
void void
LoginPage::onServerAddressEntered() LoginPage::onServerAddressEntered()
{ {
error_label_->setText(""); error_label_->setText("");
client_->setServer(serverInput_->text()); client_->setServer(serverInput_->text());
client_->versions(); client_->versions();
serverLayout_->removeWidget(errorIcon_); serverLayout_->removeWidget(errorIcon_);
errorIcon_->hide(); errorIcon_->hide();
serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight); serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
spinner_->show(); spinner_->show();
} }
void void
LoginPage::versionError(QString error) LoginPage::versionError(QString error)
{ {
// Matrix homeservers are often kept on a subdomain called 'matrix' // Matrix homeservers are often kept on a subdomain called 'matrix'
// so let's try that next, unless the address was set explicitly or the domain part of the username already // so let's try that next, unless the address was set explicitly or the domain part of the
// points to this subdomain // username already points to this subdomain
QUrl currentServer = client_->getHomeServer(); QUrl currentServer = client_->getHomeServer();
QString mxidAddress = matrixid_input_->text().split(":").at(1); QString mxidAddress = matrixid_input_->text().split(":").at(1);
if (currentServer.host() == inferredServerAddress_ && !currentServer.host().startsWith("matrix")) { if (currentServer.host() == inferredServerAddress_ &&
error_label_->setText(""); !currentServer.host().startsWith("matrix")) {
currentServer.setHost(QString("matrix.") + currentServer.host()); error_label_->setText("");
serverInput_->setText(currentServer.host()); currentServer.setHost(QString("matrix.") + currentServer.host());
client_->setServer(currentServer.host()); serverInput_->setText(currentServer.host());
client_->versions(); client_->setServer(currentServer.host());
return; client_->versions();
} return;
}
error_label_->setText(error); error_label_->setText(error);
serverInput_->show(); serverInput_->show();
spinner_->hide(); spinner_->hide();
serverLayout_->removeWidget(spinner_); serverLayout_->removeWidget(spinner_);
serverLayout_->addWidget(errorIcon_, 0, Qt::AlignVCenter | Qt::AlignRight); serverLayout_->addWidget(errorIcon_, 0, Qt::AlignVCenter | Qt::AlignRight);
errorIcon_->show(); errorIcon_->show();
matrixidLayout_->removeWidget(spinner_); matrixidLayout_->removeWidget(spinner_);
} }
void void
LoginPage::versionSuccess() LoginPage::versionSuccess()
{ {
serverLayout_->removeWidget(spinner_); serverLayout_->removeWidget(spinner_);
matrixidLayout_->removeWidget(spinner_); matrixidLayout_->removeWidget(spinner_);
spinner_->hide(); spinner_->hide();
if (serverInput_->isVisible()) if (serverInput_->isVisible())
serverInput_->hide(); serverInput_->hide();
} }
void void
LoginPage::onLoginButtonClicked() LoginPage::onLoginButtonClicked()
{ {
error_label_->setText(""); error_label_->setText("");
if (!isMatrixIdValid()) { if (!isMatrixIdValid()) {
loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org"); loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org");
} else if (password_input_->text().isEmpty()) { } else if (password_input_->text().isEmpty()) {
loginError("Empty password"); loginError("Empty password");
} else { } else {
QString user = matrixid_input_->text().split(":").at(0).split("@").at(1); QString user = matrixid_input_->text().split(":").at(0).split("@").at(1);
QString password = password_input_->text(); QString password = password_input_->text();
client_->setServer(serverInput_->text()); client_->setServer(serverInput_->text());
client_->login(user, password); client_->login(user, password);
} }
} }
void void
LoginPage::reset() LoginPage::reset()
{ {
matrixid_input_->clear(); matrixid_input_->clear();
password_input_->clear(); password_input_->clear();
serverInput_->clear(); serverInput_->clear();
spinner_->hide(); spinner_->hide();
errorIcon_->hide(); errorIcon_->hide();
serverLayout_->removeWidget(spinner_); serverLayout_->removeWidget(spinner_);
serverLayout_->removeWidget(errorIcon_); serverLayout_->removeWidget(errorIcon_);
matrixidLayout_->removeWidget(spinner_); matrixidLayout_->removeWidget(spinner_);
inferredServerAddress_.clear(); inferredServerAddress_.clear();
} }
void void
LoginPage::onBackButtonClicked() LoginPage::onBackButtonClicked()
{ {
emit backButtonClicked(); emit backButtonClicked();
} }
LoginPage::~LoginPage() LoginPage::~LoginPage()

View File

@ -25,37 +25,37 @@
LogoutDialog::LogoutDialog(QWidget *parent) LogoutDialog::LogoutDialog(QWidget *parent)
: QFrame(parent) : QFrame(parent)
{ {
setMaximumSize(400, 400); setMaximumSize(400, 400);
setStyleSheet("background-color: #f9f9f9"); setStyleSheet("background-color: #f9f9f9");
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
layout->setSpacing(30); layout->setSpacing(30);
layout->setMargin(20); layout->setMargin(20);
auto buttonLayout = new QHBoxLayout(); auto buttonLayout = new QHBoxLayout();
buttonLayout->setSpacing(0); buttonLayout->setSpacing(0);
buttonLayout->setMargin(0); buttonLayout->setMargin(0);
confirmBtn_ = new FlatButton("OK", this); confirmBtn_ = new FlatButton("OK", this);
confirmBtn_->setFontSize(conf::btn::fontSize); confirmBtn_->setFontSize(conf::btn::fontSize);
cancelBtn_ = new FlatButton(tr("CANCEL"), this); cancelBtn_ = new FlatButton(tr("CANCEL"), this);
cancelBtn_->setFontSize(conf::btn::fontSize); cancelBtn_->setFontSize(conf::btn::fontSize);
buttonLayout->addStretch(1); buttonLayout->addStretch(1);
buttonLayout->addWidget(confirmBtn_); buttonLayout->addWidget(confirmBtn_);
buttonLayout->addWidget(cancelBtn_); buttonLayout->addWidget(cancelBtn_);
QFont font; QFont font;
font.setPixelSize(conf::headerFontSize); font.setPixelSize(conf::headerFontSize);
auto label = new QLabel(tr("Logout. Are you sure?"), this); auto label = new QLabel(tr("Logout. Are you sure?"), this);
label->setFont(font); label->setFont(font);
label->setStyleSheet("color: #333333"); label->setStyleSheet("color: #333333");
layout->addWidget(label); layout->addWidget(label);
layout->addLayout(buttonLayout); layout->addLayout(buttonLayout);
connect(confirmBtn_, &QPushButton::clicked, [=]() { emit closing(true); }); connect(confirmBtn_, &QPushButton::clicked, [=]() { emit closing(true); });
connect(cancelBtn_, &QPushButton::clicked, [=]() { emit closing(false); }); connect(cancelBtn_, &QPushButton::clicked, [=]() { emit closing(false); });
} }

View File

@ -30,217 +30,221 @@ MainWindow::MainWindow(QWidget *parent)
, progress_modal_{ nullptr } , progress_modal_{ nullptr }
, spinner_{ nullptr } , spinner_{ nullptr }
{ {
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
setSizePolicy(sizePolicy); setSizePolicy(sizePolicy);
setWindowTitle("nheko"); setWindowTitle("nheko");
setObjectName("MainWindow"); setObjectName("MainWindow");
setStyleSheet("QWidget#MainWindow {background-color: #f9f9f9}"); setStyleSheet("QWidget#MainWindow {background-color: #f9f9f9}");
restoreWindowSize(); restoreWindowSize();
setMinimumSize(QSize(conf::window::minWidth, conf::window::minHeight)); setMinimumSize(QSize(conf::window::minWidth, conf::window::minHeight));
QFont font("Open Sans"); QFont font("Open Sans");
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
font.setStyleStrategy(QFont::PreferAntialias); font.setStyleStrategy(QFont::PreferAntialias);
setFont(font); setFont(font);
client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org")); client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org"));
trayIcon_ = new TrayIcon(":/logos/nheko-32.png", this); trayIcon_ = new TrayIcon(":/logos/nheko-32.png", this);
welcome_page_ = new WelcomePage(this); welcome_page_ = new WelcomePage(this);
login_page_ = new LoginPage(client_, this); login_page_ = new LoginPage(client_, this);
register_page_ = new RegisterPage(client_, this); register_page_ = new RegisterPage(client_, this);
chat_page_ = new ChatPage(client_, this); chat_page_ = new ChatPage(client_, this);
// Initialize sliding widget manager. // Initialize sliding widget manager.
sliding_stack_ = new SlidingStackWidget(this); sliding_stack_ = new SlidingStackWidget(this);
sliding_stack_->addWidget(welcome_page_); sliding_stack_->addWidget(welcome_page_);
sliding_stack_->addWidget(login_page_); sliding_stack_->addWidget(login_page_);
sliding_stack_->addWidget(register_page_); sliding_stack_->addWidget(register_page_);
sliding_stack_->addWidget(chat_page_); sliding_stack_->addWidget(chat_page_);
setCentralWidget(sliding_stack_); setCentralWidget(sliding_stack_);
connect(welcome_page_, SIGNAL(userLogin()), this, SLOT(showLoginPage())); connect(welcome_page_, SIGNAL(userLogin()), this, SLOT(showLoginPage()));
connect(welcome_page_, SIGNAL(userRegister()), this, SLOT(showRegisterPage())); connect(welcome_page_, SIGNAL(userRegister()), this, SLOT(showRegisterPage()));
connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage())); connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage())); connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage())); connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage()));
connect(chat_page_, SIGNAL(changeWindowTitle(QString)), this, SLOT(setWindowTitle(QString))); connect(
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int))); chat_page_, SIGNAL(changeWindowTitle(QString)), this, SLOT(setWindowTitle(QString)));
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int)));
connect(trayIcon_, connect(trayIcon_,
SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, this,
SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
connect(chat_page_, SIGNAL(contentLoaded()), this, SLOT(removeOverlayProgressBar())); connect(chat_page_, SIGNAL(contentLoaded()), this, SLOT(removeOverlayProgressBar()));
connect(client_.data(), connect(client_.data(),
SIGNAL(loginSuccess(QString, QString, QString)), SIGNAL(loginSuccess(QString, QString, QString)),
this, this,
SLOT(showChatPage(QString, QString, QString))); SLOT(showChatPage(QString, QString, QString)));
QSettings settings; QSettings settings;
if (hasActiveUser()) { if (hasActiveUser()) {
QString token = settings.value("auth/access_token").toString(); QString token = settings.value("auth/access_token").toString();
QString home_server = settings.value("auth/home_server").toString(); QString home_server = settings.value("auth/home_server").toString();
QString user_id = settings.value("auth/user_id").toString(); QString user_id = settings.value("auth/user_id").toString();
showChatPage(user_id, home_server, token); showChatPage(user_id, home_server, token);
} }
} }
void void
MainWindow::restoreWindowSize() MainWindow::restoreWindowSize()
{ {
QSettings settings; QSettings settings;
int savedWidth = settings.value("window/width").toInt(); int savedWidth = settings.value("window/width").toInt();
int savedheight = settings.value("window/height").toInt(); int savedheight = settings.value("window/height").toInt();
if (savedWidth == 0 || savedheight == 0) if (savedWidth == 0 || savedheight == 0)
resize(conf::window::width, conf::window::height); resize(conf::window::width, conf::window::height);
else else
resize(savedWidth, savedheight); resize(savedWidth, savedheight);
} }
void void
MainWindow::saveCurrentWindowSize() MainWindow::saveCurrentWindowSize()
{ {
QSettings settings; QSettings settings;
QSize current = size(); QSize current = size();
settings.setValue("window/width", current.width()); settings.setValue("window/width", current.width());
settings.setValue("window/height", current.height()); settings.setValue("window/height", current.height());
} }
void void
MainWindow::removeOverlayProgressBar() MainWindow::removeOverlayProgressBar()
{ {
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);
timer->setSingleShot(true); timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]() { connect(timer, &QTimer::timeout, [=]() {
timer->deleteLater(); timer->deleteLater();
if (progress_modal_ != nullptr) { if (progress_modal_ != nullptr) {
progress_modal_->deleteLater(); progress_modal_->deleteLater();
progress_modal_->fadeOut(); progress_modal_->fadeOut();
} }
if (spinner_ != nullptr) if (spinner_ != nullptr)
spinner_->deleteLater(); spinner_->deleteLater();
progress_modal_ = nullptr; progress_modal_ = nullptr;
spinner_ = nullptr; spinner_ = nullptr;
}); });
timer->start(500); timer->start(500);
} }
void void
MainWindow::showChatPage(QString userid, QString homeserver, QString token) MainWindow::showChatPage(QString userid, QString homeserver, QString token)
{ {
QSettings settings; QSettings settings;
settings.setValue("auth/access_token", token); settings.setValue("auth/access_token", token);
settings.setValue("auth/home_server", homeserver); settings.setValue("auth/home_server", homeserver);
settings.setValue("auth/user_id", userid); settings.setValue("auth/user_id", userid);
int index = sliding_stack_->getWidgetIndex(chat_page_); int index = sliding_stack_->getWidgetIndex(chat_page_);
int modalOpacityDuration = 300; int modalOpacityDuration = 300;
// If we go directly from the welcome page don't show an animation. // If we go directly from the welcome page don't show an animation.
if (sliding_stack_->currentIndex() == 0) { if (sliding_stack_->currentIndex() == 0) {
sliding_stack_->setCurrentIndex(index); sliding_stack_->setCurrentIndex(index);
modalOpacityDuration = 0; modalOpacityDuration = 0;
} else { } else {
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT); sliding_stack_->slideInIndex(index,
} SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT);
}
if (spinner_ == nullptr) { if (spinner_ == nullptr) {
spinner_ = new CircularProgress(this); spinner_ = new CircularProgress(this);
spinner_->setColor("#acc7dc"); spinner_->setColor("#acc7dc");
spinner_->setSize(100); spinner_->setSize(100);
} }
if (progress_modal_ == nullptr) { if (progress_modal_ == nullptr) {
progress_modal_ = new OverlayModal(this, spinner_); progress_modal_ = new OverlayModal(this, spinner_);
progress_modal_->fadeIn(); progress_modal_->fadeIn();
progress_modal_->setDuration(modalOpacityDuration); progress_modal_->setDuration(modalOpacityDuration);
} }
login_page_->reset(); login_page_->reset();
chat_page_->bootstrap(userid, homeserver, token); chat_page_->bootstrap(userid, homeserver, token);
instance_ = this; instance_ = this;
} }
void void
MainWindow::showWelcomePage() MainWindow::showWelcomePage()
{ {
int index = sliding_stack_->getWidgetIndex(welcome_page_); int index = sliding_stack_->getWidgetIndex(welcome_page_);
if (sliding_stack_->currentIndex() == sliding_stack_->getWidgetIndex(login_page_)) if (sliding_stack_->currentIndex() == sliding_stack_->getWidgetIndex(login_page_))
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::RIGHT_TO_LEFT); sliding_stack_->slideInIndex(index,
else SlidingStackWidget::AnimationDirection::RIGHT_TO_LEFT);
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT); else
sliding_stack_->slideInIndex(index,
SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT);
} }
void void
MainWindow::showLoginPage() MainWindow::showLoginPage()
{ {
int index = sliding_stack_->getWidgetIndex(login_page_); int index = sliding_stack_->getWidgetIndex(login_page_);
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT); sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::LEFT_TO_RIGHT);
} }
void void
MainWindow::showRegisterPage() MainWindow::showRegisterPage()
{ {
int index = sliding_stack_->getWidgetIndex(register_page_); int index = sliding_stack_->getWidgetIndex(register_page_);
sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::RIGHT_TO_LEFT); sliding_stack_->slideInIndex(index, SlidingStackWidget::AnimationDirection::RIGHT_TO_LEFT);
} }
void void
MainWindow::closeEvent(QCloseEvent *event) MainWindow::closeEvent(QCloseEvent *event)
{ {
if (isVisible()) { if (isVisible()) {
event->ignore(); event->ignore();
hide(); hide();
} }
} }
void void
MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
{ {
switch (reason) { switch (reason) {
case QSystemTrayIcon::Trigger: case QSystemTrayIcon::Trigger:
if (!isVisible()) { if (!isVisible()) {
show(); show();
} else { } else {
hide(); hide();
} }
break; break;
default: default:
break; break;
} }
} }
bool bool
MainWindow::hasActiveUser() MainWindow::hasActiveUser()
{ {
QSettings settings; QSettings settings;
return settings.contains("auth/access_token") && settings.contains("auth/home_server") && return settings.contains("auth/access_token") && settings.contains("auth/home_server") &&
settings.contains("auth/user_id"); settings.contains("auth/user_id");
} }
MainWindow * MainWindow *
MainWindow::instance() MainWindow::instance()
{ {
return instance_; return instance_;
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()

View File

@ -25,14 +25,14 @@
void void
ProfileResponse::deserialize(const QJsonDocument &data) ProfileResponse::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Response is not a JSON object"); throw DeserializationException("Response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (object.contains("avatar_url")) if (object.contains("avatar_url"))
avatar_url_ = QUrl(object.value("avatar_url").toString()); avatar_url_ = QUrl(object.value("avatar_url").toString());
if (object.contains("displayname")) if (object.contains("displayname"))
display_name_ = object.value("displayname").toString(); display_name_ = object.value("displayname").toString();
} }

View File

@ -30,126 +30,127 @@ RoomSearchInput::RoomSearchInput(QWidget *parent)
bool bool
RoomSearchInput::focusNextPrevChild(bool next) RoomSearchInput::focusNextPrevChild(bool next)
{ {
Q_UNUSED(next); Q_UNUSED(next);
return false; return false;
} }
void void
RoomSearchInput::keyPressEvent(QKeyEvent *event) RoomSearchInput::keyPressEvent(QKeyEvent *event)
{ {
if (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Down) { if (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Down) {
emit selectNextCompletion(); emit selectNextCompletion();
event->accept(); event->accept();
return; return;
} else if (event->key() == Qt::Key_Up) { } else if (event->key() == Qt::Key_Up) {
emit selectPreviousCompletion(); emit selectPreviousCompletion();
event->accept(); event->accept();
return; return;
} }
TextField::keyPressEvent(event); TextField::keyPressEvent(event);
} }
void void
RoomSearchInput::hideEvent(QHideEvent *event) RoomSearchInput::hideEvent(QHideEvent *event)
{ {
emit hiding(); emit hiding();
TextField::hideEvent(event); TextField::hideEvent(event);
} }
QuickSwitcher::QuickSwitcher(QWidget *parent) QuickSwitcher::QuickSwitcher(QWidget *parent)
: QFrame(parent) : QFrame(parent)
{ {
setMaximumWidth(450); setMaximumWidth(450);
setStyleSheet("background-color: white"); setStyleSheet("background-color: white");
QFont font; QFont font;
font.setPixelSize(20); font.setPixelSize(20);
roomSearch_ = new RoomSearchInput(this); roomSearch_ = new RoomSearchInput(this);
roomSearch_->setFont(font); roomSearch_->setFont(font);
roomSearch_->setPlaceholderText(tr("Find a room...")); roomSearch_->setPlaceholderText(tr("Find a room..."));
completer_ = new QCompleter(); completer_ = new QCompleter();
completer_->setCaseSensitivity(Qt::CaseInsensitive); completer_->setCaseSensitivity(Qt::CaseInsensitive);
completer_->setCompletionMode(QCompleter::PopupCompletion); completer_->setCompletionMode(QCompleter::PopupCompletion);
completer_->setWidget(this); completer_->setWidget(this);
topLayout_ = new QVBoxLayout(this); topLayout_ = new QVBoxLayout(this);
topLayout_->addWidget(roomSearch_); topLayout_->addWidget(roomSearch_);
connect(completer_, SIGNAL(highlighted(QString)), roomSearch_, SLOT(setText(QString))); connect(completer_, SIGNAL(highlighted(QString)), roomSearch_, SLOT(setText(QString)));
connect(roomSearch_, &QLineEdit::textEdited, this, [=](const QString &prefix) { connect(roomSearch_, &QLineEdit::textEdited, this, [=](const QString &prefix) {
if (prefix.isEmpty()) { if (prefix.isEmpty()) {
completer_->popup()->hide(); completer_->popup()->hide();
selection_ = -1; selection_ = -1;
return; return;
} }
if (prefix != completer_->completionPrefix()) { if (prefix != completer_->completionPrefix()) {
completer_->setCompletionPrefix(prefix); completer_->setCompletionPrefix(prefix);
selection_ = -1; selection_ = -1;
} }
completer_->popup()->setWindowFlags(completer_->popup()->windowFlags() | Qt::ToolTip | completer_->popup()->setWindowFlags(completer_->popup()->windowFlags() |
Qt::NoDropShadowWindowHint); Qt::ToolTip | Qt::NoDropShadowWindowHint);
completer_->popup()->setAttribute(Qt::WA_ShowWithoutActivating); completer_->popup()->setAttribute(Qt::WA_ShowWithoutActivating);
completer_->complete(); completer_->complete();
}); });
connect(roomSearch_, &RoomSearchInput::selectNextCompletion, this, [=]() { connect(roomSearch_, &RoomSearchInput::selectNextCompletion, this, [=]() {
selection_ += 1; selection_ += 1;
if (!completer_->setCurrentRow(selection_)) { if (!completer_->setCurrentRow(selection_)) {
selection_ = 0; selection_ = 0;
completer_->setCurrentRow(selection_); completer_->setCurrentRow(selection_);
} }
completer_->popup()->setCurrentIndex(completer_->currentIndex()); completer_->popup()->setCurrentIndex(completer_->currentIndex());
}); });
connect(roomSearch_, &RoomSearchInput::selectPreviousCompletion, this, [=]() { connect(roomSearch_, &RoomSearchInput::selectPreviousCompletion, this, [=]() {
selection_ -= 1; selection_ -= 1;
if (!completer_->setCurrentRow(selection_)) { if (!completer_->setCurrentRow(selection_)) {
selection_ = completer_->completionCount() - 1; selection_ = completer_->completionCount() - 1;
completer_->setCurrentRow(selection_); completer_->setCurrentRow(selection_);
} }
completer_->popup()->setCurrentIndex(completer_->currentIndex()); completer_->popup()->setCurrentIndex(completer_->currentIndex());
}); });
connect(roomSearch_, &RoomSearchInput::hiding, this, [=]() { completer_->popup()->hide(); }); connect(
connect(roomSearch_, &QLineEdit::returnPressed, this, [=]() { roomSearch_, &RoomSearchInput::hiding, this, [=]() { completer_->popup()->hide(); });
emit closing(); connect(roomSearch_, &QLineEdit::returnPressed, this, [=]() {
emit roomSelected(rooms_[this->roomSearch_->text().trimmed()]); emit closing();
emit roomSelected(rooms_[this->roomSearch_->text().trimmed()]);
roomSearch_->clear(); roomSearch_->clear();
}); });
} }
void void
QuickSwitcher::setRoomList(const QMap<QString, QString> &rooms) QuickSwitcher::setRoomList(const QMap<QString, QString> &rooms)
{ {
rooms_ = rooms; rooms_ = rooms;
QStringList items = rooms.keys(); QStringList items = rooms.keys();
completer_->setModel(new QStringListModel(items)); completer_->setModel(new QStringListModel(items));
} }
void void
QuickSwitcher::showEvent(QShowEvent *) QuickSwitcher::showEvent(QShowEvent *)
{ {
roomSearch_->setFocus(); roomSearch_->setFocus();
} }
void void
QuickSwitcher::keyPressEvent(QKeyEvent *event) QuickSwitcher::keyPressEvent(QKeyEvent *event)
{ {
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
roomSearch_->clear(); roomSearch_->clear();
event->accept(); event->accept();
emit closing(); emit closing();
} }
} }

View File

@ -31,29 +31,29 @@ RegisterRequest::RegisterRequest(const QString &username, const QString &passwor
QByteArray QByteArray
RegisterRequest::serialize() noexcept RegisterRequest::serialize() noexcept
{ {
QJsonObject body{ { "username", user_ }, { "password", password_ } }; QJsonObject body{ { "username", user_ }, { "password", password_ } };
return QJsonDocument(body).toJson(QJsonDocument::Compact); return QJsonDocument(body).toJson(QJsonDocument::Compact);
} }
void void
RegisterResponse::deserialize(const QJsonDocument &data) RegisterResponse::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Response is not a JSON object"); throw DeserializationException("Response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (!object.contains("access_token")) if (!object.contains("access_token"))
throw DeserializationException("Missing access_token param"); throw DeserializationException("Missing access_token param");
if (!object.contains("home_server")) if (!object.contains("home_server"))
throw DeserializationException("Missing home_server param"); throw DeserializationException("Missing home_server param");
if (!object.contains("user_id")) if (!object.contains("user_id"))
throw DeserializationException("Missing user_id param"); throw DeserializationException("Missing user_id param");
access_token_ = object.value("access_token").toString(); access_token_ = object.value("access_token").toString();
home_server_ = object.value("home_server").toString(); home_server_ = object.value("home_server").toString();
user_id_ = object.value("user_id").toString(); user_id_ = object.value("user_id").toString();
} }

View File

@ -26,156 +26,159 @@ RegisterPage::RegisterPage(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, client_(client) , client_(client)
{ {
setStyleSheet("background-color: #f9f9f9"); setStyleSheet("background-color: #f9f9f9");
top_layout_ = new QVBoxLayout(); top_layout_ = new QVBoxLayout();
back_layout_ = new QHBoxLayout(); back_layout_ = new QHBoxLayout();
back_layout_->setSpacing(0); back_layout_->setSpacing(0);
back_layout_->setContentsMargins(5, 5, -1, -1); back_layout_->setContentsMargins(5, 5, -1, -1);
back_button_ = new FlatButton(this); back_button_ = new FlatButton(this);
back_button_->setMinimumSize(QSize(30, 30)); back_button_->setMinimumSize(QSize(30, 30));
QIcon icon; QIcon icon;
icon.addFile(":/icons/icons/left-angle.png", QSize(), QIcon::Normal, QIcon::Off); icon.addFile(":/icons/icons/left-angle.png", QSize(), QIcon::Normal, QIcon::Off);
back_button_->setIcon(icon); back_button_->setIcon(icon);
back_button_->setIconSize(QSize(24, 24)); back_button_->setIconSize(QSize(24, 24));
back_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter); back_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter);
back_layout_->addStretch(1); back_layout_->addStretch(1);
logo_ = new Avatar(this); logo_ = new Avatar(this);
logo_->setImage(QImage(":/logos/nheko-128.png")); logo_->setImage(QImage(":/logos/nheko-128.png"));
logo_->setSize(80); logo_->setSize(80);
logo_layout_ = new QHBoxLayout(); logo_layout_ = new QHBoxLayout();
logo_layout_->setMargin(0); logo_layout_->setMargin(0);
logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter); logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter);
form_wrapper_ = new QHBoxLayout(); form_wrapper_ = new QHBoxLayout();
form_widget_ = new QWidget(); form_widget_ = new QWidget();
form_widget_->setMinimumSize(QSize(350, 300)); form_widget_->setMinimumSize(QSize(350, 300));
form_layout_ = new QVBoxLayout(); form_layout_ = new QVBoxLayout();
form_layout_->setSpacing(20); form_layout_->setSpacing(20);
form_layout_->setContentsMargins(0, 0, 0, 40); form_layout_->setContentsMargins(0, 0, 0, 40);
form_widget_->setLayout(form_layout_); form_widget_->setLayout(form_layout_);
form_wrapper_->addStretch(1); form_wrapper_->addStretch(1);
form_wrapper_->addWidget(form_widget_); form_wrapper_->addWidget(form_widget_);
form_wrapper_->addStretch(1); form_wrapper_->addStretch(1);
username_input_ = new TextField(); username_input_ = new TextField();
username_input_->setTextColor("#333333"); username_input_->setTextColor("#333333");
username_input_->setLabel(tr("Username")); username_input_->setLabel(tr("Username"));
username_input_->setInkColor("#555459"); username_input_->setInkColor("#555459");
username_input_->setBackgroundColor("#f9f9f9"); username_input_->setBackgroundColor("#f9f9f9");
password_input_ = new TextField(); password_input_ = new TextField();
password_input_->setTextColor("#333333"); password_input_->setTextColor("#333333");
password_input_->setLabel(tr("Password")); password_input_->setLabel(tr("Password"));
password_input_->setInkColor("#555459"); password_input_->setInkColor("#555459");
password_input_->setBackgroundColor("#f9f9f9"); password_input_->setBackgroundColor("#f9f9f9");
password_input_->setEchoMode(QLineEdit::Password); password_input_->setEchoMode(QLineEdit::Password);
password_confirmation_ = new TextField(); password_confirmation_ = new TextField();
password_confirmation_->setTextColor("#333333"); password_confirmation_->setTextColor("#333333");
password_confirmation_->setLabel(tr("Password confirmation")); password_confirmation_->setLabel(tr("Password confirmation"));
password_confirmation_->setInkColor("#555459"); password_confirmation_->setInkColor("#555459");
password_confirmation_->setBackgroundColor("#f9f9f9"); password_confirmation_->setBackgroundColor("#f9f9f9");
password_confirmation_->setEchoMode(QLineEdit::Password); password_confirmation_->setEchoMode(QLineEdit::Password);
server_input_ = new TextField(); server_input_ = new TextField();
server_input_->setTextColor("#333333"); server_input_->setTextColor("#333333");
server_input_->setLabel(tr("Home Server")); server_input_->setLabel(tr("Home Server"));
server_input_->setInkColor("#555459"); server_input_->setInkColor("#555459");
server_input_->setBackgroundColor("#f9f9f9"); server_input_->setBackgroundColor("#f9f9f9");
form_layout_->addWidget(username_input_, Qt::AlignHCenter, 0); form_layout_->addWidget(username_input_, Qt::AlignHCenter, 0);
form_layout_->addWidget(password_input_, Qt::AlignHCenter, 0); form_layout_->addWidget(password_input_, Qt::AlignHCenter, 0);
form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter, 0); form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter, 0);
form_layout_->addWidget(server_input_, Qt::AlignHCenter, 0); form_layout_->addWidget(server_input_, Qt::AlignHCenter, 0);
button_layout_ = new QHBoxLayout(); button_layout_ = new QHBoxLayout();
button_layout_->setSpacing(0); button_layout_->setSpacing(0);
button_layout_->setMargin(0); button_layout_->setMargin(0);
QFont font; QFont font;
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
error_label_ = new QLabel(this); error_label_ = new QLabel(this);
error_label_->setFont(font); error_label_->setFont(font);
error_label_->setStyleSheet("color: #E22826"); error_label_->setStyleSheet("color: #E22826");
register_button_ = new RaisedButton(tr("REGISTER"), this); register_button_ = new RaisedButton(tr("REGISTER"), this);
register_button_->setBackgroundColor(QColor("#333333")); register_button_->setBackgroundColor(QColor("#333333"));
register_button_->setForegroundColor(QColor("white")); register_button_->setForegroundColor(QColor("white"));
register_button_->setMinimumSize(350, 65); register_button_->setMinimumSize(350, 65);
register_button_->setFontSize(conf::btn::fontSize); register_button_->setFontSize(conf::btn::fontSize);
register_button_->setCornerRadius(conf::btn::cornerRadius); register_button_->setCornerRadius(conf::btn::cornerRadius);
button_layout_->addStretch(1); button_layout_->addStretch(1);
button_layout_->addWidget(register_button_); button_layout_->addWidget(register_button_);
button_layout_->addStretch(1); button_layout_->addStretch(1);
top_layout_->addLayout(back_layout_); top_layout_->addLayout(back_layout_);
top_layout_->addLayout(logo_layout_); top_layout_->addLayout(logo_layout_);
top_layout_->addLayout(form_wrapper_); top_layout_->addLayout(form_wrapper_);
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addLayout(button_layout_); top_layout_->addLayout(button_layout_);
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter); top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter);
connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked())); connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked()));
connect(register_button_, SIGNAL(clicked()), this, SLOT(onRegisterButtonClicked())); connect(register_button_, SIGNAL(clicked()), this, SLOT(onRegisterButtonClicked()));
connect(username_input_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(username_input_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(password_input_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(password_input_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(password_confirmation_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(password_confirmation_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(server_input_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(server_input_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(client_.data(), SIGNAL(registerError(const QString &)), this, SLOT(registerError(const QString &))); connect(client_.data(),
SIGNAL(registerError(const QString &)),
this,
SLOT(registerError(const QString &)));
username_input_->setValidator(&InputValidator::Localpart); username_input_->setValidator(&InputValidator::Localpart);
password_input_->setValidator(&InputValidator::Password); password_input_->setValidator(&InputValidator::Password);
server_input_->setValidator(&InputValidator::Domain); server_input_->setValidator(&InputValidator::Domain);
setLayout(top_layout_); setLayout(top_layout_);
} }
void void
RegisterPage::onBackButtonClicked() RegisterPage::onBackButtonClicked()
{ {
emit backButtonClicked(); emit backButtonClicked();
} }
void void
RegisterPage::registerError(const QString &msg) RegisterPage::registerError(const QString &msg)
{ {
error_label_->setText(msg); error_label_->setText(msg);
} }
void void
RegisterPage::onRegisterButtonClicked() RegisterPage::onRegisterButtonClicked()
{ {
error_label_->setText(""); error_label_->setText("");
if (!username_input_->hasAcceptableInput()) { if (!username_input_->hasAcceptableInput()) {
registerError(tr("Invalid username")); registerError(tr("Invalid username"));
} else if (!password_input_->hasAcceptableInput()) { } else if (!password_input_->hasAcceptableInput()) {
registerError(tr("Password is not long enough (min 8 chars)")); registerError(tr("Password is not long enough (min 8 chars)"));
} else if (password_input_->text() != password_confirmation_->text()) { } else if (password_input_->text() != password_confirmation_->text()) {
registerError(tr("Passwords don't match")); registerError(tr("Passwords don't match"));
} else if (!server_input_->hasAcceptableInput()) { } else if (!server_input_->hasAcceptableInput()) {
registerError(tr("Invalid server name")); registerError(tr("Invalid server name"));
} else { } else {
QString username = username_input_->text(); QString username = username_input_->text();
QString password = password_input_->text(); QString password = password_input_->text();
QString server = server_input_->text(); QString server = server_input_->text();
client_->registerUser(username, password, server); client_->registerUser(username, password, server);
} }
} }
RegisterPage::~RegisterPage() RegisterPage::~RegisterPage()

View File

@ -26,9 +26,9 @@
#include "Theme.h" #include "Theme.h"
RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings, RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
RoomState state, RoomState state,
QString room_id, QString room_id,
QWidget *parent) QWidget *parent)
: QWidget(parent) : QWidget(parent)
, state_(state) , state_(state)
, roomId_(room_id) , roomId_(room_id)
@ -37,264 +37,277 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
, maxHeight_(IconSize + 2 * Padding) , maxHeight_(IconSize + 2 * Padding)
, unreadMsgCount_(0) , unreadMsgCount_(0)
{ {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setMouseTracking(true); setMouseTracking(true);
setAttribute(Qt::WA_Hover); setAttribute(Qt::WA_Hover);
setFixedHeight(maxHeight_); setFixedHeight(maxHeight_);
QPainterPath path; QPainterPath path;
path.addRect(0, 0, parent->width(), height()); path.addRect(0, 0, parent->width(), height());
ripple_overlay_ = new RippleOverlay(this); ripple_overlay_ = new RippleOverlay(this);
ripple_overlay_->setClipPath(path); ripple_overlay_->setClipPath(path);
ripple_overlay_->setClipping(true); ripple_overlay_->setClipping(true);
menu_ = new Menu(this); menu_ = new Menu(this);
toggleNotifications_ = new QAction(notificationText(), this); toggleNotifications_ = new QAction(notificationText(), this);
connect(toggleNotifications_, &QAction::triggered, this, [=]() { roomSettings_->toggleNotifications(); }); connect(toggleNotifications_, &QAction::triggered, this, [=]() {
roomSettings_->toggleNotifications();
});
menu_->addAction(toggleNotifications_); menu_->addAction(toggleNotifications_);
} }
QString QString
RoomInfoListItem::notificationText() RoomInfoListItem::notificationText()
{ {
if (roomSettings_.isNull() || roomSettings_->isNotificationsEnabled()) if (roomSettings_.isNull() || roomSettings_->isNotificationsEnabled())
return QString(tr("Disable notifications")); return QString(tr("Disable notifications"));
return tr("Enable notifications"); return tr("Enable notifications");
} }
void void
RoomInfoListItem::resizeEvent(QResizeEvent *) RoomInfoListItem::resizeEvent(QResizeEvent *)
{ {
// Update ripple's clipping path. // Update ripple's clipping path.
QPainterPath path; QPainterPath path;
path.addRect(0, 0, width(), height()); path.addRect(0, 0, width(), height());
ripple_overlay_->setClipPath(path); ripple_overlay_->setClipPath(path);
ripple_overlay_->setClipping(true); ripple_overlay_->setClipping(true);
} }
void void
RoomInfoListItem::paintEvent(QPaintEvent *event) RoomInfoListItem::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
QPainter p(this); QPainter p(this);
p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::TextAntialiasing);
p.setRenderHint(QPainter::SmoothPixmapTransform); p.setRenderHint(QPainter::SmoothPixmapTransform);
p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::Antialiasing);
if (isPressed_) if (isPressed_)
p.fillRect(rect(), QColor("#38A3D8")); p.fillRect(rect(), QColor("#38A3D8"));
else if (underMouse()) else if (underMouse())
p.fillRect(rect(), QColor(200, 200, 200, 128)); p.fillRect(rect(), QColor(200, 200, 200, 128));
else else
p.fillRect(rect(), QColor("#F8FBFE")); p.fillRect(rect(), QColor("#F8FBFE"));
QFont font; QFont font;
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
QFontMetrics metrics(font); QFontMetrics metrics(font);
p.setPen(QColor("#333")); p.setPen(QColor("#333"));
QRect avatarRegion(Padding, Padding, IconSize, IconSize); QRect avatarRegion(Padding, Padding, IconSize, IconSize);
// Description line with the default font. // Description line with the default font.
int bottom_y = maxHeight_ - Padding - Padding / 3 - metrics.ascent() / 2; int bottom_y = maxHeight_ - Padding - Padding / 3 - metrics.ascent() / 2;
if (width() > ui::sidebar::SmallSize) { if (width() > ui::sidebar::SmallSize) {
if (isPressed_) { if (isPressed_) {
QPen pen(QColor("white")); QPen pen(QColor("white"));
p.setPen(pen); p.setPen(pen);
} }
font.setPixelSize(conf::roomlist::fonts::heading); font.setPixelSize(conf::roomlist::fonts::heading);
p.setFont(font); p.setFont(font);
// Name line. // Name line.
QFontMetrics fontNameMetrics(font); QFontMetrics fontNameMetrics(font);
int top_y = 2 * Padding + fontNameMetrics.ascent() / 2; int top_y = 2 * Padding + fontNameMetrics.ascent() / 2;
auto name = auto name = metrics.elidedText(
metrics.elidedText(state_.getName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8); state_.getName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8);
p.drawText(QPoint(2 * Padding + IconSize, top_y), name); p.drawText(QPoint(2 * Padding + IconSize, top_y), name);
if (!isPressed_) { if (!isPressed_) {
QPen pen(QColor("#5d6565")); QPen pen(QColor("#5d6565"));
p.setPen(pen); p.setPen(pen);
} }
font.setPixelSize(conf::fontSize); font.setPixelSize(conf::fontSize);
p.setFont(font); p.setFont(font);
auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5; auto msgStampWidth = QFontMetrics(font).width(lastMsgInfo_.timestamp) + 5;
// The limit is the space between the end of the avatar and the start of the timestamp. // The limit is the space between the end of the avatar and the start of the
int usernameLimit = std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - 20); // timestamp.
auto userName = metrics.elidedText(lastMsgInfo_.username, Qt::ElideRight, usernameLimit); int usernameLimit =
std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - 20);
auto userName =
metrics.elidedText(lastMsgInfo_.username, Qt::ElideRight, usernameLimit);
font.setBold(true); font.setBold(true);
p.setFont(font); p.setFont(font);
p.drawText(QPoint(2 * Padding + IconSize, bottom_y), userName); p.drawText(QPoint(2 * Padding + IconSize, bottom_y), userName);
int nameWidth = QFontMetrics(font).width(userName); int nameWidth = QFontMetrics(font).width(userName);
font.setBold(false); font.setBold(false);
p.setFont(font); p.setFont(font);
// The limit is the space between the end of the username and the start of the timestamp. // The limit is the space between the end of the username and the start of the
int descriptionLimit = std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5); // timestamp.
auto description = metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit); int descriptionLimit =
p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y), description); std::max(0, width() - 3 * Padding - msgStampWidth - IconSize - nameWidth - 5);
auto description =
metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit);
p.drawText(QPoint(2 * Padding + IconSize + nameWidth, bottom_y), description);
// We either show the bubble or the last message timestamp. // We either show the bubble or the last message timestamp.
if (unreadMsgCount_ == 0) { if (unreadMsgCount_ == 0) {
font.setBold(true); font.setBold(true);
p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y), lastMsgInfo_.timestamp); p.drawText(QPoint(width() - Padding - msgStampWidth, bottom_y),
} lastMsgInfo_.timestamp);
} }
}
font.setBold(false); font.setBold(false);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
// We using the first letter of room's name. // We using the first letter of room's name.
if (roomAvatar_.isNull()) { if (roomAvatar_.isNull()) {
QBrush brush; QBrush brush;
brush.setStyle(Qt::SolidPattern); brush.setStyle(Qt::SolidPattern);
brush.setColor("#eee"); brush.setColor("#eee");
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(brush); p.setBrush(brush);
p.drawEllipse(avatarRegion.center(), IconSize / 2, IconSize / 2); p.drawEllipse(avatarRegion.center(), IconSize / 2, IconSize / 2);
font.setPixelSize(conf::roomlist::fonts::bubble); font.setPixelSize(conf::roomlist::fonts::bubble);
p.setFont(font); p.setFont(font);
p.setPen(QColor("#333")); p.setPen(QColor("#333"));
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
p.drawText(avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(state_.getName()[0])); p.drawText(
} else { avatarRegion.translated(0, -1), Qt::AlignCenter, QChar(state_.getName()[0]));
p.save(); } else {
p.save();
QPainterPath path; QPainterPath path;
path.addEllipse(Padding, Padding, IconSize, IconSize); path.addEllipse(Padding, Padding, IconSize, IconSize);
p.setClipPath(path); p.setClipPath(path);
p.drawPixmap(avatarRegion, roomAvatar_); p.drawPixmap(avatarRegion, roomAvatar_);
p.restore(); p.restore();
} }
if (unreadMsgCount_ > 0) { if (unreadMsgCount_ > 0) {
QColor textColor("white"); QColor textColor("white");
QColor backgroundColor("#38A3D8"); QColor backgroundColor("#38A3D8");
QBrush brush; QBrush brush;
brush.setStyle(Qt::SolidPattern); brush.setStyle(Qt::SolidPattern);
brush.setColor(backgroundColor); brush.setColor(backgroundColor);
if (isPressed_) if (isPressed_)
brush.setColor(textColor); brush.setColor(textColor);
QFont unreadCountFont; QFont unreadCountFont;
unreadCountFont.setPixelSize(conf::roomlist::fonts::badge); unreadCountFont.setPixelSize(conf::roomlist::fonts::badge);
unreadCountFont.setBold(true); unreadCountFont.setBold(true);
p.setBrush(brush); p.setBrush(brush);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setFont(unreadCountFont); p.setFont(unreadCountFont);
int diameter = 20; int diameter = 20;
QRectF r(width() - diameter - Padding, bottom_y - diameter / 2 - 5, diameter, diameter); QRectF r(
width() - diameter - Padding, bottom_y - diameter / 2 - 5, diameter, diameter);
if (width() == ui::sidebar::SmallSize) if (width() == ui::sidebar::SmallSize)
r = QRectF(width() - diameter - 5, height() - diameter - 5, diameter, diameter); r = QRectF(
width() - diameter - 5, height() - diameter - 5, diameter, diameter);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawEllipse(r); p.drawEllipse(r);
p.setPen(QPen(textColor)); p.setPen(QPen(textColor));
if (isPressed_) if (isPressed_)
p.setPen(QPen(backgroundColor)); p.setPen(QPen(backgroundColor));
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
p.drawText(r.translated(0, -0.5), Qt::AlignCenter, QString::number(unreadMsgCount_)); p.drawText(
} r.translated(0, -0.5), Qt::AlignCenter, QString::number(unreadMsgCount_));
}
} }
void void
RoomInfoListItem::updateUnreadMessageCount(int count) RoomInfoListItem::updateUnreadMessageCount(int count)
{ {
unreadMsgCount_ += count; unreadMsgCount_ += count;
update(); update();
} }
void void
RoomInfoListItem::clearUnreadMessageCount() RoomInfoListItem::clearUnreadMessageCount()
{ {
unreadMsgCount_ = 0; unreadMsgCount_ = 0;
update(); update();
} }
void void
RoomInfoListItem::setPressedState(bool state) RoomInfoListItem::setPressedState(bool state)
{ {
if (!isPressed_ && state) { if (!isPressed_ && state) {
isPressed_ = state; isPressed_ = state;
update(); update();
} else if (isPressed_ && !state) { } else if (isPressed_ && !state) {
isPressed_ = state; isPressed_ = state;
update(); update();
} }
} }
void void
RoomInfoListItem::setState(const RoomState &new_state) RoomInfoListItem::setState(const RoomState &new_state)
{ {
state_ = new_state; state_ = new_state;
update(); update();
} }
void void
RoomInfoListItem::contextMenuEvent(QContextMenuEvent *event) RoomInfoListItem::contextMenuEvent(QContextMenuEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
toggleNotifications_->setText(notificationText()); toggleNotifications_->setText(notificationText());
menu_->popup(event->globalPos()); menu_->popup(event->globalPos());
} }
void void
RoomInfoListItem::mousePressEvent(QMouseEvent *event) RoomInfoListItem::mousePressEvent(QMouseEvent *event)
{ {
if (event->buttons() == Qt::RightButton) { if (event->buttons() == Qt::RightButton) {
QWidget::mousePressEvent(event); QWidget::mousePressEvent(event);
return; return;
} }
emit clicked(roomId_); emit clicked(roomId_);
setPressedState(true); setPressedState(true);
// Ripple on mouse position by default. // Ripple on mouse position by default.
QPoint pos = event->pos(); QPoint pos = event->pos();
qreal radiusEndValue = static_cast<qreal>(width()) / 3; qreal radiusEndValue = static_cast<qreal>(width()) / 3;
Ripple *ripple = new Ripple(pos); Ripple *ripple = new Ripple(pos);
ripple->setRadiusEndValue(radiusEndValue); ripple->setRadiusEndValue(radiusEndValue);
ripple->setOpacityStartValue(0.15); ripple->setOpacityStartValue(0.15);
ripple->setColor(QColor("white")); ripple->setColor(QColor("white"));
ripple->radiusAnimation()->setDuration(200); ripple->radiusAnimation()->setDuration(200);
ripple->opacityAnimation()->setDuration(400); ripple->opacityAnimation()->setDuration(400);
ripple_overlay_->addRipple(ripple); ripple_overlay_->addRipple(ripple);
} }
RoomInfoListItem::~RoomInfoListItem() RoomInfoListItem::~RoomInfoListItem()

View File

@ -27,38 +27,38 @@ RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, client_(client) , client_(client)
{ {
setStyleSheet("QWidget { border: none; }"); setStyleSheet("QWidget { border: none; }");
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0); sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0); sizePolicy.setVerticalStretch(0);
setSizePolicy(sizePolicy); setSizePolicy(sizePolicy);
topLayout_ = new QVBoxLayout(this); topLayout_ = new QVBoxLayout(this);
topLayout_->setSpacing(0); topLayout_->setSpacing(0);
topLayout_->setMargin(0); topLayout_->setMargin(0);
scrollArea_ = new QScrollArea(this); scrollArea_ = new QScrollArea(this);
scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea_->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); scrollArea_->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
scrollArea_->setWidgetResizable(true); scrollArea_->setWidgetResizable(true);
scrollArea_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); scrollArea_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);
scrollAreaContents_ = new QWidget(); scrollAreaContents_ = new QWidget();
contentsLayout_ = new QVBoxLayout(scrollAreaContents_); contentsLayout_ = new QVBoxLayout(scrollAreaContents_);
contentsLayout_->setSpacing(0); contentsLayout_->setSpacing(0);
contentsLayout_->setMargin(0); contentsLayout_->setMargin(0);
contentsLayout_->addStretch(1); contentsLayout_->addStretch(1);
scrollArea_->setWidget(scrollAreaContents_); scrollArea_->setWidget(scrollAreaContents_);
topLayout_->addWidget(scrollArea_); topLayout_->addWidget(scrollArea_);
connect(client_.data(), connect(client_.data(),
SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)), SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)),
this, this,
SLOT(updateRoomAvatar(const QString &, const QPixmap &))); SLOT(updateRoomAvatar(const QString &, const QPixmap &)));
} }
RoomList::~RoomList() RoomList::~RoomList()
@ -68,137 +68,140 @@ RoomList::~RoomList()
void void
RoomList::clear() RoomList::clear()
{ {
rooms_.clear(); rooms_.clear();
} }
void void
RoomList::updateUnreadMessageCount(const QString &roomid, int count) RoomList::updateUnreadMessageCount(const QString &roomid, int count)
{ {
if (!rooms_.contains(roomid)) { if (!rooms_.contains(roomid)) {
qWarning() << "UpdateUnreadMessageCount: Unknown roomid"; qWarning() << "UpdateUnreadMessageCount: Unknown roomid";
return; return;
} }
rooms_[roomid]->updateUnreadMessageCount(count); rooms_[roomid]->updateUnreadMessageCount(count);
calculateUnreadMessageCount(); calculateUnreadMessageCount();
} }
void void
RoomList::calculateUnreadMessageCount() RoomList::calculateUnreadMessageCount()
{ {
int total_unread_msgs = 0; int total_unread_msgs = 0;
for (const auto &room : rooms_) for (const auto &room : rooms_)
total_unread_msgs += room->unreadMessageCount(); total_unread_msgs += room->unreadMessageCount();
emit totalUnreadMessageCountUpdated(total_unread_msgs); emit totalUnreadMessageCountUpdated(total_unread_msgs);
} }
void void
RoomList::setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &settings, RoomList::setInitialRooms(const QMap<QString, QSharedPointer<RoomSettings>> &settings,
const QMap<QString, RoomState> &states) const QMap<QString, RoomState> &states)
{ {
rooms_.clear(); rooms_.clear();
if (settings.size() != states.size()) { if (settings.size() != states.size()) {
qWarning() << "Initializing room list"; qWarning() << "Initializing room list";
qWarning() << "Different number of room states and room settings"; qWarning() << "Different number of room states and room settings";
return; return;
} }
for (auto it = states.constBegin(); it != states.constEnd(); it++) { for (auto it = states.constBegin(); it != states.constEnd(); it++) {
auto room_id = it.key(); auto room_id = it.key();
auto state = it.value(); auto state = it.value();
if (!state.getAvatar().toString().isEmpty()) if (!state.getAvatar().toString().isEmpty())
client_->fetchRoomAvatar(room_id, state.getAvatar()); client_->fetchRoomAvatar(room_id, state.getAvatar());
RoomInfoListItem *room_item = new RoomInfoListItem(settings[room_id], state, room_id, scrollArea_); RoomInfoListItem *room_item =
connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom); new RoomInfoListItem(settings[room_id], state, room_id, scrollArea_);
connect(
room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom);
rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item)); rooms_.insert(room_id, QSharedPointer<RoomInfoListItem>(room_item));
int pos = contentsLayout_->count() - 1; int pos = contentsLayout_->count() - 1;
contentsLayout_->insertWidget(pos, room_item); contentsLayout_->insertWidget(pos, room_item);
} }
if (rooms_.isEmpty()) if (rooms_.isEmpty())
return; return;
auto first_room = rooms_.first(); auto first_room = rooms_.first();
first_room->setPressedState(true); first_room->setPressedState(true);
emit roomChanged(rooms_.firstKey()); emit roomChanged(rooms_.firstKey());
} }
void void
RoomList::sync(const QMap<QString, RoomState> &states) RoomList::sync(const QMap<QString, RoomState> &states)
{ {
for (auto it = states.constBegin(); it != states.constEnd(); it++) { for (auto it = states.constBegin(); it != states.constEnd(); it++) {
auto room_id = it.key(); auto room_id = it.key();
auto state = it.value(); auto state = it.value();
// TODO: Add the new room to the list. // TODO: Add the new room to the list.
if (!rooms_.contains(room_id)) if (!rooms_.contains(room_id))
continue; continue;
auto room = rooms_[room_id]; auto room = rooms_[room_id];
auto current_avatar = room->state().getAvatar(); auto current_avatar = room->state().getAvatar();
auto new_avatar = state.getAvatar(); auto new_avatar = state.getAvatar();
if (current_avatar != new_avatar && !new_avatar.toString().isEmpty()) if (current_avatar != new_avatar && !new_avatar.toString().isEmpty())
client_->fetchRoomAvatar(room_id, new_avatar); client_->fetchRoomAvatar(room_id, new_avatar);
room->setState(state); room->setState(state);
} }
} }
void void
RoomList::highlightSelectedRoom(const QString &room_id) RoomList::highlightSelectedRoom(const QString &room_id)
{ {
emit roomChanged(room_id); emit roomChanged(room_id);
if (!rooms_.contains(room_id)) { if (!rooms_.contains(room_id)) {
qDebug() << "RoomList: clicked unknown roomid"; qDebug() << "RoomList: clicked unknown roomid";
return; return;
} }
// TODO: Send a read receipt for the last event. // TODO: Send a read receipt for the last event.
auto room = rooms_[room_id]; auto room = rooms_[room_id];
room->clearUnreadMessageCount(); room->clearUnreadMessageCount();
calculateUnreadMessageCount(); calculateUnreadMessageCount();
for (auto it = rooms_.constBegin(); it != rooms_.constEnd(); it++) { for (auto it = rooms_.constBegin(); it != rooms_.constEnd(); it++) {
if (it.key() != room_id) { if (it.key() != room_id) {
it.value()->setPressedState(false); it.value()->setPressedState(false);
} else { } else {
it.value()->setPressedState(true); it.value()->setPressedState(true);
scrollArea_->ensureWidgetVisible(qobject_cast<QWidget *>(it.value().data())); scrollArea_->ensureWidgetVisible(
} qobject_cast<QWidget *>(it.value().data()));
} }
}
} }
void void
RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img) RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
{ {
if (!rooms_.contains(roomid)) { if (!rooms_.contains(roomid)) {
qWarning() << "Avatar update on non existent room" << roomid; qWarning() << "Avatar update on non existent room" << roomid;
return; return;
} }
rooms_.value(roomid)->setAvatar(img.toImage()); rooms_.value(roomid)->setAvatar(img.toImage());
} }
void void
RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info) RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info)
{ {
if (!rooms_.contains(roomid)) { if (!rooms_.contains(roomid)) {
qWarning() << "Description update on non existent room" << roomid << info.body; qWarning() << "Description update on non existent room" << roomid << info.body;
return; return;
} }
rooms_.value(roomid)->setDescriptionMessage(info); rooms_.value(roomid)->setDescriptionMessage(info);
} }

View File

@ -20,24 +20,24 @@
void void
RoomMessages::deserialize(const QJsonDocument &data) RoomMessages::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("response is not a JSON object"); throw DeserializationException("response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (!object.contains("start")) if (!object.contains("start"))
throw DeserializationException("start key is missing"); throw DeserializationException("start key is missing");
if (!object.contains("end")) if (!object.contains("end"))
throw DeserializationException("end key is missing"); throw DeserializationException("end key is missing");
if (!object.contains("chunk")) if (!object.contains("chunk"))
throw DeserializationException("chunk key is missing"); throw DeserializationException("chunk key is missing");
if (!object.value("chunk").isArray()) if (!object.value("chunk").isArray())
throw DeserializationException("chunk isn't a JSON array"); throw DeserializationException("chunk isn't a JSON array");
start_ = object.value("start").toString(); start_ = object.value("start").toString();
end_ = object.value("end").toString(); end_ = object.value("end").toString();
chunk_ = object.value("chunk").toArray(); chunk_ = object.value("chunk").toArray();
} }

View File

@ -20,19 +20,19 @@
SlidingStackWidget::SlidingStackWidget(QWidget *parent) SlidingStackWidget::SlidingStackWidget(QWidget *parent)
: QStackedWidget(parent) : QStackedWidget(parent)
{ {
window_ = parent; window_ = parent;
if (parent == Q_NULLPTR) { if (parent == Q_NULLPTR) {
qDebug() << "Using nullptr for parent"; qDebug() << "Using nullptr for parent";
window_ = this; window_ = this;
} }
current_position_ = QPoint(0, 0); current_position_ = QPoint(0, 0);
speed_ = 400; speed_ = 400;
now_ = 0; now_ = 0;
next_ = 0; next_ = 0;
active_ = false; active_ = false;
animation_type_ = QEasingCurve::InOutCirc; animation_type_ = QEasingCurve::InOutCirc;
} }
SlidingStackWidget::~SlidingStackWidget() SlidingStackWidget::~SlidingStackWidget()
@ -42,116 +42,116 @@ SlidingStackWidget::~SlidingStackWidget()
void void
SlidingStackWidget::slideInNext() SlidingStackWidget::slideInNext()
{ {
int now = currentIndex(); int now = currentIndex();
if (now < count() - 1) if (now < count() - 1)
slideInIndex(now + 1); slideInIndex(now + 1);
} }
void void
SlidingStackWidget::slideInPrevious() SlidingStackWidget::slideInPrevious()
{ {
int now = currentIndex(); int now = currentIndex();
if (now > 0) if (now > 0)
slideInIndex(now - 1); slideInIndex(now - 1);
} }
void void
SlidingStackWidget::slideInIndex(int index, AnimationDirection direction) SlidingStackWidget::slideInIndex(int index, AnimationDirection direction)
{ {
// Take into consideration possible index overflow/undeflow. // Take into consideration possible index overflow/undeflow.
if (index > count() - 1) { if (index > count() - 1) {
direction = AnimationDirection::RIGHT_TO_LEFT; direction = AnimationDirection::RIGHT_TO_LEFT;
index = index % count(); index = index % count();
} else if (index < 0) { } else if (index < 0) {
direction = AnimationDirection::LEFT_TO_RIGHT; direction = AnimationDirection::LEFT_TO_RIGHT;
index = (index + count()) % count(); index = (index + count()) % count();
} }
slideInWidget(widget(index), direction); slideInWidget(widget(index), direction);
} }
void void
SlidingStackWidget::slideInWidget(QWidget *next_widget, AnimationDirection direction) SlidingStackWidget::slideInWidget(QWidget *next_widget, AnimationDirection direction)
{ {
// If an animation is currenlty executing we should wait for it to finish before // If an animation is currenlty executing we should wait for it to finish before
// another transition can start. // another transition can start.
if (active_) if (active_)
return; return;
active_ = true; active_ = true;
int now = currentIndex(); int now = currentIndex();
int next = indexOf(next_widget); int next = indexOf(next_widget);
if (now == next) { if (now == next) {
active_ = false; active_ = false;
return; return;
} }
int offset_x = frameRect().width(); int offset_x = frameRect().width();
next_widget->setGeometry(0, 0, offset_x, 0); next_widget->setGeometry(0, 0, offset_x, 0);
if (direction == AnimationDirection::LEFT_TO_RIGHT) { if (direction == AnimationDirection::LEFT_TO_RIGHT) {
offset_x = -offset_x; offset_x = -offset_x;
} }
QPoint pnext = next_widget->pos(); QPoint pnext = next_widget->pos();
QPoint pnow = widget(now)->pos(); QPoint pnow = widget(now)->pos();
current_position_ = pnow; current_position_ = pnow;
// Reposition the next widget outside of the display area. // Reposition the next widget outside of the display area.
next_widget->move(pnext.x() - offset_x, pnext.y()); next_widget->move(pnext.x() - offset_x, pnext.y());
// Make the widget visible. // Make the widget visible.
next_widget->show(); next_widget->show();
next_widget->raise(); next_widget->raise();
// Animate both the next and now widget. // Animate both the next and now widget.
QPropertyAnimation *animation_now = new QPropertyAnimation(widget(now), "pos", this); QPropertyAnimation *animation_now = new QPropertyAnimation(widget(now), "pos", this);
animation_now->setDuration(speed_); animation_now->setDuration(speed_);
animation_now->setEasingCurve(animation_type_); animation_now->setEasingCurve(animation_type_);
animation_now->setStartValue(QPoint(pnow.x(), pnow.y())); animation_now->setStartValue(QPoint(pnow.x(), pnow.y()));
animation_now->setEndValue(QPoint(pnow.x() + offset_x, pnow.y())); animation_now->setEndValue(QPoint(pnow.x() + offset_x, pnow.y()));
QPropertyAnimation *animation_next = new QPropertyAnimation(next_widget, "pos", this); QPropertyAnimation *animation_next = new QPropertyAnimation(next_widget, "pos", this);
animation_next->setDuration(speed_); animation_next->setDuration(speed_);
animation_next->setEasingCurve(animation_type_); animation_next->setEasingCurve(animation_type_);
animation_next->setStartValue(QPoint(pnext.x() - offset_x, pnext.y())); animation_next->setStartValue(QPoint(pnext.x() - offset_x, pnext.y()));
animation_next->setEndValue(QPoint(pnext.x(), pnext.y())); animation_next->setEndValue(QPoint(pnext.x(), pnext.y()));
QParallelAnimationGroup *animation_group = new QParallelAnimationGroup(this); QParallelAnimationGroup *animation_group = new QParallelAnimationGroup(this);
animation_group->addAnimation(animation_now); animation_group->addAnimation(animation_now);
animation_group->addAnimation(animation_next); animation_group->addAnimation(animation_next);
connect(animation_group, SIGNAL(finished()), this, SLOT(onAnimationFinished())); connect(animation_group, SIGNAL(finished()), this, SLOT(onAnimationFinished()));
next_ = next; next_ = next;
now_ = now; now_ = now;
animation_group->start(); animation_group->start();
} }
void void
SlidingStackWidget::onAnimationFinished() SlidingStackWidget::onAnimationFinished()
{ {
setCurrentIndex(next_); setCurrentIndex(next_);
// The old widget is no longer necessary so we can hide it and // The old widget is no longer necessary so we can hide it and
// move it back to its original position. // move it back to its original position.
widget(now_)->hide(); widget(now_)->hide();
widget(now_)->move(current_position_); widget(now_)->move(current_position_);
active_ = false; active_ = false;
emit animationFinished(); emit animationFinished();
} }
int int
SlidingStackWidget::getWidgetIndex(QWidget *widget) SlidingStackWidget::getWidgetIndex(QWidget *widget)
{ {
return indexOf(widget); return indexOf(widget);
} }

View File

@ -23,59 +23,59 @@
Splitter::Splitter(QWidget *parent) Splitter::Splitter(QWidget *parent)
: QSplitter(parent) : QSplitter(parent)
{ {
connect(this, &QSplitter::splitterMoved, this, &Splitter::onSplitterMoved); connect(this, &QSplitter::splitterMoved, this, &Splitter::onSplitterMoved);
setChildrenCollapsible(false); setChildrenCollapsible(false);
} }
void void
Splitter::onSplitterMoved(int pos, int index) Splitter::onSplitterMoved(int pos, int index)
{ {
Q_UNUSED(pos); Q_UNUSED(pos);
Q_UNUSED(index); Q_UNUSED(index);
auto s = sizes(); auto s = sizes();
if (s.count() < 2) { if (s.count() < 2) {
qWarning() << "Splitter needs at least two children"; qWarning() << "Splitter needs at least two children";
return; return;
} }
if (s[0] == ui::sidebar::NormalSize) { if (s[0] == ui::sidebar::NormalSize) {
rightMoveCount_ += 1; rightMoveCount_ += 1;
if (rightMoveCount_ > moveEventLimit_) { if (rightMoveCount_ > moveEventLimit_) {
auto left = widget(0); auto left = widget(0);
auto pos = left->mapFromGlobal(QCursor::pos()); auto pos = left->mapFromGlobal(QCursor::pos());
// if we are coming from the right, the cursor should // if we are coming from the right, the cursor should
// end up on the first widget. // end up on the first widget.
if (left->rect().contains(pos)) { if (left->rect().contains(pos)) {
left->setMinimumWidth(ui::sidebar::SmallSize); left->setMinimumWidth(ui::sidebar::SmallSize);
left->setMaximumWidth(ui::sidebar::SmallSize); left->setMaximumWidth(ui::sidebar::SmallSize);
rightMoveCount_ = 0; rightMoveCount_ = 0;
} }
} }
} else if (s[0] == ui::sidebar::SmallSize) { } else if (s[0] == ui::sidebar::SmallSize) {
leftMoveCount_ += 1; leftMoveCount_ += 1;
if (leftMoveCount_ > moveEventLimit_) { if (leftMoveCount_ > moveEventLimit_) {
auto left = widget(0); auto left = widget(0);
auto right = widget(1); auto right = widget(1);
auto pos = right->mapFromGlobal(QCursor::pos()); auto pos = right->mapFromGlobal(QCursor::pos());
// We move the start a little further so the transition isn't so abrupt. // We move the start a little further so the transition isn't so abrupt.
auto extended = right->rect(); auto extended = right->rect();
extended.translate(100, 0); extended.translate(100, 0);
// if we are coming from the left, the cursor should // if we are coming from the left, the cursor should
// end up on the second widget. // end up on the second widget.
if (extended.contains(pos)) { if (extended.contains(pos)) {
left->setMinimumWidth(ui::sidebar::NormalSize); left->setMinimumWidth(ui::sidebar::NormalSize);
left->setMaximumWidth(2 * ui::sidebar::NormalSize); left->setMaximumWidth(2 * ui::sidebar::NormalSize);
leftMoveCount_ = 0; leftMoveCount_ = 0;
} }
} }
} }
} }

View File

@ -27,166 +27,166 @@
void void
SyncResponse::deserialize(const QJsonDocument &data) SyncResponse::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Sync response is not a JSON object"); throw DeserializationException("Sync response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (object.value("next_batch") == QJsonValue::Undefined) if (object.value("next_batch") == QJsonValue::Undefined)
throw DeserializationException("Sync: missing next_batch parameter"); throw DeserializationException("Sync: missing next_batch parameter");
if (object.value("rooms") == QJsonValue::Undefined) if (object.value("rooms") == QJsonValue::Undefined)
throw DeserializationException("Sync: missing rooms parameter"); throw DeserializationException("Sync: missing rooms parameter");
rooms_.deserialize(object.value("rooms")); rooms_.deserialize(object.value("rooms"));
next_batch_ = object.value("next_batch").toString(); next_batch_ = object.value("next_batch").toString();
} }
void void
Rooms::deserialize(const QJsonValue &data) Rooms::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Rooms value is not a JSON object"); throw DeserializationException("Rooms value is not a JSON object");
QJsonObject object = data.toObject(); QJsonObject object = data.toObject();
if (!object.contains("join")) if (!object.contains("join"))
throw DeserializationException("rooms/join is missing"); throw DeserializationException("rooms/join is missing");
if (!object.contains("invite")) if (!object.contains("invite"))
throw DeserializationException("rooms/invite is missing"); throw DeserializationException("rooms/invite is missing");
if (!object.contains("leave")) if (!object.contains("leave"))
throw DeserializationException("rooms/leave is missing"); throw DeserializationException("rooms/leave is missing");
if (!object.value("join").isObject()) if (!object.value("join").isObject())
throw DeserializationException("rooms/join must be a JSON object"); throw DeserializationException("rooms/join must be a JSON object");
if (!object.value("invite").isObject()) if (!object.value("invite").isObject())
throw DeserializationException("rooms/invite must be a JSON object"); throw DeserializationException("rooms/invite must be a JSON object");
if (!object.value("leave").isObject()) if (!object.value("leave").isObject())
throw DeserializationException("rooms/leave must be a JSON object"); throw DeserializationException("rooms/leave must be a JSON object");
auto join = object.value("join").toObject(); auto join = object.value("join").toObject();
for (auto it = join.constBegin(); it != join.constEnd(); it++) { for (auto it = join.constBegin(); it != join.constEnd(); it++) {
JoinedRoom tmp_room; JoinedRoom tmp_room;
try { try {
tmp_room.deserialize(it.value()); tmp_room.deserialize(it.value());
join_.insert(it.key(), tmp_room); join_.insert(it.key(), tmp_room);
} catch (DeserializationException &e) { } catch (DeserializationException &e) {
qWarning() << e.what(); qWarning() << e.what();
qWarning() << "Skipping malformed object for room" << it.key(); qWarning() << "Skipping malformed object for room" << it.key();
} }
} }
} }
void void
JoinedRoom::deserialize(const QJsonValue &data) JoinedRoom::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("JoinedRoom is not a JSON object"); throw DeserializationException("JoinedRoom is not a JSON object");
QJsonObject object = data.toObject(); QJsonObject object = data.toObject();
if (!object.contains("state")) if (!object.contains("state"))
throw DeserializationException("join/state is missing"); throw DeserializationException("join/state is missing");
if (!object.contains("timeline")) if (!object.contains("timeline"))
throw DeserializationException("join/timeline is missing"); throw DeserializationException("join/timeline is missing");
if (!object.contains("account_data")) if (!object.contains("account_data"))
throw DeserializationException("join/account_data is missing"); throw DeserializationException("join/account_data is missing");
if (!object.contains("unread_notifications")) if (!object.contains("unread_notifications"))
throw DeserializationException("join/unread_notifications is missing"); throw DeserializationException("join/unread_notifications is missing");
if (!object.value("state").isObject()) if (!object.value("state").isObject())
throw DeserializationException("join/state should be an object"); throw DeserializationException("join/state should be an object");
QJsonObject state = object.value("state").toObject(); QJsonObject state = object.value("state").toObject();
if (!state.contains("events")) if (!state.contains("events"))
throw DeserializationException("join/state/events is missing"); throw DeserializationException("join/state/events is missing");
state_.deserialize(state.value("events")); state_.deserialize(state.value("events"));
timeline_.deserialize(object.value("timeline")); timeline_.deserialize(object.value("timeline"));
} }
void void
Event::deserialize(const QJsonValue &data) Event::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Event is not a JSON object"); throw DeserializationException("Event is not a JSON object");
QJsonObject object = data.toObject(); QJsonObject object = data.toObject();
if (!object.contains("content")) if (!object.contains("content"))
throw DeserializationException("event/content is missing"); throw DeserializationException("event/content is missing");
if (!object.contains("unsigned")) if (!object.contains("unsigned"))
throw DeserializationException("event/content is missing"); throw DeserializationException("event/content is missing");
if (!object.contains("sender")) if (!object.contains("sender"))
throw DeserializationException("event/sender is missing"); throw DeserializationException("event/sender is missing");
if (!object.contains("event_id")) if (!object.contains("event_id"))
throw DeserializationException("event/event_id is missing"); throw DeserializationException("event/event_id is missing");
// TODO: Make this optional // TODO: Make this optional
/* if (!object.contains("state_key")) */ /* if (!object.contains("state_key")) */
/* throw DeserializationException("event/state_key is missing"); */ /* throw DeserializationException("event/state_key is missing"); */
if (!object.contains("type")) if (!object.contains("type"))
throw DeserializationException("event/type is missing"); throw DeserializationException("event/type is missing");
if (!object.contains("origin_server_ts")) if (!object.contains("origin_server_ts"))
throw DeserializationException("event/origin_server_ts is missing"); throw DeserializationException("event/origin_server_ts is missing");
content_ = object.value("content").toObject(); content_ = object.value("content").toObject();
unsigned_ = object.value("unsigned").toObject(); unsigned_ = object.value("unsigned").toObject();
sender_ = object.value("sender").toString(); sender_ = object.value("sender").toString();
state_key_ = object.value("state_key").toString(); state_key_ = object.value("state_key").toString();
type_ = object.value("type").toString(); type_ = object.value("type").toString();
event_id_ = object.value("event_id").toString(); event_id_ = object.value("event_id").toString();
origin_server_ts_ = object.value("origin_server_ts").toDouble(); origin_server_ts_ = object.value("origin_server_ts").toDouble();
} }
void void
State::deserialize(const QJsonValue &data) State::deserialize(const QJsonValue &data)
{ {
if (!data.isArray()) if (!data.isArray())
throw DeserializationException("State is not a JSON array"); throw DeserializationException("State is not a JSON array");
events_ = data.toArray(); events_ = data.toArray();
} }
void void
Timeline::deserialize(const QJsonValue &data) Timeline::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Timeline is not a JSON object"); throw DeserializationException("Timeline is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
if (!object.contains("events")) if (!object.contains("events"))
throw DeserializationException("timeline/events is missing"); throw DeserializationException("timeline/events is missing");
if (!object.contains("prev_batch")) if (!object.contains("prev_batch"))
throw DeserializationException("timeline/prev_batch is missing"); throw DeserializationException("timeline/prev_batch is missing");
if (!object.contains("limited")) if (!object.contains("limited"))
throw DeserializationException("timeline/limited is missing"); throw DeserializationException("timeline/limited is missing");
prev_batch_ = object.value("prev_batch").toString(); prev_batch_ = object.value("prev_batch").toString();
limited_ = object.value("limited").toBool(); limited_ = object.value("limited").toBool();
if (!object.value("events").isArray()) if (!object.value("events").isArray())
throw DeserializationException("timeline/events is not a JSON array"); throw DeserializationException("timeline/events is not a JSON array");
events_ = object.value("events").toArray(); events_ = object.value("events").toArray();
} }

View File

@ -27,69 +27,75 @@
MsgCountComposedIcon::MsgCountComposedIcon(const QString &filename) MsgCountComposedIcon::MsgCountComposedIcon(const QString &filename)
: QIconEngine() : QIconEngine()
{ {
icon_ = QIcon(filename); icon_ = QIcon(filename);
} }
void void
MsgCountComposedIcon::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) MsgCountComposedIcon::paint(QPainter *painter,
const QRect &rect,
QIcon::Mode mode,
QIcon::State state)
{ {
painter->setRenderHint(QPainter::TextAntialiasing); painter->setRenderHint(QPainter::TextAntialiasing);
painter->setRenderHint(QPainter::SmoothPixmapTransform); painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->setRenderHint(QPainter::Antialiasing); painter->setRenderHint(QPainter::Antialiasing);
icon_.paint(painter, rect, Qt::AlignCenter, mode, state); icon_.paint(painter, rect, Qt::AlignCenter, mode, state);
if (msgCount <= 0) if (msgCount <= 0)
return; return;
QColor backgroundColor("red"); QColor backgroundColor("red");
QColor textColor("white"); QColor textColor("white");
QBrush brush; QBrush brush;
brush.setStyle(Qt::SolidPattern); brush.setStyle(Qt::SolidPattern);
brush.setColor(backgroundColor); brush.setColor(backgroundColor);
painter->setBrush(brush); painter->setBrush(brush);
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
painter->setFont(QFont("Open Sans", 8, QFont::Black)); painter->setFont(QFont("Open Sans", 8, QFont::Black));
QRectF bubble(rect.width() - BubbleDiameter, rect.height() - BubbleDiameter, BubbleDiameter, BubbleDiameter); QRectF bubble(rect.width() - BubbleDiameter,
painter->drawEllipse(bubble); rect.height() - BubbleDiameter,
painter->setPen(QPen(textColor)); BubbleDiameter,
painter->setBrush(Qt::NoBrush); BubbleDiameter);
painter->drawText(bubble, Qt::AlignCenter, QString::number(msgCount)); painter->drawEllipse(bubble);
painter->setPen(QPen(textColor));
painter->setBrush(Qt::NoBrush);
painter->drawText(bubble, Qt::AlignCenter, QString::number(msgCount));
} }
QIconEngine * QIconEngine *
MsgCountComposedIcon::clone() const MsgCountComposedIcon::clone() const
{ {
return new MsgCountComposedIcon(*this); return new MsgCountComposedIcon(*this);
} }
TrayIcon::TrayIcon(const QString &filename, QWidget *parent) TrayIcon::TrayIcon(const QString &filename, QWidget *parent)
: QSystemTrayIcon(parent) : QSystemTrayIcon(parent)
{ {
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
setIcon(QIcon(filename)); setIcon(QIcon(filename));
#else #else
icon_ = new MsgCountComposedIcon(filename); icon_ = new MsgCountComposedIcon(filename);
setIcon(QIcon(icon_)); setIcon(QIcon(icon_));
#endif #endif
QMenu *menu = new QMenu(parent); QMenu *menu = new QMenu(parent);
viewAction_ = new QAction(tr("Show"), parent); viewAction_ = new QAction(tr("Show"), parent);
quitAction_ = new QAction(tr("Quit"), parent); quitAction_ = new QAction(tr("Quit"), parent);
connect(viewAction_, SIGNAL(triggered()), parent, SLOT(show())); connect(viewAction_, SIGNAL(triggered()), parent, SLOT(show()));
connect(quitAction_, &QAction::triggered, this, [=]() { QApplication::quit(); }); connect(quitAction_, &QAction::triggered, this, [=]() { QApplication::quit(); });
menu->addAction(viewAction_); menu->addAction(viewAction_);
menu->addAction(quitAction_); menu->addAction(quitAction_);
setContextMenu(menu); setContextMenu(menu);
// We wait a little for the icon to load. // We wait a little for the icon to load.
QTimer::singleShot(500, this, [=]() { show(); }); QTimer::singleShot(500, this, [=]() { show(); });
} }
void void
@ -97,20 +103,20 @@ TrayIcon::setUnreadCount(int count)
{ {
// Use the native badge counter in MacOS. // Use the native badge counter in MacOS.
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
if (count == 0) if (count == 0)
QtMac::setBadgeLabelText(""); QtMac::setBadgeLabelText("");
else else
QtMac::setBadgeLabelText(QString::number(count)); QtMac::setBadgeLabelText(QString::number(count));
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
// FIXME: Find a way to use Windows apis for the badge counter (if any). // FIXME: Find a way to use Windows apis for the badge counter (if any).
#else #else
// Custom drawing on Linux. // Custom drawing on Linux.
// FIXME: It doesn't seem to work on KDE. // FIXME: It doesn't seem to work on KDE.
MsgCountComposedIcon *tmp = static_cast<MsgCountComposedIcon *>(icon_->clone()); MsgCountComposedIcon *tmp = static_cast<MsgCountComposedIcon *>(icon_->clone());
tmp->msgCount = count; tmp->msgCount = count;
setIcon(QIcon(tmp)); setIcon(QIcon(tmp));
icon_ = tmp; icon_ = tmp;
#endif #endif
} }

View File

@ -31,92 +31,95 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
, logoutDialog_{ nullptr } , logoutDialog_{ nullptr }
, logoutButtonSize_{ 32 } , logoutButtonSize_{ 32 }
{ {
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
setSizePolicy(sizePolicy); setSizePolicy(sizePolicy);
setMinimumSize(QSize(0, 65)); setMinimumSize(QSize(0, 65));
topLayout_ = new QHBoxLayout(this); topLayout_ = new QHBoxLayout(this);
topLayout_->setSpacing(0); topLayout_->setSpacing(0);
topLayout_->setMargin(5); topLayout_->setMargin(5);
avatarLayout_ = new QHBoxLayout(); avatarLayout_ = new QHBoxLayout();
textLayout_ = new QVBoxLayout(); textLayout_ = new QVBoxLayout();
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this);
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
userAvatar_->setSize(55); userAvatar_->setSize(55);
userAvatar_->setBackgroundColor("#f9f9f9"); userAvatar_->setBackgroundColor("#f9f9f9");
userAvatar_->setTextColor("#333333"); userAvatar_->setTextColor("#333333");
QFont nameFont("Open Sans SemiBold"); QFont nameFont("Open Sans SemiBold");
nameFont.setPixelSize(conf::userInfoWidget::fonts::displayName); nameFont.setPixelSize(conf::userInfoWidget::fonts::displayName);
displayNameLabel_ = new QLabel(this); displayNameLabel_ = new QLabel(this);
displayNameLabel_->setFont(nameFont); displayNameLabel_->setFont(nameFont);
displayNameLabel_->setStyleSheet("padding: 0 9px; color: #171919; margin-bottom: -10px;"); displayNameLabel_->setStyleSheet("padding: 0 9px; color: #171919; margin-bottom: -10px;");
displayNameLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); displayNameLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop);
QFont useridFont("Open Sans"); QFont useridFont("Open Sans");
useridFont.setPixelSize(conf::userInfoWidget::fonts::userid); useridFont.setPixelSize(conf::userInfoWidget::fonts::userid);
userIdLabel_ = new QLabel(this); userIdLabel_ = new QLabel(this);
userIdLabel_->setFont(useridFont); userIdLabel_->setFont(useridFont);
userIdLabel_->setStyleSheet("padding: 0 8px 8px 8px; color: #555459;"); userIdLabel_->setStyleSheet("padding: 0 8px 8px 8px; color: #555459;");
userIdLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); userIdLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);
avatarLayout_->addWidget(userAvatar_); avatarLayout_->addWidget(userAvatar_);
textLayout_->addWidget(displayNameLabel_); textLayout_->addWidget(displayNameLabel_);
textLayout_->addWidget(userIdLabel_); textLayout_->addWidget(userIdLabel_);
topLayout_->addLayout(avatarLayout_); topLayout_->addLayout(avatarLayout_);
topLayout_->addLayout(textLayout_); topLayout_->addLayout(textLayout_);
topLayout_->addStretch(1); topLayout_->addStretch(1);
buttonLayout_ = new QHBoxLayout(); buttonLayout_ = new QHBoxLayout();
buttonLayout_->setSpacing(0); buttonLayout_->setSpacing(0);
buttonLayout_->setMargin(0); buttonLayout_->setMargin(0);
logoutButton_ = new FlatButton(this); logoutButton_ = new FlatButton(this);
logoutButton_->setForegroundColor(QColor("#555459")); logoutButton_->setForegroundColor(QColor("#555459"));
logoutButton_->setFixedSize(logoutButtonSize_, logoutButtonSize_); logoutButton_->setFixedSize(logoutButtonSize_, logoutButtonSize_);
logoutButton_->setCornerRadius(logoutButtonSize_ / 2); logoutButton_->setCornerRadius(logoutButtonSize_ / 2);
QIcon icon; QIcon icon;
icon.addFile(":/icons/icons/power-button-off.png", QSize(), QIcon::Normal, QIcon::Off); icon.addFile(":/icons/icons/power-button-off.png", QSize(), QIcon::Normal, QIcon::Off);
logoutButton_->setIcon(icon); logoutButton_->setIcon(icon);
logoutButton_->setIconSize(QSize(logoutButtonSize_ / 2, logoutButtonSize_ / 2)); logoutButton_->setIconSize(QSize(logoutButtonSize_ / 2, logoutButtonSize_ / 2));
buttonLayout_->addWidget(logoutButton_); buttonLayout_->addWidget(logoutButton_);
topLayout_->addLayout(buttonLayout_); topLayout_->addLayout(buttonLayout_);
// Show the confirmation dialog. // Show the confirmation dialog.
connect(logoutButton_, &QPushButton::clicked, this, [=]() { connect(logoutButton_, &QPushButton::clicked, this, [=]() {
if (logoutDialog_ == nullptr) { if (logoutDialog_ == nullptr) {
logoutDialog_ = new LogoutDialog(this); logoutDialog_ = new LogoutDialog(this);
connect(logoutDialog_, SIGNAL(closing(bool)), this, SLOT(closeLogoutDialog(bool))); connect(logoutDialog_,
} SIGNAL(closing(bool)),
this,
SLOT(closeLogoutDialog(bool)));
}
if (logoutModal_ == nullptr) { if (logoutModal_ == nullptr) {
logoutModal_ = new OverlayModal(MainWindow::instance(), logoutDialog_); logoutModal_ = new OverlayModal(MainWindow::instance(), logoutDialog_);
logoutModal_->setDuration(100); logoutModal_->setDuration(100);
logoutModal_->setColor(QColor(55, 55, 55, 170)); logoutModal_->setColor(QColor(55, 55, 55, 170));
} }
logoutModal_->fadeIn(); logoutModal_->fadeIn();
}); });
} }
void void
UserInfoWidget::closeLogoutDialog(bool isLoggingOut) UserInfoWidget::closeLogoutDialog(bool isLoggingOut)
{ {
logoutModal_->fadeOut(); logoutModal_->fadeOut();
if (isLoggingOut) { if (isLoggingOut) {
// Waiting for the modal to fade out. // Waiting for the modal to fade out.
QTimer::singleShot(100, this, [=]() { emit logout(); }); QTimer::singleShot(100, this, [=]() { emit logout(); });
} }
} }
UserInfoWidget::~UserInfoWidget() UserInfoWidget::~UserInfoWidget()
@ -126,52 +129,52 @@ UserInfoWidget::~UserInfoWidget()
void void
UserInfoWidget::resizeEvent(QResizeEvent *event) UserInfoWidget::resizeEvent(QResizeEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
if (width() <= ui::sidebar::SmallSize) { if (width() <= ui::sidebar::SmallSize) {
topLayout_->setContentsMargins(0, 0, logoutButtonSize_ / 2 - 5 / 2, 0); topLayout_->setContentsMargins(0, 0, logoutButtonSize_ / 2 - 5 / 2, 0);
userAvatar_->hide(); userAvatar_->hide();
displayNameLabel_->hide(); displayNameLabel_->hide();
userIdLabel_->hide(); userIdLabel_->hide();
} else { } else {
topLayout_->setMargin(5); topLayout_->setMargin(5);
userAvatar_->show(); userAvatar_->show();
displayNameLabel_->show(); displayNameLabel_->show();
userIdLabel_->show(); userIdLabel_->show();
} }
} }
void void
UserInfoWidget::reset() UserInfoWidget::reset()
{ {
displayNameLabel_->setText(""); displayNameLabel_->setText("");
userIdLabel_->setText(""); userIdLabel_->setText("");
userAvatar_->setLetter(QChar('?')); userAvatar_->setLetter(QChar('?'));
} }
void void
UserInfoWidget::setAvatar(const QImage &img) UserInfoWidget::setAvatar(const QImage &img)
{ {
avatar_image_ = img; avatar_image_ = img;
userAvatar_->setImage(img); userAvatar_->setImage(img);
} }
void void
UserInfoWidget::setDisplayName(const QString &name) UserInfoWidget::setDisplayName(const QString &name)
{ {
if (name.isEmpty()) if (name.isEmpty())
display_name_ = user_id_.split(':')[0].split('@')[1]; display_name_ = user_id_.split(':')[0].split('@')[1];
else else
display_name_ = name; display_name_ = name;
displayNameLabel_->setText(display_name_); displayNameLabel_->setText(display_name_);
userAvatar_->setLetter(QChar(display_name_[0])); userAvatar_->setLetter(QChar(display_name_[0]));
} }
void void
UserInfoWidget::setUserId(const QString &userid) UserInfoWidget::setUserId(const QString &userid)
{ {
user_id_ = userid; user_id_ = userid;
userIdLabel_->setText(userid); userIdLabel_->setText(userid);
} }

View File

@ -27,38 +27,39 @@
void void
VersionsResponse::deserialize(const QJsonDocument &data) VersionsResponse::deserialize(const QJsonDocument &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("Versions response is not a JSON object"); throw DeserializationException("Versions response is not a JSON object");
QJsonObject object = data.object(); QJsonObject object = data.object();
if (object.value("versions") == QJsonValue::Undefined) if (object.value("versions") == QJsonValue::Undefined)
throw DeserializationException("Versions: missing version list"); throw DeserializationException("Versions: missing version list");
auto versions = object.value("versions").toArray(); auto versions = object.value("versions").toArray();
for (auto const &elem : versions) { for (auto const &elem : versions) {
QString str = elem.toString(); QString str = elem.toString();
QRegExp rx("r(\\d+)\\.(\\d+)\\.(\\d+)"); QRegExp rx("r(\\d+)\\.(\\d+)\\.(\\d+)");
if (rx.indexIn(str) == -1) if (rx.indexIn(str) == -1)
throw DeserializationException("Invalid version string in versions response"); throw DeserializationException(
"Invalid version string in versions response");
struct Version_ v; struct Version_ v;
v.major_ = rx.cap(1).toUInt(); v.major_ = rx.cap(1).toUInt();
v.minor_ = rx.cap(2).toUInt(); v.minor_ = rx.cap(2).toUInt();
v.patch_ = rx.cap(3).toUInt(); v.patch_ = rx.cap(3).toUInt();
supported_versions_.push_back(v); supported_versions_.push_back(v);
} }
} }
bool bool
VersionsResponse::isVersionSupported(unsigned int major, unsigned int minor, unsigned int patch) VersionsResponse::isVersionSupported(unsigned int major, unsigned int minor, unsigned int patch)
{ {
for (auto &v : supported_versions_) { for (auto &v : supported_versions_) {
if (v.major_ == major && v.minor_ == minor && v.patch_ >= patch) if (v.major_ == major && v.minor_ == minor && v.patch_ >= patch)
return true; return true;
} }
return false; return false;
} }

View File

@ -24,78 +24,79 @@
WelcomePage::WelcomePage(QWidget *parent) WelcomePage::WelcomePage(QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
top_layout_ = new QVBoxLayout(this); top_layout_ = new QVBoxLayout(this);
top_layout_->setSpacing(0); top_layout_->setSpacing(0);
top_layout_->setMargin(0); top_layout_->setMargin(0);
intro_banner_ = new QLabel(this); intro_banner_ = new QLabel(this);
intro_banner_->setPixmap(QPixmap(":/logos/nheko-256.png")); intro_banner_->setPixmap(QPixmap(":/logos/nheko-256.png"));
intro_banner_->setAlignment(Qt::AlignCenter); intro_banner_->setAlignment(Qt::AlignCenter);
intro_text_ = new QLabel(this); intro_text_ = new QLabel(this);
QString heading(tr("Welcome to nheko! The desktop client for the Matrix protocol.")); QString heading(tr("Welcome to nheko! The desktop client for the Matrix protocol."));
QString main(tr("Enjoy your stay!")); QString main(tr("Enjoy your stay!"));
intro_text_->setText(QString("<p align=\"center\" style=\"margin: 0; line-height: 2pt\">" intro_text_->setText(QString("<p align=\"center\" style=\"margin: 0; line-height: 2pt\">"
" <span style=\" font-size:18px; color:#515151;\"> %1 </span>" " <span style=\" font-size:18px; color:#515151;\"> %1 </span>"
"</p>" "</p>"
"<p align=\"center\" style=\"margin: 1pt; line-height: 2pt;\">" "<p align=\"center\" style=\"margin: 1pt; line-height: 2pt;\">"
" <span style=\" font-size:18px; color:#515151;\"> %2 </span>" " <span style=\" font-size:18px; color:#515151;\"> %2 </span>"
"</p>") "</p>")
.arg(heading) .arg(heading)
.arg(main)); .arg(main));
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addWidget(intro_banner_); top_layout_->addWidget(intro_banner_);
top_layout_->addStretch(1); top_layout_->addStretch(1);
top_layout_->addWidget(intro_text_, 0, Qt::AlignCenter); top_layout_->addWidget(intro_text_, 0, Qt::AlignCenter);
top_layout_->addStretch(1); top_layout_->addStretch(1);
button_layout_ = new QHBoxLayout(); button_layout_ = new QHBoxLayout();
button_layout_->setSpacing(0); button_layout_->setSpacing(0);
button_layout_->setContentsMargins(0, 20, 0, 80); button_layout_->setContentsMargins(0, 20, 0, 80);
register_button_ = new RaisedButton(tr("REGISTER"), this); register_button_ = new RaisedButton(tr("REGISTER"), this);
register_button_->setBackgroundColor(QColor("#333333")); register_button_->setBackgroundColor(QColor("#333333"));
register_button_->setForegroundColor(QColor("white")); register_button_->setForegroundColor(QColor("white"));
register_button_->setMinimumSize(240, 60); register_button_->setMinimumSize(240, 60);
register_button_->setFontSize(conf::btn::fontSize); register_button_->setFontSize(conf::btn::fontSize);
register_button_->setCornerRadius(conf::btn::cornerRadius); register_button_->setCornerRadius(conf::btn::cornerRadius);
login_button_ = new RaisedButton(tr("LOGIN"), this); login_button_ = new RaisedButton(tr("LOGIN"), this);
login_button_->setBackgroundColor(QColor("#333333")); login_button_->setBackgroundColor(QColor("#333333"));
login_button_->setForegroundColor(QColor("white")); login_button_->setForegroundColor(QColor("white"));
login_button_->setMinimumSize(240, 60); login_button_->setMinimumSize(240, 60);
login_button_->setFontSize(conf::btn::fontSize); login_button_->setFontSize(conf::btn::fontSize);
login_button_->setCornerRadius(conf::btn::cornerRadius); login_button_->setCornerRadius(conf::btn::cornerRadius);
button_spacer_ = new QSpacerItem(20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); button_spacer_ =
new QSpacerItem(20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
button_layout_->addStretch(1); button_layout_->addStretch(1);
button_layout_->addWidget(register_button_); button_layout_->addWidget(register_button_);
button_layout_->addItem(button_spacer_); button_layout_->addItem(button_spacer_);
button_layout_->addWidget(login_button_); button_layout_->addWidget(login_button_);
button_layout_->addStretch(1); button_layout_->addStretch(1);
top_layout_->addLayout(button_layout_); top_layout_->addLayout(button_layout_);
connect(register_button_, SIGNAL(clicked()), this, SLOT(onRegisterButtonClicked())); connect(register_button_, SIGNAL(clicked()), this, SLOT(onRegisterButtonClicked()));
connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked())); connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked()));
} }
void void
WelcomePage::onLoginButtonClicked() WelcomePage::onLoginButtonClicked()
{ {
emit userLogin(); emit userLogin();
} }
void void
WelcomePage::onRegisterButtonClicked() WelcomePage::onRegisterButtonClicked()
{ {
emit userRegister(); emit userRegister();
} }
WelcomePage::~WelcomePage() WelcomePage::~WelcomePage()

View File

@ -24,32 +24,32 @@ using namespace matrix::events;
void void
AliasesEventContent::deserialize(const QJsonValue &data) AliasesEventContent::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("AliasesEventContent is not a JSON object"); throw DeserializationException("AliasesEventContent is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
if (object.value("aliases") == QJsonValue::Undefined) if (object.value("aliases") == QJsonValue::Undefined)
throw DeserializationException("aliases key is missing"); throw DeserializationException("aliases key is missing");
auto aliases = object.value("aliases").toArray(); auto aliases = object.value("aliases").toArray();
for (const auto &alias : aliases) for (const auto &alias : aliases)
aliases_.push_back(alias.toString()); aliases_.push_back(alias.toString());
} }
QJsonObject QJsonObject
AliasesEventContent::serialize() const AliasesEventContent::serialize() const
{ {
QJsonObject object; QJsonObject object;
QJsonArray aliases; QJsonArray aliases;
for (const auto &alias : aliases_) for (const auto &alias : aliases_)
aliases.push_back(alias); aliases.push_back(alias);
if (aliases.size() > 0) if (aliases.size() > 0)
object["aliases"] = aliases; object["aliases"] = aliases;
return object; return object;
} }

View File

@ -24,27 +24,27 @@ using namespace matrix::events;
void void
AvatarEventContent::deserialize(const QJsonValue &data) AvatarEventContent::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("AvatarEventContent is not a JSON object"); throw DeserializationException("AvatarEventContent is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
if (object.value("url") == QJsonValue::Undefined) if (object.value("url") == QJsonValue::Undefined)
throw DeserializationException("url key is missing"); throw DeserializationException("url key is missing");
url_ = QUrl(object.value("url").toString()); url_ = QUrl(object.value("url").toString());
if (!url_.isValid()) if (!url_.isValid())
qWarning() << "Invalid avatar url" << url_; qWarning() << "Invalid avatar url" << url_;
} }
QJsonObject QJsonObject
AvatarEventContent::serialize() const AvatarEventContent::serialize() const
{ {
QJsonObject object; QJsonObject object;
if (!url_.isEmpty()) if (!url_.isEmpty())
object["url"] = url_.toString(); object["url"] = url_.toString();
return object; return object;
} }

View File

@ -22,24 +22,24 @@ using namespace matrix::events;
void void
CanonicalAliasEventContent::deserialize(const QJsonValue &data) CanonicalAliasEventContent::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("CanonicalAliasEventContent is not a JSON object"); throw DeserializationException("CanonicalAliasEventContent is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
if (object.value("alias") == QJsonValue::Undefined) if (object.value("alias") == QJsonValue::Undefined)
throw DeserializationException("alias key is missing"); throw DeserializationException("alias key is missing");
alias_ = object.value("alias").toString(); alias_ = object.value("alias").toString();
} }
QJsonObject QJsonObject
CanonicalAliasEventContent::serialize() const CanonicalAliasEventContent::serialize() const
{ {
QJsonObject object; QJsonObject object;
if (!alias_.isEmpty()) if (!alias_.isEmpty())
object["alias"] = alias_; object["alias"] = alias_;
return object; return object;
} }

View File

@ -22,24 +22,24 @@ using namespace matrix::events;
void void
CreateEventContent::deserialize(const QJsonValue &data) CreateEventContent::deserialize(const QJsonValue &data)
{ {
if (!data.isObject()) if (!data.isObject())
throw DeserializationException("CreateEventContent is not a JSON object"); throw DeserializationException("CreateEventContent is not a JSON object");
auto object = data.toObject(); auto object = data.toObject();
if (object.value("creator") == QJsonValue::Undefined) if (object.value("creator") == QJsonValue::Undefined)
throw DeserializationException("creator key is missing"); throw DeserializationException("creator key is missing");
creator_ = object.value("creator").toString(); creator_ = object.value("creator").toString();
} }
QJsonObject QJsonObject
CreateEventContent::serialize() const CreateEventContent::serialize() const
{ {
QJsonObject object; QJsonObject object;
if (!creator_.isEmpty()) if (!creator_.isEmpty())
object["creator"] = creator_; object["creator"] = creator_;
return object; return object;
} }

Some files were not shown because too many files have changed in this diff Show More