Merge branch 'master' into windowsIconFix

This commit is contained in:
Marcel 2017-11-06 14:40:37 +01:00 committed by GitHub
commit 43dc553225
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
204 changed files with 4912 additions and 4000 deletions

20
.ci/linux/deploy.sh Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
mkdir -p appdir
cp build/nheko appdir/
cp resources/nheko.desktop appdir/
cp resources/nheko*.png appdir/
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
chmod a+x linuxdeployqt*.AppImage
unset QTDIR
unset QT_PLUGIN_PATH
unset LD_LIBRARY_PATH
./linuxdeployqt*.AppImage ./appdir/*.desktop -bundle-non-qt-libs
./linuxdeployqt*.AppImage ./appdir/*.desktop -appimage
chmod +x nheko-x86_64.AppImage

13
.ci/macos/deploy.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
# Add Qt binaries to path
PATH=/usr/local/opt/qt/bin/:${PATH}
cp -fp ./build/nheko dist/MacOS/Nheko.app/Contents/MacOS
sudo macdeployqt dist/MacOS/Nheko.app -dmg
user=$(id -nu)
sudo chown ${user} dist/MacOS/Nheko.dmg
mv dist/MacOS/Nheko.dmg .

View File

@ -1,13 +1,14 @@
---
Language: Cpp
Standard: Cpp11
AccessModifierOffset: -8
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: true
BasedOnStyle: Mozilla
BreakBeforeBraces: Linux
ColumnLimit: 100
IndentCaseLabels: false
IndentWidth: 8
KeepEmptyLinesAtTheStartOfBlocks: false
PointerAlignment: Right
Cpp11BracedListStyle: true

20
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,20 @@
<!--
If you want to request a feature or ask a question, feel free to remove all the irrelevant text.
-->
### System:
- Nheko commit/version:
- Operating System:
- Qt version:
- C++ compiler:
- Desktop Environment: <!-- for Linux -->
### Actual behavior
### Expected behavior
### Steps to reproduce
<!-- If the program crashed. -->
### Debugger traceback

View File

@ -25,5 +25,29 @@ before_script:
- cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
script:
- make -C build -j2
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/run-tests.sh; fi
- if [ $TRAVIS_OS_NAME == osx ]; then make lint; fi
- if [ $TRAVIS_OS_NAME == osx ]; then ./.ci/macos/deploy.sh; fi
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/run-tests.sh; fi
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/deploy.sh; fi
deploy:
- skip_cleanup: true
overwrite: true
provider: releases
api_key:
secure: oprXzESukFiXBeF2BXkXUlegsAQc95Ub4kc/OkoNFaYBvqpA+IGpWHmHCx5JPny/OT3Kc2Urpe2JUeGSWDHZ7UCKDjH+NzGP3uN82fHh/HiszG/Srw7+hWEHm1ve+gMK9GS8pr+yUsUrPP0UfVXlPoI4pBWa4zGi2Ndb/SqvjCgIHFLtGyoBo6CydKQ/AyWiXSMKDfJL+Dx4JLIPP4RTCBJy8ZrZ8m/a5Tgy4Ij6+djjrgYCZCEhGxSYw7xDIT/9SV8g9NkrbisqBDrILzAH8Yhe4XMRMXo88OAxV5+Vb9Rw1hrqczez6lpFDbJetv8MjofND+pSoAFwtjaL1wTFK9Ud6w4O9AuHlEQH9cGVdvsxFcosRwJVh58x51JM9ptoktqhx/HHJBTuCHCYYlHwtRwbwqnMYdLzKZG5FnujT8DG+9mcva1fL6tzW/XD505VPMWwXFC/2/pvolgAkTFFXYSALAwZlK3IgoXU8Gok/3B4iHofzQsFf6Yq3BI/88x7tVASUqiYhoKrO50+gb6pNIRCyWgGUiBEVXBp6Ziq3ORQPyQJg7i9HHUGTUu74yvGLHWLwjNQzZP/hxJZK3VlJxzyXntdOxiJc8iOzNrU+rPKBAlAaE6bQDOoniIysEgdD5BXHTLFzPvts4P1n2Ckor5/rNJ+qXR8GU+/y7e1GKU=
file: nheko-x86_64.AppImage
on:
condition: $TRAVIS_OS_NAME == linux
repo: mujx/nheko
tags: true
- skip_cleanup: true
overwrite: true
provider: releases
api_key:
secure: oprXzESukFiXBeF2BXkXUlegsAQc95Ub4kc/OkoNFaYBvqpA+IGpWHmHCx5JPny/OT3Kc2Urpe2JUeGSWDHZ7UCKDjH+NzGP3uN82fHh/HiszG/Srw7+hWEHm1ve+gMK9GS8pr+yUsUrPP0UfVXlPoI4pBWa4zGi2Ndb/SqvjCgIHFLtGyoBo6CydKQ/AyWiXSMKDfJL+Dx4JLIPP4RTCBJy8ZrZ8m/a5Tgy4Ij6+djjrgYCZCEhGxSYw7xDIT/9SV8g9NkrbisqBDrILzAH8Yhe4XMRMXo88OAxV5+Vb9Rw1hrqczez6lpFDbJetv8MjofND+pSoAFwtjaL1wTFK9Ud6w4O9AuHlEQH9cGVdvsxFcosRwJVh58x51JM9ptoktqhx/HHJBTuCHCYYlHwtRwbwqnMYdLzKZG5FnujT8DG+9mcva1fL6tzW/XD505VPMWwXFC/2/pvolgAkTFFXYSALAwZlK3IgoXU8Gok/3B4iHofzQsFf6Yq3BI/88x7tVASUqiYhoKrO50+gb6pNIRCyWgGUiBEVXBp6Ziq3ORQPyQJg7i9HHUGTUu74yvGLHWLwjNQzZP/hxJZK3VlJxzyXntdOxiJc8iOzNrU+rPKBAlAaE6bQDOoniIysEgdD5BXHTLFzPvts4P1n2Ckor5/rNJ+qXR8GU+/y7e1GKU=
file: Nheko.dmg
on:
condition: $TRAVIS_OS_NAME == osx
repo: mujx/nheko
tags: true

View File

@ -56,6 +56,7 @@ endif()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5Concurrent REQUIRED)
if (APPLE)
find_package(Qt5MacExtras REQUIRED)
@ -140,8 +141,8 @@ endif()
#
set(SRC_FILES
src/AvatarProvider.cc
src/ChatPage.cc
src/Cache.cc
src/ChatPage.cc
src/Deserializable.cc
src/EmojiCategory.cc
src/EmojiItemDelegate.cc
@ -150,9 +151,6 @@ set(SRC_FILES
src/EmojiProvider.cc
src/ImageItem.cc
src/ImageOverlayDialog.cc
src/TimelineItem.cc
src/TimelineView.cc
src/TimelineViewManager.cc
src/InputValidator.cc
src/JoinRoomDialog.cc
src/LeaveRoomDialog.cc
@ -162,34 +160,44 @@ set(SRC_FILES
src/MainWindow.cc
src/MatrixClient.cc
src/Profile.cc
src/RoomInfoListItem.cc
src/RoomMessages.cc
src/RoomList.cc
src/RoomState.cc
src/QuickSwitcher.cc
src/Register.cc
src/RegisterPage.cc
src/RoomInfoListItem.cc
src/RoomList.cc
src/RoomMessages.cc
src/RoomState.cc
src/SideBarActions.cc
src/UserSettingsPage.cc
src/Splitter.cc
src/Sync.cc
src/TextInputWidget.cc
src/TrayIcon.cc
src/TimelineItem.cc
src/TimelineView.cc
src/TimelineViewManager.cc
src/TopRoomBar.cc
src/TrayIcon.cc
src/TypingDisplay.cc
src/UserInfoWidget.cc
src/Versions.cc
src/WelcomePage.cc
src/QuickSwitcher.cc
src/main.cc
src/ui/Avatar.cc
src/ui/Badge.cc
src/ui/LoadingIndicator.cc
src/ui/FlatButton.cc
src/ui/FloatingButton.cc
src/ui/Label.cc
src/ui/OverlayModal.cc
src/ui/ScrollBar.cc
src/ui/SnackBar.cc
src/ui/RaisedButton.cc
src/ui/Ripple.cc
src/ui/RippleOverlay.cc
src/ui/OverlayWidget.cc
src/ui/TextField.cc
src/ui/ToggleButton.cc
src/ui/Theme.cc
src/ui/ThemeManager.cc
)
@ -234,38 +242,45 @@ qt5_wrap_cpp(MOC_HEADERS
include/EmojiItemDelegate.h
include/EmojiPanel.h
include/EmojiPickButton.h
include/ui/FloatingButton.h
include/ImageItem.h
include/ImageOverlayDialog.h
include/JoinRoomDialog.h
include/TimelineItem.h
include/TimelineView.h
include/TimelineViewManager.h
include/LeaveRoomDialog.h
include/LoginPage.h
include/LogoutDialog.h
include/MainWindow.h
include/MatrixClient.h
include/QuickSwitcher.h
include/RegisterPage.h
include/RoomInfoListItem.h
include/RoomList.h
include/SideBarActions.h
include/UserSettingsPage.h
include/Splitter.h
include/UserInfoWidget.h
include/TextInputWidget.h
include/TimelineItem.h
include/TimelineView.h
include/TimelineViewManager.h
include/TopRoomBar.h
include/TrayIcon.h
include/TextInputWidget.h
include/QuickSwitcher.h
include/TypingDisplay.h
include/UserInfoWidget.h
include/WelcomePage.h
include/ui/Avatar.h
include/ui/Badge.h
include/ui/LoadingIndicator.h
include/ui/FlatButton.h
include/ui/Label.h
include/ui/OverlayWidget.h
include/ui/ScrollBar.h
include/ui/SnackBar.h
include/ui/RaisedButton.h
include/ui/Ripple.h
include/ui/RippleOverlay.h
include/ui/TextField.h
include/ui/ToggleButton.h
include/ui/Theme.h
include/ui/ThemeManager.h
)
@ -297,9 +312,6 @@ add_library(matrix_events ${MATRIX_EVENTS} src/Deserializable.cc)
target_link_libraries(matrix_events Qt5::Core)
if (BUILD_TESTS)
#
# Build tests.
#
enable_testing()
find_package(GTest REQUIRED)
@ -317,16 +329,13 @@ if (BUILD_TESTS)
add_test(MatrixEvents events_test)
add_test(MatrixEventCollection event_collection_test)
add_test(MatrixMessageEvents message_events)
else()
#
# Build the executable.
#
if(APPVEYOR_BUILD)
set (NHEKO_LIBS matrix_events Qt5::Widgets Qt5::Network lmdb)
else()
set (NHEKO_LIBS matrix_events Qt5::Widgets Qt5::Network ${LMDB_LIBRARY})
endif()
if(APPVEYOR_BUILD)
set (NHEKO_LIBS matrix_events Qt5::Widgets Qt5::Network Qt5::Concurrent lmdb)
else()
set (NHEKO_LIBS matrix_events Qt5::Widgets Qt5::Network Qt5::Concurrent ${LMDB_LIBRARY})
endif()
set (NHEKO_DEPS ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC} ${LANG_QRC} ${QM_SRC} ${META_FILES_TO_INCLUDE})
if(APPLE)

View File

@ -9,7 +9,7 @@ debug:
@cmake --build build
release-debug:
@cmake -DBUILD_TESTS=OFF -H. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake --build build
test:
@ -17,6 +17,9 @@ test:
@cmake --build build
@cd build && GTEST_COLOR=1 ctest --verbose
linux-appimage:
@./.ci/linux/deploy.sh
app: release-debug $(APP_TEMPLATE)
@cp -fp ./build/$(APP_NAME) $(APP_TEMPLATE)/Contents/MacOS
@echo "Created '$(APP_NAME).app' in '$(APP_TEMPLATE)'"

View File

@ -12,25 +12,33 @@ feels more like a mainstream chat app ([Riot], Telegram etc) and less like an IR
### Features
Most of the features you would expect from a chat application are missing right now
but you can of course receive and send messages in the rooms that you are a member of.
but we are getting close to a more feature complete client.
Specifically there is support for:
- Joining & leaving rooms
- Sending & receiving images and emoji.
- Typing notifications.
### Installation
There are pre-built nigtly releases [here](https://github.com/mujx/nheko/releases/tag/nightly) for Linux ([AppImage](https://appimage.org/)), Mac and Windows.
#### Arch Linux
```bash
pacaur -S nheko-git
```
#### Fedora
```bash
sudo dnf copr enable xvitaly/matrix
sudo dnf install nheko
```
#### Gentoo Linux
```bash
sudo layman -a matrix
sudo emerge -a nheko
```
#### Windows
You can find a NSIS installer [here](https://ci.appveyor.com/project/mujx/nheko/branch/master/artifacts).
### Build Requirements
- Qt5 (5.7 or greater). Qt 5.7 adds support for color font rendering with
@ -95,15 +103,7 @@ make -C build
The `nheko` binary will be located in the `build` directory.
##### MacOS
You can create an app bundle with `make app`. The output will be located at
`dist/MacOS/Nheko.app` which can be copied to `/Applications/Nheko.app`.
You can also create a disk image with `make dmg`. The output will be located at
`dist/MacOS/Nheko.dmg`
##### Nix
#### Nix
Download the repo as mentioned above and run
@ -129,6 +129,7 @@ Here is a screen shot to get a feel for the UI, but things will probably change.
### Third party
- [Emoji One](http://emojione.com)
- [Font Awesome](http://fontawesome.io/)
- [Open Sans](https://fonts.google.com/specimen/Open+Sans)
[Matrix]:https://matrix.org

View File

@ -92,6 +92,17 @@ after_build:
- set PATH=%BUILD%\tools\bin;%PATH%
- binarycreator.exe -f -c installer\config\config.xml -p installer\packages %DIST%-installer.exe
deploy:
description: "Development builds"
provider: GitHub
auth_token:
secure: YqB7hcM+4482eSHhtVR7ZA7N7lE78y8BC897/7UDTBQd+NWdWFW/6S+oKDie9TT7
artifact: nheko_setup.exe
force_update: true
prerelease: true
on:
appveyor_repo_tag: true
artifacts:
- path: nheko_win_64.zip
- path: NhekoRelease\nheko.exe

View File

@ -18,12 +18,17 @@
#pragma once
#include <QImage>
#include <QObject>
#include <QSharedPointer>
#include <QUrl>
#include "MatrixClient.h"
#include "TimelineItem.h"
class MatrixClient;
class TimelineItem;
struct AvatarData
{
QImage img;
QUrl url;
};
class AvatarProvider : public QObject
{
@ -40,8 +45,8 @@ private:
static void updateAvatar(const QString &uid, const QImage &img);
static QSharedPointer<MatrixClient> client_;
static QMap<QString, QList<TimelineItem *>> toBeResolved_;
static QMap<QString, QImage> userAvatars_;
static QMap<QString, QUrl> avatarUrls_;
using UserID = QString;
static QMap<UserID, AvatarData> avatars_;
static QMap<UserID, QList<TimelineItem *>> toBeResolved_;
};

View File

@ -20,7 +20,7 @@
#include <QDir>
#include <lmdb++.h>
#include "RoomState.h"
class RoomState;
class Cache
{
@ -33,11 +33,11 @@ public:
QString nextBatchToken() const;
QMap<QString, RoomState> states();
inline void deleteData();
inline void unmount();
inline QString memberDbName(const QString &roomid);
void deleteData();
void unmount() { isMounted_ = false; };
void removeRoom(const QString &roomid);
void setup();
private:
void setNextBatchToken(lmdb::txn &txn, const QString &token);
@ -52,22 +52,3 @@ private:
QString userId_;
QString cacheDirectory_;
};
inline void
Cache::unmount()
{
isMounted_ = false;
}
inline QString
Cache::memberDbName(const QString &roomid)
{
return QString("m.%1").arg(roomid);
}
inline void
Cache::deleteData()
{
if (!cacheDirectory_.isEmpty())
QDir(cacheDirectory_).removeRecursively();
}

View File

@ -17,21 +17,37 @@
#pragma once
#include <QHBoxLayout>
#include <QMap>
#include <QPixmap>
#include <QTimer>
#include <QWidget>
#include "Cache.h"
#include "MatrixClient.h"
#include "QuickSwitcher.h"
#include "RoomList.h"
#include "RoomSettings.h"
#include "RoomState.h"
#include "Splitter.h"
#include "TextInputWidget.h"
#include "TimelineViewManager.h"
#include "TopRoomBar.h"
#include "UserInfoWidget.h"
#include "MemberEventContent.h"
#include "MessageEvent.h"
#include "StateEvent.h"
class Cache;
class MatrixClient;
class OverlayModal;
class QuickSwitcher;
class RoomList;
class RoomSettings;
class RoomState;
class SideBarActions;
class Splitter;
class SyncResponse;
class TextInputWidget;
class TimelineViewManager;
class TopRoomBar;
class TypingDisplay;
class UserInfoWidget;
class JoinedRoom;
class LeftRoom;
constexpr int CONSENSUS_TIMEOUT = 1000;
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
class ChatPage : public QWidget
{
@ -43,12 +59,16 @@ public:
// Initialize all the components of the UI.
void bootstrap(QString userid, QString homeserver, QString token);
void showQuickSwitcher();
signals:
void contentLoaded();
void close();
void changeWindowTitle(const QString &msg);
void unreadMessages(int count);
void showNotification(const QString &msg);
void showLoginPage(const QString &msg);
void showUserSettingsPage();
private slots:
void showUnreadMessageNotification(int count);
@ -59,18 +79,32 @@ private slots:
void syncCompleted(const SyncResponse &response);
void syncFailed(const QString &msg);
void changeTopRoomInfo(const QString &room_id);
void startSync();
void logout();
void addRoom(const QString &room_id);
void removeRoom(const QString &room_id);
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
void updateDisplayNames(const RoomState &state);
using UserID = QString;
using RoomStates = QMap<UserID, RoomState>;
using JoinedRooms = QMap<UserID, JoinedRoom>;
using LeftRooms = QMap<UserID, LeftRoom>;
using Membership = matrix::events::StateEvent<matrix::events::MemberEventContent>;
using Memberships = QMap<UserID, Membership>;
void removeLeftRooms(const LeftRooms &rooms);
void updateJoinedRooms(const JoinedRooms &rooms);
Memberships getMemberships(const QJsonArray &events) const;
RoomStates generateMembershipDifference(const JoinedRooms &rooms,
const RoomStates &states) const;
void updateTypingUsers(const QString &roomid, const QList<QString> &user_ids);
void updateUserMetadata(const QJsonArray &events);
void updateUserDisplayName(const Membership &event);
void updateUserAvatarUrl(const Membership &event);
void loadStateFromCache();
void showQuickSwitcher();
void deleteConfigs();
void resetUI();
QHBoxLayout *topLayout_;
Splitter *splitter;
@ -89,12 +123,15 @@ private:
RoomList *room_list_;
TimelineViewManager *view_manager_;
SideBarActions *sidebarActions_;
TopRoomBar *top_bar_;
TextInputWidget *text_input_;
TypingDisplay *typingDisplay_;
QTimer *sync_timer_;
int sync_interval_;
// Safety net if consensus is not possible or too slow.
QTimer *showContentTimer_;
QTimer *consensusTimer_;
QString current_room_;
QMap<QString, QPixmap> room_avatars_;
@ -104,12 +141,20 @@ private:
QMap<QString, RoomState> state_manager_;
QMap<QString, QSharedPointer<RoomSettings>> settingsManager_;
QuickSwitcher *quickSwitcher_ = nullptr;
OverlayModal *quickSwitcherModal_ = nullptr;
// Keeps track of the users currently typing on each room.
QMap<QString, QList<QString>> typingUsers_;
QTimer *typingRefresher_;
QSharedPointer<QuickSwitcher> quickSwitcher_;
QSharedPointer<OverlayModal> quickSwitcherModal_;
// Matrix Client API provider.
QSharedPointer<MatrixClient> client_;
// LMDB wrapper.
QSharedPointer<Cache> cache_;
// If the number of failures exceeds a certain threshold we
// return to the login page.
int initialSyncFailures = 0;
};

View File

@ -4,70 +4,70 @@
//
// Font sizes are in pixels.
namespace conf
{
namespace conf {
// Global settings.
static const int fontSize = 12;
static const int emojiSize = 14;
static const int headerFontSize = 21;
static constexpr int fontSize = 12;
static constexpr int textInputFontSize = 14;
static constexpr int emojiSize = 14;
static constexpr int headerFontSize = 21;
static constexpr int typingNotificationFontSize = 11;
// Window geometry.
namespace window
{
static const int height = 600;
static const int width = 1066;
namespace window {
static constexpr int height = 600;
static constexpr int width = 1066;
static const int minHeight = 600;
static const int minWidth = 950;
static constexpr int minHeight = height;
static constexpr int minWidth = 950;
} // namespace window
namespace textInput {
static constexpr int height = 50;
}
namespace sidebarActions {
static constexpr int height = textInput::height;
static constexpr int iconSize = 28;
}
// Button settings.
namespace btn
{
static const int fontSize = 20;
static const int cornerRadius = 3;
}
namespace btn {
static constexpr int fontSize = 20;
static constexpr int cornerRadius = 3;
} // namespace btn
// RoomList specific.
namespace roomlist
{
namespace fonts
{
static const int heading = 13;
static const int badge = 10;
static const int bubble = 20;
namespace roomlist {
namespace fonts {
static constexpr int heading = 13;
static constexpr int badge = 10;
static constexpr int bubble = 20;
} // namespace fonts
} // namespace roomlist
namespace userInfoWidget
{
namespace fonts
{
static const int displayName = 16;
static const int userid = 14;
namespace userInfoWidget {
namespace fonts {
static constexpr int displayName = 16;
static constexpr int userid = 14;
} // namespace fonts
} // namespace userInfoWidget
namespace topRoomBar
{
namespace fonts
{
static const int roomName = 15;
static const int roomDescription = 13;
namespace topRoomBar {
namespace fonts {
static constexpr int roomName = 15;
static constexpr int roomDescription = 13;
} // namespace fonts
} // namespace topRoomBar
namespace timeline
{
static const int msgMargin = 11;
static const int avatarSize = 36;
static const int headerSpacing = 5;
static const int headerLeftMargin = 15;
namespace timeline {
static constexpr int msgMargin = 11;
static constexpr int avatarSize = 36;
static constexpr int headerSpacing = 5;
static constexpr int headerLeftMargin = 15;
namespace fonts
{
static const int timestamp = 9;
}
}
namespace fonts {
static constexpr int timestamp = 9;
} // namespace fonts
} // namespace timeline
} // namespace conf

View File

@ -21,7 +21,6 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
class DeserializationException : public std::exception
{

View File

@ -17,15 +17,14 @@
#pragma once
#include <QHBoxLayout>
#include <QLabel>
#include <QLayout>
#include <QListView>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QWidget>
#include "EmojiItemDelegate.h"
#include "EmojiProvider.h"
class EmojiProvider;
class EmojiCategory : public QWidget
{
@ -39,7 +38,10 @@ signals:
void emojiSelected(const QString &emoji);
private slots:
inline void clickIndex(const QModelIndex &);
void clickIndex(const QModelIndex &index)
{
emit emojiSelected(index.data(Qt::UserRole).toString());
};
private:
QVBoxLayout *mainLayout_;
@ -52,9 +54,3 @@ private:
QLabel *category_;
};
inline void
EmojiCategory::clickIndex(const QModelIndex &index)
{
emit emojiSelected(index.data(Qt::UserRole).toString());
}

View File

@ -20,11 +20,11 @@
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QScrollArea>
#include <QWidget>
#include "EmojiCategory.h"
#include "EmojiProvider.h"
class EmojiCategory;
class EmojiPanel : public QWidget
{
Q_OBJECT

View File

@ -20,9 +20,10 @@
#include <QEvent>
#include <QWidget>
#include "EmojiPanel.h"
#include "FlatButton.h"
class EmojiPanel;
class EmojiPickButton : public FlatButton
{
Q_OBJECT
@ -43,5 +44,5 @@ private:
// Horizontal distance from panel's bottom right corner.
int horizontal_distance_ = 70;
EmojiPanel *panel_;
QSharedPointer<EmojiPanel> panel_;
};

View File

@ -17,11 +17,10 @@
#pragma once
#include <QFile>
#include <QList>
#include <QMap>
struct Emoji {
struct Emoji
{
// Unicode code.
QString unicode;
// Keyboard shortcut e.g :emoji:

View File

@ -24,6 +24,7 @@
#include "Image.h"
#include "MatrixClient.h"
#include "MessageEvent.h"
namespace events = matrix::events;
namespace msgs = matrix::events::messages;

View File

@ -17,7 +17,6 @@
#pragma once
#include <QRegExp>
#include <QRegExpValidator>
class InputValidator

View File

@ -3,7 +3,7 @@
#include <QFrame>
#include <QLineEdit>
#include "FlatButton.h"
class FlatButton;
class JoinRoomDialog : public QFrame
{

View File

@ -2,7 +2,7 @@
#include <QFrame>
#include "FlatButton.h"
class FlatButton;
class LeaveRoomDialog : public QFrame
{

View File

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

View File

@ -17,18 +17,17 @@
#pragma once
#include <QHBoxLayout>
#include <QLabel>
#include <QLayout>
#include <QSharedPointer>
#include <QVBoxLayout>
#include <QWidget>
#include "FlatButton.h"
#include "LoadingIndicator.h"
#include "MatrixClient.h"
#include "OverlayModal.h"
#include "RaisedButton.h"
#include "TextField.h"
class FlatButton;
class LoadingIndicator;
class MatrixClient;
class OverlayModal;
class RaisedButton;
class TextField;
class LoginPage : public QWidget
{
@ -43,6 +42,10 @@ public:
signals:
void backButtonClicked();
public slots:
// Displays errors produced during the login.
void loginError(QString error_message);
private slots:
// Callback for the back button.
void onBackButtonClicked();
@ -56,9 +59,6 @@ private slots:
// Callback for probing the manually entered server
void onServerAddressEntered();
// Displays errors produced during the login.
void loginError(QString error_message);
// Callback for errors produced during server probing
void versionError(QString error_message);

View File

@ -19,7 +19,7 @@
#include <QFrame>
#include "FlatButton.h"
class FlatButton;
class LogoutDialog : public QFrame
{

View File

@ -19,15 +19,20 @@
#include <QMainWindow>
#include <QSharedPointer>
#include <QStackedWidget>
#include <QSystemTrayIcon>
#include "ChatPage.h"
#include "LoadingIndicator.h"
#include "LoginPage.h"
#include "MatrixClient.h"
#include "OverlayModal.h"
#include "RegisterPage.h"
#include "TrayIcon.h"
#include "WelcomePage.h"
class ChatPage;
class LoadingIndicator;
class LoginPage;
class MatrixClient;
class OverlayModal;
class RegisterPage;
class SnackBar;
class TrayIcon;
class UserSettingsPage;
class UserSettings;
class WelcomePage;
class MainWindow : public QMainWindow
{
@ -55,6 +60,7 @@ private slots:
// Show the register page in the main window.
void showRegisterPage();
void showUserSettingsPage();
// Show the chat page and start communicating with the given access token.
void showChatPage(QString user_id, QString home_server, QString token);
@ -81,14 +87,19 @@ private:
// The main chat area.
ChatPage *chat_page_;
UserSettingsPage *userSettingsPage_;
QSharedPointer<UserSettings> userSettings_;
// Used to hide undefined states between page transitions.
OverlayModal *progress_modal_;
LoadingIndicator *spinner_;
QSharedPointer<OverlayModal> progressModal_;
QSharedPointer<LoadingIndicator> spinner_;
// Matrix Client API provider.
QSharedPointer<MatrixClient> client_;
// Tray icon that shows the unread message count.
TrayIcon *trayIcon_;
// Notifications display.
QSharedPointer<SnackBar> snackBar_;
};

View File

@ -17,12 +17,14 @@
#pragma once
#include <QtNetwork/QNetworkAccessManager>
#include <QNetworkAccessManager>
#include <QUrl>
#include "MessageEvent.h"
#include "Profile.h"
#include "RoomMessages.h"
#include "Sync.h"
class SyncResponse;
class Profile;
class RoomMessages;
/*
* MatrixClient provides the high level API to communicate with
@ -50,14 +52,16 @@ public:
void fetchUserAvatar(const QString &userId, const QUrl &avatarUrl);
void fetchOwnAvatar(const QUrl &avatar_url);
void downloadImage(const QString &event_id, const QUrl &url);
void messages(const QString &room_id, const QString &from_token, int limit = 20) noexcept;
void messages(const QString &room_id, const QString &from_token, int limit = 30) noexcept;
void uploadImage(const QString &roomid, const QString &filename);
void joinRoom(const QString &roomIdOrAlias);
void leaveRoom(const QString &roomId);
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
void removeTypingNotification(const QString &roomid);
inline QUrl getHomeServer();
inline int transactionId();
inline void incrementTransactionId();
QUrl getHomeServer() { return server_; };
int transactionId() { return txn_id_; };
void incrementTransactionId() { txn_id_ += 1; };
void reset() noexcept;
@ -65,9 +69,12 @@ public slots:
void getOwnProfile() noexcept;
void logout() noexcept;
inline void setServer(const QString &server);
inline void setAccessToken(const QString &token);
inline void setNextBatchToken(const QString &next_batch);
void setServer(const QString &server)
{
server_ = QUrl(QString("https://%1").arg(server));
};
void setAccessToken(const QString &token) { token_ = token; };
void setNextBatchToken(const QString &next_batch) { next_batch_ = next_batch; };
signals:
void loginError(const QString &error);
@ -91,56 +98,17 @@ signals:
// Returned profile data for the user's account.
void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name);
void initialSyncCompleted(const SyncResponse &response);
void initialSyncFailed(const QString &msg);
void syncCompleted(const SyncResponse &response);
void syncFailed(const QString &msg);
void joinFailed(const QString &msg);
void messageSent(const QString &event_id, const QString &roomid, const int txn_id);
void emoteSent(const QString &event_id, const QString &roomid, const int txn_id);
void messagesRetrieved(const QString &room_id, const RoomMessages &msgs);
void joinedRoom(const QString &room_id);
void leftRoom(const QString &room_id);
private slots:
void onResponse(QNetworkReply *reply);
private:
enum class Endpoint {
GetOwnAvatar,
GetOwnProfile,
GetProfile,
Image,
InitialSync,
ImageUpload,
Login,
Logout,
Messages,
Register,
RoomAvatar,
SendRoomMessage,
Sync,
UserAvatar,
Versions,
JoinRoom,
LeaveRoom,
};
// Response handlers.
void onGetOwnAvatarResponse(QNetworkReply *reply);
void onGetOwnProfileResponse(QNetworkReply *reply);
void onImageResponse(QNetworkReply *reply);
void onInitialSyncResponse(QNetworkReply *reply);
void onImageUploadResponse(QNetworkReply *reply);
void onLoginResponse(QNetworkReply *reply);
void onLogoutResponse(QNetworkReply *reply);
void onMessagesResponse(QNetworkReply *reply);
void onRegisterResponse(QNetworkReply *reply);
void onRoomAvatarResponse(QNetworkReply *reply);
void onSendRoomMessage(QNetworkReply *reply);
void onSyncResponse(QNetworkReply *reply);
void onUserAvatarResponse(QNetworkReply *reply);
void onVersionsResponse(QNetworkReply *reply);
void onJoinRoomResponse(QNetworkReply *reply);
void onLeaveRoomResponse(QNetworkReply *reply);
// Client API prefix.
QString clientApiUrl_;
@ -159,39 +127,3 @@ private:
// Token to be used for the next sync.
QString next_batch_;
};
inline QUrl
MatrixClient::getHomeServer()
{
return server_;
}
inline int
MatrixClient::transactionId()
{
return txn_id_;
}
inline void
MatrixClient::setServer(const QString &server)
{
server_ = QUrl(QString("https://%1").arg(server));
}
inline void
MatrixClient::setAccessToken(const QString &token)
{
token_ = token;
}
inline void
MatrixClient::setNextBatchToken(const QString &next_batch)
{
next_batch_ = next_batch;
}
inline void
MatrixClient::incrementTransactionId()
{
txn_id_ += 1;
}

View File

@ -20,29 +20,17 @@
#include <QJsonDocument>
#include <QUrl>
#include "Deserializable.h"
class Deserializable;
class ProfileResponse : public Deserializable
{
public:
void deserialize(const QJsonDocument &data) override;
inline QUrl getAvatarUrl();
inline QString getDisplayName();
QUrl getAvatarUrl() { return avatar_url_; };
QString getDisplayName() { return display_name_; };
private:
QUrl avatar_url_;
QString display_name_;
};
inline QUrl
ProfileResponse::getAvatarUrl()
{
return avatar_url_;
}
inline QString
ProfileResponse::getDisplayName()
{
return display_name_;
}

View File

@ -19,7 +19,7 @@
#include <QJsonDocument>
#include "Deserializable.h"
class Deserializable;
class RegisterRequest
{
@ -29,55 +29,25 @@ public:
QByteArray serialize() noexcept;
inline void setPassword(QString password);
inline void setUser(QString username);
void setPassword(QString password) { password_ = password; };
void setUser(QString username) { user_ = username; };
private:
QString user_;
QString password_;
};
inline void
RegisterRequest::setPassword(QString password)
{
password_ = password;
}
inline void
RegisterRequest::setUser(QString username)
{
user_ = username;
}
class RegisterResponse : public Deserializable
{
public:
void deserialize(const QJsonDocument &data) override;
inline QString getAccessToken();
inline QString getHomeServer();
inline QString getUserId();
QString getAccessToken() { return access_token_; };
QString getHomeServer() { return home_server_; };
QString getUserId() { return user_id_; };
private:
QString access_token_;
QString home_server_;
QString user_id_;
};
inline QString
RegisterResponse::getAccessToken()
{
return access_token_;
}
inline QString
RegisterResponse::getHomeServer()
{
return home_server_;
}
inline QString
RegisterResponse::getUserId()
{
return user_id_;
}

View File

@ -17,17 +17,15 @@
#pragma once
#include <QHBoxLayout>
#include <QLabel>
#include <QLayout>
#include <QSharedPointer>
#include <QVBoxLayout>
#include <QWidget>
#include "Avatar.h"
#include "FlatButton.h"
#include "MatrixClient.h"
#include "RaisedButton.h"
#include "TextField.h"
class Avatar;
class FlatButton;
class MatrixClient;
class RaisedButton;
class TextField;
class RegisterPage : public QWidget
{

View File

@ -21,12 +21,14 @@
#include <QSharedPointer>
#include <QWidget>
#include "Menu.h"
#include "RippleOverlay.h"
#include "RoomSettings.h"
#include "RoomState.h"
struct DescInfo {
class Menu;
class RippleOverlay;
class RoomSettings;
struct DescInfo
{
QString username;
QString userid;
QString body;
@ -49,11 +51,12 @@ public:
void clearUnreadMessageCount();
void setState(const RoomState &state);
inline bool isPressed() const;
inline RoomState state() const;
inline void setAvatar(const QImage &avatar_image);
inline int unreadMessageCount() const;
inline void setDescriptionMessage(const DescInfo &info);
bool isPressed() const { return isPressed_; };
RoomState state() const { return state_; };
int unreadMessageCount() const { return unreadMsgCount_; };
void setAvatar(const QImage &avatar_image);
void setDescriptionMessage(const DescInfo &info);
signals:
void clicked(const QString &room_id);
@ -96,36 +99,3 @@ private:
int maxHeight_;
int unreadMsgCount_ = 0;
};
inline int
RoomInfoListItem::unreadMessageCount() const
{
return unreadMsgCount_;
}
inline bool
RoomInfoListItem::isPressed() const
{
return isPressed_;
}
inline RoomState
RoomInfoListItem::state() const
{
return state_;
}
inline void
RoomInfoListItem::setAvatar(const QImage &img)
{
roomAvatar_ = QPixmap::fromImage(
img.scaled(IconSize, IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
update();
}
inline void
RoomInfoListItem::setDescriptionMessage(const DescInfo &info)
{
lastMsgInfo_ = info;
update();
}

View File

@ -17,19 +17,22 @@
#pragma once
#include <QMap>
#include <QPushButton>
#include <QScrollArea>
#include <QSharedPointer>
#include <QVBoxLayout>
#include <QWidget>
#include "JoinRoomDialog.h"
#include "LeaveRoomDialog.h"
#include "MatrixClient.h"
#include "OverlayModal.h"
#include "RoomInfoListItem.h"
#include "RoomState.h"
#include "Sync.h"
class JoinRoomDialog;
class LeaveRoomDialog;
class MatrixClient;
class OverlayModal;
class RoomInfoListItem;
class RoomSettings;
class RoomState;
class Sync;
struct DescInfo;
class RoomList : public QWidget
{
@ -76,8 +79,8 @@ private:
OverlayModal *joinRoomModal_;
JoinRoomDialog *joinRoomDialog_;
OverlayModal *leaveRoomModal;
LeaveRoomDialog *leaveRoomDialog_;
QSharedPointer<OverlayModal> leaveRoomModal_;
QSharedPointer<LeaveRoomDialog> leaveRoomDialog_;
QMap<QString, QSharedPointer<RoomInfoListItem>> rooms_;

View File

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

View File

@ -35,10 +35,7 @@ public:
settings.setValue(path_, isNotificationsEnabled_);
};
bool isNotificationsEnabled()
{
return isNotificationsEnabled_;
};
bool isNotificationsEnabled() { return isNotificationsEnabled_; };
void toggleNotifications()
{

View File

@ -41,6 +41,9 @@ namespace events = matrix::events;
class RoomState
{
public:
RoomState();
RoomState(const QJsonArray &events);
// Calculate room data that are not immediatly accessible. Like room name and
// avatar.
//
@ -49,9 +52,9 @@ public:
void resolveAvatar();
void parse(const QJsonObject &object);
inline QUrl getAvatar() const;
inline QString getName() const;
inline QString getTopic() const;
QUrl getAvatar() const { return avatar_; };
QString getName() const { return name_; };
QString getTopic() const { return topic.content().topic().simplified(); };
void removeLeaveMemberships();
void update(const RoomState &state);
@ -71,7 +74,8 @@ public:
events::StateEvent<events::TopicEventContent> topic;
// Contains the m.room.member events for all the joined users.
QMap<QString, events::StateEvent<events::MemberEventContent>> memberships;
using UserID = QString;
QMap<UserID, events::StateEvent<events::MemberEventContent>> memberships;
private:
QUrl avatar_;
@ -81,21 +85,3 @@ private:
// avatar event this should be empty.
QString userAvatar_;
};
inline QString
RoomState::getTopic() const
{
return topic.content().topic().simplified();
}
inline QString
RoomState::getName() const
{
return name_;
}
inline QUrl
RoomState::getAvatar() const
{
return avatar_;
}

29
include/SideBarActions.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <QHBoxLayout>
#include <QResizeEvent>
#include <QWidget>
#include "FlatButton.h"
class SideBarActions : public QWidget
{
Q_OBJECT
public:
SideBarActions(QWidget *parent = nullptr);
~SideBarActions();
signals:
void showSettings();
protected:
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *layout_;
FlatButton *settingsBtn_;
FlatButton *createRoomBtn_;
FlatButton *joinRoomBtn_;
};

View File

@ -18,24 +18,22 @@
#pragma once
#include <QJsonArray>
#include <QJsonDocument>
#include <QMap>
#include <QString>
#include "Deserializable.h"
class Event : public Deserializable
{
public:
inline QJsonObject content() const;
inline QJsonObject unsigned_content() const;
QJsonObject content() const { return content_; };
QJsonObject unsigned_content() const { return unsigned_; };
inline QString sender() const;
inline QString state_key() const;
inline QString type() const;
inline QString eventId() const;
QString sender() const { return sender_; };
QString state_key() const { return state_key_; };
QString type() const { return type_; };
QString eventId() const { return event_id_; };
inline uint64_t timestamp() const;
uint64_t timestamp() const { return origin_server_ts_; };
void deserialize(const QJsonValue &data) override;
@ -51,70 +49,22 @@ private:
uint64_t origin_server_ts_;
};
inline QJsonObject
Event::content() const
{
return content_;
}
inline QJsonObject
Event::unsigned_content() const
{
return unsigned_;
}
inline QString
Event::sender() const
{
return sender_;
}
inline QString
Event::state_key() const
{
return state_key_;
}
inline QString
Event::type() const
{
return type_;
}
inline QString
Event::eventId() const
{
return event_id_;
}
inline uint64_t
Event::timestamp() const
{
return origin_server_ts_;
}
class State : public Deserializable
{
public:
void deserialize(const QJsonValue &data) override;
inline QJsonArray events() const;
QJsonArray events() const { return events_; };
private:
QJsonArray events_;
};
inline QJsonArray
State::events() const
{
return events_;
}
class Timeline : public Deserializable
{
public:
inline QJsonArray events() const;
inline QString previousBatch() const;
inline bool limited() const;
QJsonArray events() const { return events_; };
QString previousBatch() const { return prev_batch_; };
bool limited() const { return limited_; };
void deserialize(const QJsonValue &data) override;
@ -124,58 +74,29 @@ private:
bool limited_;
};
inline QJsonArray
Timeline::events() const
{
return events_;
}
inline QString
Timeline::previousBatch() const
{
return prev_batch_;
}
inline bool
Timeline::limited() const
{
return limited_;
}
// TODO: Add support for ehpmeral, account_data, undread_notifications
// TODO: Add support for account_data, undread_notifications
class JoinedRoom : public Deserializable
{
public:
inline State state() const;
inline Timeline timeline() const;
State state() const { return state_; };
Timeline timeline() const { return timeline_; };
QList<QString> typingUserIDs() const { return typingUserIDs_; };
void deserialize(const QJsonValue &data) override;
private:
State state_;
Timeline timeline_;
/* Ephemeral ephemeral_; */
QList<QString> typingUserIDs_;
/* AccountData account_data_; */
/* UnreadNotifications unread_notifications_; */
};
inline State
JoinedRoom::state() const
{
return state_;
}
inline Timeline
JoinedRoom::timeline() const
{
return timeline_;
}
class LeftRoom : public Deserializable
{
public:
inline State state() const;
inline Timeline timeline() const;
State state() const { return state_; };
Timeline timeline() const { return timeline_; };
void deserialize(const QJsonValue &data) override;
@ -184,24 +105,12 @@ private:
Timeline timeline_;
};
inline State
LeftRoom::state() const
{
return state_;
}
inline Timeline
LeftRoom::timeline() const
{
return timeline_;
}
// TODO: Add support for invited and left rooms.
class Rooms : public Deserializable
{
public:
inline QMap<QString, JoinedRoom> join() const;
inline QMap<QString, LeftRoom> leave() const;
QMap<QString, JoinedRoom> join() const { return join_; };
QMap<QString, LeftRoom> leave() const { return leave_; };
void deserialize(const QJsonValue &data) override;
private:
@ -209,38 +118,14 @@ private:
QMap<QString, LeftRoom> leave_;
};
inline QMap<QString, JoinedRoom>
Rooms::join() const
{
return join_;
}
inline QMap<QString, LeftRoom>
Rooms::leave() const
{
return leave_;
}
class SyncResponse : public Deserializable
{
public:
void deserialize(const QJsonDocument &data) override;
inline QString nextBatch() const;
inline Rooms rooms() const;
QString nextBatch() const { return next_batch_; };
Rooms rooms() const { return rooms_; };
private:
QString next_batch_;
Rooms rooms_;
};
inline Rooms
SyncResponse::rooms() const
{
return rooms_;
}
inline QString
SyncResponse::nextBatch() const
{
return next_batch_;
}

View File

@ -17,6 +17,8 @@
#pragma once
#include <deque>
#include <QHBoxLayout>
#include <QPaintEvent>
#include <QTextEdit>
@ -29,17 +31,36 @@
namespace msgs = matrix::events::messages;
static const QString EMOTE_COMMAND("/me ");
class FilteredTextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit FilteredTextEdit(QWidget *parent = nullptr);
void keyPressEvent(QKeyEvent *event);
void stopTyping();
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
void submit();
signals:
void enterPressed();
void startedTyping();
void stoppedTyping();
void message(QString);
void command(QString name, QString args);
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
std::deque<QString> true_history_, working_history_;
size_t history_index_;
QTimer *typingTimer_;
void textChanged();
void afterCompletion(int);
};
class TextInputWidget : public QFrame
@ -50,11 +71,12 @@ public:
TextInputWidget(QWidget *parent = 0);
~TextInputWidget();
void stopTyping();
public slots:
void onSendButtonClicked();
void openFileSelection();
void hideUploadSpinner();
inline void focusLineEdit();
void focusLineEdit() { input_->setFocus(); };
private slots:
void addSelectedEmoji(const QString &emoji);
@ -63,10 +85,17 @@ signals:
void sendTextMessage(QString msg);
void sendEmoteMessage(QString msg);
void uploadImage(QString filename);
void sendJoinRoomRequest(const QString &room);
void startedTyping();
void stoppedTyping();
protected:
void focusInEvent(QFocusEvent *event);
private:
void showUploadSpinner();
QString parseEmoteCommand(const QString &cmd);
void command(QString name, QString args);
QHBoxLayout *topLayout_;
FilteredTextEdit *input_;
@ -77,9 +106,3 @@ private:
FlatButton *sendMessageBtn_;
EmojiPickButton *emojiBtn_;
};
inline void
TextInputWidget::focusLineEdit()
{
input_->setFocus();
}

View File

@ -19,12 +19,7 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QWidget>
#include "ImageItem.h"
#include "Sync.h"
#include "Avatar.h"
#include "Emote.h"
#include "Image.h"
#include "MessageEvent.h"
@ -32,6 +27,9 @@
#include "RoomInfoListItem.h"
#include "Text.h"
class ImageItem;
class Avatar;
namespace events = matrix::events;
namespace msgs = matrix::events::messages;
@ -65,7 +63,7 @@ public:
QWidget *parent);
void setUserAvatar(const QImage &pixmap);
inline DescInfo descriptionMessage() const;
DescInfo descriptionMessage() const { return descriptionMsg_; };
~TimelineItem();
@ -98,9 +96,3 @@ private:
QLabel *userName_;
QLabel *body_;
};
inline DescInfo
TimelineItem::descriptionMessage() const
{
return descriptionMsg_;
}

View File

@ -17,29 +17,31 @@
#pragma once
#include <QHBoxLayout>
#include <QLayout>
#include <QList>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
#include "ScrollBar.h"
#include "Sync.h"
#include "TimelineItem.h"
#include "Emote.h"
#include "Image.h"
#include "MessageEvent.h"
#include "Notice.h"
#include "RoomInfoListItem.h"
#include "Text.h"
class FloatingButton;
class MatrixClient;
class RoomMessages;
class ScrollBar;
class Timeline;
class TimelineItem;
struct DescInfo;
namespace msgs = matrix::events::messages;
namespace events = matrix::events;
// Contains info about a message shown in the history view
// but not yet confirmed by the homeserver through sync.
struct PendingMessage {
struct PendingMessage
{
int txn_id;
QString body;
QString event_id;
@ -50,12 +52,12 @@ struct PendingMessage {
, body(body)
, event_id(event_id)
, widget(widget)
{
}
{}
};
// In which place new TimelineItems should be inserted.
enum class TimelineDirection {
enum class TimelineDirection
{
Top,
Bottom,
};
@ -97,6 +99,9 @@ public slots:
// Add old events at the top of the timeline.
void addBackwardsEvents(const QString &room_id, const RoomMessages &msgs);
// Whether or not the initial batch has been loaded.
bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; };
signals:
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
@ -116,7 +121,7 @@ private:
const QString &userid);
void removePendingMessage(const QString &eventid, const QString &body);
inline bool isDuplicate(const QString &event_id);
bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); };
// Return nullptr if the event couldn't be parsed.
TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction);
@ -137,12 +142,11 @@ private:
bool isPaginationInProgress_ = false;
// Keeps track whether or not the user has visited the view.
bool isInitialized = false;
bool isTimelineFinished = false;
bool isInitialSync = true;
bool isPaginationScrollPending_ = false;
bool isInitialized = false;
bool isTimelineFinished = false;
bool isInitialSync = true;
const int SCROLL_BAR_GAP = 400;
const int SCROLL_BAR_GAP = 200;
QTimer *paginationTimer_;
@ -152,14 +156,12 @@ private:
int oldPosition_;
int oldHeight_;
FloatingButton *scrollDownBtn_;
TimelineDirection lastMessageDirection_;
// The events currently rendered. Used for duplicate detection.
QMap<QString, bool> eventIds_;
QList<PendingMessage> pending_msgs_;
QSharedPointer<MatrixClient> client_;
};
inline bool
TimelineView::isDuplicate(const QString &event_id)
{
return eventIds_.contains(event_id);
}

View File

@ -17,16 +17,16 @@
#pragma once
#include <QDebug>
#include <QMap>
#include <QSharedPointer>
#include <QStackedWidget>
#include <QWidget>
#include "MatrixClient.h"
#include "MessageEvent.h"
#include "RoomInfoListItem.h"
#include "Sync.h"
#include "TimelineView.h"
class JoinedRoom;
class MatrixClient;
class RoomInfoListItem;
class Rooms;
class TimelineView;
struct DescInfo;
class TimelineViewManager : public QStackedWidget
{
@ -47,6 +47,9 @@ public:
void sync(const Rooms &rooms);
void clearAll();
// Check if all the timelines have been loaded.
bool hasLoaded() const;
static QString chooseRandomColor();
static QString displayName(const QString &userid);

View File

@ -18,21 +18,21 @@
#pragma once
#include <QAction>
#include <QDebug>
#include <QIcon>
#include <QImage>
#include <QLabel>
#include <QMenu>
#include <QPaintEvent>
#include <QSharedPointer>
#include <QVBoxLayout>
#include <QWidget>
#include "Avatar.h"
#include "FlatButton.h"
#include "LeaveRoomDialog.h"
#include "Menu.h"
#include "OverlayModal.h"
#include "RoomSettings.h"
class Avatar;
class FlatButton;
class Label;
class LeaveRoomDialog;
class Menu;
class OverlayModal;
class RoomSettings;
static const QString URL_HTML = "<a href=\"\\1\" style=\"color: #333333\">\\1</a>";
static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)");
@ -44,10 +44,10 @@ public:
TopRoomBar(QWidget *parent = 0);
~TopRoomBar();
inline void updateRoomAvatar(const QImage &avatar_image);
inline void updateRoomAvatar(const QIcon &icon);
inline void updateRoomName(const QString &name);
inline void updateRoomTopic(QString topic);
void updateRoomAvatar(const QImage &avatar_image);
void updateRoomAvatar(const QIcon &icon);
void updateRoomName(const QString &name);
void updateRoomTopic(QString topic);
void updateRoomAvatarFromName(const QString &name);
void setRoomSettings(QSharedPointer<RoomSettings> settings);
@ -58,6 +58,7 @@ signals:
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private slots:
void closeLeaveRoomDialog(bool leaving);
@ -67,7 +68,7 @@ private:
QVBoxLayout *textLayout_;
QLabel *nameLabel_;
QLabel *topicLabel_;
Label *topicLabel_;
QSharedPointer<RoomSettings> roomSettings_;
@ -77,45 +78,13 @@ private:
FlatButton *settingsBtn_;
OverlayModal *leaveRoomModal;
LeaveRoomDialog *leaveRoomDialog_;
QSharedPointer<OverlayModal> leaveRoomModal_;
QSharedPointer<LeaveRoomDialog> leaveRoomDialog_;
Avatar *avatar_;
int buttonSize_;
QString roomName_;
QString roomTopic_;
};
inline void
TopRoomBar::updateRoomAvatar(const QImage &avatar_image)
{
avatar_->setImage(avatar_image);
update();
}
inline void
TopRoomBar::updateRoomAvatar(const QIcon &icon)
{
avatar_->setIcon(icon);
update();
}
inline void
TopRoomBar::updateRoomName(const QString &name)
{
QString elidedText =
QFontMetrics(nameLabel_->font()).elidedText(name, Qt::ElideRight, width() * 0.8);
nameLabel_->setText(elidedText);
update();
}
inline void
TopRoomBar::updateRoomTopic(QString topic)
{
topic.replace(URL_REGEX, URL_HTML);
QString elidedText =
QFontMetrics(topicLabel_->font()).elidedText(topic, Qt::ElideRight, width() * 0.6);
topicLabel_->setText(topic);
update();
}

View File

@ -20,7 +20,6 @@
#include <QAction>
#include <QIcon>
#include <QIconEngine>
#include <QMenu>
#include <QPainter>
#include <QRect>
#include <QSystemTrayIcon>

21
include/TypingDisplay.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <QPaintEvent>
#include <QWidget>
class TypingDisplay : public QWidget
{
Q_OBJECT
public:
TypingDisplay(QWidget *parent = nullptr);
void setUsers(const QStringList &user_ids);
protected:
void paintEvent(QPaintEvent *event) override;
private:
QString text_;
int leftPadding_;
};

View File

@ -17,15 +17,13 @@
#pragma once
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
#include <QLabel>
#include <QLayout>
#include "Avatar.h"
#include "FlatButton.h"
#include "LogoutDialog.h"
#include "OverlayModal.h"
class Avatar;
class FlatButton;
class LogoutDialog;
class OverlayModal;
class UserInfoWidget : public QWidget
{
@ -68,8 +66,8 @@ private:
QImage avatar_image_;
OverlayModal *logoutModal_;
LogoutDialog *logoutDialog_;
QSharedPointer<OverlayModal> logoutModal_;
QSharedPointer<LogoutDialog> logoutDialog_;
int logoutButtonSize_;
};

View File

@ -0,0 +1,81 @@
/*
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QComboBox>
#include <QFrame>
#include <QLayout>
#include <QSharedPointer>
#include <QWidget>
class Toggle;
constexpr int OptionMargin = 6;
constexpr int LayoutSideMargin = 300;
class UserSettings
{
public:
UserSettings();
void save();
void load();
void setTheme(QString theme) { theme_ = theme; }
void setTray(bool state) { isTrayEnabled_ = state; }
QString theme() const { return !theme_.isEmpty() ? theme_ : "default"; }
bool isTrayEnabled() const { return isTrayEnabled_; }
private:
QString theme_;
bool isTrayEnabled_;
};
class HorizontalLine : public QFrame
{
Q_OBJECT
public:
HorizontalLine(QWidget *parent = nullptr);
};
class UserSettingsPage : public QWidget
{
Q_OBJECT
public:
UserSettingsPage(QSharedPointer<UserSettings> settings, QWidget *parent = 0);
protected:
void showEvent(QShowEvent *event) override;
signals:
void moveBack();
void trayOptionChanged(bool value);
private:
// Layouts
QVBoxLayout *topLayout_;
QHBoxLayout *topBarLayout_;
// Shared settings object.
QSharedPointer<UserSettings> settings_;
Toggle *trayToggle_;
QComboBox *themeCombo_;
};

View File

@ -20,7 +20,7 @@
#include <QJsonDocument>
#include <QVector>
#include "Deserializable.h"
class Deserializable;
class VersionsResponse : public Deserializable
{
@ -30,7 +30,8 @@ public:
bool isVersionSupported(unsigned int major, unsigned int minor, unsigned int patch);
private:
struct Version_ {
struct Version_
{
unsigned int major_;
unsigned int minor_;
unsigned int patch_;

View File

@ -17,7 +17,9 @@
#pragma once
#include "RaisedButton.h"
#include <QWidget>
class RaisedButton;
class WelcomePage : public QWidget
{

View File

@ -22,10 +22,8 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
class AliasesEventContent
: public Deserializable
, public Serializable
@ -34,16 +32,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QList<QString> aliases() const;
QList<QString> aliases() const { return aliases_; };
private:
QList<QString> aliases_;
};
inline QList<QString>
AliasesEventContent::aliases() const
{
return aliases_;
}
} // namespace events
} // namespace matrix

View File

@ -22,10 +22,8 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
/*
* A picture that is associated with the room.
*/
@ -38,16 +36,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QUrl url() const;
QUrl url() const { return url_; };
private:
QUrl url_;
};
inline QUrl
AvatarEventContent::url() const
{
return url_;
}
} // namespace events
} // namespace matrix

View File

@ -22,10 +22,8 @@
#include "CanonicalAliasEventContent.h"
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
/*
* This event is used to inform the room about which alias should be considered
* the canonical one. This could be for display purposes or as suggestion to
@ -40,16 +38,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QString alias() const;
QString alias() const { return alias_; };
private:
QString alias_;
};
inline QString
CanonicalAliasEventContent::alias() const
{
return alias_;
}
} // namespace events
} // namespace matrix

View File

@ -21,10 +21,8 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
/*
* This is the first event in a room and cannot be changed. It acts as the root
* of all other events.
@ -38,17 +36,12 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QString creator() const;
QString creator() const { return creator_; };
private:
// The user_id of the room creator. This is set by the homeserver.
QString creator_;
};
inline QString
CreateEventContent::creator() const
{
return creator_;
}
} // namespace events
} // namespace matrix

View File

@ -22,11 +22,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class EventType
{
namespace events
{
enum class EventType {
/// m.room.aliases
RoomAliases,
/// m.room.avatar
@ -67,8 +66,8 @@ class Event
, public Serializable
{
public:
inline Content content() const;
inline EventType eventType() const;
Content content() const;
EventType eventType() const;
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;

View File

@ -21,11 +21,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class HistoryVisibility
{
namespace events
{
enum class HistoryVisibility {
Invited,
Joined,
Shared,
@ -37,7 +36,7 @@ class HistoryVisibilityEventContent
, public Serializable
{
public:
inline HistoryVisibility historyVisibility() const;
HistoryVisibility historyVisibility() const { return history_visibility_; };
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
@ -46,10 +45,5 @@ private:
HistoryVisibility history_visibility_;
};
inline HistoryVisibility
HistoryVisibilityEventContent::historyVisibility() const
{
return history_visibility_;
}
} // namespace events
} // namespace matrix

View File

@ -21,11 +21,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class JoinRule
{
namespace events
{
enum class JoinRule {
// A user who wishes to join the room must first receive
// an invite to the room from someone already inside of the room.
Invite,
@ -52,16 +51,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline JoinRule joinRule() const;
JoinRule joinRule() const { return join_rule_; };
private:
JoinRule join_rule_;
};
inline JoinRule
JoinRulesEventContent::joinRule() const
{
return join_rule_;
}
} // namespace events
} // namespace matrix

View File

@ -22,11 +22,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class Membership
{
namespace events
{
enum class Membership {
// The user is banned.
Ban,
@ -55,9 +54,9 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QUrl avatarUrl() const;
inline QString displayName() const;
inline Membership membershipState() const;
QUrl avatarUrl() const { return avatar_url_; };
QString displayName() const { return display_name_; };
Membership membershipState() const { return membership_state_; };
private:
QUrl avatar_url_;
@ -65,22 +64,5 @@ private:
Membership membership_state_;
};
inline QUrl
MemberEventContent::avatarUrl() const
{
return avatar_url_;
}
inline QString
MemberEventContent::displayName() const
{
return display_name_;
}
inline Membership
MemberEventContent::membershipState() const
{
return membership_state_;
}
} // namespace events
} // namespace matrix

View File

@ -20,15 +20,13 @@
#include "MessageEventContent.h"
#include "RoomEvent.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
template<class MsgContent>
class MessageEvent : public RoomEvent<MessageEventContent>
{
public:
inline MsgContent msgContent() const;
MsgContent msgContent() const;
void deserialize(const QJsonValue &data) override;
@ -52,9 +50,9 @@ MessageEvent<MsgContent>::deserialize(const QJsonValue &data)
msg_content_.deserialize(data.toObject().value("content").toObject());
}
namespace messages
namespace messages {
struct ThumbnailInfo
{
struct ThumbnailInfo {
int h;
int w;
int size;

View File

@ -21,11 +21,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class MessageEventType
{
namespace events
{
enum class MessageEventType {
// m.audio
Audio,
@ -65,16 +64,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QString body() const;
QString body() const { return body_; };
private:
QString body_;
};
inline QString
MessageEventContent::body() const
{
return body_;
}
} // namespace events
} // namespace matrix

View File

@ -21,10 +21,8 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
/*
* A human-friendly room name designed to be displayed to the end-user.
*/
@ -37,16 +35,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QString name() const;
QString name() const { return name_; };
private:
QString name_;
};
inline QString
NameEventContent::name() const
{
return name_;
}
} // namespace events
} // namespace matrix

View File

@ -22,11 +22,10 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
enum class PowerLevels
{
namespace events
{
enum class PowerLevels {
User = 0,
Moderator = 50,
Admin = 100,
@ -44,14 +43,14 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline int banLevel() const;
inline int inviteLevel() const;
inline int kickLevel() const;
inline int redactLevel() const;
int banLevel() const { return ban_; };
int inviteLevel() const { return invite_; };
int kickLevel() const { return kick_; };
int redactLevel() const { return redact_; };
inline int eventsDefaultLevel() const;
inline int stateDefaultLevel() const;
inline int usersDefaultLevel() const;
int eventsDefaultLevel() const { return events_default_; };
int stateDefaultLevel() const { return state_default_; };
int usersDefaultLevel() const { return users_default_; };
int eventLevel(QString event_type) const;
int userLevel(QString user_id) const;
@ -70,46 +69,5 @@ private:
QMap<QString, int> users_;
};
inline int
PowerLevelsEventContent::banLevel() const
{
return ban_;
}
inline int
PowerLevelsEventContent::inviteLevel() const
{
return invite_;
}
inline int
PowerLevelsEventContent::kickLevel() const
{
return kick_;
}
inline int
PowerLevelsEventContent::redactLevel() const
{
return redact_;
}
inline int
PowerLevelsEventContent::eventsDefaultLevel() const
{
return events_default_;
}
inline int
PowerLevelsEventContent::stateDefaultLevel() const
{
return state_default_;
}
inline int
PowerLevelsEventContent::usersDefaultLevel() const
{
return users_default_;
}
} // namespace events
} // namespace matrix

View File

@ -22,18 +22,16 @@
#include "Event.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
template<class Content>
class RoomEvent : public Event<Content>
{
public:
inline QString eventId() const;
inline QString roomId() const;
inline QString sender() const;
inline uint64_t timestamp() const;
QString eventId() const;
QString roomId() const;
QString sender() const;
uint64_t timestamp() const;
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;

View File

@ -21,16 +21,14 @@
#include "RoomEvent.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
template<class Content>
class StateEvent : public RoomEvent<Content>
{
public:
inline QString stateKey() const;
inline Content previousContent() const;
QString stateKey() const;
Content previousContent() const;
void deserialize(const QJsonValue &data);
QJsonObject serialize() const;

View File

@ -21,10 +21,8 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace matrix {
namespace events {
/*
* A topic is a short message detailing what is currently being discussed in the
* room.
@ -38,16 +36,11 @@ public:
void deserialize(const QJsonValue &data) override;
QJsonObject serialize() const override;
inline QString topic() const;
QString topic() const { return topic_; };
private:
QString topic_;
};
inline QString
TopicEventContent::topic() const
{
return topic_;
}
} // namespace events
} // namespace matrix

View File

@ -21,13 +21,11 @@
#include "Deserializable.h"
namespace matrix
namespace matrix {
namespace events {
namespace messages {
struct AudioInfo
{
namespace events
{
namespace messages
{
struct AudioInfo {
uint64_t duration;
int size;
@ -37,8 +35,8 @@ struct AudioInfo {
class Audio : public Deserializable
{
public:
inline QString url() const;
inline AudioInfo info() const;
QString url() const { return url_; };
AudioInfo info() const { return info_; };
void deserialize(const QJsonObject &object) override;
@ -47,18 +45,6 @@ private:
AudioInfo info_;
};
inline QString
Audio::url() const
{
return url_;
}
inline AudioInfo
Audio::info() const
{
return info_;
}
} // namespace messages
} // namespace events
} // namespace matrix

View File

@ -21,12 +21,9 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace messages
{
namespace matrix {
namespace events {
namespace messages {
class Emote : public Deserializable
{
public:

View File

@ -22,13 +22,11 @@
#include "Deserializable.h"
#include "MessageEvent.h"
namespace matrix
namespace matrix {
namespace events {
namespace messages {
struct FileInfo
{
namespace events
{
namespace messages
{
struct FileInfo {
int size;
QString mimetype;
@ -39,10 +37,9 @@ struct FileInfo {
class File : public Deserializable
{
public:
inline QString url() const;
inline QString filename() const;
inline FileInfo info() const;
QString url() const { return url_; };
QString filename() const { return filename_; };
FileInfo info() const { return info_; };
void deserialize(const QJsonObject &object) override;
@ -53,24 +50,6 @@ private:
FileInfo info_;
};
inline QString
File::filename() const
{
return filename_;
}
inline QString
File::url() const
{
return url_;
}
inline FileInfo
File::info() const
{
return info_;
}
} // namespace messages
} // namespace events
} // namespace matrix

View File

@ -22,13 +22,11 @@
#include "Deserializable.h"
#include "MessageEvent.h"
namespace matrix
namespace matrix {
namespace events {
namespace messages {
struct ImageInfo
{
namespace events
{
namespace messages
{
struct ImageInfo {
int h;
int w;
int size;
@ -41,8 +39,8 @@ struct ImageInfo {
class Image : public Deserializable
{
public:
inline QString url() const;
inline ImageInfo info() const;
QString url() const { return url_; };
ImageInfo info() const { return info_; };
void deserialize(const QJsonObject &object) override;
@ -51,18 +49,6 @@ private:
ImageInfo info_;
};
inline QString
Image::url() const
{
return url_;
}
inline ImageInfo
Image::info() const
{
return info_;
}
} // namespace messages
} // namespace events
} // namespace matrix

View File

@ -22,13 +22,11 @@
#include "Deserializable.h"
#include "MessageEvent.h"
namespace matrix
namespace matrix {
namespace events {
namespace messages {
struct LocationInfo
{
namespace events
{
namespace messages
{
struct LocationInfo {
QString thumbnail_url;
ThumbnailInfo thumbnail_info;
};
@ -36,8 +34,8 @@ struct LocationInfo {
class Location : public Deserializable
{
public:
inline QString geoUri() const;
inline LocationInfo info() const;
QString geoUri() const { return geo_uri_; };
LocationInfo info() const { return info_; };
void deserialize(const QJsonObject &object) override;
@ -47,18 +45,6 @@ private:
LocationInfo info_;
};
inline QString
Location::geoUri() const
{
return geo_uri_;
}
inline LocationInfo
Location::info() const
{
return info_;
}
} // namespace messages
} // namespace events
} // namespace matrix

View File

@ -21,12 +21,9 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace messages
{
namespace matrix {
namespace events {
namespace messages {
class Notice : public Deserializable
{
public:

View File

@ -21,12 +21,9 @@
#include "Deserializable.h"
namespace matrix
{
namespace events
{
namespace messages
{
namespace matrix {
namespace events {
namespace messages {
class Text : public Deserializable
{
public:

View File

@ -22,13 +22,11 @@
#include "Deserializable.h"
#include "MessageEvent.h"
namespace matrix
namespace matrix {
namespace events {
namespace messages {
struct VideoInfo
{
namespace events
{
namespace messages
{
struct VideoInfo {
int h;
int w;
int size;
@ -42,8 +40,8 @@ struct VideoInfo {
class Video : public Deserializable
{
public:
inline QString url() const;
inline VideoInfo info() const;
QString url() const { return url_; };
VideoInfo info() const { return info_; };
void deserialize(const QJsonObject &object) override;
@ -52,18 +50,6 @@ private:
VideoInfo info_;
};
inline QString
Video::url() const
{
return url_;
}
inline VideoInfo
Video::info() const
{
return info_;
}
} // namespace messages
} // namespace events
} // namespace matrix

View File

@ -5,9 +5,9 @@
#include <QPushButton>
#include <QStateMachine>
#include "RippleOverlay.h"
#include "Theme.h"
class RippleOverlay;
class FlatButton;
class FlatButtonStateMachine : public QStateMachine

View File

@ -0,0 +1,26 @@
#pragma once
#include "RaisedButton.h"
constexpr int DIAMETER = 40;
constexpr int ICON_SIZE = 18;
constexpr int OFFSET_X = 30;
constexpr int OFFSET_Y = 20;
class FloatingButton : public RaisedButton
{
Q_OBJECT
public:
FloatingButton(const QIcon &icon, QWidget *parent = nullptr);
QSize sizeHint() const override { return QSize(DIAMETER, DIAMETER); };
QRect buttonGeometry() const;
protected:
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
};

26
include/ui/Label.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <QLabel>
class Label : public QLabel
{
Q_OBJECT
public:
explicit Label(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
explicit Label(const QString &text,
QWidget *parent = Q_NULLPTR,
Qt::WindowFlags f = Qt::WindowFlags());
~Label() override {}
signals:
void clicked(QMouseEvent *e);
void pressed(QMouseEvent *e);
void released(QMouseEvent *e);
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
QPoint pressPosition_;
};

View File

@ -19,23 +19,11 @@ public:
void start();
void stop();
QColor color()
{
return color_;
}
void setColor(QColor color)
{
color_ = color;
}
QColor color() { return color_; }
void setColor(QColor color) { color_ = color; }
int interval()
{
return interval_;
}
void setInterval(int interval)
{
interval_ = interval;
}
int interval() { return interval_; }
void setInterval(int interval) { interval_ = interval; }
private slots:
void onTimeout();

81
include/ui/SnackBar.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include <QCoreApplication>
#include <QPaintEvent>
#include <QStateMachine>
#include <QTimer>
#include "OverlayWidget.h"
enum class SnackBarPosition
{
Bottom,
Top,
};
class SnackBar : public OverlayWidget
{
Q_OBJECT
public:
explicit SnackBar(QWidget *parent);
~SnackBar();
inline void setBackgroundColor(const QColor &color);
inline void setTextColor(const QColor &color);
inline void setPosition(SnackBarPosition pos);
public slots:
void showMessage(const QString &msg);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private slots:
void onTimeout();
void hideMessage();
private:
void stopTimers();
void start();
QColor bgColor_;
QColor textColor_;
qreal bgOpacity_;
qreal offset_;
QList<QString> messages_;
QTimer *showTimer_;
QTimer *hideTimer_;
int duration_;
int boxWidth_;
int boxHeight_;
int boxPadding_;
SnackBarPosition position_;
};
inline void
SnackBar::setPosition(SnackBarPosition pos)
{
position_ = pos;
update();
}
inline void
SnackBar::setBackgroundColor(const QColor &color)
{
bgColor_ = color;
update();
}
inline void
SnackBar::setTextColor(const QColor &color)
{
textColor_ = color;
update();
}

View File

@ -4,12 +4,15 @@
#include <QHash>
#include <QObject>
namespace ui
namespace ui {
enum class AvatarType
{
enum class AvatarType { Icon, Image, Letter };
Icon,
Image,
Letter
};
namespace sidebar
{
namespace sidebar {
static const int SmallSize = 60;
static const int NormalSize = 300;
}
@ -19,19 +22,47 @@ const int FontSize = 16;
// Default avatar size. Width and height.
const int AvatarSize = 40;
enum class ButtonPreset { FlatPreset, CheckablePreset };
enum class ButtonPreset
{
FlatPreset,
CheckablePreset
};
enum class RippleStyle { CenteredRipple, PositionedRipple, NoRipple };
enum class RippleStyle
{
CenteredRipple,
PositionedRipple,
NoRipple
};
enum class OverlayStyle { NoOverlay, TintedOverlay, GrayOverlay };
enum class OverlayStyle
{
NoOverlay,
TintedOverlay,
GrayOverlay
};
enum class Role { Default, Primary, Secondary };
enum class Role
{
Default,
Primary,
Secondary
};
enum class ButtonIconPlacement { LeftIcon, RightIcon };
enum class ButtonIconPlacement
{
LeftIcon,
RightIcon
};
enum class ProgressType { DeterminateProgress, IndeterminateProgress };
enum class ProgressType
{
DeterminateProgress,
IndeterminateProgress
};
enum class Color {
enum class Color
{
Black,
BrightWhite,
FadedWhite,

110
include/ui/ToggleButton.h Normal file
View File

@ -0,0 +1,110 @@
#pragma once
#include <QAbstractButton>
#include <QColor>
class ToggleTrack;
class ToggleThumb;
enum class Position
{
Left,
Right
};
class Toggle : public QAbstractButton
{
Q_OBJECT
Q_PROPERTY(QColor activeColor WRITE setActiveColor READ activeColor)
Q_PROPERTY(QColor disabledColor WRITE setDisabledColor READ disabledColor)
Q_PROPERTY(QColor inactiveColor WRITE setInactiveColor READ inactiveColor)
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
public:
Toggle(QWidget *parent = nullptr);
void setState(bool isEnabled);
void setActiveColor(const QColor &color);
void setDisabledColor(const QColor &color);
void setInactiveColor(const QColor &color);
void setTrackColor(const QColor &color);
QColor activeColor() const { return activeColor_; };
QColor disabledColor() const { return disabledColor_; };
QColor inactiveColor() const { return inactiveColor_; };
QColor trackColor() const { return trackColor_.isValid() ? trackColor_ : QColor("#eee"); };
QSize sizeHint() const override { return QSize(64, 48); };
protected:
void paintEvent(QPaintEvent *event) override;
private:
void init();
void setupProperties();
ToggleTrack *track_;
ToggleThumb *thumb_;
QColor disabledColor_;
QColor activeColor_;
QColor inactiveColor_;
QColor trackColor_;
};
class ToggleThumb : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor thumbColor WRITE setThumbColor READ thumbColor)
public:
ToggleThumb(Toggle *parent);
Position shift() const { return position_; };
qreal offset() const { return offset_; };
QColor thumbColor() const { return thumbColor_; };
void setShift(Position position);
void setThumbColor(const QColor &color)
{
thumbColor_ = color;
update();
};
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void updateOffset();
Toggle *const toggle_;
QColor thumbColor_;
Position position_;
qreal offset_;
};
class ToggleTrack : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
public:
ToggleTrack(Toggle *parent);
void setTrackColor(const QColor &color);
QColor trackColor() const { return trackColor_; };
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
Toggle *const toggle_;
QColor trackColor_;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 603 B

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4213"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4211" /><g
id="g4205"><path
style="fill:#000000;fill-opacity:1"
id="path4207"
d="M12,0C5.373,0,0,5.372,0,12c0,6.627,5.373,12,12,12c6.628,0,12-5.373,12-12C24,5.372,18.628,0,12,0 M21.949,11H17.05c0.224-2.527,1.232-4.773,1.968-6.113C20.634,6.481,21.712,8.618,21.949,11 M13,11V2.051 c1.623,0.162,3.13,0.719,4.432,1.564C16.574,5.106,15.276,7.835,15.04,11H13z M11,11H8.961C8.723,7.835,7.425,5.106,6.568,3.615 C7.871,2.77,9.377,2.213,11,2.051V11z M11,13v8.949c-1.623-0.162-3.129-0.718-4.432-1.564C7.425,18.893,8.723,16.164,8.961,13H11z M15.04,13c0.236,3.164,1.534,5.893,2.392,7.385c-1.302,0.847-2.809,1.402-4.432,1.564V13H15.04z M4.982,4.887 C5.718,6.227,6.726,8.473,6.951,11h-4.9C2.289,8.618,3.367,6.481,4.982,4.887 M2.051,13h4.9c-0.226,2.527-1.233,4.771-1.969,6.113 C3.367,17.52,2.289,15.383,2.051,13 M19.018,19.113c-0.735-1.342-1.744-3.586-1.968-6.113h4.899 C21.712,15.383,20.634,17.52,19.018,19.113"
fill="#010202" /></g></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg2"
viewBox="0 0 32 32"
height="32"
width="32"
version="1.1">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<path
id="path4"
d="M14 8c0-1.105 0.895-2 2-2s2 0.895 2 2c0 1.105-0.895 2-2 2s-2-0.895-2-2zM16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 26c-1.105 0-2-0.895-2-2s0.895-2 2-2c1.105 0 2 0.895 2 2s-0.895 2-2 2zM16 16c-3.59 0-6.5 2.91-6.5 6.5s2.91 6.5 6.5 6.5c-7.18 0-13-5.82-13-13s5.82-13 13-13c3.59 0 6.5 2.91 6.5 6.5s-2.91 6.5-6.5 6.5z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 416 B

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata6641"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6639" /><g
id="g6631"><polygon
style="fill:#000000;fill-opacity:1"
id="polygon6633"
points="0,0 6.084,24 8,24 1.916,0 "
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path6635"
d="M21,5h-4l-1-4H4l3,12h3l1,4h2h11L21,5z M6.563,3h7.875l2,8H8.563L6.563,3z M15.395,13l-2.856,1.904 L12.063,13H15.395z M19,13l-1.5-6h1.938l2,8H16L19,13z"
fill="#010202" /></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 B

After

Width:  |  Height:  |  Size: 537 B

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4164"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4162" /><g
id="g4156"><path
style="fill:#000000;fill-opacity:1"
id="path4158"
d="M17,4.978c-1.838,0-2.876,0.396-3.68,0.934c0.513-1.172,1.768-2.934,4.68-2.934c0.552,0,1-0.448,1-1 s-0.448-1-1-1c-2.921,0-4.629,1.365-5.547,2.512c-0.064,0.078-0.119,0.162-0.18,0.244c-0.543-1.896-1.475-3.711-3.066-3.711 C8.579,0.022,7.85,0.306,7,0.978C5.027,2.54,5.329,3.902,6.492,4.999C3.609,5.222,0,7.352,0,12.969c0,4.582,4.961,11.009,9,11.009 c1.975,0,2.371-0.486,3-1c0.629,0.514,1.025,1,3,1c4.039,0,9-6.418,9-11C24,7.025,19.945,4.978,17,4.978 M8.242,2.546 c0.641-0.508,0.943-0.523,0.965-0.523c0.426,0.169,0.975,1.405,1.357,3.055c-1.527-0.629-2.741-1.352-2.98-1.846 C7.643,3.12,7.825,2.876,8.242,2.546 M15,21.978c-1.08,0-1.21-0.109-1.559-0.402l-0.176-0.146 c-0.367-0.302-0.816-0.452-1.266-0.452s-0.898,0.15-1.266,0.452l-0.176,0.146C10.21,21.868,10.08,21.978,9,21.978 c-2.813,0-7-5.389-7-9.009c0-5.823,4.488-5.991,5-5.991c1.939,0,2.484,0.471,3.387,1.251c0.107,0.092,0.215,0.185,0.323,0.276 C11.083,8.82,11.541,8.978,12,8.978s0.917-0.157,1.29-0.473c0.108-0.092,0.216-0.185,0.323-0.276 c0.902-0.78,1.447-1.251,3.387-1.251c0.512,0,5,0.168,5,6C22,16.595,17.813,21.978,15,21.978"
fill="#010202" /></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 667 B

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata6036"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6034" /><g
id="g6024"><g
id="g6578"><g
id="g6583"><path
style="fill:#000000;fill-opacity:1"
id="path6028"
d="M15.5,8C14.672,8,14,8.672,14,9.5s0.672,1.5,1.5,1.5S17,10.329,17,9.5S16.328,8,15.5,8"
fill="#010202" /><g
id="g6588"><path
fill="#010202"
d="M8.5,8C7.672,8,7,8.672,7,9.5S7.672,11,8.5,11S10,10.329,10,9.5S9.329,8,8.5,8"
id="path6026"
style="fill:#000000;fill-opacity:1" /><path
fill="#010202"
d="M18.933,0h-0.027c-0.97,0-2.138,0.787-3.018,1.497c-1.274-0.374-2.612-0.51-3.887-0.51 c-1.285,0-2.616,0.133-3.874,0.517C7.245,0.79,6.069,0,5.093,0H5.066C3.352,0,0.07,2.67,0.002,7.026 c-0.039,2.479,0.276,4.238,1.04,5.013c0.254,0.258,0.882,0.677,1.295,0.882c0.191,3.177,0.922,5.238,2.536,6.38 c0.897,0.637,2.187,0.949,3.2,1.102C8.04,20.6,8,20.795,8,21c0,1.773,2.35,3,4,3c1.648,0,4-1.227,4-3 c0-0.201-0.038-0.393-0.072-0.586c2.573-0.385,5.435-1.877,5.925-7.587c0.396-0.22,0.887-0.568,1.104-0.788 c0.763-0.774,1.079-2.534,1.04-5.013C23.929,2.67,20.646,0,18.933,0 M3.223,9.135c-0.237,0.281-0.837,1.155-0.884,1.238 c-0.15-0.41-0.368-1.349-0.337-3.291C2.053,3.801,4.48,2.11,5.093,2.051c0.256,0.015,0.731,0.27,1.265,0.646 c-1.11,1.171-2.275,2.915-2.352,5.125C3.873,8.368,3.608,8.68,3.223,9.135 M12,22c-0.901,0-1.954-0.693-2-1 c0-0.654,0.475-1.236,1-1.602V20c0,0.553,0.447,1,1,1s1-0.447,1-1v-0.602c0.524,0.365,1,0.947,1,1.602 C13.954,21.307,12.901,22,12,22 M15,18.52v0.02c-0.366-0.418-0.798-0.762-1.262-1.02c1.092-0.516,2.239-1.334,2.239-2.217 c0-1.842-1.781-2.195-3.977-2.195c-2.196,0-3.978,0.354-3.978,2.195c0,0.883,1.148,1.701,2.238,2.217 C9.799,17.777,9.368,18.121,9,18.539v-0.025c-1-0.076-2.182-0.281-2.973-0.842c-1.301-0.92-1.838-3.045-1.853-6.478 c0.008-0.014,0.016-0.028,0.023-0.041c0.496-0.826,1.49-1.45,1.804-3.102c0-2.047,1.357-3.631,2.362-4.522 C9.37,3.178,10.555,3,11.948,3c1.447,0,2.685,0.192,3.733,0.57c1,0.9,2.316,2.465,2.316,4.48c0.313,1.651,1.307,2.275,1.803,3.102 c0.035,0.058,0.068,0.117,0.102,0.178C19.843,17.297,17.953,18.34,15,18.52 M21.628,10.318c-0.037-0.065-0.074-0.13-0.113-0.195 c-0.233-0.387-0.502-0.706-0.739-0.987c-0.385-0.455-0.648-0.768-0.782-1.313c-0.076-2.209-1.241-3.954-2.353-5.124 c0.531-0.376,1.004-0.63,1.261-0.647c0.636,0.071,3.044,1.764,3.096,5.031C22.025,8.893,21.651,10.301,21.628,10.318"
id="path6030"
style="fill:#000000;fill-opacity:1" /></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

After

Width:  |  Height:  |  Size: 606 B

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4838"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4836" /><g
id="g4820"><g
id="g4822" /><g
id="g4830"><g
id="g5383"><path
style="fill:#000000;fill-opacity:1"
d="M 12 0 C 7.029 0 3 4.029 3 9 C 3 12.120081 4.5888411 14.867862 7 16.482422 L 7 21 C 7 21 9.035 24 12 24 C 14.965 24 17 21 17 21 L 17 16.482422 C 19.411159 14.867862 21 12.120081 21 9 C 21 4.029 16.971 0 12 0 z M 12 2 C 15.86 2 19 5.141 19 9 C 19 12.859 15.86 16 12 16 C 8.14 16 5 12.859 5 9 C 5 5.141 8.14 2 12 2 z M 9 17.476562 C 9.9397054 17.809261 10.946226 18 12 18 C 13.053774 18 14.060295 17.809261 15 17.476562 L 15 18.310547 C 14.089581 18.746635 13.074971 19 12 19 C 10.925029 19 9.9104192 18.746635 9 18.310547 L 9 17.476562 z M 9.2363281 20.546875 C 10.108023 20.832252 11.032636 21 12 21 C 12.965197 21 13.887813 20.832689 14.757812 20.548828 C 14.155076 21.173162 13.152816 22 12 22 C 10.89775 22 9.8827458 21.211335 9.2363281 20.546875 z "
id="path4824" /><path
fill="#010202"
d="M14.745,12.449h-0.004c-0.852-0.024-1.188-0.858-1.577-1.824c-0.421-1.061-0.703-1.561-1.182-1.566h-0.009 c-0.481,0-0.783,0.497-1.235,1.537c-0.436,0.982-0.801,1.811-1.636,1.791l-0.276-0.043c-0.565-0.171-0.853-0.691-1.284-1.794 c-0.125-0.313-0.202-0.632-0.27-0.913C7.221,9.424,7.145,9.107,7.077,9.003C7.067,9.004,7.039,9,6.99,9 C6.438,8.994,5.994,8.543,6,7.99C6.006,7.441,6.452,7,7,7h0.01c1.662,0.017,2.015,1.373,2.198,2.134 c0.486-0.981,1.304-2.058,2.797-2.075c1.531,0.018,2.28,1.153,2.731,2.141c0-0.002,0.001-0.006,0.002-0.008 C14.944,8.424,15.327,7,16.979,7h0.032C17.563,7.007,18.006,7.459,18,8.012C17.994,8.56,17.547,9,17,9h-0.011 c-0.149,0.076-0.256,0.474-0.319,0.709c-0.079,0.295-0.169,0.629-0.311,0.951C15.93,11.633,15.569,12.449,14.745,12.449"
id="path4832" /></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 581 B

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata7236"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7234" /><g
id="g7222"><path
style="fill:#000000;fill-opacity:1"
id="path7224"
d="M12,0C5.373,0,0,5.373,0,12s5.373,12,12,12s12-5.373,12-12S18.627,0,12,0 M12,22C6.486,22,2,17.514,2,12 S6.486,2,12,2s10,4.486,10,10S17.514,22,12,22"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7226"
d="M8,7C6.895,7,6,7.895,6,9s0.895,2,2,2s2-0.895,2-2S9.105,7,8,7"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7228"
d="M16,7c-1.105,0-2,0.895-2,2s0.895,2,2,2s2-0.895,2-2S17.105,7,16,7"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7230"
d="M15.232,15c-0.693,1.195-1.87,2-3.349,2c-1.477,0-2.655-0.805-3.347-2H15 M18,13H6c0,3.314,2.686,6,6,6 S18,16.314,18,13"
fill="#010202" /></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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