mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 04:58:49 +03:00
Merge master and fix conflicts
This commit is contained in:
commit
6bb73f84a3
66 changed files with 2535 additions and 460 deletions
|
@ -3,6 +3,7 @@
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
if [ "$FLATPAK" ]; then
|
if [ "$FLATPAK" ]; then
|
||||||
|
sudo apt-get -y install flatpak flatpak-builder elfutils
|
||||||
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
flatpak --noninteractive install --user flathub org.kde.Platform//5.14
|
flatpak --noninteractive install --user flathub org.kde.Platform//5.14
|
||||||
flatpak --noninteractive install --user flathub org.kde.Sdk//5.14
|
flatpak --noninteractive install --user flathub org.kde.Sdk//5.14
|
||||||
|
|
|
@ -6,7 +6,26 @@ if [ "$FLATPAK" ]; then
|
||||||
mkdir -p build-flatpak
|
mkdir -p build-flatpak
|
||||||
cd build-flatpak
|
cd build-flatpak
|
||||||
|
|
||||||
flatpak-builder --ccache --repo=repo --subject="Build of Nheko ${VERSION} `date`" app ../io.github.NhekoReborn.Nheko.json
|
jobsarg=""
|
||||||
|
if [ "$ARCH" = "arm64" ]; then
|
||||||
|
jobsarg="--jobs=2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
flatpak-builder --ccache --repo=repo --subject="Build of Nheko ${VERSION} $jobsarg `date`" app ../io.github.NhekoReborn.Nheko.json &
|
||||||
|
|
||||||
|
# to prevent flatpak builder from timing out on arm, run it in the background and print something every minute for up to 30 minutes.
|
||||||
|
minutes=0
|
||||||
|
limit=40
|
||||||
|
while kill -0 $! >/dev/null 2>&1; do
|
||||||
|
if [ $minutes == $limit ]; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
|
||||||
|
minutes=$((minutes+1))
|
||||||
|
|
||||||
|
sleep 60
|
||||||
|
done
|
||||||
|
|
||||||
flatpak build-bundle repo nheko-${VERSION}-${ARCH}.flatpak io.github.NhekoReborn.Nheko master
|
flatpak build-bundle repo nheko-${VERSION}-${ARCH}.flatpak io.github.NhekoReborn.Nheko master
|
||||||
|
|
||||||
mkdir ../artifacts
|
mkdir ../artifacts
|
||||||
|
|
11
.travis.yml
11
.travis.yml
|
@ -113,10 +113,6 @@ matrix:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- sourceline: 'ppa:alexlarsson/flatpak'
|
- sourceline: 'ppa:alexlarsson/flatpak'
|
||||||
packages:
|
|
||||||
- flatpak
|
|
||||||
- flatpak-builder
|
|
||||||
- elfutils
|
|
||||||
- os: linux
|
- os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
env:
|
env:
|
||||||
|
@ -128,20 +124,17 @@ matrix:
|
||||||
sources:
|
sources:
|
||||||
- sourceline: 'ppa:alexlarsson/flatpak'
|
- sourceline: 'ppa:alexlarsson/flatpak'
|
||||||
packages:
|
packages:
|
||||||
- flatpak
|
|
||||||
- flatpak-builder
|
|
||||||
- elfutils
|
|
||||||
- librsvg2-bin
|
- librsvg2-bin
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
# Use TRAVIS_TAG if defined, or the short commit SHA otherwise
|
# Use TRAVIS_TAG if defined, or the short commit SHA otherwise
|
||||||
- export VERSION=${TRAVIS_TAG:-$(git rev-parse --short HEAD)}
|
- export VERSION=${TRAVIS_TAG:-$(git rev-parse --short HEAD)}
|
||||||
install:
|
install:
|
||||||
- travis_wait ./.ci/install.sh
|
- ./.ci/install.sh
|
||||||
- export PATH=/usr/local/bin:${PATH}
|
- export PATH=/usr/local/bin:${PATH}
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- travis_wait ./.ci/script.sh
|
- ./.ci/script.sh
|
||||||
- sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
|
- sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
|
||||||
- cp ./.ci/bintray-release.json .
|
- cp ./.ci/bintray-release.json .
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
@ -10,7 +10,9 @@ set(
|
||||||
CACHE
|
CACHE
|
||||||
FILEPATH "Default toolchain"
|
FILEPATH "Default toolchain"
|
||||||
)
|
)
|
||||||
|
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard")
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Require C++ standard to be supported")
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "compile as PIC by default")
|
||||||
|
|
||||||
option(HUNTER_ENABLED "Enable Hunter package manager" OFF)
|
option(HUNTER_ENABLED "Enable Hunter package manager" OFF)
|
||||||
include("cmake/HunterGate.cmake")
|
include("cmake/HunterGate.cmake")
|
||||||
|
@ -333,7 +335,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG f5c78f4331b62a1e25a2d839cb38b07bb9bd7829
|
GIT_TAG 795b6a82d4f10c629ce0eb99803cc677c413f940
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(MatrixClient)
|
FetchContent_MakeAvailable(MatrixClient)
|
||||||
else()
|
else()
|
||||||
|
@ -421,7 +423,7 @@ endif()
|
||||||
|
|
||||||
# single instance functionality
|
# single instance functionality
|
||||||
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||||
add_subdirectory(third_party/SingleApplication-3.0.19/)
|
add_subdirectory(third_party/SingleApplication-3.1.3.1/)
|
||||||
|
|
||||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|
||||||
|
@ -515,6 +517,9 @@ set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC})
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa")
|
||||||
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerMac.mm src/emoji/MacHelper.mm)
|
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerMac.mm src/emoji/MacHelper.mm)
|
||||||
|
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
||||||
|
set_source_files_properties( src/notifications/ManagerMac.mm src/emoji/MacHelper.mm PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||||
|
endif()
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.cpp"
|
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.cpp"
|
||||||
|
@ -578,6 +583,13 @@ target_link_libraries(nheko PRIVATE
|
||||||
tweeny
|
tweeny
|
||||||
SingleApplication::SingleApplication)
|
SingleApplication::SingleApplication)
|
||||||
|
|
||||||
|
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
||||||
|
target_precompile_headers(nheko
|
||||||
|
PRIVATE
|
||||||
|
<string>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_link_libraries(nheko PRIVATE ntdll)
|
target_link_libraries(nheko PRIVATE ntdll)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
{
|
{
|
||||||
"sha256": "59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722",
|
"sha256": "59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722",
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2"
|
"url": "https://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -146,9 +146,9 @@
|
||||||
"name": "mtxclient",
|
"name": "mtxclient",
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"sha256": "16203a92b03c488178b31bedca9d9015b1d406443f7e5363a2e09171e50f8dfc",
|
"sha256": "7ba85bb477c9e17e2389faf2333034aa9ceae4b1c65d6bf5f7067f2799e9b770",
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/Nheko-Reborn/mtxclient/archive/f5c78f4331b62a1e25a2d839cb38b07bb9bd7829.tar.gz"
|
"url": "https://github.com/Nheko-Reborn/mtxclient/archive/795b6a82d4f10c629ce0eb99803cc677c413f940.tar.gz"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
1586
resources/langs/nheko_it.ts
Normal file
1586
resources/langs/nheko_it.ts
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ Rectangle {
|
||||||
id: avatar
|
id: avatar
|
||||||
width: 48
|
width: 48
|
||||||
height: 48
|
height: 48
|
||||||
radius: settings.avatar_circles ? height/2 : 3
|
radius: settings.avatarCircles ? height/2 : 3
|
||||||
|
|
||||||
property alias url: img.source
|
property alias url: img.source
|
||||||
property string displayName
|
property string displayName
|
||||||
|
@ -39,7 +39,7 @@ Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
width: avatar.width
|
width: avatar.width
|
||||||
height: avatar.height
|
height: avatar.height
|
||||||
radius: settings.avatar_circles ? height/2 : 3
|
radius: settings.avatarCircles ? height/2 : 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ Flow {
|
||||||
Text {
|
Text {
|
||||||
anchors.baseline: reactionCounter.baseline
|
anchors.baseline: reactionCounter.baseline
|
||||||
id: reactionText
|
id: reactionText
|
||||||
text: textMetrics.elidedText + (textMetrics.elidedText == model.key ? "" : "…")
|
text: textMetrics.elidedText + (textMetrics.elidedText == textMetrics.text ? "" : "…")
|
||||||
font.family: settings.emoji_font_family
|
font.family: settings.emoji_font_family
|
||||||
color: reaction.hovered ? colors.highlight : colors.text
|
color: reaction.hovered ? colors.highlight : colors.text
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
|
@ -65,7 +65,7 @@ Flow {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: divider
|
id: divider
|
||||||
height: reactionCounter.implicitHeight * 1.4
|
height: Math.floor(reactionCounter.implicitHeight * 1.4)
|
||||||
width: 1
|
width: 1
|
||||||
color: (reaction.hovered || model.selfReactedEvent !== '') ? colors.highlight : colors.text
|
color: (reaction.hovered || model.selfReactedEvent !== '') ? colors.highlight : colors.text
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ MouseArea {
|
||||||
messageContextMenu.show(model.id, model.type, model.isEncrypted, row)
|
messageContextMenu.show(model.id, model.type, model.isEncrypted, row)
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: (timelineSettings.message_hover_highlight && parent.containsMouse) ? colors.base : "transparent"
|
color: (settings.messageHoverHighlight && parent.containsMouse) ? colors.base : "transparent"
|
||||||
anchors.fill: row
|
anchors.fill: row
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
|
|
||||||
anchors.leftMargin: avatarSize + 4
|
anchors.leftMargin: avatarSize + 16
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ MouseArea {
|
||||||
event_id: model.id
|
event_id: model.id
|
||||||
}
|
}
|
||||||
ImageButton {
|
ImageButton {
|
||||||
visible: timelineSettings.buttons
|
visible: settings.buttonsInTimeline
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
Layout.preferredHeight: 16
|
Layout.preferredHeight: 16
|
||||||
width: 16
|
width: 16
|
||||||
|
@ -113,7 +113,7 @@ MouseArea {
|
||||||
onClicked: chat.model.replyAction(model.id)
|
onClicked: chat.model.replyAction(model.id)
|
||||||
}
|
}
|
||||||
ImageButton {
|
ImageButton {
|
||||||
visible: timelineSettings.buttons
|
visible: settings.buttonsInTimeline
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
Layout.preferredHeight: 16
|
Layout.preferredHeight: 16
|
||||||
width: 16
|
width: 16
|
||||||
|
|
|
@ -3,7 +3,6 @@ import QtQuick.Controls 2.3
|
||||||
import QtQuick.Layouts 1.2
|
import QtQuick.Layouts 1.2
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
import QtQuick.Window 2.2
|
import QtQuick.Window 2.2
|
||||||
import Qt.labs.settings 1.0
|
|
||||||
|
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
import im.nheko.EmojiModel 1.0
|
import im.nheko.EmojiModel 1.0
|
||||||
|
@ -133,12 +132,12 @@ Page {
|
||||||
|
|
||||||
visible: timelineManager.timeline != null
|
visible: timelineManager.timeline != null
|
||||||
|
|
||||||
cacheBuffer: 500
|
cacheBuffer: 400
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: chatFooter.top
|
anchors.bottom: chatFooter.top
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
anchors.leftMargin: 4
|
anchors.leftMargin: 4
|
||||||
anchors.rightMargin: scrollbar.width
|
anchors.rightMargin: scrollbar.width
|
||||||
|
@ -180,7 +179,7 @@ Page {
|
||||||
id: scrollbar
|
id: scrollbar
|
||||||
parent: chat.parent
|
parent: chat.parent
|
||||||
anchors.top: chat.top
|
anchors.top: chat.top
|
||||||
anchors.left: chat.right
|
anchors.right: chat.right
|
||||||
anchors.bottom: chat.bottom
|
anchors.bottom: chat.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +194,8 @@ Page {
|
||||||
|
|
||||||
id: wrapper
|
id: wrapper
|
||||||
property Item section
|
property Item section
|
||||||
width: chat.width
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32)
|
||||||
height: section ? section.height + timelinerow.height : timelinerow.height
|
height: section ? section.height + timelinerow.height : timelinerow.height
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
@ -265,7 +265,8 @@ Page {
|
||||||
}
|
}
|
||||||
Row {
|
Row {
|
||||||
height: userName.height
|
height: userName.height
|
||||||
spacing: 4
|
spacing: 8
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
width: avatarSize
|
width: avatarSize
|
||||||
height: avatarSize
|
height: avatarSize
|
||||||
|
|
|
@ -6,4 +6,5 @@ MatrixText {
|
||||||
width: parent ? parent.width : undefined
|
width: parent ? parent.width : undefined
|
||||||
height: isReply ? Math.min(chat.height / 8, implicitHeight) : undefined
|
height: isReply ? Math.min(chat.height / 8, implicitHeight) : undefined
|
||||||
clip: true
|
clip: true
|
||||||
|
font.pointSize: (settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? settings.fontSize * 3 : settings.fontSize
|
||||||
}
|
}
|
||||||
|
|
67
resources/qml/emoji/EmojiCategory.qml
Normal file
67
resources/qml/emoji/EmojiCategory.qml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.9
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtGraphicalEffects 1.9
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
import im.nheko.EmojiModel 1.0
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: root
|
||||||
|
property var category
|
||||||
|
property var emojiPopup
|
||||||
|
property EmojiProxyModel model: EmojiProxyModel {
|
||||||
|
sourceModel: EmojiModel {
|
||||||
|
viewCategory: category
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
cellWidth: 52
|
||||||
|
cellHeight: 52
|
||||||
|
height: 52 * ( model.count / 7 + 1 )
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
// Individual emoji
|
||||||
|
delegate: AbstractButton {
|
||||||
|
width: 48
|
||||||
|
height: 48
|
||||||
|
contentItem: Text {
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
font.family: settings.emoji_font_family
|
||||||
|
|
||||||
|
font.pixelSize: 36
|
||||||
|
text: model.unicode
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: hovered ? colors.highlight : 'transparent'
|
||||||
|
radius: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
ToolTip.text: model.shortName
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
|
||||||
|
// give the emoji a little oomf
|
||||||
|
DropShadow {
|
||||||
|
width: parent.width;
|
||||||
|
height: parent.height;
|
||||||
|
horizontalOffset: 3
|
||||||
|
verticalOffset: 3
|
||||||
|
radius: 8.0
|
||||||
|
samples: 17
|
||||||
|
color: "#80000000"
|
||||||
|
source: parent.contentItem
|
||||||
|
}
|
||||||
|
// TODO: maybe add favorites at some point?
|
||||||
|
onClicked: {
|
||||||
|
console.debug("Picked " + model.unicode + "in response to " + emojiPopup.event_id + " in room " + emojiPopup.room_id)
|
||||||
|
emojiPopup.picked(emojiPopup.room_id, emojiPopup.event_id, model.unicode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
|
#include "EventAccessors.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
|
@ -1947,12 +1948,13 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
|
||||||
|
|
||||||
json obj = json::object();
|
json obj = json::object();
|
||||||
|
|
||||||
obj["event"] = utils::serialize_event(e);
|
obj["event"] = mtx::accessors::serialize_event(e);
|
||||||
obj["token"] = res.prev_batch;
|
obj["token"] = res.prev_batch;
|
||||||
|
|
||||||
lmdb::dbi_put(txn,
|
lmdb::dbi_put(
|
||||||
|
txn,
|
||||||
db,
|
db,
|
||||||
lmdb::val(std::to_string(utils::event_timestamp(e))),
|
lmdb::val(std::to_string(obj["event"]["origin_server_ts"].get<uint64_t>())),
|
||||||
lmdb::val(obj.dump()));
|
lmdb::val(obj.dump()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2026,7 +2028,7 @@ Cache::saveTimelineMentions(lmdb::txn &txn,
|
||||||
using namespace mtx::events::state;
|
using namespace mtx::events::state;
|
||||||
|
|
||||||
for (const auto ¬if : res) {
|
for (const auto ¬if : res) {
|
||||||
const auto event_id = utils::event_id(notif.event);
|
const auto event_id = mtx::accessors::event_id(notif.event);
|
||||||
|
|
||||||
// double check that we have the correct room_id...
|
// double check that we have the correct room_id...
|
||||||
if (room_id.compare(notif.room_id) != 0) {
|
if (room_id.compare(notif.room_id) != 0) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
#include "EventAccessors.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
@ -255,7 +256,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
text_input_, &TextInputWidget::startedTyping, this, &ChatPage::sendTypingNotifications);
|
text_input_, &TextInputWidget::startedTyping, this, &ChatPage::sendTypingNotifications);
|
||||||
connect(typingRefresher_, &QTimer::timeout, this, &ChatPage::sendTypingNotifications);
|
connect(typingRefresher_, &QTimer::timeout, this, &ChatPage::sendTypingNotifications);
|
||||||
connect(text_input_, &TextInputWidget::stoppedTyping, this, [this]() {
|
connect(text_input_, &TextInputWidget::stoppedTyping, this, [this]() {
|
||||||
if (!userSettings_->isTypingNotificationsEnabled())
|
if (!userSettings_->typingNotifications())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
typingRefresher_->stop();
|
typingRefresher_->stop();
|
||||||
|
@ -482,7 +483,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
activateWindow();
|
activateWindow();
|
||||||
});
|
});
|
||||||
|
|
||||||
setGroupViewState(userSettings_->isGroupViewEnabled());
|
setGroupViewState(userSettings_->groupView());
|
||||||
|
|
||||||
connect(userSettings_.data(),
|
connect(userSettings_.data(),
|
||||||
&UserSettings::groupViewStateChanged,
|
&UserSettings::groupViewStateChanged,
|
||||||
|
@ -891,7 +892,7 @@ void
|
||||||
ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
|
ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
|
||||||
{
|
{
|
||||||
for (const auto &item : res.notifications) {
|
for (const auto &item : res.notifications) {
|
||||||
const auto event_id = utils::event_id(item.event);
|
const auto event_id = mtx::accessors::event_id(item.event);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (item.read) {
|
if (item.read) {
|
||||||
|
@ -901,7 +902,8 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res)
|
||||||
|
|
||||||
if (!cache::isNotificationSent(event_id)) {
|
if (!cache::isNotificationSent(event_id)) {
|
||||||
const auto room_id = QString::fromStdString(item.room_id);
|
const auto room_id = QString::fromStdString(item.room_id);
|
||||||
const auto user_id = utils::event_sender(item.event);
|
const auto user_id =
|
||||||
|
QString::fromStdString(mtx::accessors::sender(item.event));
|
||||||
|
|
||||||
// We should only sent one notification per event.
|
// We should only sent one notification per event.
|
||||||
cache::markSentNotification(event_id);
|
cache::markSentNotification(event_id);
|
||||||
|
@ -1213,7 +1215,7 @@ ChatPage::unbanUser(QString userid, QString reason)
|
||||||
void
|
void
|
||||||
ChatPage::sendTypingNotifications()
|
ChatPage::sendTypingNotifications()
|
||||||
{
|
{
|
||||||
if (!userSettings_->isTypingNotificationsEnabled())
|
if (!userSettings_->typingNotifications())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
http::client()->start_typing(
|
http::client()->start_typing(
|
||||||
|
@ -1349,7 +1351,7 @@ ChatPage::hideSideBars()
|
||||||
void
|
void
|
||||||
ChatPage::showSideBars()
|
ChatPage::showSideBars()
|
||||||
{
|
{
|
||||||
if (userSettings_->isGroupViewEnabled())
|
if (userSettings_->groupView())
|
||||||
communitiesList_->show();
|
communitiesList_->show();
|
||||||
|
|
||||||
sideBar_->show();
|
sideBar_->show();
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "ui/Theme.h"
|
#include "ui/Theme.h"
|
||||||
|
|
||||||
class RippleOverlay;
|
class RippleOverlay;
|
||||||
class QPainter;
|
|
||||||
class QMouseEvent;
|
class QMouseEvent;
|
||||||
|
|
||||||
class CommunitiesListItem : public QWidget
|
class CommunitiesListItem : public QWidget
|
||||||
|
|
|
@ -400,3 +400,9 @@ mtx::accessors::media_width(const mtx::events::collections::TimelineEvents &even
|
||||||
{
|
{
|
||||||
return std::visit(EventMediaWidth{}, event);
|
return std::visit(EventMediaWidth{}, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlohmann::json
|
||||||
|
mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents &event)
|
||||||
|
{
|
||||||
|
return std::visit([](const auto &e) { return nlohmann::json(e); }, event);
|
||||||
|
}
|
||||||
|
|
|
@ -63,4 +63,7 @@ media_height(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
media_width(const mtx::events::collections::TimelineEvents &event);
|
media_width(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
|
||||||
|
nlohmann::json
|
||||||
|
serialize_event(const mtx::events::collections::TimelineEvents &event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
#include "InviteeItem.h"
|
#include "InviteeItem.h"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <mtx/identifiers.hpp>
|
#include <mtx/identifiers.hpp>
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
class InviteeItem : public QWidget
|
class InviteeItem : public QWidget
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QLabel>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ LoginPage::LoginPage(QWidget *parent)
|
||||||
deviceName_->setLabel(tr("Device name"));
|
deviceName_->setLabel(tr("Device name"));
|
||||||
deviceName_->setToolTip(
|
deviceName_->setToolTip(
|
||||||
tr("A name for this device, which will be shown to others, when verifying your devices. "
|
tr("A name for this device, which will be shown to others, when verifying your devices. "
|
||||||
"If none is provided, a random string is used for privacy purposes."));
|
"If none is provided a default is used."));
|
||||||
|
|
||||||
serverInput_ = new TextField(this);
|
serverInput_ = new TextField(this);
|
||||||
serverInput_->setLabel("Homeserver address");
|
serverInput_->setLabel("Homeserver address");
|
||||||
|
@ -132,7 +133,7 @@ LoginPage::LoginPage(QWidget *parent)
|
||||||
|
|
||||||
form_layout_->addLayout(matrixidLayout_);
|
form_layout_->addLayout(matrixidLayout_);
|
||||||
form_layout_->addWidget(password_input_);
|
form_layout_->addWidget(password_input_);
|
||||||
form_layout_->addWidget(deviceName_, Qt::AlignHCenter, nullptr);
|
form_layout_->addWidget(deviceName_, Qt::AlignHCenter);
|
||||||
form_layout_->addLayout(serverLayout_);
|
form_layout_->addLayout(serverLayout_);
|
||||||
|
|
||||||
button_layout_ = new QHBoxLayout();
|
button_layout_ = new QHBoxLayout();
|
||||||
|
@ -179,6 +180,12 @@ LoginPage::LoginPage(QWidget *parent)
|
||||||
connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered()));
|
connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LoginPage::loginError(const QString &msg)
|
||||||
|
{
|
||||||
|
error_label_->setText(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LoginPage::onMatrixIdEntered()
|
LoginPage::onMatrixIdEntered()
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QLayout>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
|
@ -26,6 +24,9 @@ class LoadingIndicator;
|
||||||
class OverlayModal;
|
class OverlayModal;
|
||||||
class RaisedButton;
|
class RaisedButton;
|
||||||
class TextField;
|
class TextField;
|
||||||
|
class QLabel;
|
||||||
|
class QVBoxLayout;
|
||||||
|
class QHBoxLayout;
|
||||||
|
|
||||||
namespace mtx {
|
namespace mtx {
|
||||||
namespace responses {
|
namespace responses {
|
||||||
|
@ -65,7 +66,7 @@ protected:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Displays errors produced during the login.
|
// Displays errors produced during the login.
|
||||||
void loginError(const QString &msg) { error_label_->setText(msg); }
|
void loginError(const QString &msg);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Callback for the back button.
|
// Callback for the back button.
|
||||||
|
|
|
@ -148,7 +148,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
trayIcon_->setVisible(userSettings_->isTrayEnabled());
|
trayIcon_->setVisible(userSettings_->tray());
|
||||||
|
|
||||||
if (hasActiveUser()) {
|
if (hasActiveUser()) {
|
||||||
QString token = settings.value("auth/access_token").toString();
|
QString token = settings.value("auth/access_token").toString();
|
||||||
|
@ -286,7 +286,7 @@ void
|
||||||
MainWindow::closeEvent(QCloseEvent *event)
|
MainWindow::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
if (!qApp->isSavingSession() && isVisible() && pageSupportsTray() &&
|
if (!qApp->isSavingSession() && isVisible() && pageSupportsTray() &&
|
||||||
userSettings_->isTrayEnabled()) {
|
userSettings_->tray()) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@ MxcImageResponse::run()
|
||||||
auto data = cache::image(fileName);
|
auto data = cache::image(fileName);
|
||||||
if (!data.isNull()) {
|
if (!data.isNull()) {
|
||||||
m_image = utils::readImage(&data);
|
m_image = utils::readImage(&data);
|
||||||
m_image = m_image.scaled(m_requestedSize, Qt::KeepAspectRatio);
|
m_image = m_image.scaled(
|
||||||
|
m_requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
m_image.setText("mxc url", "mxc://" + m_id);
|
m_image.setText("mxc url", "mxc://" + m_id);
|
||||||
|
|
||||||
if (!m_image.isNull()) {
|
if (!m_image.isNull()) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
@ -106,10 +107,10 @@ RegisterPage::RegisterPage(QWidget *parent)
|
||||||
tr("A server that allows registration. Since matrix is decentralized, you need to first "
|
tr("A server that allows registration. Since matrix is decentralized, you need to first "
|
||||||
"find a server you can register on or host your own."));
|
"find a server you can register on or host your own."));
|
||||||
|
|
||||||
form_layout_->addWidget(username_input_, Qt::AlignHCenter, nullptr);
|
form_layout_->addWidget(username_input_, Qt::AlignHCenter);
|
||||||
form_layout_->addWidget(password_input_, Qt::AlignHCenter, nullptr);
|
form_layout_->addWidget(password_input_, Qt::AlignHCenter);
|
||||||
form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter, nullptr);
|
form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter);
|
||||||
form_layout_->addWidget(server_input_, Qt::AlignHCenter, nullptr);
|
form_layout_->addWidget(server_input_, Qt::AlignHCenter);
|
||||||
|
|
||||||
button_layout_ = new QHBoxLayout();
|
button_layout_ = new QHBoxLayout();
|
||||||
button_layout_->setSpacing(0);
|
button_layout_->setSpacing(0);
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QWidget>
|
||||||
#include <QLayout>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <mtx/user_interactive.hpp>
|
#include <mtx/user_interactive.hpp>
|
||||||
|
@ -26,6 +26,9 @@
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
class RaisedButton;
|
class RaisedButton;
|
||||||
class TextField;
|
class TextField;
|
||||||
|
class QLabel;
|
||||||
|
class QVBoxLayout;
|
||||||
|
class QHBoxLayout;
|
||||||
|
|
||||||
class RegisterPage : public QWidget
|
class RegisterPage : public QWidget
|
||||||
{
|
{
|
||||||
|
|
|
@ -451,7 +451,7 @@ RoomInfoListItem::calculateImportance() const
|
||||||
// returns ImportanceDisabled or Invite
|
// returns ImportanceDisabled or Invite
|
||||||
if (isInvite()) {
|
if (isInvite()) {
|
||||||
return Invite;
|
return Invite;
|
||||||
} else if (!settings->isSortByImportanceEnabled()) {
|
} else if (!settings->sortByImportance()) {
|
||||||
return ImportanceDisabled;
|
return ImportanceDisabled;
|
||||||
} else if (unreadHighlightedMsgCount_) {
|
} else if (unreadHighlightedMsgCount_) {
|
||||||
return NewMentions;
|
return NewMentions;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScroller>
|
#include <QScroller>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleOption>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleOption>
|
||||||
|
|
||||||
#include <mtx/requests.hpp>
|
#include <mtx/requests.hpp>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ class Menu;
|
||||||
class TextLabel;
|
class TextLabel;
|
||||||
class OverlayModal;
|
class OverlayModal;
|
||||||
|
|
||||||
class QPainter;
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleOption>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QWidget>
|
||||||
#include <QLayout>
|
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
class OverlayModal;
|
class OverlayModal;
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QHBoxLayout;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
class UserInfoWidget : public QWidget
|
class UserInfoWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QScroller>
|
#include <QScroller>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
@ -51,17 +52,20 @@ void
|
||||||
UserSettings::load()
|
UserSettings::load()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
isTrayEnabled_ = settings.value("user/window/tray", false).toBool();
|
tray_ = settings.value("user/window/tray", false).toBool();
|
||||||
hasDesktopNotifications_ = settings.value("user/desktop_notifications", true).toBool();
|
hasDesktopNotifications_ = settings.value("user/desktop_notifications", true).toBool();
|
||||||
isStartInTrayEnabled_ = settings.value("user/window/start_in_tray", false).toBool();
|
startInTray_ = settings.value("user/window/start_in_tray", false).toBool();
|
||||||
isGroupViewEnabled_ = settings.value("user/group_view", true).toBool();
|
groupView_ = settings.value("user/group_view", true).toBool();
|
||||||
isButtonsInTimelineEnabled_ = settings.value("user/timeline/buttons", true).toBool();
|
buttonsInTimeline_ = settings.value("user/timeline/buttons", true).toBool();
|
||||||
isMessageHoverHighlightEnabled_ =
|
timelineMaxWidth_ = settings.value("user/timeline/max_width", 0).toInt();
|
||||||
|
messageHoverHighlight_ =
|
||||||
settings.value("user/timeline/message_hover_highlight", false).toBool();
|
settings.value("user/timeline/message_hover_highlight", false).toBool();
|
||||||
isMarkdownEnabled_ = settings.value("user/markdown_enabled", true).toBool();
|
enlargeEmojiOnlyMessages_ =
|
||||||
isTypingNotificationsEnabled_ = settings.value("user/typing_notifications", true).toBool();
|
settings.value("user/timeline/enlarge_emoji_only_msg", false).toBool();
|
||||||
|
markdown_ = settings.value("user/markdown_enabled", true).toBool();
|
||||||
|
typingNotifications_ = settings.value("user/typing_notifications", true).toBool();
|
||||||
sortByImportance_ = settings.value("user/sort_by_unread", true).toBool();
|
sortByImportance_ = settings.value("user/sort_by_unread", true).toBool();
|
||||||
isReadReceiptsEnabled_ = settings.value("user/read_receipts", true).toBool();
|
readReceipts_ = settings.value("user/read_receipts", true).toBool();
|
||||||
theme_ = settings.value("user/theme", defaultTheme_).toString();
|
theme_ = settings.value("user/theme", defaultTheme_).toString();
|
||||||
font_ = settings.value("user/font_family", "default").toString();
|
font_ = settings.value("user/font_family", "default").toString();
|
||||||
avatarCircles_ = settings.value("user/avatar_circles", true).toBool();
|
avatarCircles_ = settings.value("user/avatar_circles", true).toBool();
|
||||||
|
@ -71,34 +75,183 @@ UserSettings::load()
|
||||||
|
|
||||||
applyTheme();
|
applyTheme();
|
||||||
}
|
}
|
||||||
|
void
|
||||||
|
UserSettings::setMessageHoverHighlight(bool state)
|
||||||
|
{
|
||||||
|
if (state == messageHoverHighlight_)
|
||||||
|
return;
|
||||||
|
messageHoverHighlight_ = state;
|
||||||
|
emit messageHoverHighlightChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
UserSettings::setEnlargeEmojiOnlyMessages(bool state)
|
||||||
|
{
|
||||||
|
if (state == enlargeEmojiOnlyMessages_)
|
||||||
|
return;
|
||||||
|
enlargeEmojiOnlyMessages_ = state;
|
||||||
|
emit enlargeEmojiOnlyMessagesChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
void
|
||||||
|
UserSettings::setTray(bool state)
|
||||||
|
{
|
||||||
|
if (state == tray_)
|
||||||
|
return;
|
||||||
|
tray_ = state;
|
||||||
|
emit trayChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setStartInTray(bool state)
|
||||||
|
{
|
||||||
|
if (state == startInTray_)
|
||||||
|
return;
|
||||||
|
startInTray_ = state;
|
||||||
|
emit startInTrayChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setGroupView(bool state)
|
||||||
|
{
|
||||||
|
if (groupView_ != state)
|
||||||
|
emit groupViewStateChanged(state);
|
||||||
|
|
||||||
|
groupView_ = state;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setMarkdown(bool state)
|
||||||
|
{
|
||||||
|
if (state == markdown_)
|
||||||
|
return;
|
||||||
|
markdown_ = state;
|
||||||
|
emit markdownChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setReadReceipts(bool state)
|
||||||
|
{
|
||||||
|
if (state == readReceipts_)
|
||||||
|
return;
|
||||||
|
readReceipts_ = state;
|
||||||
|
emit readReceiptsChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setTypingNotifications(bool state)
|
||||||
|
{
|
||||||
|
if (state == typingNotifications_)
|
||||||
|
return;
|
||||||
|
typingNotifications_ = state;
|
||||||
|
emit typingNotificationsChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setSortByImportance(bool state)
|
||||||
|
{
|
||||||
|
if (state == sortByImportance_)
|
||||||
|
return;
|
||||||
|
sortByImportance_ = state;
|
||||||
|
emit roomSortingChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setButtonsInTimeline(bool state)
|
||||||
|
{
|
||||||
|
if (state == buttonsInTimeline_)
|
||||||
|
return;
|
||||||
|
buttonsInTimeline_ = state;
|
||||||
|
emit buttonInTimelineChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setTimelineMaxWidth(int state)
|
||||||
|
{
|
||||||
|
if (state == timelineMaxWidth_)
|
||||||
|
return;
|
||||||
|
timelineMaxWidth_ = state;
|
||||||
|
emit timelineMaxWidthChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setDesktopNotifications(bool state)
|
||||||
|
{
|
||||||
|
if (state == hasDesktopNotifications_)
|
||||||
|
return;
|
||||||
|
hasDesktopNotifications_ = state;
|
||||||
|
emit desktopNotificationsChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setAvatarCircles(bool state)
|
||||||
|
{
|
||||||
|
if (state == avatarCircles_)
|
||||||
|
return;
|
||||||
|
avatarCircles_ = state;
|
||||||
|
emit avatarCirclesChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setDecryptSidebar(bool state)
|
||||||
|
{
|
||||||
|
if (state == decryptSidebar_)
|
||||||
|
return;
|
||||||
|
decryptSidebar_ = state;
|
||||||
|
emit decryptSidebarChanged(state);
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setFontSize(double size)
|
UserSettings::setFontSize(double size)
|
||||||
{
|
{
|
||||||
|
if (size == baseFontSize_)
|
||||||
|
return;
|
||||||
baseFontSize_ = size;
|
baseFontSize_ = size;
|
||||||
|
emit fontSizeChanged(size);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setFontFamily(QString family)
|
UserSettings::setFontFamily(QString family)
|
||||||
{
|
{
|
||||||
|
if (family == font_)
|
||||||
|
return;
|
||||||
font_ = family;
|
font_ = family;
|
||||||
|
emit fontChanged(family);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setEmojiFontFamily(QString family)
|
UserSettings::setEmojiFontFamily(QString family)
|
||||||
{
|
{
|
||||||
|
if (family == emojiFont_)
|
||||||
|
return;
|
||||||
emojiFont_ = family;
|
emojiFont_ = family;
|
||||||
|
emit emojiFontChanged(family);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserSettings::setTheme(QString theme)
|
UserSettings::setTheme(QString theme)
|
||||||
{
|
{
|
||||||
|
if (theme == theme)
|
||||||
|
return;
|
||||||
theme_ = theme;
|
theme_ = theme;
|
||||||
save();
|
save();
|
||||||
applyTheme();
|
applyTheme();
|
||||||
|
emit themeChanged(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -161,29 +314,33 @@ UserSettings::save()
|
||||||
settings.beginGroup("user");
|
settings.beginGroup("user");
|
||||||
|
|
||||||
settings.beginGroup("window");
|
settings.beginGroup("window");
|
||||||
settings.setValue("tray", isTrayEnabled_);
|
settings.setValue("tray", tray_);
|
||||||
settings.setValue("start_in_tray", isStartInTrayEnabled_);
|
settings.setValue("start_in_tray", startInTray_);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
settings.beginGroup("timeline");
|
settings.beginGroup("timeline");
|
||||||
settings.setValue("buttons", isButtonsInTimelineEnabled_);
|
settings.setValue("buttons", buttonsInTimeline_);
|
||||||
settings.setValue("message_hover_highlight", isMessageHoverHighlightEnabled_);
|
settings.setValue("message_hover_highlight", messageHoverHighlight_);
|
||||||
|
settings.setValue("enlarge_emoji_only_msg", enlargeEmojiOnlyMessages_);
|
||||||
|
settings.setValue("max_width", timelineMaxWidth_);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
settings.setValue("avatar_circles", avatarCircles_);
|
settings.setValue("avatar_circles", avatarCircles_);
|
||||||
settings.setValue("decrypt_sidebar", decryptSidebar_);
|
settings.setValue("decrypt_sidebar", decryptSidebar_);
|
||||||
settings.setValue("font_size", baseFontSize_);
|
settings.setValue("font_size", baseFontSize_);
|
||||||
settings.setValue("typing_notifications", isTypingNotificationsEnabled_);
|
settings.setValue("typing_notifications", typingNotifications_);
|
||||||
settings.setValue("minor_events", sortByImportance_);
|
settings.setValue("minor_events", sortByImportance_);
|
||||||
settings.setValue("read_receipts", isReadReceiptsEnabled_);
|
settings.setValue("read_receipts", readReceipts_);
|
||||||
settings.setValue("group_view", isGroupViewEnabled_);
|
settings.setValue("group_view", groupView_);
|
||||||
settings.setValue("markdown_enabled", isMarkdownEnabled_);
|
settings.setValue("markdown_enabled", markdown_);
|
||||||
settings.setValue("desktop_notifications", hasDesktopNotifications_);
|
settings.setValue("desktop_notifications", hasDesktopNotifications_);
|
||||||
settings.setValue("theme", theme());
|
settings.setValue("theme", theme());
|
||||||
settings.setValue("font_family", font_);
|
settings.setValue("font_family", font_);
|
||||||
settings.setValue("emoji_font_family", emojiFont_);
|
settings.setValue("emoji_font_family", emojiFont_);
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
|
settings.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
HorizontalLine::HorizontalLine(QWidget *parent)
|
HorizontalLine::HorizontalLine(QWidget *parent)
|
||||||
|
@ -239,16 +396,18 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
timelineButtonsToggle_ = new Toggle{this};
|
timelineButtonsToggle_ = new Toggle{this};
|
||||||
typingNotifications_ = new Toggle{this};
|
typingNotifications_ = new Toggle{this};
|
||||||
messageHoverHighlight_ = new Toggle{this};
|
messageHoverHighlight_ = new Toggle{this};
|
||||||
|
enlargeEmojiOnlyMessages_ = new Toggle{this};
|
||||||
sortByImportance_ = new Toggle{this};
|
sortByImportance_ = new Toggle{this};
|
||||||
readReceipts_ = new Toggle{this};
|
readReceipts_ = new Toggle{this};
|
||||||
markdownEnabled_ = new Toggle{this};
|
markdown_ = new Toggle{this};
|
||||||
desktopNotifications_ = new Toggle{this};
|
desktopNotifications_ = new Toggle{this};
|
||||||
scaleFactorCombo_ = new QComboBox{this};
|
scaleFactorCombo_ = new QComboBox{this};
|
||||||
fontSizeCombo_ = new QComboBox{this};
|
fontSizeCombo_ = new QComboBox{this};
|
||||||
fontSelectionCombo_ = new QComboBox{this};
|
fontSelectionCombo_ = new QComboBox{this};
|
||||||
emojiFontSelectionCombo_ = new QComboBox{this};
|
emojiFontSelectionCombo_ = new QComboBox{this};
|
||||||
|
timelineMaxWidthSpin_ = new QSpinBox{this};
|
||||||
|
|
||||||
if (!settings_->isTrayEnabled())
|
if (!settings_->tray())
|
||||||
startInTrayToggle_->setDisabled(true);
|
startInTrayToggle_->setDisabled(true);
|
||||||
|
|
||||||
avatarCircles_->setFixedSize(64, 48);
|
avatarCircles_->setFixedSize(64, 48);
|
||||||
|
@ -291,6 +450,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
int themeIndex = themeCombo_->findText(themeStr);
|
int themeIndex = themeCombo_->findText(themeStr);
|
||||||
themeCombo_->setCurrentIndex(themeIndex);
|
themeCombo_->setCurrentIndex(themeIndex);
|
||||||
|
|
||||||
|
timelineMaxWidthSpin_->setMinimum(0);
|
||||||
|
timelineMaxWidthSpin_->setMaximum(100'000'000);
|
||||||
|
timelineMaxWidthSpin_->setSingleStep(10);
|
||||||
|
|
||||||
auto encryptionLabel_ = new QLabel{tr("ENCRYPTION"), this};
|
auto encryptionLabel_ = new QLabel{tr("ENCRYPTION"), this};
|
||||||
encryptionLabel_->setFixedHeight(encryptionLabel_->minimumHeight() + LayoutTopMargin);
|
encryptionLabel_->setFixedHeight(encryptionLabel_->minimumHeight() + LayoutTopMargin);
|
||||||
encryptionLabel_->setAlignment(Qt::AlignBottom);
|
encryptionLabel_->setAlignment(Qt::AlignBottom);
|
||||||
|
@ -323,11 +486,15 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
sessionKeysLayout->addWidget(sessionKeysExportBtn, 0, Qt::AlignRight);
|
sessionKeysLayout->addWidget(sessionKeysExportBtn, 0, Qt::AlignRight);
|
||||||
sessionKeysLayout->addWidget(sessionKeysImportBtn, 0, Qt::AlignRight);
|
sessionKeysLayout->addWidget(sessionKeysImportBtn, 0, Qt::AlignRight);
|
||||||
|
|
||||||
auto boxWrap = [this, &font](QString labelText, QWidget *field) {
|
auto boxWrap = [this, &font](QString labelText, QWidget *field, QString tooltipText = "") {
|
||||||
auto label = new QLabel{labelText, this};
|
auto label = new QLabel{labelText, this};
|
||||||
label->setFont(font);
|
label->setFont(font);
|
||||||
label->setMargin(OptionMargin);
|
label->setMargin(OptionMargin);
|
||||||
|
|
||||||
|
if (!tooltipText.isEmpty()) {
|
||||||
|
label->setToolTip(tooltipText);
|
||||||
|
}
|
||||||
|
|
||||||
auto layout = new QHBoxLayout;
|
auto layout = new QHBoxLayout;
|
||||||
layout->addWidget(field, 0, Qt::AlignRight);
|
layout->addWidget(field, 0, Qt::AlignRight);
|
||||||
|
|
||||||
|
@ -336,25 +503,70 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
|
|
||||||
formLayout_->addRow(general_);
|
formLayout_->addRow(general_);
|
||||||
formLayout_->addRow(new HorizontalLine{this});
|
formLayout_->addRow(new HorizontalLine{this});
|
||||||
boxWrap(tr("Minimize to tray"), trayToggle_);
|
boxWrap(
|
||||||
boxWrap(tr("Start in tray"), startInTrayToggle_);
|
tr("Minimize to tray"),
|
||||||
|
trayToggle_,
|
||||||
|
tr("Keep the application running in the background after closing the client window."));
|
||||||
|
boxWrap(tr("Start in tray"),
|
||||||
|
startInTrayToggle_,
|
||||||
|
tr("Start the application in the background without showing the client window."));
|
||||||
formLayout_->addRow(new HorizontalLine{this});
|
formLayout_->addRow(new HorizontalLine{this});
|
||||||
boxWrap(tr("Circular Avatars"), avatarCircles_);
|
boxWrap(tr("Circular Avatars"),
|
||||||
boxWrap(tr("Group's sidebar"), groupViewToggle_);
|
avatarCircles_,
|
||||||
boxWrap(tr("Decrypt messages in sidebar"), decryptSidebar_);
|
tr("Change the appearance of user avatars in chats.\nOFF - square, ON - Circle."));
|
||||||
boxWrap(tr("Show buttons in timeline"), timelineButtonsToggle_);
|
boxWrap(tr("Group's sidebar"),
|
||||||
boxWrap(tr("Typing notifications"), typingNotifications_);
|
groupViewToggle_,
|
||||||
boxWrap(tr("Sort rooms by unreads"), sortByImportance_);
|
tr("Show a column containing groups and tags next to the room list."));
|
||||||
|
boxWrap(tr("Decrypt messages in sidebar"),
|
||||||
|
decryptSidebar_,
|
||||||
|
tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in "
|
||||||
|
"encrypted chats."));
|
||||||
|
boxWrap(tr("Show buttons in timeline"),
|
||||||
|
timelineButtonsToggle_,
|
||||||
|
tr("Show buttons to quickly reply, react or access additional options next to each "
|
||||||
|
"message."));
|
||||||
|
boxWrap(tr("Limit width of timeline"),
|
||||||
|
timelineMaxWidthSpin_,
|
||||||
|
tr("Set the max width of messages in the timeline (in pixels). This can help "
|
||||||
|
"readability on wide screen, when Nheko is maximised"));
|
||||||
|
boxWrap(tr("Typing notifications"),
|
||||||
|
typingNotifications_,
|
||||||
|
tr("Show who is typing in a room.\nThis will also enable or disable sending typing "
|
||||||
|
"notifications to others."));
|
||||||
|
boxWrap(
|
||||||
|
tr("Sort rooms by unreads"),
|
||||||
|
sortByImportance_,
|
||||||
|
tr(
|
||||||
|
"Display rooms with new messages first.\nIf this is off, the list of rooms will only "
|
||||||
|
"be sorted by the timestamp of the last message in a room.\nIf this is on, rooms which "
|
||||||
|
"have active notifications (the small circle with a number in it) will be sorted on "
|
||||||
|
"top. Rooms, that you have muted, will still be sorted by timestamp, since you don't "
|
||||||
|
"seem to consider them as important as the other rooms."));
|
||||||
formLayout_->addRow(new HorizontalLine{this});
|
formLayout_->addRow(new HorizontalLine{this});
|
||||||
boxWrap(tr("Read receipts"), readReceipts_);
|
boxWrap(tr("Read receipts"),
|
||||||
boxWrap(tr("Send messages as Markdown"), markdownEnabled_);
|
readReceipts_,
|
||||||
boxWrap(tr("Desktop notifications"), desktopNotifications_);
|
tr("Show if your message was read.\nStatus is displayed next to timestamps."));
|
||||||
boxWrap(tr("Highlight message on hover"), messageHoverHighlight_);
|
boxWrap(
|
||||||
|
tr("Send messages as Markdown"),
|
||||||
|
markdown_,
|
||||||
|
tr("Allow using markdown in messages.\nWhen disabled, all messages are sent as a plain "
|
||||||
|
"text."));
|
||||||
|
boxWrap(tr("Desktop notifications"),
|
||||||
|
desktopNotifications_,
|
||||||
|
tr("Notify about received message when the client is not currently focused."));
|
||||||
|
boxWrap(tr("Highlight message on hover"),
|
||||||
|
messageHoverHighlight_,
|
||||||
|
tr("Change the background color of messages when you hover over them."));
|
||||||
|
boxWrap(tr("Large Emoji in timeline"),
|
||||||
|
enlargeEmojiOnlyMessages_,
|
||||||
|
tr("Make font size larger if messages with only a few emojis are displayed."));
|
||||||
formLayout_->addRow(uiLabel_);
|
formLayout_->addRow(uiLabel_);
|
||||||
formLayout_->addRow(new HorizontalLine{this});
|
formLayout_->addRow(new HorizontalLine{this});
|
||||||
|
|
||||||
#if !defined(Q_OS_MAC)
|
#if !defined(Q_OS_MAC)
|
||||||
boxWrap(tr("Scale factor"), scaleFactorCombo_);
|
boxWrap(tr("Scale factor"),
|
||||||
|
scaleFactorCombo_,
|
||||||
|
tr("Change the scale factor of the whole user interface."));
|
||||||
#else
|
#else
|
||||||
scaleFactorCombo_->hide();
|
scaleFactorCombo_->hide();
|
||||||
#endif
|
#endif
|
||||||
|
@ -400,78 +612,87 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
topLayout_->addWidget(versionInfo);
|
topLayout_->addWidget(versionInfo);
|
||||||
|
|
||||||
connect(themeCombo_,
|
connect(themeCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &text) {
|
[this](const QString &text) {
|
||||||
settings_->setTheme(text.toLower());
|
settings_->setTheme(text.toLower());
|
||||||
emit themeChanged();
|
emit themeChanged();
|
||||||
});
|
});
|
||||||
connect(scaleFactorCombo_,
|
connect(scaleFactorCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[](const QString &factor) { utils::setScaleFactor(factor.toFloat()); });
|
[](const QString &factor) { utils::setScaleFactor(factor.toFloat()); });
|
||||||
connect(fontSizeCombo_,
|
connect(fontSizeCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &size) { settings_->setFontSize(size.trimmed().toDouble()); });
|
[this](const QString &size) { settings_->setFontSize(size.trimmed().toDouble()); });
|
||||||
connect(fontSelectionCombo_,
|
connect(fontSelectionCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &family) { settings_->setFontFamily(family.trimmed()); });
|
[this](const QString &family) { settings_->setFontFamily(family.trimmed()); });
|
||||||
connect(emojiFontSelectionCombo_,
|
connect(emojiFontSelectionCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &family) { settings_->setEmojiFontFamily(family.trimmed()); });
|
[this](const QString &family) { settings_->setEmojiFontFamily(family.trimmed()); });
|
||||||
connect(trayToggle_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(trayToggle_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setTray(!isDisabled);
|
settings_->setTray(!disabled);
|
||||||
if (isDisabled) {
|
if (disabled) {
|
||||||
startInTrayToggle_->setDisabled(true);
|
startInTrayToggle_->setDisabled(true);
|
||||||
} else {
|
} else {
|
||||||
startInTrayToggle_->setEnabled(true);
|
startInTrayToggle_->setEnabled(true);
|
||||||
}
|
}
|
||||||
emit trayOptionChanged(!isDisabled);
|
emit trayOptionChanged(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(startInTrayToggle_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(startInTrayToggle_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setStartInTray(!isDisabled);
|
settings_->setStartInTray(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(groupViewToggle_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(groupViewToggle_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setGroupView(!isDisabled);
|
settings_->setGroupView(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(decryptSidebar_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(decryptSidebar_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setDecryptSidebar(!isDisabled);
|
settings_->setDecryptSidebar(!disabled);
|
||||||
emit decryptSidebarChanged();
|
emit decryptSidebarChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(avatarCircles_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(avatarCircles_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setAvatarCircles(!isDisabled);
|
settings_->setAvatarCircles(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(markdownEnabled_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(markdown_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setMarkdownEnabled(!isDisabled);
|
settings_->setMarkdown(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(typingNotifications_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(typingNotifications_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setTypingNotifications(!isDisabled);
|
settings_->setTypingNotifications(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(sortByImportance_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(sortByImportance_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setSortByImportance(!isDisabled);
|
settings_->setSortByImportance(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(timelineButtonsToggle_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(timelineButtonsToggle_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setButtonsInTimeline(!isDisabled);
|
settings_->setButtonsInTimeline(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(readReceipts_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(readReceipts_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setReadReceipts(!isDisabled);
|
settings_->setReadReceipts(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(desktopNotifications_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(desktopNotifications_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setDesktopNotifications(!isDisabled);
|
settings_->setDesktopNotifications(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(messageHoverHighlight_, &Toggle::toggled, this, [this](bool isDisabled) {
|
connect(messageHoverHighlight_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
settings_->setMessageHoverHighlight(!isDisabled);
|
settings_->setMessageHoverHighlight(!disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(enlargeEmojiOnlyMessages_, &Toggle::toggled, this, [this](bool disabled) {
|
||||||
|
settings_->setEnlargeEmojiOnlyMessages(!disabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(timelineMaxWidthSpin_,
|
||||||
|
qOverload<int>(&QSpinBox::valueChanged),
|
||||||
|
this,
|
||||||
|
[this](int newValue) { settings_->setTimelineMaxWidth(newValue); });
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
sessionKeysImportBtn, &QPushButton::clicked, this, &UserSettingsPage::importSessionKeys);
|
sessionKeysImportBtn, &QPushButton::clicked, this, &UserSettingsPage::importSessionKeys);
|
||||||
|
|
||||||
|
@ -493,19 +714,21 @@ UserSettingsPage::showEvent(QShowEvent *)
|
||||||
utils::restoreCombobox(themeCombo_, settings_->theme());
|
utils::restoreCombobox(themeCombo_, settings_->theme());
|
||||||
|
|
||||||
// FIXME: Toggle treats true as "off"
|
// FIXME: Toggle treats true as "off"
|
||||||
trayToggle_->setState(!settings_->isTrayEnabled());
|
trayToggle_->setState(!settings_->tray());
|
||||||
startInTrayToggle_->setState(!settings_->isStartInTrayEnabled());
|
startInTrayToggle_->setState(!settings_->startInTray());
|
||||||
groupViewToggle_->setState(!settings_->isGroupViewEnabled());
|
groupViewToggle_->setState(!settings_->groupView());
|
||||||
decryptSidebar_->setState(!settings_->isDecryptSidebarEnabled());
|
decryptSidebar_->setState(!settings_->decryptSidebar());
|
||||||
avatarCircles_->setState(!settings_->isAvatarCirclesEnabled());
|
avatarCircles_->setState(!settings_->avatarCircles());
|
||||||
typingNotifications_->setState(!settings_->isTypingNotificationsEnabled());
|
typingNotifications_->setState(!settings_->typingNotifications());
|
||||||
sortByImportance_->setState(!settings_->isSortByImportanceEnabled());
|
sortByImportance_->setState(!settings_->sortByImportance());
|
||||||
timelineButtonsToggle_->setState(!settings_->isButtonsInTimelineEnabled());
|
timelineButtonsToggle_->setState(!settings_->buttonsInTimeline());
|
||||||
readReceipts_->setState(!settings_->isReadReceiptsEnabled());
|
readReceipts_->setState(!settings_->readReceipts());
|
||||||
markdownEnabled_->setState(!settings_->isMarkdownEnabled());
|
markdown_->setState(!settings_->markdown());
|
||||||
desktopNotifications_->setState(!settings_->hasDesktopNotifications());
|
desktopNotifications_->setState(!settings_->hasDesktopNotifications());
|
||||||
messageHoverHighlight_->setState(!settings_->isMessageHoverHighlightEnabled());
|
messageHoverHighlight_->setState(!settings_->messageHoverHighlight());
|
||||||
|
enlargeEmojiOnlyMessages_->setState(!settings_->enlargeEmojiOnlyMessages());
|
||||||
deviceIdValue_->setText(QString::fromStdString(http::client()->device_id()));
|
deviceIdValue_->setText(QString::fromStdString(http::client()->device_id()));
|
||||||
|
timelineMaxWidthSpin_->setValue(settings_->timelineMaxWidth());
|
||||||
|
|
||||||
deviceFingerprintValue_->setText(
|
deviceFingerprintValue_->setText(
|
||||||
utils::humanReadableFingerprint(olm::client()->identity_keys().ed25519));
|
utils::humanReadableFingerprint(olm::client()->identity_keys().ed25519));
|
||||||
|
|
|
@ -17,17 +17,19 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QFormLayout>
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLabel>
|
|
||||||
#include <QLayout>
|
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class Toggle;
|
class Toggle;
|
||||||
|
class QLabel;
|
||||||
|
class QFormLayout;
|
||||||
|
class QComboBox;
|
||||||
|
class QSpinBox;
|
||||||
|
class QHBoxLayout;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
constexpr int OptionMargin = 6;
|
constexpr int OptionMargin = 6;
|
||||||
constexpr int LayoutTopMargin = 50;
|
constexpr int LayoutTopMargin = 50;
|
||||||
|
@ -37,6 +39,36 @@ class UserSettings : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
|
||||||
|
Q_PROPERTY(bool messageHoverHighlight READ messageHoverHighlight WRITE
|
||||||
|
setMessageHoverHighlight NOTIFY messageHoverHighlightChanged)
|
||||||
|
Q_PROPERTY(bool enlargeEmojiOnlyMessages READ enlargeEmojiOnlyMessages WRITE
|
||||||
|
setEnlargeEmojiOnlyMessages NOTIFY enlargeEmojiOnlyMessagesChanged)
|
||||||
|
Q_PROPERTY(bool tray READ tray WRITE setTray NOTIFY trayChanged)
|
||||||
|
Q_PROPERTY(bool startInTray READ startInTray WRITE setStartInTray NOTIFY startInTrayChanged)
|
||||||
|
Q_PROPERTY(bool groupView READ groupView WRITE setGroupView NOTIFY groupViewStateChanged)
|
||||||
|
Q_PROPERTY(bool markdown READ markdown WRITE setMarkdown NOTIFY markdownChanged)
|
||||||
|
Q_PROPERTY(bool typingNotifications READ typingNotifications WRITE setTypingNotifications
|
||||||
|
NOTIFY typingNotificationsChanged)
|
||||||
|
Q_PROPERTY(bool sortByImportance READ sortByImportance WRITE setSortByImportance NOTIFY
|
||||||
|
roomSortingChanged)
|
||||||
|
Q_PROPERTY(bool buttonsInTimeline READ buttonsInTimeline WRITE setButtonsInTimeline NOTIFY
|
||||||
|
buttonInTimelineChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool readReceipts READ readReceipts WRITE setReadReceipts NOTIFY readReceiptsChanged)
|
||||||
|
Q_PROPERTY(bool desktopNotifications READ hasDesktopNotifications WRITE
|
||||||
|
setDesktopNotifications NOTIFY desktopNotificationsChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool avatarCircles READ avatarCircles WRITE setAvatarCircles NOTIFY avatarCirclesChanged)
|
||||||
|
Q_PROPERTY(bool decryptSidebar READ decryptSidebar WRITE setDecryptSidebar NOTIFY
|
||||||
|
decryptSidebarChanged)
|
||||||
|
Q_PROPERTY(int timelineMaxWidth READ timelineMaxWidth WRITE setTimelineMaxWidth NOTIFY
|
||||||
|
timelineMaxWidthChanged)
|
||||||
|
Q_PROPERTY(double fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged)
|
||||||
|
Q_PROPERTY(QString font READ font WRITE setFontFamily NOTIFY fontChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
QString emojiFont READ emojiFont WRITE setEmojiFontFamily NOTIFY emojiFontChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UserSettings();
|
UserSettings();
|
||||||
|
|
||||||
|
@ -44,104 +76,62 @@ public:
|
||||||
void load();
|
void load();
|
||||||
void applyTheme();
|
void applyTheme();
|
||||||
void setTheme(QString theme);
|
void setTheme(QString theme);
|
||||||
void setMessageHoverHighlight(bool state)
|
void setMessageHoverHighlight(bool state);
|
||||||
{
|
void setEnlargeEmojiOnlyMessages(bool state);
|
||||||
isMessageHoverHighlightEnabled_ = state;
|
void setTray(bool state);
|
||||||
save();
|
void setStartInTray(bool state);
|
||||||
}
|
|
||||||
void setTray(bool state)
|
|
||||||
{
|
|
||||||
isTrayEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setStartInTray(bool state)
|
|
||||||
{
|
|
||||||
isStartInTrayEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFontSize(double size);
|
void setFontSize(double size);
|
||||||
void setFontFamily(QString family);
|
void setFontFamily(QString family);
|
||||||
void setEmojiFontFamily(QString family);
|
void setEmojiFontFamily(QString family);
|
||||||
|
void setGroupView(bool state);
|
||||||
void setGroupView(bool state)
|
void setMarkdown(bool state);
|
||||||
{
|
void setReadReceipts(bool state);
|
||||||
if (isGroupViewEnabled_ != state)
|
void setTypingNotifications(bool state);
|
||||||
emit groupViewStateChanged(state);
|
void setSortByImportance(bool state);
|
||||||
|
void setButtonsInTimeline(bool state);
|
||||||
isGroupViewEnabled_ = state;
|
void setTimelineMaxWidth(int state);
|
||||||
save();
|
void setDesktopNotifications(bool state);
|
||||||
}
|
void setAvatarCircles(bool state);
|
||||||
|
void setDecryptSidebar(bool state);
|
||||||
void setMarkdownEnabled(bool state)
|
|
||||||
{
|
|
||||||
isMarkdownEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setReadReceipts(bool state)
|
|
||||||
{
|
|
||||||
isReadReceiptsEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTypingNotifications(bool state)
|
|
||||||
{
|
|
||||||
isTypingNotificationsEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSortByImportance(bool state)
|
|
||||||
{
|
|
||||||
sortByImportance_ = state;
|
|
||||||
emit roomSortingChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setButtonsInTimeline(bool state)
|
|
||||||
{
|
|
||||||
isButtonsInTimelineEnabled_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDesktopNotifications(bool state)
|
|
||||||
{
|
|
||||||
hasDesktopNotifications_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAvatarCircles(bool state)
|
|
||||||
{
|
|
||||||
avatarCircles_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDecryptSidebar(bool state)
|
|
||||||
{
|
|
||||||
decryptSidebar_ = state;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
|
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
|
||||||
bool isMessageHoverHighlightEnabled() const { return isMessageHoverHighlightEnabled_; }
|
bool messageHoverHighlight() const { return messageHoverHighlight_; }
|
||||||
bool isTrayEnabled() const { return isTrayEnabled_; }
|
bool enlargeEmojiOnlyMessages() const { return enlargeEmojiOnlyMessages_; }
|
||||||
bool isStartInTrayEnabled() const { return isStartInTrayEnabled_; }
|
bool tray() const { return tray_; }
|
||||||
bool isGroupViewEnabled() const { return isGroupViewEnabled_; }
|
bool startInTray() const { return startInTray_; }
|
||||||
bool isAvatarCirclesEnabled() const { return avatarCircles_; }
|
bool groupView() const { return groupView_; }
|
||||||
bool isDecryptSidebarEnabled() const { return decryptSidebar_; }
|
bool avatarCircles() const { return avatarCircles_; }
|
||||||
bool isMarkdownEnabled() const { return isMarkdownEnabled_; }
|
bool decryptSidebar() const { return decryptSidebar_; }
|
||||||
bool isTypingNotificationsEnabled() const { return isTypingNotificationsEnabled_; }
|
bool markdown() const { return markdown_; }
|
||||||
bool isSortByImportanceEnabled() const { return sortByImportance_; }
|
bool typingNotifications() const { return typingNotifications_; }
|
||||||
bool isButtonsInTimelineEnabled() const { return isButtonsInTimelineEnabled_; }
|
bool sortByImportance() const { return sortByImportance_; }
|
||||||
bool isReadReceiptsEnabled() const { return isReadReceiptsEnabled_; }
|
bool buttonsInTimeline() const { return buttonsInTimeline_; }
|
||||||
|
bool readReceipts() const { return readReceipts_; }
|
||||||
bool hasDesktopNotifications() const { return hasDesktopNotifications_; }
|
bool hasDesktopNotifications() const { return hasDesktopNotifications_; }
|
||||||
|
int timelineMaxWidth() const { return timelineMaxWidth_; }
|
||||||
double fontSize() const { return baseFontSize_; }
|
double fontSize() const { return baseFontSize_; }
|
||||||
QString font() const { return font_; }
|
QString font() const { return font_; }
|
||||||
QString emojiFont() const { return emojiFont_; }
|
QString emojiFont() const { return emojiFont_; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void groupViewStateChanged(bool state);
|
void groupViewStateChanged(bool state);
|
||||||
void roomSortingChanged();
|
void roomSortingChanged(bool state);
|
||||||
|
void themeChanged(QString state);
|
||||||
|
void messageHoverHighlightChanged(bool state);
|
||||||
|
void enlargeEmojiOnlyMessagesChanged(bool state);
|
||||||
|
void trayChanged(bool state);
|
||||||
|
void startInTrayChanged(bool state);
|
||||||
|
void markdownChanged(bool state);
|
||||||
|
void typingNotificationsChanged(bool state);
|
||||||
|
void buttonInTimelineChanged(bool state);
|
||||||
|
void readReceiptsChanged(bool state);
|
||||||
|
void desktopNotificationsChanged(bool state);
|
||||||
|
void avatarCirclesChanged(bool state);
|
||||||
|
void decryptSidebarChanged(bool state);
|
||||||
|
void timelineMaxWidthChanged(int state);
|
||||||
|
void fontSizeChanged(double state);
|
||||||
|
void fontChanged(QString state);
|
||||||
|
void emojiFontChanged(QString state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
|
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
|
||||||
|
@ -150,18 +140,20 @@ private:
|
||||||
? "light"
|
? "light"
|
||||||
: "system";
|
: "system";
|
||||||
QString theme_;
|
QString theme_;
|
||||||
bool isMessageHoverHighlightEnabled_;
|
bool messageHoverHighlight_;
|
||||||
bool isTrayEnabled_;
|
bool enlargeEmojiOnlyMessages_;
|
||||||
bool isStartInTrayEnabled_;
|
bool tray_;
|
||||||
bool isGroupViewEnabled_;
|
bool startInTray_;
|
||||||
bool isMarkdownEnabled_;
|
bool groupView_;
|
||||||
bool isTypingNotificationsEnabled_;
|
bool markdown_;
|
||||||
|
bool typingNotifications_;
|
||||||
bool sortByImportance_;
|
bool sortByImportance_;
|
||||||
bool isButtonsInTimelineEnabled_;
|
bool buttonsInTimeline_;
|
||||||
bool isReadReceiptsEnabled_;
|
bool readReceipts_;
|
||||||
bool hasDesktopNotifications_;
|
bool hasDesktopNotifications_;
|
||||||
bool avatarCircles_;
|
bool avatarCircles_;
|
||||||
bool decryptSidebar_;
|
bool decryptSidebar_;
|
||||||
|
int timelineMaxWidth_;
|
||||||
double baseFontSize_;
|
double baseFontSize_;
|
||||||
QString font_;
|
QString font_;
|
||||||
QString emojiFont_;
|
QString emojiFont_;
|
||||||
|
@ -211,9 +203,10 @@ private:
|
||||||
Toggle *timelineButtonsToggle_;
|
Toggle *timelineButtonsToggle_;
|
||||||
Toggle *typingNotifications_;
|
Toggle *typingNotifications_;
|
||||||
Toggle *messageHoverHighlight_;
|
Toggle *messageHoverHighlight_;
|
||||||
|
Toggle *enlargeEmojiOnlyMessages_;
|
||||||
Toggle *sortByImportance_;
|
Toggle *sortByImportance_;
|
||||||
Toggle *readReceipts_;
|
Toggle *readReceipts_;
|
||||||
Toggle *markdownEnabled_;
|
Toggle *markdown_;
|
||||||
Toggle *desktopNotifications_;
|
Toggle *desktopNotifications_;
|
||||||
Toggle *avatarCircles_;
|
Toggle *avatarCircles_;
|
||||||
Toggle *decryptSidebar_;
|
Toggle *decryptSidebar_;
|
||||||
|
@ -226,5 +219,7 @@ private:
|
||||||
QComboBox *fontSelectionCombo_;
|
QComboBox *fontSelectionCombo_;
|
||||||
QComboBox *emojiFontSelectionCombo_;
|
QComboBox *emojiFontSelectionCombo_;
|
||||||
|
|
||||||
|
QSpinBox *timelineMaxWidthSpin_;
|
||||||
|
|
||||||
int sideMargin_ = 0;
|
int sideMargin_ = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,6 +51,14 @@ utils::localUser()
|
||||||
return QString::fromStdString(http::client()->user_id().to_string());
|
return QString::fromStdString(http::client()->user_id().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
utils::codepointIsEmoji(uint code)
|
||||||
|
{
|
||||||
|
// TODO: Be more precise here.
|
||||||
|
return (code >= 0x2600 && code <= 0x27bf) || (code >= 0x1f300 && code <= 0x1f3ff) ||
|
||||||
|
(code >= 0x1f000 && code <= 0x1faff);
|
||||||
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
utils::replaceEmoji(const QString &body)
|
utils::replaceEmoji(const QString &body)
|
||||||
{
|
{
|
||||||
|
@ -63,9 +71,7 @@ utils::replaceEmoji(const QString &body)
|
||||||
|
|
||||||
bool insideFontBlock = false;
|
bool insideFontBlock = false;
|
||||||
for (auto &code : utf32_string) {
|
for (auto &code : utf32_string) {
|
||||||
// TODO: Be more precise here.
|
if (utils::codepointIsEmoji(code)) {
|
||||||
if ((code >= 0x2600 && code <= 0x27bf) || (code >= 0x1f300 && code <= 0x1f3ff) ||
|
|
||||||
(code >= 0x1f000 && code <= 0x1faff)) {
|
|
||||||
if (!insideFontBlock) {
|
if (!insideFontBlock) {
|
||||||
fmtBody += QString("<font face=\"" + userFontFamily + "\">");
|
fmtBody += QString("<font face=\"" + userFontFamily + "\">");
|
||||||
insideFontBlock = true;
|
insideFontBlock = true;
|
||||||
|
@ -136,13 +142,13 @@ utils::descriptiveTime(const QDateTime &then)
|
||||||
const auto days = then.daysTo(now);
|
const auto days = then.daysTo(now);
|
||||||
|
|
||||||
if (days == 0)
|
if (days == 0)
|
||||||
return then.time().toString(Qt::DefaultLocaleShortDate);
|
return QLocale::system().toString(then.time(), QLocale::ShortFormat);
|
||||||
else if (days < 2)
|
else if (days < 2)
|
||||||
return QString(QCoreApplication::translate("descriptiveTime", "Yesterday"));
|
return QString(QCoreApplication::translate("descriptiveTime", "Yesterday"));
|
||||||
else if (days < 7)
|
else if (days < 7)
|
||||||
return then.toString("dddd");
|
return then.toString("dddd");
|
||||||
|
|
||||||
return then.date().toString(Qt::DefaultLocaleShortDate);
|
return QLocale::system().toString(then.date(), QLocale::ShortFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
DescInfo
|
DescInfo
|
||||||
|
|
39
src/Utils.h
39
src/Utils.h
|
@ -36,6 +36,9 @@ namespace utils {
|
||||||
|
|
||||||
using TimelineEvent = mtx::events::collections::TimelineEvents;
|
using TimelineEvent = mtx::events::collections::TimelineEvents;
|
||||||
|
|
||||||
|
bool
|
||||||
|
codepointIsEmoji(uint code);
|
||||||
|
|
||||||
QString
|
QString
|
||||||
replaceEmoji(const QString &body);
|
replaceEmoji(const QString &body);
|
||||||
|
|
||||||
|
@ -183,42 +186,6 @@ erase_if(ContainerT &items, const PredicateT &predicate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t
|
|
||||||
event_timestamp(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return std::visit([](auto msg) { return msg.origin_server_ts; }, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline nlohmann::json
|
|
||||||
serialize_event(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return std::visit([](auto msg) { return json(msg); }, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline mtx::events::EventType
|
|
||||||
event_type(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return std::visit([](auto msg) { return msg.type; }, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string
|
|
||||||
event_id(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return std::visit([](auto msg) { return msg.event_id; }, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QString
|
|
||||||
eventId(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return QString::fromStdString(event_id(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QString
|
|
||||||
event_sender(const mtx::events::collections::TimelineEvents &event)
|
|
||||||
{
|
|
||||||
return std::visit([](auto msg) { return QString::fromStdString(msg.sender); }, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
QString
|
QString
|
||||||
message_body(const mtx::events::collections::TimelineEvents &event)
|
message_body(const mtx::events::collections::TimelineEvents &event)
|
||||||
|
|
|
@ -112,7 +112,7 @@ CreateRoom::CreateRoom(QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(visibilityCombo_,
|
connect(visibilityCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &text) {
|
[this](const QString &text) {
|
||||||
if (text == "Private") {
|
if (text == "Private") {
|
||||||
request_.visibility = mtx::requests::Visibility::Private;
|
request_.visibility = mtx::requests::Visibility::Private;
|
||||||
|
@ -122,7 +122,7 @@ CreateRoom::CreateRoom(QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(presetCombo_,
|
connect(presetCombo_,
|
||||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
|
||||||
[this](const QString &text) {
|
[this](const QString &text) {
|
||||||
if (text == "Private Chat") {
|
if (text == "Private Chat") {
|
||||||
request_.preset = mtx::requests::Preset::PrivateChat;
|
request_.preset = mtx::requests::Preset::PrivateChat;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QLabel>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QLabel>
|
|
||||||
#include <QListWidgetItem>
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
class QLabel;
|
||||||
class TextField;
|
class TextField;
|
||||||
class QListWidget;
|
class QListWidget;
|
||||||
|
class QListWidgetItem;
|
||||||
|
|
||||||
namespace dialogs {
|
namespace dialogs {
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QLabel>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
@ -74,15 +75,17 @@ ReceiptItem::dateFormat(const QDateTime &then) const
|
||||||
auto days = then.daysTo(now);
|
auto days = then.daysTo(now);
|
||||||
|
|
||||||
if (days == 0)
|
if (days == 0)
|
||||||
return tr("Today %1").arg(then.time().toString(Qt::DefaultLocaleShortDate));
|
return tr("Today %1")
|
||||||
|
.arg(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||||
else if (days < 2)
|
else if (days < 2)
|
||||||
return tr("Yesterday %1").arg(then.time().toString(Qt::DefaultLocaleShortDate));
|
return tr("Yesterday %1")
|
||||||
|
.arg(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||||
else if (days < 7)
|
else if (days < 7)
|
||||||
return QString("%1 %2")
|
return QString("%1 %2")
|
||||||
.arg(then.toString("dddd"))
|
.arg(then.toString("dddd"))
|
||||||
.arg(then.time().toString(Qt::DefaultLocaleShortDate));
|
.arg(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||||
|
|
||||||
return then.toString(Qt::DefaultLocaleShortDate);
|
return QLocale::system().toString(then.time(), QLocale::ShortFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadReceipts::ReadReceipts(QWidget *parent)
|
ReadReceipts::ReadReceipts(QWidget *parent)
|
||||||
|
@ -163,3 +166,10 @@ ReadReceipts::paintEvent(QPaintEvent *)
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ReadReceipts::hideEvent(QHideEvent *event)
|
||||||
|
{
|
||||||
|
userList_->clear();
|
||||||
|
QFrame::hideEvent(event);
|
||||||
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QListWidget>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
|
class QLabel;
|
||||||
|
class QListWidget;
|
||||||
|
class QHBoxLayout;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace dialogs {
|
namespace dialogs {
|
||||||
|
|
||||||
|
@ -47,11 +47,7 @@ public slots:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void hideEvent(QHideEvent *event) override
|
void hideEvent(QHideEvent *event) override;
|
||||||
{
|
|
||||||
userList_->clear();
|
|
||||||
QFrame::hideEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *topLabel_;
|
QLabel *topLabel_;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QEvent>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
@ -41,6 +42,17 @@ constexpr int WIDGET_SPACING = 15;
|
||||||
constexpr int TEXT_SPACING = 4;
|
constexpr int TEXT_SPACING = 4;
|
||||||
constexpr int BUTTON_SPACING = 2 * TEXT_SPACING;
|
constexpr int BUTTON_SPACING = 2 * TEXT_SPACING;
|
||||||
|
|
||||||
|
bool
|
||||||
|
ClickableFilter::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
|
emit clicked();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
EditModal::EditModal(const QString &roomId, QWidget *parent)
|
EditModal::EditModal(const QString &roomId, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, roomId_{roomId}
|
, roomId_{roomId}
|
||||||
|
@ -93,6 +105,28 @@ EditModal::EditModal(const QString &roomId, QWidget *parent)
|
||||||
move(center.x() - (width() * 0.5), center.y() - (height() * 0.5));
|
move(center.x() - (width() * 0.5), center.y() - (height() * 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditModal::topicEventSent()
|
||||||
|
{
|
||||||
|
errorField_->hide();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditModal::nameEventSent(const QString &name)
|
||||||
|
{
|
||||||
|
errorField_->hide();
|
||||||
|
emit nameChanged(name);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EditModal::error(const QString &msg)
|
||||||
|
{
|
||||||
|
errorField_->setText(msg);
|
||||||
|
errorField_->show();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EditModal::applyClicked()
|
EditModal::applyClicked()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QEvent>
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QLabel>
|
|
||||||
|
|
||||||
#include <mtx/events/guest_access.hpp>
|
#include <mtx/events/guest_access.hpp>
|
||||||
|
|
||||||
|
@ -21,6 +19,8 @@ class QPixmap;
|
||||||
class TextField;
|
class TextField;
|
||||||
class TextField;
|
class TextField;
|
||||||
class Toggle;
|
class Toggle;
|
||||||
|
class QLabel;
|
||||||
|
class QEvent;
|
||||||
|
|
||||||
class ClickableFilter : public QObject
|
class ClickableFilter : public QObject
|
||||||
{
|
{
|
||||||
|
@ -35,15 +35,7 @@ signals:
|
||||||
void clicked();
|
void clicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
{
|
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
|
||||||
emit clicked();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QObject::eventFilter(obj, event);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convenience class which connects events emmited from threads
|
/// Convenience class which connects events emmited from threads
|
||||||
|
@ -72,24 +64,9 @@ signals:
|
||||||
void nameChanged(const QString &roomName);
|
void nameChanged(const QString &roomName);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void topicEventSent()
|
void topicEventSent();
|
||||||
{
|
void nameEventSent(const QString &name);
|
||||||
errorField_->hide();
|
void error(const QString &msg);
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nameEventSent(const QString &name)
|
|
||||||
{
|
|
||||||
errorField_->hide();
|
|
||||||
emit nameChanged(name);
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void error(const QString &msg)
|
|
||||||
{
|
|
||||||
errorField_->setText(msg);
|
|
||||||
errorField_->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyClicked();
|
void applyClicked();
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QListView>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QLabel>
|
|
||||||
#include <QLayout>
|
|
||||||
#include <QListView>
|
|
||||||
#include <QStandardItemModel>
|
|
||||||
|
|
||||||
#include "ItemDelegate.h"
|
#include "ItemDelegate.h"
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QListView;
|
||||||
|
class QStandardItemModel;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace emoji {
|
namespace emoji {
|
||||||
|
|
||||||
class Category : public QWidget
|
class Category : public QWidget
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <QLabel>
|
||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPoint>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "../AvatarProvider.h"
|
#include "../AvatarProvider.h"
|
||||||
|
@ -10,6 +7,8 @@
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
struct SearchResult;
|
struct SearchResult;
|
||||||
|
class QLabel;
|
||||||
|
class QHBoxLayout;
|
||||||
|
|
||||||
class PopupItem : public QWidget
|
class PopupItem : public QWidget
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPoint>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
#include "EventAccessors.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "UserMentions.h"
|
#include "UserMentions.h"
|
||||||
//#include "timeline/TimelineItem.h"
|
|
||||||
|
|
||||||
using namespace popups;
|
using namespace popups;
|
||||||
|
|
||||||
|
@ -75,12 +75,15 @@ UserMentions::initializeMentions(const QMap<QString, mtx::responses::Notificatio
|
||||||
|
|
||||||
for (const auto &item : notifs) {
|
for (const auto &item : notifs) {
|
||||||
for (const auto ¬if : item.notifications) {
|
for (const auto ¬if : item.notifications) {
|
||||||
const auto event_id = QString::fromStdString(utils::event_id(notif.event));
|
const auto event_id =
|
||||||
|
QString::fromStdString(mtx::accessors::event_id(notif.event));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto room_id = QString::fromStdString(notif.room_id);
|
const auto room_id = QString::fromStdString(notif.room_id);
|
||||||
const auto user_id = utils::event_sender(notif.event);
|
const auto user_id =
|
||||||
const auto body = utils::event_body(notif.event);
|
QString::fromStdString(mtx::accessors::sender(notif.event));
|
||||||
|
const auto body =
|
||||||
|
QString::fromStdString(mtx::accessors::body(notif.event));
|
||||||
|
|
||||||
pushItem(event_id,
|
pushItem(event_id,
|
||||||
user_id,
|
user_id,
|
||||||
|
|
|
@ -219,6 +219,7 @@ TimelineModel::roleNames() const
|
||||||
{Section, "section"},
|
{Section, "section"},
|
||||||
{Type, "type"},
|
{Type, "type"},
|
||||||
{TypeString, "typeString"},
|
{TypeString, "typeString"},
|
||||||
|
{IsOnlyEmoji, "isOnlyEmoji"},
|
||||||
{Body, "body"},
|
{Body, "body"},
|
||||||
{FormattedBody, "formattedBody"},
|
{FormattedBody, "formattedBody"},
|
||||||
{UserId, "userId"},
|
{UserId, "userId"},
|
||||||
|
@ -284,6 +285,22 @@ TimelineModel::data(const QString &id, int role) const
|
||||||
return QVariant(toRoomEventType(event));
|
return QVariant(toRoomEventType(event));
|
||||||
case TypeString:
|
case TypeString:
|
||||||
return QVariant(toRoomEventTypeString(event));
|
return QVariant(toRoomEventTypeString(event));
|
||||||
|
case IsOnlyEmoji: {
|
||||||
|
QString qBody = QString::fromStdString(body(event));
|
||||||
|
|
||||||
|
QVector<uint> utf32_string = qBody.toUcs4();
|
||||||
|
int emojiCount = 0;
|
||||||
|
|
||||||
|
for (auto &code : utf32_string) {
|
||||||
|
if (utils::codepointIsEmoji(code)) {
|
||||||
|
emojiCount++;
|
||||||
|
} else {
|
||||||
|
return QVariant(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant(emojiCount);
|
||||||
|
}
|
||||||
case Body:
|
case Body:
|
||||||
return QVariant(utils::replaceEmoji(QString::fromStdString(body(event))));
|
return QVariant(utils::replaceEmoji(QString::fromStdString(body(event))));
|
||||||
case FormattedBody: {
|
case FormattedBody: {
|
||||||
|
@ -386,6 +403,7 @@ TimelineModel::data(const QString &id, int role) const
|
||||||
// m.insert(names[Section], data(id, static_cast<int>(Section)));
|
// m.insert(names[Section], data(id, static_cast<int>(Section)));
|
||||||
m.insert(names[Type], data(id, static_cast<int>(Type)));
|
m.insert(names[Type], data(id, static_cast<int>(Type)));
|
||||||
m.insert(names[TypeString], data(id, static_cast<int>(TypeString)));
|
m.insert(names[TypeString], data(id, static_cast<int>(TypeString)));
|
||||||
|
m.insert(names[IsOnlyEmoji], data(id, static_cast<int>(IsOnlyEmoji)));
|
||||||
m.insert(names[Body], data(id, static_cast<int>(Body)));
|
m.insert(names[Body], data(id, static_cast<int>(Body)));
|
||||||
m.insert(names[FormattedBody], data(id, static_cast<int>(FormattedBody)));
|
m.insert(names[FormattedBody], data(id, static_cast<int>(FormattedBody)));
|
||||||
m.insert(names[UserId], data(id, static_cast<int>(UserId)));
|
m.insert(names[UserId], data(id, static_cast<int>(UserId)));
|
||||||
|
@ -810,7 +828,7 @@ TimelineModel::escapeEmoji(QString str) const
|
||||||
void
|
void
|
||||||
TimelineModel::viewRawMessage(QString id) const
|
TimelineModel::viewRawMessage(QString id) const
|
||||||
{
|
{
|
||||||
std::string ev = utils::serialize_event(events.value(id)).dump(4);
|
std::string ev = mtx::accessors::serialize_event(events.value(id)).dump(4);
|
||||||
auto dialog = new dialogs::RawMessage(QString::fromStdString(ev));
|
auto dialog = new dialogs::RawMessage(QString::fromStdString(ev));
|
||||||
Q_UNUSED(dialog);
|
Q_UNUSED(dialog);
|
||||||
}
|
}
|
||||||
|
@ -824,7 +842,7 @@ TimelineModel::viewDecryptedRawMessage(QString id) const
|
||||||
event = decryptEvent(*e).event;
|
event = decryptEvent(*e).event;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ev = utils::serialize_event(event).dump(4);
|
std::string ev = mtx::accessors::serialize_event(event).dump(4);
|
||||||
auto dialog = new dialogs::RawMessage(QString::fromStdString(ev));
|
auto dialog = new dialogs::RawMessage(QString::fromStdString(ev));
|
||||||
Q_UNUSED(dialog);
|
Q_UNUSED(dialog);
|
||||||
}
|
}
|
||||||
|
@ -1849,6 +1867,8 @@ TimelineModel::formatMemberEvent(QString id)
|
||||||
rendered = tr("%1 changed their display name.").arg(name);
|
rendered = tr("%1 changed their display name.").arg(name);
|
||||||
else if (avatarChanged)
|
else if (avatarChanged)
|
||||||
rendered = tr("%1 changed their avatar.").arg(name);
|
rendered = tr("%1 changed their avatar.").arg(name);
|
||||||
|
else
|
||||||
|
rendered = tr("%1 changed some profile info.").arg(name);
|
||||||
// the case of nothing changed but join follows join shouldn't happen, so
|
// the case of nothing changed but join follows join shouldn't happen, so
|
||||||
// just show it as join
|
// just show it as join
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -142,6 +142,7 @@ public:
|
||||||
Section,
|
Section,
|
||||||
Type,
|
Type,
|
||||||
TypeString,
|
TypeString,
|
||||||
|
IsOnlyEmoji,
|
||||||
Body,
|
Body,
|
||||||
FormattedBody,
|
FormattedBody,
|
||||||
UserId,
|
UserId,
|
||||||
|
|
|
@ -21,7 +21,7 @@ Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
|
||||||
void
|
void
|
||||||
TimelineViewManager::updateEncryptedDescriptions()
|
TimelineViewManager::updateEncryptedDescriptions()
|
||||||
{
|
{
|
||||||
auto decrypt = settings->isDecryptSidebarEnabled();
|
auto decrypt = settings->decryptSidebar();
|
||||||
QHash<QString, QSharedPointer<TimelineModel>>::iterator i;
|
QHash<QString, QSharedPointer<TimelineModel>>::iterator i;
|
||||||
for (i = models.begin(); i != models.end(); ++i) {
|
for (i = models.begin(); i != models.end(); ++i) {
|
||||||
auto ptr = i.value();
|
auto ptr = i.value();
|
||||||
|
@ -96,6 +96,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
||||||
#endif
|
#endif
|
||||||
container->setMinimumSize(200, 200);
|
container->setMinimumSize(200, 200);
|
||||||
view->rootContext()->setContextProperty("timelineManager", this);
|
view->rootContext()->setContextProperty("timelineManager", this);
|
||||||
|
view->rootContext()->setContextProperty("settings", settings.data());
|
||||||
updateColorPalette();
|
updateColorPalette();
|
||||||
view->engine()->addImageProvider("MxcImage", imgProvider);
|
view->engine()->addImageProvider("MxcImage", imgProvider);
|
||||||
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
||||||
|
@ -121,7 +122,7 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
|
||||||
const auto &room_model = models.value(QString::fromStdString(room_id));
|
const auto &room_model = models.value(QString::fromStdString(room_id));
|
||||||
room_model->addEvents(room.timeline);
|
room_model->addEvents(room.timeline);
|
||||||
|
|
||||||
if (ChatPage::instance()->userSettings()->isTypingNotificationsEnabled()) {
|
if (ChatPage::instance()->userSettings()->typingNotifications()) {
|
||||||
std::vector<QString> typing;
|
std::vector<QString> typing;
|
||||||
typing.reserve(room.ephemeral.typing.size());
|
typing.reserve(room.ephemeral.typing.size());
|
||||||
for (const auto &user : room.ephemeral.typing) {
|
for (const auto &user : room.ephemeral.typing) {
|
||||||
|
@ -141,7 +142,7 @@ TimelineViewManager::addRoom(const QString &room_id)
|
||||||
{
|
{
|
||||||
if (!models.contains(room_id)) {
|
if (!models.contains(room_id)) {
|
||||||
QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id));
|
QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id));
|
||||||
newRoom->setDecryptDescription(settings->isDecryptSidebarEnabled());
|
newRoom->setDecryptDescription(settings->decryptSidebar());
|
||||||
|
|
||||||
connect(newRoom.data(),
|
connect(newRoom.data(),
|
||||||
&TimelineModel::newEncryptedImage,
|
&TimelineModel::newEncryptedImage,
|
||||||
|
@ -225,7 +226,7 @@ TimelineViewManager::queueTextMessage(const QString &msg)
|
||||||
mtx::events::msg::Text text = {};
|
mtx::events::msg::Text text = {};
|
||||||
text.body = msg.trimmed().toStdString();
|
text.body = msg.trimmed().toStdString();
|
||||||
|
|
||||||
if (settings->isMarkdownEnabled()) {
|
if (settings->markdown()) {
|
||||||
text.formatted_body = utils::markdownToHtml(msg).toStdString();
|
text.formatted_body = utils::markdownToHtml(msg).toStdString();
|
||||||
|
|
||||||
// Don't send formatted_body, when we don't need to
|
// Don't send formatted_body, when we don't need to
|
||||||
|
@ -253,7 +254,7 @@ TimelineViewManager::queueTextMessage(const QString &msg)
|
||||||
|
|
||||||
// NOTE(Nico): rich replies always need a formatted_body!
|
// NOTE(Nico): rich replies always need a formatted_body!
|
||||||
text.format = "org.matrix.custom.html";
|
text.format = "org.matrix.custom.html";
|
||||||
if (settings->isMarkdownEnabled())
|
if (settings->markdown())
|
||||||
text.formatted_body =
|
text.formatted_body =
|
||||||
utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
|
utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
|
||||||
.toStdString();
|
.toStdString();
|
||||||
|
@ -276,7 +277,7 @@ TimelineViewManager::queueEmoteMessage(const QString &msg)
|
||||||
mtx::events::msg::Emote emote;
|
mtx::events::msg::Emote emote;
|
||||||
emote.body = msg.trimmed().toStdString();
|
emote.body = msg.trimmed().toStdString();
|
||||||
|
|
||||||
if (html != msg.trimmed().toHtmlEscaped() && settings->isMarkdownEnabled()) {
|
if (html != msg.trimmed().toHtmlEscaped() && settings->markdown()) {
|
||||||
emote.formatted_body = html.toStdString();
|
emote.formatted_body = html.toStdString();
|
||||||
emote.format = "org.matrix.custom.html";
|
emote.format = "org.matrix.custom.html";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include "AvatarProvider.h"
|
#include "AvatarProvider.h"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QFontMetrics>
|
#include <QFontMetrics>
|
||||||
#include <QPaintDevice>
|
#include <QPaintDevice>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
class Painter : public QPainter
|
class Painter : public QPainter
|
||||||
|
@ -163,5 +164,5 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Painter &_painter;
|
Painter &_painter;
|
||||||
QPainter::RenderHints hints_ = 0;
|
QPainter::RenderHints hints_ = {};
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,4 +6,11 @@
|
||||||
/examples/basic/basic
|
/examples/basic/basic
|
||||||
/examples/calculator/calculator
|
/examples/calculator/calculator
|
||||||
/examples/sending_arguments/sending_arguments
|
/examples/sending_arguments/sending_arguments
|
||||||
CMakeLists.txt.user
|
/**/CMakeLists.txt.user
|
||||||
|
/**/CMakeCache.txt
|
||||||
|
/**/CMakeCache/*
|
||||||
|
/**/CMakeFiles/*
|
||||||
|
/**/Makefile
|
||||||
|
/**/cmake_install.cmake
|
||||||
|
/**/*_autogen/
|
||||||
|
libSingleApplication.a
|
|
@ -1,6 +1,40 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
If by accident I have forgotten to credit someone in the CHANGELOG, email me and I will fix it.
|
||||||
|
|
||||||
|
__3.1.3.1__
|
||||||
|
---------
|
||||||
|
* CMake build system improvements
|
||||||
|
* Fixed Clang Tidy warnings
|
||||||
|
|
||||||
|
_Hennadii Chernyshchyk_
|
||||||
|
|
||||||
|
__3.1.3__
|
||||||
|
---------
|
||||||
|
* Improved `CMakeLists.txt`
|
||||||
|
|
||||||
|
_Hennadii Chernyshchyk_
|
||||||
|
|
||||||
|
__3.1.2__
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Fix a crash when exiting an application on Android and iOS
|
||||||
|
|
||||||
|
_Emeric Grange_
|
||||||
|
|
||||||
|
__3.1.1a__
|
||||||
|
----------
|
||||||
|
|
||||||
|
* Added currentUser() method that returns the user the current instance is running as.
|
||||||
|
|
||||||
|
_Leander Schulten_
|
||||||
|
|
||||||
|
__3.1.0a__
|
||||||
|
----------
|
||||||
|
|
||||||
|
* Added primaryUser() method that returns the user the primary instance is running as.
|
||||||
|
|
||||||
__3.0.19__
|
__3.0.19__
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -1,45 +1,34 @@
|
||||||
cmake_minimum_required(VERSION 3.1.0)
|
cmake_minimum_required(VERSION 3.7.0)
|
||||||
|
|
||||||
project(SingleApplication)
|
project(SingleApplication LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
# SingleApplication base class
|
|
||||||
set(QAPPLICATION_CLASS QCoreApplication CACHE STRING "Inheritance class for SingleApplication")
|
|
||||||
set_property(CACHE QAPPLICATION_CLASS PROPERTY STRINGS QApplication QGuiApplication QCoreApplication)
|
|
||||||
|
|
||||||
# Libary target
|
|
||||||
add_library(${PROJECT_NAME} STATIC
|
add_library(${PROJECT_NAME} STATIC
|
||||||
singleapplication.cpp
|
singleapplication.cpp
|
||||||
singleapplication_p.cpp
|
singleapplication_p.cpp
|
||||||
)
|
)
|
||||||
|
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||||
|
|
||||||
# Find dependencies
|
# Find dependencies
|
||||||
find_package(Qt5Network)
|
find_package(Qt5 COMPONENTS Network REQUIRED)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network)
|
||||||
|
|
||||||
if(QAPPLICATION_CLASS STREQUAL QApplication)
|
if(QAPPLICATION_CLASS STREQUAL QApplication)
|
||||||
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
|
||||||
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
|
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
|
||||||
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Gui)
|
||||||
else()
|
else()
|
||||||
|
set(QAPPLICATION_CLASS QCoreApplication)
|
||||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||||
endif()
|
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core)
|
||||||
target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
|
|
||||||
|
|
||||||
# Link dependencies
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network)
|
|
||||||
if(QAPPLICATION_CLASS STREQUAL QApplication)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
|
|
||||||
elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui)
|
|
||||||
else()
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
|
target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
|
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) Itay Grudev 2015 - 2016
|
Copyright (c) Itay Grudev 2015 - 2020
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
|
@ -1,5 +1,6 @@
|
||||||
SingleApplication
|
SingleApplication
|
||||||
=================
|
=================
|
||||||
|
[![CI](https://github.com/itay-grudev/SingleApplication/workflows/CI:%20Build%20Test/badge.svg)](https://github.com/itay-grudev/SingleApplication/actions)
|
||||||
|
|
||||||
This is a replacement of the QtSingleApplication for `Qt5`.
|
This is a replacement of the QtSingleApplication for `Qt5`.
|
||||||
|
|
||||||
|
@ -15,18 +16,6 @@ class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
|
||||||
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
||||||
classes.
|
classes.
|
||||||
|
|
||||||
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
|
||||||
instance of your Application is your Primary Instance. It would check if the
|
|
||||||
shared memory block exists and if not it will start a `QLocalServer` and listen
|
|
||||||
for connections. Each subsequent instance of your application would check if the
|
|
||||||
shared memory block exists and if it does, it will connect to the QLocalServer
|
|
||||||
to notify the primary instance that a new instance had been started, after which
|
|
||||||
it would terminate with status code `0`. In the Primary Instance
|
|
||||||
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
|
||||||
that a new instance had been started.
|
|
||||||
|
|
||||||
The library uses `stdlib` to terminate the program with the `exit()` function.
|
|
||||||
|
|
||||||
You can use the library as if you use any other `QCoreApplication` derived
|
You can use the library as if you use any other `QCoreApplication` derived
|
||||||
class:
|
class:
|
||||||
|
|
||||||
|
@ -43,8 +32,7 @@ int main( int argc, char* argv[] )
|
||||||
```
|
```
|
||||||
|
|
||||||
To include the library files I would recommend that you add it as a git
|
To include the library files I would recommend that you add it as a git
|
||||||
submodule to your project and include it's contents with a `.pri` file. Here is
|
submodule to your project. Here is how:
|
||||||
how:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
||||||
|
@ -66,13 +54,27 @@ Then include the subdirectory in your `CMakeLists.txt` project file.
|
||||||
```cmake
|
```cmake
|
||||||
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||||
add_subdirectory(src/third-party/singleapplication)
|
add_subdirectory(src/third-party/singleapplication)
|
||||||
|
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
||||||
|
instance of your Application is your Primary Instance. It would check if the
|
||||||
|
shared memory block exists and if not it will start a `QLocalServer` and listen
|
||||||
|
for connections. Each subsequent instance of your application would check if the
|
||||||
|
shared memory block exists and if it does, it will connect to the QLocalServer
|
||||||
|
to notify the primary instance that a new instance had been started, after which
|
||||||
|
it would terminate with status code `0`. In the Primary Instance
|
||||||
|
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
||||||
|
that a new instance had been started.
|
||||||
|
|
||||||
|
The library uses `stdlib` to terminate the program with the `exit()` function.
|
||||||
|
|
||||||
Also don't forget to specify which `QCoreApplication` class your app is using if it
|
Also don't forget to specify which `QCoreApplication` class your app is using if it
|
||||||
is not `QCoreApplication` as in examples above.
|
is not `QCoreApplication` as in examples above.
|
||||||
|
|
||||||
The `Instance Started` signal
|
The `Instance Started` signal
|
||||||
------------------------
|
-----------------------------
|
||||||
|
|
||||||
The SingleApplication class implements a `instanceStarted()` signal. You can
|
The SingleApplication class implements a `instanceStarted()` signal. You can
|
||||||
bind to that signal to raise your application's window when a new instance had
|
bind to that signal to raise your application's window when a new instance had
|
||||||
|
@ -204,6 +206,22 @@ qint64 SingleApplication::primaryPid()
|
||||||
|
|
||||||
Returns the process ID (PID) of the primary instance.
|
Returns the process ID (PID) of the primary instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::primaryUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the primary instance is running as.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QString SingleApplication::currentUser()
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns the username the current instance is running as.
|
||||||
|
|
||||||
### Signals
|
### Signals
|
||||||
|
|
||||||
```cpp
|
```cpp
|
1
third_party/SingleApplication-3.1.3.1/SingleApplication
vendored
Normal file
1
third_party/SingleApplication-3.1.3.1/SingleApplication
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "singleapplication.h"
|
|
@ -1,6 +1,6 @@
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) Itay Grudev 2015 - 2018
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -85,7 +85,7 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancesInfo* inst = static_cast<InstancesInfo*>( d->memory->data() );
|
auto *inst = static_cast<InstancesInfo*>( d->memory->data() );
|
||||||
QElapsedTimer time;
|
QElapsedTimer time;
|
||||||
time.start();
|
time.start();
|
||||||
|
|
||||||
|
@ -172,7 +172,19 @@ qint64 SingleApplication::primaryPid()
|
||||||
return d->primaryPid();
|
return d->primaryPid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SingleApplication::sendMessage( QByteArray message, int timeout )
|
QString SingleApplication::primaryUser()
|
||||||
|
{
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
return d->primaryUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleApplication::currentUser()
|
||||||
|
{
|
||||||
|
Q_D(SingleApplication);
|
||||||
|
return d->getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
|
||||||
{
|
{
|
||||||
Q_D(SingleApplication);
|
Q_D(SingleApplication);
|
||||||
|
|
|
@ -43,7 +43,7 @@ class SingleApplication : public QAPPLICATION_CLASS
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
typedef QAPPLICATION_CLASS app_t;
|
using app_t = QAPPLICATION_CLASS;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +86,7 @@ public:
|
||||||
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
|
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
|
||||||
*/
|
*/
|
||||||
explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 );
|
explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 );
|
||||||
~SingleApplication();
|
~SingleApplication() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns if the instance is the primary instance
|
* @brief Returns if the instance is the primary instance
|
||||||
|
@ -112,6 +112,18 @@ public:
|
||||||
*/
|
*/
|
||||||
qint64 primaryPid();
|
qint64 primaryPid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the user running the primary instance
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString primaryUser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the username of the current user
|
||||||
|
* @returns {QString}
|
||||||
|
*/
|
||||||
|
QString currentUser();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a message to the primary instance. Returns true on success.
|
* @brief Sends a message to the primary instance. Returns true on success.
|
||||||
* @param {int} timeout - Timeout for connecting
|
* @param {int} timeout - Timeout for connecting
|
||||||
|
@ -119,7 +131,7 @@ public:
|
||||||
* @note sendMessage() will return false if invoked from the primary
|
* @note sendMessage() will return false if invoked from the primary
|
||||||
* instance.
|
* instance.
|
||||||
*/
|
*/
|
||||||
bool sendMessage( QByteArray message, int timeout = 100 );
|
bool sendMessage( const QByteArray &message, int timeout = 100 );
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void instanceStarted();
|
void instanceStarted();
|
20
third_party/SingleApplication-3.1.3.1/singleapplication.pri
vendored
Normal file
20
third_party/SingleApplication-3.1.3.1/singleapplication.pri
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
QT += core network
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
HEADERS += $$PWD/SingleApplication \
|
||||||
|
$$PWD/singleapplication.h \
|
||||||
|
$$PWD/singleapplication_p.h
|
||||||
|
SOURCES += $$PWD/singleapplication.cpp \
|
||||||
|
$$PWD/singleapplication_p.cpp
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
msvc:LIBS += Advapi32.lib
|
||||||
|
gcc:LIBS += -ladvapi32
|
||||||
|
}
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
$$PWD/README.md \
|
||||||
|
$$PWD/CHANGELOG.md \
|
||||||
|
$$PWD/Windows.md
|
|
@ -1,6 +1,6 @@
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) Itay Grudev 2015 - 2018
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -69,19 +69,53 @@ SingleApplicationPrivate::~SingleApplicationPrivate()
|
||||||
delete socket;
|
delete socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( memory != nullptr ) {
|
||||||
memory->lock();
|
memory->lock();
|
||||||
InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
|
auto *inst = static_cast<InstancesInfo*>(memory->data());
|
||||||
if( server != nullptr ) {
|
if( server != nullptr ) {
|
||||||
server->close();
|
server->close();
|
||||||
delete server;
|
delete server;
|
||||||
inst->primary = false;
|
inst->primary = false;
|
||||||
inst->primaryPid = -1;
|
inst->primaryPid = -1;
|
||||||
|
inst->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
inst->checksum = blockChecksum();
|
||||||
}
|
}
|
||||||
memory->unlock();
|
memory->unlock();
|
||||||
|
|
||||||
delete memory;
|
delete memory;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SingleApplicationPrivate::getUsername()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wchar_t username[UNLEN + 1];
|
||||||
|
// Specifies size of the buffer on input
|
||||||
|
DWORD usernameLength = UNLEN + 1;
|
||||||
|
if( GetUserNameW( username, &usernameLength ) )
|
||||||
|
return QString::fromWCharArray( username );
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
return QString::fromLocal8Bit( qgetenv( "USERNAME" ) );
|
||||||
|
#else
|
||||||
|
return qEnvironmentVariable( "USERNAME" );
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
QString username;
|
||||||
|
uid_t uid = geteuid();
|
||||||
|
struct passwd *pw = getpwuid( uid );
|
||||||
|
if( pw )
|
||||||
|
username = QString::fromLocal8Bit( pw->pw_name );
|
||||||
|
if ( username.isEmpty() ) {
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||||
|
username = QString::fromLocal8Bit( qgetenv( "USER" ) );
|
||||||
|
#else
|
||||||
|
username = qEnvironmentVariable( "USER" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void SingleApplicationPrivate::genBlockServerName()
|
void SingleApplicationPrivate::genBlockServerName()
|
||||||
{
|
{
|
||||||
|
@ -105,28 +139,7 @@ void SingleApplicationPrivate::genBlockServerName()
|
||||||
|
|
||||||
// User level block requires a user specific data in the hash
|
// User level block requires a user specific data in the hash
|
||||||
if( options & SingleApplication::Mode::User ) {
|
if( options & SingleApplication::Mode::User ) {
|
||||||
#ifdef Q_OS_WIN
|
appData.addData( getUsername().toUtf8() );
|
||||||
wchar_t username [ UNLEN + 1 ];
|
|
||||||
// Specifies size of the buffer on input
|
|
||||||
DWORD usernameLength = UNLEN + 1;
|
|
||||||
if( GetUserNameW( username, &usernameLength ) ) {
|
|
||||||
appData.addData( QString::fromWCharArray(username).toUtf8() );
|
|
||||||
} else {
|
|
||||||
appData.addData( qgetenv("USERNAME") );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_UNIX
|
|
||||||
QByteArray username;
|
|
||||||
uid_t uid = geteuid();
|
|
||||||
struct passwd *pw = getpwuid(uid);
|
|
||||||
if( pw ) {
|
|
||||||
username = pw->pw_name;
|
|
||||||
}
|
|
||||||
if( username.isEmpty() ) {
|
|
||||||
username = qgetenv("USER");
|
|
||||||
}
|
|
||||||
appData.addData(username);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
|
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
|
||||||
|
@ -136,10 +149,11 @@ void SingleApplicationPrivate::genBlockServerName()
|
||||||
|
|
||||||
void SingleApplicationPrivate::initializeMemoryBlock()
|
void SingleApplicationPrivate::initializeMemoryBlock()
|
||||||
{
|
{
|
||||||
InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
|
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
||||||
inst->primary = false;
|
inst->primary = false;
|
||||||
inst->secondary = 0;
|
inst->secondary = 0;
|
||||||
inst->primaryPid = -1;
|
inst->primaryPid = -1;
|
||||||
|
inst->primaryUser[0] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
inst->checksum = blockChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +183,12 @@ void SingleApplicationPrivate::startPrimary()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reset the number of connections
|
// Reset the number of connections
|
||||||
InstancesInfo* inst = static_cast <InstancesInfo*>( memory->data() );
|
auto *inst = static_cast <InstancesInfo*>( memory->data() );
|
||||||
|
|
||||||
inst->primary = true;
|
inst->primary = true;
|
||||||
inst->primaryPid = q->applicationPid();
|
inst->primaryPid = q->applicationPid();
|
||||||
|
strncpy( inst->primaryUser, getUsername().toUtf8().data(), 127 );
|
||||||
|
inst->primaryUser[127] = '\0';
|
||||||
inst->checksum = blockChecksum();
|
inst->checksum = blockChecksum();
|
||||||
|
|
||||||
instanceNumber = 0;
|
instanceNumber = 0;
|
||||||
|
@ -250,13 +266,25 @@ qint64 SingleApplicationPrivate::primaryPid()
|
||||||
qint64 pid;
|
qint64 pid;
|
||||||
|
|
||||||
memory->lock();
|
memory->lock();
|
||||||
InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
|
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
||||||
pid = inst->primaryPid;
|
pid = inst->primaryPid;
|
||||||
memory->unlock();
|
memory->unlock();
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString SingleApplicationPrivate::primaryUser()
|
||||||
|
{
|
||||||
|
QByteArray username;
|
||||||
|
|
||||||
|
memory->lock();
|
||||||
|
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
||||||
|
username = inst->primaryUser;
|
||||||
|
memory->unlock();
|
||||||
|
|
||||||
|
return QString::fromUtf8( username );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Executed when a connection has been made to the LocalServer
|
* @brief Executed when a connection has been made to the LocalServer
|
||||||
*/
|
*/
|
|
@ -1,6 +1,6 @@
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) Itay Grudev 2015 - 2016
|
// Copyright (c) Itay Grudev 2015 - 2020
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -42,14 +42,13 @@ struct InstancesInfo {
|
||||||
quint32 secondary;
|
quint32 secondary;
|
||||||
qint64 primaryPid;
|
qint64 primaryPid;
|
||||||
quint16 checksum;
|
quint16 checksum;
|
||||||
|
char primaryUser[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectionInfo {
|
struct ConnectionInfo {
|
||||||
explicit ConnectionInfo() :
|
qint64 msgLen = 0;
|
||||||
msgLen(0), instanceId(0), stage(0) {}
|
quint32 instanceId = 0;
|
||||||
qint64 msgLen;
|
quint8 stage = 0;
|
||||||
quint32 instanceId;
|
|
||||||
quint8 stage;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SingleApplicationPrivate : public QObject {
|
class SingleApplicationPrivate : public QObject {
|
||||||
|
@ -69,8 +68,9 @@ public:
|
||||||
Q_DECLARE_PUBLIC(SingleApplication)
|
Q_DECLARE_PUBLIC(SingleApplication)
|
||||||
|
|
||||||
SingleApplicationPrivate( SingleApplication *q_ptr );
|
SingleApplicationPrivate( SingleApplication *q_ptr );
|
||||||
~SingleApplicationPrivate();
|
~SingleApplicationPrivate() override;
|
||||||
|
|
||||||
|
QString getUsername();
|
||||||
void genBlockServerName();
|
void genBlockServerName();
|
||||||
void initializeMemoryBlock();
|
void initializeMemoryBlock();
|
||||||
void startPrimary();
|
void startPrimary();
|
||||||
|
@ -78,6 +78,7 @@ public:
|
||||||
void connectToPrimary(int msecs, ConnectionType connectionType );
|
void connectToPrimary(int msecs, ConnectionType connectionType );
|
||||||
quint16 blockChecksum();
|
quint16 blockChecksum();
|
||||||
qint64 primaryPid();
|
qint64 primaryPid();
|
||||||
|
QString primaryUser();
|
||||||
void readInitMessageHeader(QLocalSocket *socket);
|
void readInitMessageHeader(QLocalSocket *socket);
|
||||||
void readInitMessageBody(QLocalSocket *socket);
|
void readInitMessageBody(QLocalSocket *socket);
|
||||||
|
|
Loading…
Reference in a new issue