Compare commits
317 Commits
work/tobia
...
release/25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b009b9aac0 | ||
|
|
a133180925 | ||
|
|
78d2b12fa7 | ||
|
|
8e80e643f4 | ||
|
|
09e81a51b6 | ||
|
|
4c64ff5925 | ||
|
|
00a497f0d2 | ||
|
|
6f91a45c8e | ||
|
|
6cfdf9dab9 | ||
|
|
3fefdf57ac | ||
|
|
94df22832e | ||
|
|
86cecf49c1 | ||
|
|
71e6acef76 | ||
|
|
9966e02eaf | ||
|
|
cd776b8bd7 | ||
|
|
55f1de221c | ||
|
|
090ef3ac7a | ||
|
|
27c49714de | ||
|
|
18fdba2f7a | ||
|
|
a1615118d0 | ||
|
|
9d816158f5 | ||
|
|
d8619356d3 | ||
|
|
6b6ccdaff0 | ||
|
|
18a29bc46b | ||
|
|
76180ace07 | ||
|
|
c439fa7e45 | ||
|
|
9cadce88bb | ||
|
|
d8984dc812 | ||
|
|
3f096da49b | ||
|
|
bb51b1d677 | ||
|
|
e45ccc00c3 | ||
|
|
c6f041d0bb | ||
|
|
566f9de72a | ||
|
|
6abc398033 | ||
|
|
bef4f370b6 | ||
|
|
b18c12f149 | ||
|
|
e267f9f667 | ||
|
|
32d264a3aa | ||
|
|
77f9e43c82 | ||
|
|
bc0d1aff35 | ||
|
|
bc594ec8a2 | ||
|
|
2a7f0b406c | ||
|
|
c9f685a733 | ||
|
|
5be43575fc | ||
|
|
558519f355 | ||
|
|
f83e2e2677 | ||
|
|
4c4f406c41 | ||
|
|
2f8a873202 | ||
|
|
78b3cfe916 | ||
|
|
0bc529da2d | ||
|
|
6ad6121dfa | ||
|
|
7b5b7a67ae | ||
|
|
59c8b82bc2 | ||
|
|
c6aec89b61 | ||
|
|
2ef3fd9d6c | ||
|
|
e64b6033f3 | ||
|
|
82989e7ef2 | ||
|
|
ddf272ab2b | ||
|
|
4d4b44e011 | ||
|
|
a17d7e18fd | ||
|
|
1e78f119f1 | ||
|
|
b6a4b67c22 | ||
|
|
e965e1680f | ||
|
|
7d4cc7a5cf | ||
|
|
112b4b54e5 | ||
|
|
782f096f21 | ||
|
|
57e0f04086 | ||
|
|
a639011db6 | ||
|
|
26e7f3780c | ||
|
|
8c96d05799 | ||
|
|
bc6e22bc6d | ||
|
|
4371c3f7e5 | ||
|
|
b88ee65a4c | ||
|
|
033e865a27 | ||
|
|
75ba46e292 | ||
|
|
d492ed038a | ||
|
|
b29108a2f7 | ||
|
|
2790d430ae | ||
|
|
23f61fff36 | ||
|
|
254d105e35 | ||
|
|
6dde57a786 | ||
|
|
d803fcb874 | ||
|
|
90e70a9295 | ||
|
|
2090e4dc0e | ||
|
|
5ced491d54 | ||
|
|
e156d4da90 | ||
|
|
b3aa2abd89 | ||
|
|
7627d6d0e2 | ||
|
|
77da7e6c7d | ||
|
|
1e3ce9d6cd | ||
|
|
321561fd89 | ||
|
|
856bc7b713 | ||
|
|
10e9b8d8f8 | ||
|
|
9f1803c551 | ||
|
|
9260c92026 | ||
|
|
9c7030a5db | ||
|
|
909e20889e | ||
|
|
74f4c291a0 | ||
|
|
242a248bf3 | ||
|
|
dfb0bb75f4 | ||
|
|
3cefd4b1ef | ||
|
|
3f3ce6b421 | ||
|
|
73d910421a | ||
|
|
1da44f3ae3 | ||
|
|
08836010c6 | ||
|
|
13042d9ba6 | ||
|
|
0e4b52ee62 | ||
|
|
4c32280343 | ||
|
|
a2e540d6ef | ||
|
|
573c8925d2 | ||
|
|
6c0bd850b0 | ||
|
|
1da9719314 | ||
|
|
3cd5f3a1c6 | ||
|
|
b4108f2eef | ||
|
|
bb7de18341 | ||
|
|
7b8328fce6 | ||
|
|
aeee6570c0 | ||
|
|
780b9a6f9b | ||
|
|
0ba06882d1 | ||
|
|
ce131a53e5 | ||
|
|
e9421e28dd | ||
|
|
1c64a6b5f0 | ||
|
|
9b5200c344 | ||
|
|
5baf4ab823 | ||
|
|
58a72a08f2 | ||
|
|
c9b97d4d0d | ||
|
|
2a7d61c73b | ||
|
|
f55bd28e10 | ||
|
|
2a67861099 | ||
|
|
273d962707 | ||
|
|
5e8b44fea6 | ||
|
|
be9e2ec7d0 | ||
|
|
ee042cc1a2 | ||
|
|
25c0bc131a | ||
|
|
7def8c066c | ||
|
|
1ddaf37e52 | ||
|
|
40694f502a | ||
|
|
d9f4a0a032 | ||
|
|
5e392f3101 | ||
|
|
ce1ac6128e | ||
|
|
a9d08a6ee2 | ||
|
|
24d4829ba9 | ||
|
|
a121c39b6e | ||
|
|
f009420c20 | ||
|
|
069e0d8f16 | ||
|
|
1f1db11197 | ||
|
|
be92e56c3a | ||
|
|
d1fc426513 | ||
|
|
c778ba8b24 | ||
|
|
07fb3160eb | ||
|
|
7444d68280 | ||
|
|
1d5536401d | ||
|
|
099e996f2f | ||
|
|
6d9974b2b1 | ||
|
|
f65e9f7599 | ||
|
|
4a39810923 | ||
|
|
6720e2dfaa | ||
|
|
eb1bf2ed2b | ||
|
|
cc26b1b62f | ||
|
|
59c2c88eb6 | ||
|
|
99e8fd16eb | ||
|
|
eaa4bdb0b7 | ||
|
|
892b61e6bb | ||
|
|
6d56b673c4 | ||
|
|
f59e5a4b3c | ||
|
|
16e3fd4476 | ||
|
|
82d0fdefd2 | ||
|
|
cbde14d58b | ||
|
|
f3c37e4304 | ||
|
|
369008cec3 | ||
|
|
1a2af57901 | ||
|
|
dbb41d061c | ||
|
|
d1d3c43c6f | ||
|
|
ba2b1529ea | ||
|
|
b5150f82f0 | ||
|
|
00c81de035 | ||
|
|
52d4451932 | ||
|
|
3efc11b9aa | ||
|
|
5fd9f07664 | ||
|
|
bec9f36bce | ||
|
|
a631acc0ac | ||
|
|
b729aaf6ee | ||
|
|
94b7fc5cdf | ||
|
|
ec5355d86e | ||
|
|
1a43d15c6d | ||
|
|
7356a68f4c | ||
|
|
1070427a0d | ||
|
|
196ef535ca | ||
|
|
88fd173829 | ||
|
|
8b0698c670 | ||
|
|
5b07a0ff45 | ||
|
|
ba1d175d67 | ||
|
|
36ce55e892 | ||
|
|
ba4a83d38c | ||
|
|
5c49c35b82 | ||
|
|
2b0251c593 | ||
|
|
3b08d0f382 | ||
|
|
f64e8a3192 | ||
|
|
eab45e761a | ||
|
|
0f03290c57 | ||
|
|
59f87bb2c2 | ||
|
|
9afc10160d | ||
|
|
cfc7f50a1f | ||
|
|
a2fc00365e | ||
|
|
466cfd971d | ||
|
|
8e83febb24 | ||
|
|
12072b0a73 | ||
|
|
83b1daac07 | ||
|
|
981ea053a6 | ||
|
|
e41fd7d986 | ||
|
|
a88a82ca08 | ||
|
|
23dc88df60 | ||
|
|
520b1daeec | ||
|
|
cbe7ace32d | ||
|
|
2b4471ea91 | ||
|
|
88e1e1dd2a | ||
|
|
94ea1305b2 | ||
|
|
960377838d | ||
|
|
a48e8662d6 | ||
|
|
9c90a38efc | ||
|
|
8696a24127 | ||
|
|
f2d1b4c1e1 | ||
|
|
4cdc2b5e58 | ||
|
|
e26f02d9e2 | ||
|
|
5d83fe9a1d | ||
|
|
6a506f237a | ||
|
|
3a5a0153d8 | ||
|
|
27519b8788 | ||
|
|
dd45fe16a5 | ||
|
|
161815acff | ||
|
|
438edf2155 | ||
|
|
6607a4b72c | ||
|
|
8f0c4ab133 | ||
|
|
78e5cd51cd | ||
|
|
f5da44655e | ||
|
|
a91863c60d | ||
|
|
29e3a09aba | ||
|
|
a59952f189 | ||
|
|
b169da25ab | ||
|
|
833e357d70 | ||
|
|
f9bf2b8f7a | ||
|
|
7b27579f2d | ||
|
|
edb9d9f54e | ||
|
|
abf9a486d0 | ||
|
|
b0bc19c055 | ||
|
|
71776ef275 | ||
|
|
8dc7d1d39d | ||
|
|
adb9e59503 | ||
|
|
518044e34a | ||
|
|
d6d747bb99 | ||
|
|
f390702a7a | ||
|
|
e056360ddd | ||
|
|
85163791ce | ||
|
|
b5a853bc96 | ||
|
|
e4cd6ce5a6 | ||
|
|
84fa68e3ae | ||
|
|
649dc7a815 | ||
|
|
b87e43660c | ||
|
|
511138e3bb | ||
|
|
5a3c23d000 | ||
|
|
1036384023 | ||
|
|
e3f618489b | ||
|
|
cfedd4fdb5 | ||
|
|
812e5beee6 | ||
|
|
17b632eb78 | ||
|
|
877d5f34f7 | ||
|
|
c93ce52ba1 | ||
|
|
2504ca3f5c | ||
|
|
5be05032be | ||
|
|
81e5061831 | ||
|
|
3b419e18a3 | ||
|
|
1a1190d7bd | ||
|
|
5b4d3df6ee | ||
|
|
f53d47fa28 | ||
|
|
67d5711cc4 | ||
|
|
9f51b1e7ab | ||
|
|
5ac296ee71 | ||
|
|
1b8adcc91a | ||
|
|
1e78209cd7 | ||
|
|
0fd924be7b | ||
|
|
d67cb89505 | ||
|
|
0d0f88e251 | ||
|
|
4cbd4a034c | ||
|
|
e7ed07e386 | ||
|
|
390654fa4a | ||
|
|
e8830b56d8 | ||
|
|
bbf2587908 | ||
|
|
409b6da160 | ||
|
|
9d8c9853ce | ||
|
|
b3781e0db4 | ||
|
|
fbcb2379fb | ||
|
|
e8ad4a5dee | ||
|
|
6c57c41993 | ||
|
|
ce0014f846 | ||
|
|
e5df412258 | ||
|
|
0c482aa463 | ||
|
|
2df3a21fb5 | ||
|
|
9dd438e8a2 | ||
|
|
cea5006e15 | ||
|
|
8ff3b31497 | ||
|
|
c7a9f9f07e | ||
|
|
1de10a4b87 | ||
|
|
d7f19efbd6 | ||
|
|
a3a28b2472 | ||
|
|
919fc8b821 | ||
|
|
b80a2f94f4 | ||
|
|
6d18d1a237 | ||
|
|
a2d64d2955 | ||
|
|
95617e3210 | ||
|
|
1522f7086e | ||
|
|
14167d197f | ||
|
|
c377cf05b8 | ||
|
|
4a52bc04fb | ||
|
|
53cd230d16 | ||
|
|
e7b204b9fd | ||
|
|
4d91ae96e3 | ||
|
|
b422d641de |
@@ -44,6 +44,22 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "opencv",
|
||||
"config-opts": [
|
||||
"-DBUILD_TESTS=OFF",
|
||||
"-DWITH_GTK=OFF",
|
||||
"-DBUILD_LIST=core,imgproc"
|
||||
],
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/opencv/opencv"
|
||||
}
|
||||
],
|
||||
"builddir": true
|
||||
},
|
||||
{
|
||||
"name": "kquickimageeditor",
|
||||
"config-opts": [
|
||||
@@ -131,7 +147,7 @@
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/quotient-im/libQuotient.git",
|
||||
"branch": "dev",
|
||||
"branch": "0.9.6.1",
|
||||
"disable-submodules": true
|
||||
}
|
||||
],
|
||||
@@ -190,14 +206,6 @@
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "patches/0001-Revert-Bump-KF6-dependency-version.patch"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "patches/0001-Revert-Use-new-Kirigami-builtin-column-resize-handle.patch"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ Dependencies:
|
||||
'frameworks/ki18n': '@latest-kf6'
|
||||
'frameworks/kconfig': '@latest-kf6'
|
||||
'frameworks/syntax-highlighting': '@latest-kf6'
|
||||
'frameworks/kiconthemes': '@latest-kf6'
|
||||
'frameworks/kitemmodels': '@latest-kf6'
|
||||
'frameworks/kquickcharts': '@latest-kf6'
|
||||
'frameworks/knotifications': '@latest-kf6'
|
||||
'frameworks/kcolorscheme': '@latest-kf6'
|
||||
'frameworks/kiconthemes': '@latest-kf6'
|
||||
'libraries/kquickimageeditor': '@latest-kf6'
|
||||
'frameworks/sonnet': '@latest-kf6'
|
||||
'frameworks/prison': '@latest-kf6'
|
||||
@@ -29,7 +29,6 @@ Dependencies:
|
||||
'frameworks/kio': '@latest-kf6'
|
||||
'frameworks/kwindowsystem': '@latest-kf6'
|
||||
'frameworks/kstatusnotifieritem': '@latest-kf6'
|
||||
'frameworks/kcrash': '@latest-kf6'
|
||||
- 'on': ['Linux', 'FreeBSD']
|
||||
'require':
|
||||
'frameworks/kdbusaddons': '@latest-kf6'
|
||||
|
||||
@@ -8,14 +8,14 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# KDE Applications version, managed by release script.
|
||||
set(RELEASE_SERVICE_VERSION_MAJOR "25")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "11")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set(RELEASE_SERVICE_VERSION_MINOR "12")
|
||||
set(RELEASE_SERVICE_VERSION_MICRO "3")
|
||||
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
set(KF_MIN_VERSION "6.17")
|
||||
set(QT_MIN_VERSION "6.8")
|
||||
set(QT_MIN_VERSION "6.9")
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
|
||||
@@ -24,7 +24,7 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(KDE_COMPILERSETTINGS_LEVEL 6.0)
|
||||
set(KDE_COMPILERSETTINGS_LEVEL 6.17)
|
||||
|
||||
include(FeatureSummary)
|
||||
include(ECMSetupVersion)
|
||||
@@ -39,6 +39,7 @@ include(ECMCheckOutboundLicense)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
include(ECMAddAndroidApk)
|
||||
include(ECMQmlModule)
|
||||
include(ECMDeprecationSettings)
|
||||
include(GenerateExportHeader)
|
||||
include(ECMGenerateHeaders)
|
||||
if (NOT ANDROID)
|
||||
@@ -51,6 +52,8 @@ endif()
|
||||
|
||||
set(QUOTIENT_FORCE_NAMESPACED_INCLUDES TRUE)
|
||||
|
||||
ecm_set_disabled_deprecation_versions(Qt 6.9.0 KF 6.17.0)
|
||||
|
||||
ecm_setup_version(${PROJECT_VERSION}
|
||||
VARIABLE_PREFIX NEOCHAT
|
||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/neochat-version.h
|
||||
@@ -66,7 +69,7 @@ if (QT_KNOWN_POLICY_QTP0004)
|
||||
qt_policy(SET QTP0004 NEW)
|
||||
endif ()
|
||||
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels IconThemes ColorScheme)
|
||||
find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Kirigami I18n Notifications Config CoreAddons Sonnet ItemModels ColorScheme IconThemes)
|
||||
set_package_properties(KF6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Basic application components"
|
||||
@@ -75,7 +78,7 @@ set_package_properties(KF6Kirigami PROPERTIES
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Kirigami application UI framework"
|
||||
)
|
||||
find_package(KF6KirigamiAddons 1.6.0 REQUIRED)
|
||||
find_package(KF6KirigamiAddons 1.10.0 REQUIRED)
|
||||
|
||||
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose)
|
||||
@@ -89,7 +92,7 @@ if(ANDROID)
|
||||
)
|
||||
else()
|
||||
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Widgets)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem Crash)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS QQC2DesktopStyle KIO WindowSystem StatusNotifierItem)
|
||||
find_package(KF6SyntaxHighlighting ${KF_MIN_VERSION} REQUIRED)
|
||||
set_package_properties(KF6QQC2DesktopStyle PROPERTIES
|
||||
TYPE RUNTIME
|
||||
@@ -107,7 +110,7 @@ if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
||||
find_package(KF6DBusAddons ${KF_MIN_VERSION} REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(QuotientQt6 0.9.1)
|
||||
find_package(QuotientQt6 0.9.3)
|
||||
set_package_properties(QuotientQt6 PROPERTIES
|
||||
TYPE REQUIRED
|
||||
DESCRIPTION "Qt wrapper around Matrix API"
|
||||
|
||||
@@ -63,7 +63,7 @@ void ActionsTest::testActions_data()
|
||||
QTest::addColumn<std::optional<QString>>("resultText");
|
||||
QTest::addColumn<std::optional<Quotient::RoomMessageEvent::MsgType>>("type");
|
||||
|
||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\_(ツ)_/¯ Hello"_s)
|
||||
QTest::newRow("shrug") << u"/shrug Hello"_s << std::make_optional(u"¯\\\\\\_(ツ)\\_/¯ Hello"_s)
|
||||
<< std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("lenny") << u"/lenny Hello"_s << std::make_optional(u"( ͡° ͜ʖ ͡°) Hello"_s) << std::make_optional(Quotient::RoomMessageEvent::MsgType::Text);
|
||||
QTest::newRow("tableflip") << u"/tableflip Hello"_s << std::make_optional(u"(╯°□°)╯︵ ┻━┻ Hello"_s)
|
||||
|
||||
@@ -28,6 +28,7 @@ private:
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void testMaximizeMedia();
|
||||
void testResolveMatrixLinks();
|
||||
};
|
||||
|
||||
void RoomManagerTest::initTestCase()
|
||||
@@ -128,5 +129,13 @@ void RoomManagerTest::testMaximizeMedia()
|
||||
QVERIFY(spy[1][0] == 0);
|
||||
}
|
||||
|
||||
void RoomManagerTest::testResolveMatrixLinks()
|
||||
{
|
||||
// Test if resolving a non-joined room will bring up the confirmation dialog.
|
||||
const QSignalSpy askToJoinSpy(&RoomManager::instance(), &RoomManager::askJoinRoom);
|
||||
RoomManager::instance().resolveResource(QStringLiteral("matrix:r/testbuild:matrix.org"), QStringLiteral("join"));
|
||||
QTRY_COMPARE(askToJoinSpy.size(), 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN(RoomManagerTest)
|
||||
#include "roommanagertest.moc"
|
||||
|
||||
@@ -4,15 +4,12 @@
|
||||
#include "server.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QHttpServer>
|
||||
#include <QHttpServerResponder>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
#include <QSslServer>
|
||||
#include <QUuid>
|
||||
|
||||
#include <Quotient/networkaccessmanager.h>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,6 @@ Name[sv]=NeoChat
|
||||
Name[ta]=நியோச்சாட்
|
||||
Name[tr]=NeoChat
|
||||
Name[uk]=NeoChat
|
||||
Name[x-test]=xxNeoChatxx
|
||||
Name[zh_CN]=NeoChat
|
||||
Name[zh_TW]=NeoChat
|
||||
GenericName=Matrix Client
|
||||
@@ -88,7 +87,6 @@ GenericName[sv]=Matrix-klient
|
||||
GenericName[ta]=Matrix வாங்கி
|
||||
GenericName[tr]=Matrix İstemcisi
|
||||
GenericName[uk]=Клієнт Matrix
|
||||
GenericName[x-test]=xxMatrix Clientxx
|
||||
GenericName[zh_CN]=Matrix 客户端
|
||||
GenericName[zh_TW]=Matrix 用戶端
|
||||
Comment=Chat on Matrix
|
||||
@@ -114,6 +112,7 @@ Comment[lv]=Tērzējiet „Matrix“ tīklā
|
||||
Comment[nl]=Chat op Matrix
|
||||
Comment[pl]=Rozmawiaj na Matriksie
|
||||
Comment[pt_BR]=Bate papo na Matrix
|
||||
Comment[ro]=Discutați pe Matrix
|
||||
Comment[ru]=Общение в Matrix
|
||||
Comment[sa]=Matrix इत्यत्र गपशपं कुर्वन्तु
|
||||
Comment[sl]=Klepet na Matrixu
|
||||
@@ -121,7 +120,6 @@ Comment[sv]=Chatta på Matrix
|
||||
Comment[ta]=மேட்ரிக்ஸில் உரையாட உதவும்
|
||||
Comment[tr]=Matrix üzerinde sohbet edin
|
||||
Comment[uk]=Спілкування у Matrix
|
||||
Comment[x-test]=xxChat on Matrixxx
|
||||
Comment[zh_CN]=在 Matrix 上聊天
|
||||
Comment[zh_TW]=在 Matrix 上聊天
|
||||
MimeType=x-scheme-handler/matrix;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
From dbd1cefd0f07a6942aef450f8f3e082aa3b1cc25 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Fella <tobias.fella@kde.org>
|
||||
Date: Sun, 17 Aug 2025 20:04:04 +0200
|
||||
Subject: [PATCH] Revert "Bump KF6 dependency version"
|
||||
|
||||
This reverts commit 18a6ea98232b3a734905fb18eebba9cf39bf5325.
|
||||
---
|
||||
CMakeLists.txt | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 10fe66daa..cd063113d 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -14,7 +14,7 @@ set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_
|
||||
|
||||
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
-set(KF_MIN_VERSION "6.17")
|
||||
+set(KF_MIN_VERSION "6.12")
|
||||
set(QT_MIN_VERSION "6.8")
|
||||
|
||||
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
--
|
||||
2.50.1
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
From ca72345b8ee550be2172d8ac5e5dc9e4c2b508c9 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Fella <tobias.fella@kde.org>
|
||||
Date: Sun, 17 Aug 2025 20:00:08 +0200
|
||||
Subject: [PATCH] Revert "Use new Kirigami builtin column resize handle"
|
||||
|
||||
This reverts commit de97275a387abcbca6fcb185bcbd1b69c30f5c66.
|
||||
---
|
||||
src/app/qml/Main.qml | 1 -
|
||||
src/rooms/RoomListPage.qml | 70 +++++++++++++++++++++++++++++---------
|
||||
2 files changed, 54 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/src/app/qml/Main.qml b/src/app/qml/Main.qml
|
||||
index ea8955674..6eed271c1 100644
|
||||
--- a/src/app/qml/Main.qml
|
||||
+++ b/src/app/qml/Main.qml
|
||||
@@ -45,7 +45,6 @@ Kirigami.ApplicationWindow {
|
||||
showExisting: true
|
||||
onConnectionChosen: root.load()
|
||||
}
|
||||
- columnView.columnResizeMode: pageStack.wideMode ? Kirigami.ColumnView.DynamicColumns : Kirigami.ColumnView.SingleColumn
|
||||
globalToolBar.canContainHandles: true
|
||||
globalToolBar {
|
||||
style: Kirigami.ApplicationHeaderStyle.ToolBar
|
||||
diff --git a/src/rooms/RoomListPage.qml b/src/rooms/RoomListPage.qml
|
||||
index 2ac211fd5..f5586d789 100644
|
||||
--- a/src/rooms/RoomListPage.qml
|
||||
+++ b/src/rooms/RoomListPage.qml
|
||||
@@ -17,22 +17,13 @@ import org.kde.neochat
|
||||
Kirigami.Page {
|
||||
id: root
|
||||
|
||||
- Kirigami.ColumnView.interactiveResizeEnabled: true
|
||||
- Kirigami.ColumnView.minimumWidth: _private.collapsedSize + spaceDrawer.width + 1
|
||||
- Kirigami.ColumnView.maximumWidth: _private.defaultWidth + spaceDrawer.width + 1
|
||||
- Kirigami.ColumnView.onInteractiveResizingChanged: {
|
||||
- if (!Kirigami.ColumnView.interactiveResizing && collapsed) {
|
||||
- Kirigami.ColumnView.preferredWidth = root.Kirigami.ColumnView.minimumWidth;
|
||||
- }
|
||||
- }
|
||||
- Kirigami.ColumnView.preferredWidth: _private.currentWidth + spaceDrawer.width + 1
|
||||
- Kirigami.ColumnView.onPreferredWidthChanged: {
|
||||
- if (width > _private.collapseWidth) {
|
||||
- NeoChatConfig.collapsed = false;
|
||||
- } else if (Kirigami.ColumnView.interactiveResizing) {
|
||||
- NeoChatConfig.collapsed = true;
|
||||
- }
|
||||
- }
|
||||
+ /**
|
||||
+ * @brief The current width of the room list.
|
||||
+ *
|
||||
+ * @note Other objects can access the value but the private function makes sure
|
||||
+ * that only the internal members can modify it.
|
||||
+ */
|
||||
+ readonly property int currentWidth: _private.currentWidth + spaceDrawer.width + 1
|
||||
|
||||
required property NeoChatConnection connection
|
||||
|
||||
@@ -40,6 +31,10 @@ Kirigami.Page {
|
||||
|
||||
signal search
|
||||
|
||||
+ onCurrentWidthChanged: pageStack.defaultColumnWidth = root.currentWidth
|
||||
+ Component.onCompleted: pageStack.defaultColumnWidth = root.currentWidth
|
||||
+
|
||||
+
|
||||
onCollapsedChanged: {
|
||||
if (collapsed) {
|
||||
RoomManager.sortFilterRoomTreeModel.filterText = "";
|
||||
@@ -252,6 +247,49 @@ Kirigami.Page {
|
||||
sourceComponent: Kirigami.Settings.isMobile ? exploreComponentMobile : userInfoDesktop
|
||||
}
|
||||
|
||||
+ MouseArea {
|
||||
+ anchors.top: parent.top
|
||||
+ anchors.bottom: parent.bottom
|
||||
+ parent: applicationWindow().overlay.parent
|
||||
+
|
||||
+ x: root.currentWidth - width / 2
|
||||
+ width: Kirigami.Units.smallSpacing * 2
|
||||
+ z: root.z + 1
|
||||
+ enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35
|
||||
+ visible: enabled
|
||||
+ cursorShape: Qt.SplitHCursor
|
||||
+
|
||||
+ property int _lastX
|
||||
+
|
||||
+ onPressed: mouse => {
|
||||
+ _lastX = mouse.x;
|
||||
+ }
|
||||
+ onPositionChanged: mouse => {
|
||||
+ if (_lastX == -1) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (mouse.x > _lastX) {
|
||||
+ // we moved to the right
|
||||
+ if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) {
|
||||
+ // Here we get back directly to a more wide mode.
|
||||
+ _private.currentWidth = _private.defaultWidth;
|
||||
+ NeoChatConfig.collapsed = false;
|
||||
+ } else if (_private.currentWidth >= _private.collapseWidth) {
|
||||
+ // Increase page width
|
||||
+ _private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX));
|
||||
+ }
|
||||
+ } else if (mouse.x < _lastX) {
|
||||
+ const tmpWidth = _private.currentWidth - (_lastX - mouse.x);
|
||||
+ if (tmpWidth < _private.collapseWidth) {
|
||||
+ _private.currentWidth = Qt.binding(() => _private.collapsedSize);
|
||||
+ NeoChatConfig.collapsed = true;
|
||||
+ } else {
|
||||
+ _private.currentWidth = tmpWidth;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
Component {
|
||||
id: userInfo
|
||||
UserInfo {
|
||||
--
|
||||
2.50.1
|
||||
|
||||
1716
po/ar/neochat.po
1716
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1508
po/ast/neochat.po
1508
po/ast/neochat.po
File diff suppressed because it is too large
Load Diff
1675
po/az/neochat.po
1675
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1681
po/ca/neochat.po
1681
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1673
po/cs/neochat.po
1673
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1628
po/da/neochat.po
1628
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
2839
po/de/neochat.po
2839
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1729
po/el/neochat.po
1729
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1772
po/en_GB/neochat.po
1772
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1761
po/eo/neochat.po
1761
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1608
po/es/neochat.po
1608
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1773
po/eu/neochat.po
1773
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
2064
po/fi/neochat.po
2064
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1806
po/fr/neochat.po
1806
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
7002
po/ga/neochat.po
Normal file
7002
po/ga/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
1774
po/gl/neochat.po
1774
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
1695
po/he/neochat.po
1695
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
1755
po/hi/neochat.po
1755
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
2067
po/hu/neochat.po
2067
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
2258
po/ia/neochat.po
2258
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1723
po/id/neochat.po
1723
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1654
po/ie/neochat.po
1654
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1738
po/it/neochat.po
1738
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1499
po/ja/neochat.po
1499
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1698
po/ka/neochat.po
1698
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
2157
po/ko/neochat.po
2157
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
2392
po/lt/neochat.po
2392
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1995
po/lv/neochat.po
1995
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1703
po/nl/neochat.po
1703
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1636
po/nn/neochat.po
1636
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1672
po/pa/neochat.po
1672
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
2628
po/pl/neochat.po
2628
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1712
po/pt/neochat.po
1712
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
122
po/pt_BR/docs/neochat/man-neochat.1.docbook
Normal file
122
po/pt_BR/docs/neochat/man-neochat.1.docbook
Normal file
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN" "dtd/kdedbx45.dtd" [
|
||||
<!ENTITY % Brazilian-Portuguese "INCLUDE">
|
||||
]>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
-->
|
||||
|
||||
<refentry lang="&language;">
|
||||
<refentryinfo>
|
||||
<title
|
||||
>Manual do Usuário do NeoChat</title>
|
||||
<author
|
||||
><firstname
|
||||
>Carl</firstname
|
||||
><surname
|
||||
>Schwan</surname
|
||||
> <contrib
|
||||
>NeoChat man page.</contrib
|
||||
> <email
|
||||
>carl@carlschwan.eu</email
|
||||
></author>
|
||||
<date
|
||||
>01/11/2022</date>
|
||||
<releaseinfo
|
||||
>22.09</releaseinfo>
|
||||
<productname
|
||||
>NeoChat</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>
|
||||
<command
|
||||
>neochat</command>
|
||||
</refentrytitle>
|
||||
<manvolnum
|
||||
>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname
|
||||
>neochat</refname>
|
||||
<refpurpose
|
||||
>Cliente para interação com o protocolo de mensagens Matrix.</refpurpose>
|
||||
</refnamediv>
|
||||
<!-- body begins here -->
|
||||
<refsynopsisdiv id='synopsis'>
|
||||
<cmdsynopsis
|
||||
><command
|
||||
>neochat</command
|
||||
> <arg choice="opt"
|
||||
><replaceable
|
||||
>URI</replaceable
|
||||
></arg
|
||||
> </cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsect1 id="description">
|
||||
<title
|
||||
>Descrição</title>
|
||||
<para
|
||||
>O <command
|
||||
>neochat</command
|
||||
> é um aplicativo de bate-papo para o protocolo Matrix. Ele funciona tanto em computadores quanto em dispositivos móveis. </para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options"
|
||||
><title
|
||||
>Opções</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term
|
||||
><option
|
||||
>URI</option
|
||||
></term>
|
||||
<listitem>
|
||||
<para
|
||||
>O URI da matriz para um usuário ou uma sala. Por exemplo, matrix:u/usuário:exemplo.org e matrix:r/root:exemplo.org. Isso fará com que o NeoChat tente abrir a sala ou conversa especificada. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="bug">
|
||||
<title
|
||||
>Relatar bugs</title>
|
||||
<para
|
||||
>Você pode reportar erros e solicitar novas funcionalidades em <ulink url="https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General"
|
||||
>https://bugs.kde.org/enter_bug.cgi?product=NeoChat&component=General</ulink
|
||||
></para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title
|
||||
>Veja também</title>
|
||||
<simplelist>
|
||||
<member
|
||||
>Lista de perguntas frequentes sobre o Matrix <ulink url="https://matrix.org/faq/"
|
||||
>https://matrix.org/faq/</ulink
|
||||
> </member>
|
||||
<member
|
||||
>kf5options(7)</member>
|
||||
<member
|
||||
>qt5options(7)</member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="copyright"
|
||||
><title
|
||||
>Direitos autorais</title>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Tobias Fella </para>
|
||||
<para
|
||||
>Direitos autorais © 2020-2022 Carl Schwan </para>
|
||||
<para
|
||||
>Licença: GNU General Public Versão 3 ou posterior <ulink url="https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
>https://www.gnu.org/licenses/gpl-3.0.html</ulink
|
||||
>></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
1762
po/pt_BR/neochat.po
1762
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
7049
po/ro/neochat.po
Normal file
7049
po/ro/neochat.po
Normal file
File diff suppressed because it is too large
Load Diff
2196
po/ru/neochat.po
2196
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1755
po/sa/neochat.po
1755
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
1703
po/sk/neochat.po
1703
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1709
po/sl/neochat.po
1709
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1706
po/sv/neochat.po
1706
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
2188
po/ta/neochat.po
2188
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1633
po/tok/neochat.po
1633
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1725
po/tr/neochat.po
1725
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1719
po/uk/neochat.po
1719
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1697
po/zh_CN/neochat.po
1697
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
2022
po/zh_TW/neochat.po
2022
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,8 @@ if(ANDROID OR WIN32)
|
||||
set_source_files_properties(qml/GlobalMenuStub.qml PROPERTIES
|
||||
QT_QML_SOURCE_TYPENAME GlobalMenu
|
||||
)
|
||||
else()
|
||||
set(EXTRA_IMPORTS org.kde.purpose)
|
||||
endif()
|
||||
|
||||
ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||
@@ -101,6 +103,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||
qml/ReasonDialog.qml
|
||||
qml/NewPollDialog.qml
|
||||
qml/UserMenu.qml
|
||||
qml/MeetingDialog.qml
|
||||
DEPENDENCIES
|
||||
QtCore
|
||||
QtQuick
|
||||
@@ -117,8 +120,8 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
||||
org.kde.neochat.login
|
||||
org.kde.neochat.chatbar
|
||||
org.kde.config
|
||||
org.kde.purpose
|
||||
org.kde.syntaxhighlighting
|
||||
${EXTRA_IMPORTS}
|
||||
)
|
||||
|
||||
if(NOT ANDROID AND NOT WIN32)
|
||||
@@ -150,6 +153,7 @@ target_include_directories(neochat-app PRIVATE ${CMAKE_BINARY_DIR})
|
||||
|
||||
target_link_libraries(neochat-app PRIVATE
|
||||
neochat
|
||||
KF6::IconThemes
|
||||
)
|
||||
|
||||
ecm_add_app_icon(NEOCHAT_ICON ICONS ${CMAKE_SOURCE_DIR}/128-logo.png)
|
||||
@@ -200,8 +204,9 @@ target_link_libraries(neochat PUBLIC
|
||||
KF6::ConfigGui
|
||||
KF6::CoreAddons
|
||||
KF6::SonnetCore
|
||||
KF6::IconThemes
|
||||
KF6::ItemModels
|
||||
KF6::I18nQml
|
||||
KirigamiApp
|
||||
QuotientQt6
|
||||
Login
|
||||
Rooms
|
||||
@@ -209,10 +214,6 @@ target_link_libraries(neochat PUBLIC
|
||||
Spaces
|
||||
)
|
||||
|
||||
if (TARGET KF6::Crash)
|
||||
target_link_libraries(neochat PUBLIC KF6::Crash)
|
||||
endif()
|
||||
|
||||
kconfig_target_kcfg_file(neochat FILE neochatconfig.kcfg CLASS_NAME NeoChatConfig MUTATORS GENERATE_PROPERTIES DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR SINGLETON GENERATE_MOC QML_REGISTRATION)
|
||||
|
||||
if(NEOCHAT_FLATPAK)
|
||||
@@ -323,6 +324,7 @@ if(ANDROID)
|
||||
"kt-restore-defaults-symbolic"
|
||||
"user-symbolic"
|
||||
"mark-location-symbolic"
|
||||
"amarok_playcount"
|
||||
|
||||
${KIRIGAMI_ADDONS_ICONS}
|
||||
)
|
||||
@@ -351,7 +353,8 @@ endif()
|
||||
install(TARGETS neochat-app ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
if (NOT ANDROID AND NOT WIN32 AND NOT APPLE)
|
||||
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
|
||||
# krunner plugin must be the same as the app id for flatpak to export it
|
||||
install(FILES plasma-runner-neochat.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins RENAME org.kde.neochat.desktop)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <Quotient/qt_connection_util.h>
|
||||
#include <Quotient/settings.h>
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include "enums/roomsortparameter.h"
|
||||
#include "general_logging.h"
|
||||
#include "mediasizehelper.h"
|
||||
@@ -26,9 +25,7 @@
|
||||
#include "models/roomlistmodel.h"
|
||||
#include "models/roomtreemodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
#include "notificationsmanager.h"
|
||||
#include "proxycontroller.h"
|
||||
#include "roommanager.h"
|
||||
|
||||
@@ -309,8 +306,7 @@ void Controller::listenForNotifications()
|
||||
connect(timer, &QTimer::timeout, qGuiApp, &QGuiApplication::quit);
|
||||
|
||||
connect(connector, &KUnifiedPush::Connector::messageReceived, [timer](const QByteArray &data) {
|
||||
instance().m_notificationsManager.postPushNotification(data);
|
||||
timer->stop();
|
||||
NotificationsManager::postPushNotification(data);
|
||||
});
|
||||
|
||||
// Wait five seconds to see if we received any messages or this happened to be an erroneous activation.
|
||||
|
||||
@@ -33,13 +33,10 @@
|
||||
#include <KWindowSystem>
|
||||
#endif
|
||||
|
||||
#if __has_include("KCrash")
|
||||
#include <KCrash>
|
||||
#endif
|
||||
|
||||
#include <KIconTheme>
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedQmlContext>
|
||||
#include <KLocalizedString>
|
||||
#include <KirigamiApp>
|
||||
|
||||
#include "neochat-version.h"
|
||||
|
||||
@@ -104,33 +101,22 @@ Q_DECL_EXPORT
|
||||
#endif
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
KIconTheme::initTheme();
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
|
||||
// We currently need to do this ourselves,
|
||||
// KirigamiApp currently called this after constructing the app which breaks icons on Windows.
|
||||
KIconTheme::initTheme();
|
||||
|
||||
#ifdef HAVE_WEBVIEW
|
||||
QtWebView::initialize();
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi);
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
QGuiApplication app(argc, argv);
|
||||
QQuickStyle::setStyle(u"org.kde.breeze"_s);
|
||||
#else
|
||||
QIcon::setFallbackThemeName("breeze"_L1);
|
||||
QApplication app(argc, argv);
|
||||
// Default to org.kde.desktop style unless the user forces another style
|
||||
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
|
||||
QQuickStyle::setStyle(u"org.kde.desktop"_s);
|
||||
}
|
||||
#endif
|
||||
KirigamiApp::App app(argc, argv);
|
||||
KirigamiApp kirigamiApp;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
}
|
||||
|
||||
QApplication::setStyle(u"breeze"_s);
|
||||
QFont font(u"Segoe UI Emoji"_s);
|
||||
font.setPointSize(10);
|
||||
@@ -177,10 +163,6 @@ int main(int argc, char *argv[])
|
||||
KAboutData::setApplicationData(about);
|
||||
QGuiApplication::setWindowIcon(QIcon::fromTheme(u"org.kde.neochat"_s));
|
||||
|
||||
#if __has_include("KCrash")
|
||||
KCrash::initialize();
|
||||
#endif
|
||||
|
||||
Connection::setEncryptionDefault(true);
|
||||
Connection::setDirectChatEncryptionDefault(true);
|
||||
|
||||
@@ -205,7 +187,7 @@ int main(int argc, char *argv[])
|
||||
parser.addOption(testOption);
|
||||
|
||||
#ifdef HAVE_KUNIFIEDPUSH
|
||||
QCommandLineOption dbusActivatedOption(u"dbus-activated"_s, i18n("Internal usage only."));
|
||||
QCommandLineOption dbusActivatedOption(u"dbus-activated"_s);
|
||||
dbusActivatedOption.setFlags(QCommandLineOption::Flag::HiddenFromHelp);
|
||||
parser.addOption(dbusActivatedOption);
|
||||
#endif
|
||||
@@ -219,8 +201,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
#ifdef HAVE_KUNIFIEDPUSH
|
||||
if (parser.isSet(dbusActivatedOption)) {
|
||||
// We want to be replaceable by the main client
|
||||
KDBusService service(KDBusService::Replace);
|
||||
#ifdef HAVE_KDBUSADDONS
|
||||
// We *don't* want to use KDBusService here. I don't know why, but it makes activation super unreliable. We don't really need it anyway.
|
||||
if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.neochat"))) {
|
||||
// Gracefully fail if NeoChat is already running
|
||||
qWarning() << "NeoChat already running, not sending push notifications.";
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RUNNER
|
||||
// If we are built with KRunner and KUnifiedPush support, we need to do something special.
|
||||
@@ -279,7 +267,7 @@ int main(int argc, char *argv[])
|
||||
});
|
||||
#endif
|
||||
|
||||
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||
KLocalization::setupLocalizedContext(&engine);
|
||||
engine.setNetworkAccessManagerFactory(new NetworkAccessManagerFactory());
|
||||
|
||||
if (parser.isSet("ignore-ssl-errors"_L1)) {
|
||||
@@ -294,7 +282,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
engine.addImageProvider(u"blurhash"_s, new BlurhashImageProvider);
|
||||
|
||||
engine.loadFromModule("org.kde.neochat", "Main");
|
||||
if (!kirigamiApp.start("org.kde.neochat", "Main", &engine)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!parser.positionalArguments().isEmpty() && !parser.isSet("share"_L1)) {
|
||||
RoomManager::instance().setUrlArgument(parser.positionalArguments()[0]);
|
||||
|
||||
@@ -58,7 +58,7 @@ QVariant NotificationsModel::data(const QModelIndex &index, int role) const
|
||||
QHash<int, QByteArray> NotificationsModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{TextRole, "text"},
|
||||
{TextRole, "notificationText"},
|
||||
{RoomIdRole, "roomId"},
|
||||
{AuthorName, "authorName"},
|
||||
{AuthorAvatar, "authorAvatar"},
|
||||
|
||||
@@ -42,7 +42,6 @@ Name[sv]=NeoChat
|
||||
Name[ta]=நியோச்சாட்
|
||||
Name[tr]=NeoChat
|
||||
Name[uk]=NeoChat
|
||||
Name[x-test]=xxNeoChatxx
|
||||
Name[zh_CN]=NeoChat
|
||||
Name[zh_TW]=NeoChat
|
||||
DesktopEntry=org.kde.neochat
|
||||
@@ -87,7 +86,6 @@ Comment[sv]=En klient för matrix, det decentraliserade kommunikationsprotokolle
|
||||
Comment[ta]=மையமில்லா தகவல் பரிமாற்ற நெறிமுறையான மேட்ரிக்ஸுக்கான செயலி
|
||||
Comment[tr]=Merkezi olmayan iletişim protokolü Matrix için bir istemci
|
||||
Comment[uk]=Клієнт matrix, децентралізованого протоколу обміну даними
|
||||
Comment[x-test]=xxA client for matrix, the decentralized communication protocolxx
|
||||
Comment[zh_CN]=分布式通讯协议 Matrix 的客户端
|
||||
Comment[zh_TW]=去中心化通訊協定 Matrix 的用戶端
|
||||
|
||||
@@ -134,7 +132,6 @@ Name[sv]=Nytt meddelande
|
||||
Name[ta]=புதிய செய்தி
|
||||
Name[tr]=Yeni İleti
|
||||
Name[uk]=Нове повідомлення
|
||||
Name[x-test]=xxNew messagexx
|
||||
Name[zh_CN]=新消息
|
||||
Name[zh_TW]=新訊息
|
||||
Comment=There is a new message
|
||||
@@ -177,7 +174,6 @@ Comment[sv]=Det finns ett nytt meddelande
|
||||
Comment[ta]=ஒரு புதிய செய்தி உள்ளது
|
||||
Comment[tr]=Yeni bir ileti var
|
||||
Comment[uk]=Надійшло нове повідомлення
|
||||
Comment[x-test]=xxThere is a new messagexx
|
||||
Comment[zh_CN]=有新消息
|
||||
Comment[zh_TW]=有新的訊息
|
||||
Action=Popup
|
||||
@@ -215,6 +211,7 @@ Name[pa]=ਨਵਾਂ ਸੱਦਾ
|
||||
Name[pl]=Nowe zaproszenie
|
||||
Name[pt]=Novo Convite
|
||||
Name[pt_BR]=Novo convite
|
||||
Name[ro]=Invitație nouă
|
||||
Name[ru]=Новое приглашение
|
||||
Name[sa]=नवीन आमन्त्रणम्
|
||||
Name[sl]=Novo povabilo
|
||||
@@ -222,7 +219,6 @@ Name[sv]=Ny inbjudan
|
||||
Name[ta]=புதிய அழைப்பிதழ்
|
||||
Name[tr]=Yeni Davet
|
||||
Name[uk]=Нове запрошення
|
||||
Name[x-test]=xxNew Invitationxx
|
||||
Name[zh_CN]=新邀请
|
||||
Name[zh_TW]=新邀請
|
||||
Comment=There is a new invitation to a room
|
||||
@@ -257,14 +253,14 @@ Comment[pa]=ਰੂਮ ਲਈ ਨਵਾਂ ਸੱਦਾ ਹੈ
|
||||
Comment[pl]=Dostępna jest nowe zaproszenie do pokoju
|
||||
Comment[pt]=Existe um novo convite para uma sala
|
||||
Comment[pt_BR]=Existe um novo convite para uma sala
|
||||
Comment[ro]=E o nouă invitație la o cameră
|
||||
Comment[ru]=Доступно новое приглашение в комнату
|
||||
Comment[sa]=कक्षस्य नूतनं निमन्त्रणम् अस्ति
|
||||
Comment[sl]=Tam je novo povabilo v sobo
|
||||
Comment[sv]=Det finns en ny inbjudan till ett rum
|
||||
Comment[ta]=ஓர் அரங்கிற்கான புதிய அழைப்பிதழ் உள்ளது
|
||||
Comment[tr]=Bir odaya yeni bir davetiye var
|
||||
Comment[tr]=Bir odaya yeni bir davet var
|
||||
Comment[uk]=У кімнаті нове запрошення
|
||||
Comment[x-test]=xxThere is a new invitation to a roomxx
|
||||
Comment[zh_CN]=有新的聊天室邀请
|
||||
Comment[zh_TW]=有新的加入聊天室邀請
|
||||
Action=Popup
|
||||
@@ -296,6 +292,7 @@ Name[nl]=Gedeelde
|
||||
Name[nn]=Del
|
||||
Name[pl]=Udostępnij
|
||||
Name[pt_BR]=Compartilhar
|
||||
Name[ro]=Partajare
|
||||
Name[ru]=Публикация
|
||||
Name[sa]=संविभागः
|
||||
Name[sl]=Deli
|
||||
@@ -303,7 +300,6 @@ Name[sv]=Dela
|
||||
Name[ta]=பகிர்
|
||||
Name[tr]=Paylaş
|
||||
Name[uk]=Оприлюднення
|
||||
Name[x-test]=xxSharexx
|
||||
Name[zh_CN]=分享
|
||||
Name[zh_TW]=分享
|
||||
Comment=The result of sharing a piece of content
|
||||
@@ -331,6 +327,7 @@ Comment[nl]=Het resultaat van het delen van een stukje inhoud
|
||||
Comment[nn]=Resultatet av deling av innhald
|
||||
Comment[pl]=Wynik udostępniania kawałka treści
|
||||
Comment[pt_BR]=O resultado de compartilhar um conteúdo
|
||||
Comment[ro]=Rezultatul partajării unei bucăți de conținut
|
||||
Comment[ru]=Результат публикации данных
|
||||
Comment[sa]=सामग्रीखण्डस्य साझाकरणस्य परिणामः
|
||||
Comment[sl]=Rezultat deljenega kosa vsebine
|
||||
@@ -338,7 +335,6 @@ Comment[sv]=Resultatet av att dela innehåll
|
||||
Comment[ta]=எதையோ பகிர்ந்ததன் விளைவு
|
||||
Comment[tr]=Bir parça içerik paylaşımının sonucu
|
||||
Comment[uk]=Результат оприлюднення даних
|
||||
Comment[x-test]=xxThe result of sharing a piece of contentxx
|
||||
Comment[zh_CN]=分享一个内容得到的结果
|
||||
Comment[zh_TW]=分享一份內容之後的結果
|
||||
Action=Popup
|
||||
|
||||
@@ -66,6 +66,10 @@
|
||||
</entry>
|
||||
</group>
|
||||
<group name="Timeline">
|
||||
<entry name="FontScale" type="double">
|
||||
<label>Scaling factor for font sizes</label>
|
||||
<default>1.0</default>
|
||||
</entry>
|
||||
<entry name="ShowAvatarInTimeline" type="bool">
|
||||
<label>Show avatar in the timeline</label>
|
||||
<default>true</default>
|
||||
|
||||
@@ -216,12 +216,12 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
||||
}
|
||||
});
|
||||
|
||||
notification->setTitle(room->displayName());
|
||||
|
||||
QString entry;
|
||||
if (sender == room->displayName()) {
|
||||
notification->setTitle(sender);
|
||||
if (room->isDirectChat()) {
|
||||
entry = text.toHtmlEscaped();
|
||||
} else {
|
||||
notification->setTitle(room->displayName());
|
||||
entry = i18n("%1: %2", sender, text.toHtmlEscaped());
|
||||
}
|
||||
|
||||
@@ -253,7 +253,9 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
||||
notification->setReplyAction(std::move(replyAction));
|
||||
}
|
||||
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
if (Controller::instance().accounts()->rowCount() > 1) {
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
}
|
||||
notification->sendEvent();
|
||||
}
|
||||
|
||||
@@ -347,7 +349,9 @@ void NotificationsManager::doPostInviteNotification(QPointer<NeoChatRoom> room)
|
||||
m_invitations.remove(room->id());
|
||||
});
|
||||
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
if (Controller::instance().accounts()->rowCount() > 1) {
|
||||
notification->setHint(u"x-kde-origin-name"_s, room->localMember().id());
|
||||
}
|
||||
|
||||
notification->sendEvent();
|
||||
}
|
||||
@@ -388,7 +392,7 @@ void NotificationsManager::postPushNotification(const QByteArray &message)
|
||||
|
||||
#ifdef HAVE_KIO
|
||||
auto openAction = notification->addAction(i18n("Open NeoChat"));
|
||||
connect(openAction, &KNotificationAction::activated, this, [=]() {
|
||||
connect(openAction, &KNotificationAction::activated, notification, [=]() {
|
||||
QString properId = roomId;
|
||||
properId = properId.replace(u"#"_s, QString());
|
||||
properId = properId.replace(u"!"_s, QString());
|
||||
@@ -402,8 +406,6 @@ void NotificationsManager::postPushNotification(const QByteArray &message)
|
||||
connect(notification, &KNotification::closed, qGuiApp, &QGuiApplication::quit);
|
||||
|
||||
notification->sendEvent();
|
||||
|
||||
m_notifications.insert(roomId, {json["ts"_L1].toVariant().toLongLong(), notification});
|
||||
} else {
|
||||
qWarning() << "Skipping unsupported push notification" << type;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
/**
|
||||
* @brief Display a native notification for the given push notification.
|
||||
*/
|
||||
void postPushNotification(const QByteArray &message);
|
||||
static void postPushNotification(const QByteArray &message);
|
||||
|
||||
/**
|
||||
* @brief Handle the notifications for the given connection.
|
||||
|
||||
@@ -43,7 +43,6 @@ Name[sv]=NeoChat
|
||||
Name[ta]=நியோச்சாட்
|
||||
Name[tr]=NeoChat
|
||||
Name[uk]=NeoChat
|
||||
Name[x-test]=xxNeoChatxx
|
||||
Name[zh_CN]=NeoChat
|
||||
Name[zh_TW]=NeoChat
|
||||
Comment=Find rooms in NeoChat
|
||||
@@ -76,6 +75,7 @@ Comment[nn]=Finn rom i NeoChat
|
||||
Comment[pl]=Znajdź pokoje w NeoChat
|
||||
Comment[pt]=Procurar salas no NeoChat
|
||||
Comment[pt_BR]=Encontrar salas no NeoChat
|
||||
Comment[ro]=Găsește camere în NeoChat
|
||||
Comment[ru]=Поиск комнат NeoChat
|
||||
Comment[sa]=NeoChat इत्यत्र कक्ष्याः अन्वेषणं कुर्वन्तु
|
||||
Comment[sl]=Najdi sobe v NeoChatu
|
||||
@@ -83,7 +83,6 @@ Comment[sv]=Sök efter rum i NeoChat
|
||||
Comment[ta]=நியோச்சாட்டில் அரங்குகளை கண்டுபிடிக்கும்
|
||||
Comment[tr]=NeoChat’te odalar bulun
|
||||
Comment[uk]=Пошук кімнат у NeoChat
|
||||
Comment[x-test]=xxFind rooms in NeoChatxx
|
||||
Comment[zh_CN]=在 NeoChat 查找聊天室
|
||||
Comment[zh_TW]=在 NeoChat 尋找聊天室
|
||||
X-KDE-ServiceTypes=Plasma/Runner
|
||||
|
||||
@@ -88,7 +88,7 @@ KirigamiComponents.ConvergentContextMenu {
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:inmenu", "Verify This Device")
|
||||
icon.name: "security-low"
|
||||
visible: !root.connection.isVerifiedSession()
|
||||
visible: !root.connection.isVerifiedSession
|
||||
onTriggered: {
|
||||
root.connection.startSelfVerification();
|
||||
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
|
||||
|
||||
@@ -61,7 +61,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {}, {
|
||||
((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {}, {
|
||||
title: i18nc("@title:window", "Login")
|
||||
});
|
||||
root.close();
|
||||
@@ -95,8 +95,8 @@ Kirigami.Dialog {
|
||||
accountView.decrementCurrentIndex();
|
||||
}
|
||||
}
|
||||
Keys.onEnterPressed: (accountView.currentItem as Delegates.RoundedItemDelegate).clicked()
|
||||
Keys.onReturnPressed: (accountView.currentItem as Delegates.RoundedItemDelegate).clicked()
|
||||
Keys.onEnterPressed: ((accountView.currentItem ?? accountView.footerItem) as Delegates.RoundedItemDelegate).clicked()
|
||||
Keys.onReturnPressed: ((accountView.currentItem ?? accountView.footerItem) as Delegates.RoundedItemDelegate).clicked()
|
||||
|
||||
onVisibleChanged: {
|
||||
for (let i = 0; i < accountView.count; i++) {
|
||||
|
||||
@@ -21,6 +21,7 @@ Delegates.RoundedItemDelegate {
|
||||
signal contextMenuRequested
|
||||
signal selected
|
||||
|
||||
activeFocusOnTab: true
|
||||
padding: Kirigami.Units.largeSpacing
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
|
||||
@@ -48,7 +48,7 @@ Components.AbstractMaximizeComponent {
|
||||
implicitWidth: Kirigami.Units.iconSizes.medium
|
||||
implicitHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
name: root.author.name ?? root.author.displayName
|
||||
name: root.author.displayName
|
||||
source: root.author.avatarUrl
|
||||
color: root.author.color
|
||||
}
|
||||
@@ -57,7 +57,7 @@ Components.AbstractMaximizeComponent {
|
||||
QQC2.Label {
|
||||
id: userLabel
|
||||
|
||||
text: root.author.name ?? root.author.displayName
|
||||
text: root.author.displayName
|
||||
color: root.author.color
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
@@ -91,6 +91,7 @@ Components.AbstractMaximizeComponent {
|
||||
color: Kirigami.Theme.textColor
|
||||
|
||||
font.family: "monospace"
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * NeoChatConfig.fontScale
|
||||
|
||||
Kirigami.SpellCheck.enabled: false
|
||||
|
||||
@@ -149,4 +150,6 @@ Components.AbstractMaximizeComponent {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: forceActiveFocus()
|
||||
}
|
||||
|
||||
@@ -6,16 +6,15 @@ import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.neochat
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property alias emoji: emojiLabel.text
|
||||
property alias description: descriptionLabel.text
|
||||
required property string emoji
|
||||
required property string description
|
||||
|
||||
QQC2.Label {
|
||||
id: emojiLabel
|
||||
text: root.emoji
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.huge
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
|
||||
@@ -25,7 +24,7 @@ ColumnLayout {
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 4
|
||||
}
|
||||
QQC2.Label {
|
||||
id: descriptionLabel
|
||||
text: root.description
|
||||
Layout.fillWidth: true
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
@@ -17,9 +17,6 @@ RowLayout {
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
delegate: EmojiItem {
|
||||
emoji: modelData.emoji
|
||||
description: modelData.description
|
||||
}
|
||||
delegate: EmojiItem {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ ApplicationWindow {
|
||||
property real longitude: NaN
|
||||
property string asset
|
||||
property var author
|
||||
property QtObject liveLocationModel: null
|
||||
property LiveLocationsModel liveLocationModel: null
|
||||
|
||||
flags: Qt.FramelessWindowHint | Qt.WA_TranslucentBackground
|
||||
visibility: Qt.WindowFullScreen
|
||||
@@ -59,7 +59,7 @@ ApplicationWindow {
|
||||
|
||||
Connections {
|
||||
target: mapView.map
|
||||
function onCopyrightLinkActivated() {
|
||||
function onCopyrightLinkActivated(link: string) {
|
||||
Qt.openUrlExternally(link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ Labs.MenuBar {
|
||||
|
||||
Labs.MenuItem {
|
||||
icon.name: "list-add-user"
|
||||
text: i18nc("@action:inmenu", "Find your Friends")
|
||||
text: i18nc("@action:inmenu", "Find User")
|
||||
enabled: root.connection
|
||||
onTriggered: root.appWindow.pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
|
||||
connection: root.connection
|
||||
}, {
|
||||
title: i18nc("@title", "Find your friends")
|
||||
title: i18nc("@title", "Find User")
|
||||
})
|
||||
}
|
||||
Labs.MenuItem {
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
|
||||
import QtQuick
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.neochat
|
||||
|
||||
Item {
|
||||
required property NeoChatConnection connection
|
||||
required property Kirigami.ApplicationWindow appWindow
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ Kirigami.Dialog {
|
||||
text: i18nc("@action:button", "Join room")
|
||||
icon.name: "irc-join-channel"
|
||||
onClicked: {
|
||||
RoomManager.resolveResource(root.room, "join");
|
||||
RoomManager.resolveResource(root.room, "join_confirmed");
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import QtQml
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
@@ -170,6 +171,8 @@ Kirigami.Page {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
isDone: root.session.state === KeyVerificationSession.DONE
|
||||
onDone: root.closeDialog()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ Components.AbstractMaximizeComponent {
|
||||
}
|
||||
]
|
||||
|
||||
onOpened: forceActiveFocus()
|
||||
|
||||
PositionSource {
|
||||
id: positionSource
|
||||
|
||||
|
||||
@@ -100,7 +100,8 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
function onCurrentRoomChanged() {
|
||||
if (RoomManager.currentRoom && root.pageStack.depth <= 1 && root.initialized && Kirigami.Settings.isMobile) {
|
||||
let roomPage = root.pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
|
||||
let roomPage = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomPage'));
|
||||
roomPage.forceActiveFocus();
|
||||
roomPage.backRequested.connect(event => {
|
||||
RoomManager.clearCurrentRoom();
|
||||
});
|
||||
@@ -233,7 +234,7 @@ Kirigami.ApplicationWindow {
|
||||
RoomListPage {
|
||||
id: roomList
|
||||
|
||||
onSearch: quickSwitcher.open()
|
||||
onSearch: root.quickSwitcher.open()
|
||||
|
||||
connection: root.connection
|
||||
|
||||
@@ -267,6 +268,17 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.connection
|
||||
function onLoggedOut(): void {
|
||||
root.pageStack.clear();
|
||||
let page = root.pageStack.push(Qt.createComponent('org.kde.neochat.login', 'WelcomePage'), {
|
||||
showExisting: true,
|
||||
}) as WelcomePage;
|
||||
page.connectionChosen.connect(() => root.load())
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: AccountRegistry
|
||||
function onRowsRemoved() {
|
||||
@@ -347,7 +359,11 @@ Kirigami.ApplicationWindow {
|
||||
user: user,
|
||||
connection: root.connection,
|
||||
}) as UserDetailDialog;
|
||||
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
|
||||
// FIXME: The reason why we don't want the focusedWindowItem for the room null case (aka QR codes) is because it will parent it to the soon-to-be-destroyed window item.
|
||||
// But this won't be a problem if we turn it into a Kirigami.Dialog or some other in-scene item, which it really should be.
|
||||
if (room != null) {
|
||||
dialog.parent = QmlUtils.focusedWindowItem(); // Kirigami Dialogs overwrite the parent, so we need to set it again
|
||||
}
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
|
||||
22
src/app/qml/MeetingDialog.qml
Normal file
22
src/app/qml/MeetingDialog.qml
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
import QtQuick
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Kirigami.PromptDialog {
|
||||
id: root
|
||||
|
||||
required property bool hasExistingMeeting
|
||||
|
||||
title: hasExistingMeeting ? i18nc("@title", "Join Meeting") : i18nc("@title", "Start Meeting")
|
||||
subtitle: hasExistingMeeting ? i18nc("@info:label", "You are about to join a Jitsi meeting in your web browser.") : i18nc("@info:label", "You are about to start a new Jitsi meeting in your web browser.")
|
||||
standardButtons: Kirigami.Dialog.Cancel
|
||||
|
||||
customFooterActions: Kirigami.Action {
|
||||
icon.name: "camera-video-symbolic"
|
||||
text: hasExistingMeeting ? i18nc("@action:button Join the Jitsi meeting", "Join") : i18nc("@action:button Start a new Jitsi meeting", "Start")
|
||||
onTriggered: root.accept()
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,8 @@ Kirigami.Page {
|
||||
enabled: root.model
|
||||
target: root.room
|
||||
function onChanged(): void {
|
||||
root.contentJson = model.stateEventContentJson(root.type, root.stateKey);
|
||||
root.sourceText = model.stateEventJson(root.type, root.stateKey);
|
||||
root.contentJson = root.model.stateEventContentJson(root.type, root.stateKey);
|
||||
root.sourceText = root.model.stateEventJson(root.type, root.stateKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ Kirigami.Page {
|
||||
text: i18nc("@action As in 'edit the state of this room'", "Edit state")
|
||||
icon.name: "document-edit"
|
||||
visible: root.allowEdit
|
||||
enabled: room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create"
|
||||
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog"), {
|
||||
enabled: root.room.canSendState(root.type) && (!root.stateKey.startsWith("@") || root.stateKey === root.room.connection.localUserId) && root.type !== "m.room.create"
|
||||
onTriggered: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent("org.kde.neochat", "EditStateDialog"), {
|
||||
room: root.room,
|
||||
type: root.type,
|
||||
stateKey: root.stateKey,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore as Core
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
@@ -21,13 +23,13 @@ Components.AlbumMaximizeComponent {
|
||||
*/
|
||||
required property NeoChatRoom currentRoom
|
||||
|
||||
readonly property string currentEventId: model.data(model.index(content.currentIndex, 0), TimelineMessageModel.EventIdRole)
|
||||
readonly property string currentEventId: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.EventIdRole)
|
||||
|
||||
readonly property var currentAuthor: model.data(model.index(content.currentIndex, 0), TimelineMessageModel.AuthorRole)
|
||||
readonly property var currentAuthor: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.AuthorRole)
|
||||
|
||||
readonly property var currentTime: model.data(model.index(content.currentIndex, 0), TimelineMessageModel.TimeRole)
|
||||
readonly property var currentTime: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.TimeRole)
|
||||
|
||||
readonly property var currentProgressInfo: model.data(model.index(content.currentIndex, 0), TimelineMessageModel.ProgressInfoRole)
|
||||
readonly property var currentProgressInfo: model.data(model.index((content as ListView).currentIndex, 0), TimelineMessageModel.ProgressInfoRole)
|
||||
|
||||
actions: [
|
||||
ShareAction {
|
||||
@@ -59,28 +61,28 @@ Components.AlbumMaximizeComponent {
|
||||
|
||||
downloadAction: Components.DownloadAction {
|
||||
onTriggered: {
|
||||
currentRoom.downloadFile(root.currentEventId, Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + root.currentEventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(root.currentEventId));
|
||||
root.currentRoom.downloadFile(root.currentEventId, Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + root.currentEventId.replace(":", "_").replace("/", "_").replace("+", "_") + root.currentRoom.fileNameToDownload(root.currentEventId));
|
||||
}
|
||||
}
|
||||
|
||||
playAction: Kirigami.Action {
|
||||
onTriggered: {
|
||||
MediaManager.startPlayback();
|
||||
currentItem.play();
|
||||
(root.currentItem as Components.VideoMaximizeDelegate).play();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: MediaManager
|
||||
function onPlaybackStarted() {
|
||||
if (currentItem.playbackState === MediaPlayer.PlayingState) {
|
||||
currentItem.pause();
|
||||
if ((root.currentItem as Components.VideoMaximizeDelegate).playbackState === MediaPlayer.PlayingState) {
|
||||
(root.currentItem as Components.VideoMaximizeDelegate).pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: currentRoom
|
||||
target: root.currentRoom
|
||||
|
||||
function onFileTransferProgress(id, progress, total) {
|
||||
if (id == root.currentEventId) {
|
||||
@@ -123,7 +125,7 @@ Components.AlbumMaximizeComponent {
|
||||
onItemRightClicked: RoomManager.viewEventMenu(root.currentEventId, root.currentRoom)
|
||||
|
||||
onSaveItem: {
|
||||
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
|
||||
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay) as Dialogs.FileDialog;
|
||||
dialog.selectedFile = currentRoom.fileNameToDownload(root.currentEventId);
|
||||
dialog.open();
|
||||
}
|
||||
@@ -146,7 +148,7 @@ Components.AlbumMaximizeComponent {
|
||||
if (!selectedFile) {
|
||||
return;
|
||||
}
|
||||
currentRoom.downloadFile(root.currentEventId, selectedFile);
|
||||
root.currentRoom.downloadFile(root.currentEventId, selectedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigami.delegates as KD
|
||||
import org.kde.kirigamiaddons.components as Components
|
||||
|
||||
import org.kde.neochat
|
||||
@@ -41,15 +42,23 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
delegate: QQC2.ItemDelegate {
|
||||
id: notificationDelegate
|
||||
|
||||
required property string uri
|
||||
required property string authorAvatar
|
||||
required property string authorName
|
||||
required property string roomDisplayName
|
||||
required property string notificationText
|
||||
|
||||
width: parent?.width ?? 0
|
||||
|
||||
onClicked: RoomManager.resolveResource(model.uri)
|
||||
onClicked: RoomManager.resolveResource(uri)
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Components.Avatar {
|
||||
source: model.authorAvatar
|
||||
name: model.authorName
|
||||
source: notificationDelegate.authorAvatar
|
||||
name: notificationDelegate.authorName
|
||||
implicitHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||
implicitWidth: implicitHeight
|
||||
|
||||
@@ -66,7 +75,7 @@ Kirigami.ScrollablePage {
|
||||
QQC2.Label {
|
||||
id: label
|
||||
|
||||
text: model.roomDisplayName
|
||||
text: notificationDelegate.roomDisplayName
|
||||
elide: Text.ElideRight
|
||||
font.weight: Font.Normal
|
||||
textFormat: Text.PlainText
|
||||
@@ -78,10 +87,9 @@ Kirigami.ScrollablePage {
|
||||
QQC2.Label {
|
||||
id: subtitle
|
||||
|
||||
text: model.text
|
||||
text: notificationDelegate.notificationText
|
||||
elide: Text.ElideRight
|
||||
font: Kirigami.Theme.smallFont
|
||||
opacity: root.hasNotifications ? 0.9 : 0.7
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
|
||||
@@ -27,9 +27,26 @@ Kirigami.Page {
|
||||
}
|
||||
}
|
||||
|
||||
MediaDevices {
|
||||
id: devices
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
visible: devices.videoInputs.length === 0
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
text: i18nc("@info", "No Camera Connected")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id: viewFinder
|
||||
anchors.centerIn: parent
|
||||
visible: devices.videoInputs.length > 0
|
||||
}
|
||||
|
||||
Prison.VideoScanner {
|
||||
@@ -47,6 +64,8 @@ Kirigami.Page {
|
||||
}
|
||||
|
||||
CaptureSession {
|
||||
id: session
|
||||
|
||||
camera: Camera {
|
||||
id: camera
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ Kirigami.SearchDialog {
|
||||
}
|
||||
|
||||
onAccepted: if (currentItem) {
|
||||
(currentItem as QQC2.ItemDelegate).clicked();
|
||||
(root.currentItem as RoomDelegate).clicked();
|
||||
}
|
||||
|
||||
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
|
||||
|
||||
@@ -31,7 +31,7 @@ Kirigami.Page {
|
||||
Keys.onReturnPressed: event => {
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
root.accepted(reason.text);
|
||||
root.closeDialog();
|
||||
root.Kirigami.PageStack.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ Kirigami.Page {
|
||||
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
|
||||
onClicked: {
|
||||
root.accepted(reason.text);
|
||||
root.closeDialog();
|
||||
root.Kirigami.PageStack.closeDialog();
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
icon.name: "dialog-cancel-symbolic"
|
||||
text: i18nc("@action", "Cancel")
|
||||
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
|
||||
onClicked: root.closeDialog()
|
||||
onClicked: root.Kirigami.PageStack.closeDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Window
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
@@ -56,18 +59,92 @@ Kirigami.Page {
|
||||
*/
|
||||
property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
|
||||
|
||||
/**
|
||||
* @brief The WidgetModel to use.
|
||||
*
|
||||
* This model has the list of widgets available in the current room.
|
||||
*
|
||||
* @note For loading a room in a different window, override this with a new
|
||||
* WidgetModel.
|
||||
*
|
||||
* @sa WidgetModel
|
||||
*/
|
||||
property WidgetModel widgetModel: RoomManager.widgetModel
|
||||
|
||||
title: root.currentRoom ? root.currentRoom.displayName : ""
|
||||
focus: true
|
||||
padding: 0
|
||||
|
||||
background: null // This needs to stay null, because of transparency blur
|
||||
|
||||
onHeightChanged: {
|
||||
// HACK: See TimelineView for the hack details.
|
||||
// We get the height change here *first* so we are informed this is because of a window resize and not due to the pinned message.
|
||||
resetViewSettling();
|
||||
}
|
||||
|
||||
// Resets the view settling of the timeline.
|
||||
// This should be called whenever the apparent height of the timeline changes, or else the view will scroll on its own!
|
||||
function resetViewSettling(): void {
|
||||
(timelineViewLoader.item as TimelineView).resetViewSettling();
|
||||
}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
visible: Kirigami.Settings.isMobile || !(root.Kirigami.PageStack.pageStack as Kirigami.PageRow).wideMode
|
||||
id: jitsiMeetingAction
|
||||
|
||||
readonly property bool hasExistingMeeting: root.widgetModel.jitsiIndex >= 0
|
||||
readonly property bool canStartNewMeeting: root.currentRoom.canSendState("im.vector.modular.widgets")
|
||||
|
||||
tooltip: {
|
||||
if (hasExistingMeeting) {
|
||||
return i18nc("@action:button", "Join Jitsi meeting…");
|
||||
}
|
||||
|
||||
return canStartNewMeeting ? i18nc("@action:button", "Start Jitsi meeting…") : i18nc("@action:button", "You do not have permissions to start Jitsi meetings")
|
||||
}
|
||||
icon {
|
||||
name: "camera-video-symbolic"
|
||||
color: hasExistingMeeting ? Kirigami.Theme.highlightColor : "transparent"
|
||||
}
|
||||
enabled: hasExistingMeeting || canStartNewMeeting
|
||||
visible: root.currentRoom && !root.currentRoom.isSpace
|
||||
onTriggered: {
|
||||
const dialog = Qt.createComponent("org.kde.neochat", "MeetingDialog").createObject(QQC2.Overlay.overlay, { hasExistingMeeting });
|
||||
dialog.onAccepted.connect(doAction);
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
function doAction(): void {
|
||||
let url;
|
||||
if (!hasExistingMeeting) {
|
||||
url = root.widgetModel.addJitsiConference();
|
||||
} else {
|
||||
let idx = root.widgetModel.index(root.widgetModel.jitsiIndex, 0);
|
||||
url = root.widgetModel.data(idx, WidgetModel.UrlRole);
|
||||
}
|
||||
Qt.openUrlExternally(url);
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: Kirigami.Settings.isMobile || !(root.Kirigami.PageStack.pageStack as Kirigami.PageRow)?.wideMode
|
||||
icon.name: "view-right-new"
|
||||
onTriggered: (root.QQC2.ApplicationWindow.window as Main).openRoomDrawer()
|
||||
}
|
||||
]
|
||||
|
||||
Kirigami.Action {
|
||||
enabled: root.currentRoom && !root.currentRoom.isSpace
|
||||
shortcut: "Ctrl+F"
|
||||
onTriggered: {
|
||||
((root.QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
||||
room: root.currentRoom
|
||||
}, {
|
||||
title: i18nc("@action:title", "Search")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.left: (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).get(0)
|
||||
|
||||
onCurrentRoomChanged: {
|
||||
@@ -77,9 +154,9 @@ Kirigami.Page {
|
||||
|
||||
if (root.currentRoom.tagNames.includes("m.server_notice")) {
|
||||
banner.text = i18nc("@info", "This room contains official messages from your homeserver.")
|
||||
banner.visible = true;
|
||||
banner.show("message");
|
||||
} else {
|
||||
banner.visible = false;
|
||||
banner.hideIf("message");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,28 +165,106 @@ Kirigami.Page {
|
||||
function onIsOnlineChanged() {
|
||||
if (!root.currentRoom.connection.isOnline) {
|
||||
banner.text = i18nc("@info:status", "NeoChat is offline. Please check your network connection.");
|
||||
banner.visible = true;
|
||||
banner.type = Kirigami.MessageType.Error;
|
||||
banner.show("offline");
|
||||
} else {
|
||||
banner.visible = false;
|
||||
banner.hideIf("offline");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header: Kirigami.InlineMessage {
|
||||
id: banner
|
||||
header: ColumnLayout {
|
||||
id: headerLayout
|
||||
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
spacing: 0
|
||||
|
||||
readonly property bool shouldShowPins: root.currentRoom.pinnedMessage.length > 0 && !Kirigami.Settings.isMobile
|
||||
|
||||
QQC2.Control {
|
||||
id: pinControl
|
||||
|
||||
visible: headerLayout.shouldShowPins
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Kirigami.Icon {
|
||||
source: "pin-symbolic"
|
||||
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
text: root.currentRoom.pinnedMessage
|
||||
maximumLineCount: 1
|
||||
elide: Text.ElideRight
|
||||
|
||||
onLinkActivated: link => UrlHelper.openUrl(link)
|
||||
onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") {
|
||||
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = hoveredLink;
|
||||
} else {
|
||||
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = "";
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
onTapped: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomPinnedMessagesPage'), {
|
||||
room: root.currentRoom
|
||||
}, {
|
||||
title: i18nc("@title", "Pinned Messages")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
visible: headerLayout.shouldShowPins
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
id: banner
|
||||
|
||||
// Used to keep track of messages so we can hide the right one at the right time
|
||||
property string messageId
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
position: Kirigami.InlineMessage.Position.Header
|
||||
|
||||
function show(msgid: string): void {
|
||||
messageId = msgid;
|
||||
visible = true;
|
||||
}
|
||||
|
||||
function hideIf(msgid: string): void {
|
||||
if (messageId == msgid) {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: timelineViewLoader
|
||||
anchors.fill: parent
|
||||
active: root.currentRoom && !root.currentRoom.isInvite && !root.currentRoom.isSpace
|
||||
// We need the loader to be active but invisible while the room is loading messages so signals in TimelineView work.
|
||||
visible: !root.loading
|
||||
active: root.currentRoom && !root.currentRoom.isInvite && !root.currentRoom.isSpace
|
||||
sourceComponent: TimelineView {
|
||||
id: timelineView
|
||||
messageFilterModel: root.messageFilterModel
|
||||
@@ -147,21 +302,18 @@ Kirigami.Page {
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
Kirigami.Theme.inherit: false
|
||||
color: NeoChatConfig.compactLayout ? Kirigami.Theme.backgroundColor : "transparent"
|
||||
}
|
||||
|
||||
footer: Loader {
|
||||
id: chatBarLoader
|
||||
height: active ? item.implicitHeight : 0
|
||||
height: active ? (item as ChatBar)?.implicitHeight : 0
|
||||
active: timelineViewLoader.active && !root.currentRoom.readOnly
|
||||
sourceComponent: ChatBar {
|
||||
id: chatBar
|
||||
width: parent.width
|
||||
currentRoom: root.currentRoom
|
||||
connection: root.currentRoom.connection
|
||||
connection: root.currentRoom.connection as NeoChatConnection
|
||||
|
||||
// Creating a reply (or doing anything in the chat bar) can change the height, but this isn't picked up on the root's onHeightChanged.
|
||||
onHeightChanged: root.resetViewSettling()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +355,7 @@ Kirigami.Page {
|
||||
function onShowMessage(messageType, message) {
|
||||
banner.text = message;
|
||||
banner.type = messageType;
|
||||
banner.visible = true;
|
||||
banner.show("generic");
|
||||
}
|
||||
|
||||
function onShowEventSource(eventId) {
|
||||
@@ -215,16 +367,17 @@ Kirigami.Page {
|
||||
});
|
||||
}
|
||||
|
||||
function onShowDelegateMenu(eventId: string, author, messageComponentType, plainText: string, richText: string, mimeType: string, progressInfo, isThread: bool, selectedText: string, hoveredLink: string) {
|
||||
const contextMenu = delegateContextMenu.createObject(root, {
|
||||
function onShowDelegateMenu(eventId: string, author, messageComponentType, plainText: string, richText: string, mimeType: string, progressInfo, selectedText: string, hoveredLink: string) {
|
||||
(delegateContextMenu.createObject(root, {
|
||||
author: author,
|
||||
eventId: eventId,
|
||||
plainText: plainText,
|
||||
mimeType: mimeType,
|
||||
progressInfo: progressInfo,
|
||||
messageComponentType: messageComponentType,
|
||||
});
|
||||
contextMenu.popup();
|
||||
selectedText,
|
||||
hoveredLink,
|
||||
}) as DelegateContextMenu).popup();
|
||||
}
|
||||
|
||||
function onShowMaximizedMedia(index) {
|
||||
@@ -239,12 +392,12 @@ Kirigami.Page {
|
||||
}
|
||||
|
||||
function onShowMaximizedCode(author, time, codeText, language) {
|
||||
let popup = Qt.createComponent('org.kde.neochat', 'CodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
(Qt.createComponent('org.kde.neochat', 'CodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
author: author,
|
||||
time: time,
|
||||
codeText: codeText,
|
||||
language: language
|
||||
}).open();
|
||||
}) as CodeMaximizeComponent).open();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +405,7 @@ Kirigami.Page {
|
||||
id: delegateContextMenu
|
||||
DelegateContextMenu {
|
||||
room: root.currentRoom
|
||||
connection: root.currentRoom.connection
|
||||
connection: root.currentRoom.connection as NeoChatConnection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,15 +110,15 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
let map = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
let qrCode = Qt.createComponent('org.kde.neochat', 'QrCodeMaximizeComponent').createObject(QQC2.Overlay.overlay, {
|
||||
text: barcode.content,
|
||||
title: root.room ? root.room.member(root.user.id).displayName : root.user.displayName,
|
||||
subtitle: root.user.id,
|
||||
avatarColor: root.room?.member(root.user.id).color,
|
||||
avatarSource: root.room? root.room.member(root.user.id).avatarUrl : root.user.avatarUrl
|
||||
});
|
||||
}) as QrCodeMaximizeComponent;
|
||||
root.close();
|
||||
map.open();
|
||||
qrCode.open();
|
||||
}
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
@@ -152,7 +152,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("kick") && room.containsUser(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("kick") && root.room.containsUser(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button", "Kick this user")
|
||||
icon.name: "im-kick-user"
|
||||
@@ -174,7 +174,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("invite") && !room.containsUser(root.user.id)
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("invite") && !root.room.containsUser(root.user.id)
|
||||
|
||||
enabled: root.room && !root.room.isUserBanned(root.user.id)
|
||||
text: i18nc("@action:button", "Invite this user")
|
||||
@@ -186,7 +186,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && !room.isUserBanned(root.user.id) && room.memberEffectivePowerLevel(root.user.id) < room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("ban") && !root.room.isUserBanned(root.user.id) && root.room.memberEffectivePowerLevel(root.user.id) < root.room.memberEffectivePowerLevel(root.connection.localUserId)
|
||||
|
||||
text: i18nc("@action:button", "Ban this user")
|
||||
icon.name: "im-ban-user"
|
||||
@@ -209,7 +209,7 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && room.canSendState("ban") && room.isUserBanned(root.user.id)
|
||||
visible: root.room && root.user.id !== root.connection.localUserId && root.room.canSendState("ban") && root.room.isUserBanned(root.user.id)
|
||||
|
||||
text: i18nc("@action:button", "Unban this user")
|
||||
icon.name: "im-irc"
|
||||
@@ -225,12 +225,11 @@ Kirigami.Dialog {
|
||||
text: i18nc("@action:button", "Set user power level")
|
||||
icon.name: "visibility"
|
||||
onClicked: {
|
||||
let dialog = powerLevelDialog.createObject(this, {
|
||||
(powerLevelDialog.createObject(this, {
|
||||
room: root.room,
|
||||
userId: root.user.id,
|
||||
powerLevel: root.room.memberEffectivePowerLevel(root.user.id)
|
||||
});
|
||||
dialog.open();
|
||||
}) as PowerLevelDialog).open();
|
||||
root.close();
|
||||
}
|
||||
|
||||
@@ -243,13 +242,13 @@ Kirigami.Dialog {
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
visible: root.room && (root.user.id === root.connection.localUserId || room.canSendState("redact"))
|
||||
visible: root.room && (root.user.id === root.connection.localUserId || root.room.canSendState("redact"))
|
||||
|
||||
text: i18nc("@action:button", "Remove recent messages by this user")
|
||||
icon.name: "delete"
|
||||
icon.color: Kirigami.Theme.negativeTextColor
|
||||
onClicked: {
|
||||
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
let dialog = ((QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||
title: i18nc("@title:dialog", "Remove Messages"),
|
||||
placeholder: i18nc("@info:placeholder", "Reason for removing this user's recent messages"),
|
||||
actionText: i18nc("@action:button 'Remove' as in 'Remove these messages'", "Remove"),
|
||||
@@ -279,7 +278,7 @@ Kirigami.Dialog {
|
||||
text: i18nc("@action:button %1 is the name of the user.", "Search room for %1's messages", root.room ? root.room.member(root.user.id).htmlSafeDisplayName : QmlUtils.escapeString(root.user.displayName))
|
||||
icon.name: "search-symbolic"
|
||||
onClicked: {
|
||||
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
||||
((QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow).pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RoomSearchPage'), {
|
||||
room: root.room,
|
||||
senderId: root.user.id
|
||||
}, {
|
||||
|
||||
@@ -30,7 +30,7 @@ SearchPage {
|
||||
*/
|
||||
required property NeoChatConnection connection
|
||||
|
||||
title: i18nc("@action:title", "Find Your Friends")
|
||||
title: i18nc("@action:title", "Find User")
|
||||
|
||||
Component.onCompleted: focusSearch()
|
||||
|
||||
@@ -53,6 +53,16 @@ SearchPage {
|
||||
root.closeDialog();
|
||||
}
|
||||
|
||||
QQC2.ContextMenu.menu: QQC2.Menu {
|
||||
QQC2.MenuItem {
|
||||
text: i18nc("@action:inmenu", "Copy User ID")
|
||||
icon.name: "username-copy"
|
||||
onTriggered: {
|
||||
Clipboard.saveText(userDelegate.userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
@@ -71,7 +81,7 @@ SearchPage {
|
||||
}
|
||||
QQC2.Label {
|
||||
visible: userDelegate.directChatExists
|
||||
text: i18nc("@info", "Friends")
|
||||
text: i18nc("@info", "Direct Messages")
|
||||
textFormat: Text.PlainText
|
||||
color: Kirigami.Theme.positiveTextColor
|
||||
}
|
||||
|
||||
@@ -11,7 +11,19 @@ VerificationMessage {
|
||||
|
||||
required property int reason
|
||||
|
||||
icon: "security-low"
|
||||
icon: {
|
||||
switch (root.reason) {
|
||||
case KeyVerificationSession.TIMEOUT:
|
||||
case KeyVerificationSession.REMOTE_TIMEOUT:
|
||||
case KeyVerificationSession.USER:
|
||||
case KeyVerificationSession.REMOTE_USER:
|
||||
case KeyVerificationSession.SESSION_ACCEPTED:
|
||||
case KeyVerificationSession.REMOTE_SESSION_ACCEPTED:
|
||||
return "dialog-information";
|
||||
default:
|
||||
return "security-low";
|
||||
}
|
||||
}
|
||||
text: {
|
||||
switch (root.reason) {
|
||||
case KeyVerificationSession.NONE:
|
||||
|
||||
@@ -13,6 +13,9 @@ ColumnLayout {
|
||||
|
||||
required property string icon
|
||||
required property string text
|
||||
required property bool isDone
|
||||
|
||||
signal done
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -32,6 +35,14 @@ ColumnLayout {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
QQC2.Button {
|
||||
text: i18nc("@action:button Done, we are finished with verification", "Done")
|
||||
visible: root.isDone
|
||||
onClicked: root.done()
|
||||
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "controller.h"
|
||||
#include "eventhandler.h"
|
||||
#include "models/actionsmodel.h"
|
||||
#include "models/messagefiltermodel.h"
|
||||
#include "models/sortfilterroomtreemodel.h"
|
||||
#include "neochatconfig.h"
|
||||
#include "neochatconnection.h"
|
||||
#include "neochatroom.h"
|
||||
@@ -31,6 +29,28 @@
|
||||
#include <KIO/OpenUrlJob>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Stops RoomManager from updating the last room and space config.
|
||||
*/
|
||||
class LastRoomBlocker
|
||||
{
|
||||
public:
|
||||
explicit LastRoomBlocker(RoomManager *manager)
|
||||
: m_manager(manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
|
||||
m_manager->m_dontUpdateLastRoom = true;
|
||||
}
|
||||
~LastRoomBlocker()
|
||||
{
|
||||
m_manager->m_dontUpdateLastRoom = false;
|
||||
}
|
||||
|
||||
private:
|
||||
RoomManager *m_manager;
|
||||
};
|
||||
|
||||
RoomManager::RoomManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_config(KSharedConfig::openStateConfig())
|
||||
@@ -43,6 +63,7 @@ RoomManager::RoomManager(QObject *parent)
|
||||
, m_messageFilterModel(new MessageFilterModel(this, m_timelineModel))
|
||||
, m_mediaMessageFilterModel(new MediaMessageFilterModel(this, m_messageFilterModel))
|
||||
, m_userListModel(new UserListModel(this))
|
||||
, m_widgetModel(new WidgetModel(this))
|
||||
{
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(UBUNTU_TOUCH)
|
||||
m_isMobile = true;
|
||||
@@ -55,6 +76,7 @@ RoomManager::RoomManager(QObject *parent)
|
||||
#endif
|
||||
|
||||
connect(this, &RoomManager::currentRoomChanged, this, [this]() {
|
||||
m_widgetModel->setRoom(m_currentRoom);
|
||||
m_userListModel->setRoom(m_currentRoom);
|
||||
m_timelineModel->setRoom(m_currentRoom);
|
||||
m_sortFilterRoomTreeModel->setCurrentRoom(m_currentRoom);
|
||||
@@ -197,6 +219,11 @@ void RoomManager::activateUserModel()
|
||||
m_userListModel->activate();
|
||||
}
|
||||
|
||||
WidgetModel *RoomManager::widgetModel() const
|
||||
{
|
||||
return m_widgetModel;
|
||||
}
|
||||
|
||||
void RoomManager::resolveResource(const QString &idOrUri, const QString &action)
|
||||
{
|
||||
resolveResource(Uri{idOrUri}, action);
|
||||
@@ -209,24 +236,35 @@ void RoomManager::resolveResource(Uri uri, const QString &action)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uri.type() == Uri::NonMatrix && action == "qr"_L1) {
|
||||
Q_EMIT externalUrl(uri.toUrl());
|
||||
return;
|
||||
if (action == "qr"_L1) {
|
||||
if (uri.type() == Uri::NonMatrix) {
|
||||
Q_EMIT externalUrl(uri.toUrl());
|
||||
return;
|
||||
}
|
||||
if (uri.type() != Uri::UserId) {
|
||||
uri.setAction(QStringLiteral("join"));
|
||||
} else {
|
||||
uri.setAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
// For matrix URIs:
|
||||
if (uri.type() != Uri::NonMatrix) {
|
||||
if (!m_connection) {
|
||||
return;
|
||||
}
|
||||
if (!action.isEmpty() && (uri.type() != Uri::UserId || action != "join"_L1)) {
|
||||
uri.setAction(action);
|
||||
// Once a join is confirmed, set the action to "join" so it skips the confirmation check.
|
||||
if (action == "join_confirmed"_L1) {
|
||||
uri.setAction(QStringLiteral("join"));
|
||||
}
|
||||
// TODO we should allow the user to select a connection.
|
||||
}
|
||||
|
||||
const auto result = visitResource(m_connection, uri);
|
||||
|
||||
// If we are not already in the room:
|
||||
if (result == Quotient::CouldNotResolve) {
|
||||
if ((uri.type() == Uri::RoomAlias || uri.type() == Uri::RoomId) && action != "no_join"_L1) {
|
||||
if ((uri.type() == Uri::RoomAlias || uri.type() == Uri::RoomId) && action == "join"_L1) {
|
||||
Q_EMIT askJoinRoom(uri.primaryId());
|
||||
}
|
||||
}
|
||||
@@ -308,17 +346,6 @@ void RoomManager::loadInitialRoom()
|
||||
resolveResource(m_arg);
|
||||
}
|
||||
|
||||
if (m_isMobile) {
|
||||
QString lastSpace = m_lastRoomConfig.readEntry(u"lastSpace"_s, QString());
|
||||
// We can't have empty keys in KConfig, so we stored it as "Home"
|
||||
if (lastSpace == u"Home"_s) {
|
||||
lastSpace.clear();
|
||||
}
|
||||
setCurrentSpace(lastSpace, false);
|
||||
// We don't want to open a room on startup on mobile
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_currentRoom) {
|
||||
// we opened a room with the arg parsing already
|
||||
return;
|
||||
@@ -331,16 +358,14 @@ void RoomManager::loadInitialRoom()
|
||||
|
||||
void RoomManager::openRoomForActiveConnection()
|
||||
{
|
||||
if (!m_connection) {
|
||||
setCurrentRoom({});
|
||||
setCurrentSpace({}, false);
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(m_connection);
|
||||
|
||||
auto lastSpace = m_lastRoomConfig.readEntry(u"lastSpace"_s, QString());
|
||||
if (lastSpace == u"Home"_s) {
|
||||
lastSpace.clear();
|
||||
}
|
||||
setCurrentSpace(lastSpace, true);
|
||||
// We don't want to open a room on startup on mobile
|
||||
setCurrentSpace(lastSpace, !m_isMobile);
|
||||
}
|
||||
|
||||
UriResolveResult RoomManager::visitUser(User *user, const QString &action)
|
||||
@@ -400,7 +425,7 @@ void RoomManager::joinRoom(Quotient::Connection *account, const QString &roomAli
|
||||
job.get(),
|
||||
&Quotient::BaseJob::finished,
|
||||
this,
|
||||
[this, account](Quotient::BaseJob *finish) {
|
||||
[this, account, roomAliasOrId](Quotient::BaseJob *finish) {
|
||||
if (finish->status() == Quotient::BaseJob::Success) {
|
||||
connect(
|
||||
account,
|
||||
@@ -411,7 +436,7 @@ void RoomManager::joinRoom(Quotient::Connection *account, const QString &roomAli
|
||||
},
|
||||
Qt::SingleShotConnection);
|
||||
} else {
|
||||
Q_EMIT showMessage(MessageType::Warning, i18n("Failed to join room<br />%1", finish->errorString()));
|
||||
Q_EMIT showMessage(MessageType::Warning, i18n("Failed to join %1:<br />%2", roomAliasOrId, finish->errorString()));
|
||||
}
|
||||
},
|
||||
Qt::SingleShotConnection);
|
||||
@@ -478,9 +503,8 @@ void RoomManager::setConnection(NeoChatConnection *connection)
|
||||
|
||||
m_connection = connection;
|
||||
|
||||
m_lastRoomConfig = m_config->group(m_connection->userId()).group(u"LastOpenRoom"_s);
|
||||
|
||||
if (m_connection != nullptr) {
|
||||
m_lastRoomConfig = m_config->group(m_connection->userId()).group(u"LastOpenRoom"_s);
|
||||
connect(m_connection, &NeoChatConnection::showMessage, this, &RoomManager::showMessage);
|
||||
connect(m_connection, &NeoChatConnection::createdRoom, this, [this](Quotient::Room *room) {
|
||||
resolveResource(room->id());
|
||||
@@ -498,38 +522,85 @@ void RoomManager::setConnection(NeoChatConnection *connection)
|
||||
Q_EMIT connectionChanged();
|
||||
}
|
||||
|
||||
void RoomManager::setCurrentSpace(const QString &spaceId, bool setRoom)
|
||||
void RoomManager::setCurrentSpace(const QString &spaceId, bool goToLastUsedRoom)
|
||||
{
|
||||
m_currentSpaceId = spaceId;
|
||||
|
||||
// This need to happen before the signal so TreeView.expandRecursively() can work nicely.
|
||||
m_sortFilterRoomTreeModel->setActiveSpaceId(m_currentSpaceId);
|
||||
m_sortFilterRoomTreeModel->setMode(m_currentSpaceId == u"DM"_s ? SortFilterRoomTreeModel::DirectChats : SortFilterRoomTreeModel::Rooms);
|
||||
|
||||
if (m_currentSpaceId == u"DM") {
|
||||
m_sortFilterRoomTreeModel->setMode(SortFilterRoomTreeModel::DirectChats);
|
||||
} else if (m_currentSpaceId.isEmpty()) {
|
||||
m_sortFilterRoomTreeModel->setMode(SortFilterRoomTreeModel::Rooms);
|
||||
} else {
|
||||
m_sortFilterRoomTreeModel->setMode(SortFilterRoomTreeModel::All);
|
||||
}
|
||||
|
||||
Q_EMIT currentSpaceChanged();
|
||||
if (m_connection) {
|
||||
m_lastRoomConfig.writeEntry(u"lastSpace"_s, spaceId.isEmpty() ? u"Home"_s : spaceId);
|
||||
}
|
||||
|
||||
if (!setRoom) {
|
||||
return;
|
||||
}
|
||||
// If we requested to change to the last opened room, do so:
|
||||
if (goToLastUsedRoom) {
|
||||
// We don't want to needlessly update the last room config here, that should only be done during explicit user action.
|
||||
LastRoomBlocker blocker(this);
|
||||
|
||||
// We intentionally don't want to open the last room on mobile
|
||||
if (m_isMobile) {
|
||||
return;
|
||||
}
|
||||
// We can't have empty keys in KConfig, so it's stored as "Home":
|
||||
if (const auto &lastRoom = m_lastRoomConfig.readEntry(spaceId.isEmpty() ? u"Home"_s : spaceId, QString()); !lastRoom.isEmpty()) {
|
||||
resolveResource(lastRoom, "no_join"_L1);
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't have empty keys in KConfig, so it's stored as "Home"
|
||||
if (const auto &lastRoom = m_lastRoomConfig.readEntry(spaceId.isEmpty() ? u"Home"_s : spaceId, QString()); !lastRoom.isEmpty()) {
|
||||
resolveResource(lastRoom, "no_join"_L1);
|
||||
return;
|
||||
// If no last room was opened, go to the space home:
|
||||
if (!spaceId.isEmpty() && spaceId != u"DM"_s) {
|
||||
resolveResource(spaceId, "no_join"_L1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to no room opened:
|
||||
setCurrentRoom({});
|
||||
}
|
||||
if (!spaceId.isEmpty() && spaceId != u"DM"_s) {
|
||||
resolveResource(spaceId, "no_join"_L1);
|
||||
return;
|
||||
}
|
||||
|
||||
QString RoomManager::findSpaceIdForCurrentRoom() const
|
||||
{
|
||||
if (!m_currentRoom) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
setCurrentRoom({});
|
||||
if (m_currentRoom->isDirectChat()) {
|
||||
const auto roomsInSpace = SpaceHierarchyCache::instance().getRoomListForSpace(m_currentSpaceId, false);
|
||||
if (roomsInSpace.contains(m_currentRoom->id())) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
return "DM"_L1;
|
||||
}
|
||||
const auto &parentSpaces = SpaceHierarchyCache::instance().parentSpaces(m_currentRoom->id());
|
||||
if (parentSpaces.contains(m_currentSpaceId)) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
static auto config = NeoChatConfig::self();
|
||||
if (config->allRoomsInHome()) {
|
||||
return {};
|
||||
}
|
||||
if (const auto &parent = m_connection->room(m_currentRoom->canonicalParent())) {
|
||||
for (const auto &parentParent : SpaceHierarchyCache::instance().parentSpaces(parent->id())) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(parentParent).isEmpty()) {
|
||||
return parentParent;
|
||||
}
|
||||
}
|
||||
return parent->id();
|
||||
}
|
||||
for (const auto &space : parentSpaces) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(space).isEmpty()) {
|
||||
return space;
|
||||
}
|
||||
}
|
||||
if (m_currentRoom->isSpace()) {
|
||||
return m_currentSpaceId;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void RoomManager::setCurrentRoom(const QString &roomId)
|
||||
@@ -549,56 +620,25 @@ void RoomManager::setCurrentRoom(const QString &roomId)
|
||||
}
|
||||
|
||||
Q_EMIT currentRoomChanged();
|
||||
if (m_connection) {
|
||||
|
||||
if (!m_dontUpdateLastRoom) {
|
||||
if (roomId.isEmpty()) {
|
||||
m_lastRoomConfig.deleteEntry(m_currentSpaceId);
|
||||
} else {
|
||||
// We can't have empty keys in KConfig, so name it "Home"
|
||||
if (m_currentSpaceId.isEmpty()) {
|
||||
m_lastRoomConfig.writeEntry(u"Home"_s, roomId);
|
||||
} else {
|
||||
m_lastRoomConfig.writeEntry(m_currentSpaceId, roomId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (roomId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (m_currentRoom->isSpace()) {
|
||||
return;
|
||||
}
|
||||
if (m_currentRoom->isDirectChat()) {
|
||||
if (m_currentSpaceId != "DM"_L1) {
|
||||
setCurrentSpace("DM"_L1, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto &parentSpaces = SpaceHierarchyCache::instance().parentSpaces(roomId);
|
||||
if (parentSpaces.contains(m_currentSpaceId)) {
|
||||
return;
|
||||
}
|
||||
static auto config = NeoChatConfig::self();
|
||||
if (config->allRoomsInHome()) {
|
||||
setCurrentSpace({}, false);
|
||||
return;
|
||||
}
|
||||
if (const auto &parent = m_connection->room(m_currentRoom->canonicalParent())) {
|
||||
for (const auto &parentParent : SpaceHierarchyCache::instance().parentSpaces(parent->id())) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(parentParent).isEmpty()) {
|
||||
setCurrentSpace(parentParent, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setCurrentSpace(parent->id(), false);
|
||||
return;
|
||||
}
|
||||
for (const auto &space : parentSpaces) {
|
||||
if (SpaceHierarchyCache::instance().parentSpaces(space).isEmpty()) {
|
||||
setCurrentSpace(space, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto spaceIdForRoom = findSpaceIdForCurrentRoom();
|
||||
// We can't have empty keys in KConfig, so name it "Home"
|
||||
if (spaceIdForRoom.isEmpty()) {
|
||||
m_lastRoomConfig.writeEntry(u"Home"_s, roomId);
|
||||
} else {
|
||||
m_lastRoomConfig.writeEntry(spaceIdForRoom, roomId);
|
||||
}
|
||||
|
||||
if (m_currentSpaceId != spaceIdForRoom) {
|
||||
setCurrentSpace(spaceIdForRoom, false);
|
||||
}
|
||||
}
|
||||
setCurrentSpace({}, false);
|
||||
}
|
||||
|
||||
void RoomManager::clearCurrentRoom()
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "models/sortfilterspacelistmodel.h"
|
||||
#include "models/timelinemodel.h"
|
||||
#include "models/userlistmodel.h"
|
||||
#include "models/widgetmodel.h"
|
||||
#include "neochatroommember.h"
|
||||
|
||||
class NeoChatRoom;
|
||||
@@ -129,6 +130,14 @@ class RoomManager : public QObject, public UriResolverBase
|
||||
*/
|
||||
Q_PROPERTY(UserListModel *userListModel READ userListModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief The WidgetModel that should be used for room widget visualisation.
|
||||
*
|
||||
* @note Available here so that the room page and drawer both have access to the
|
||||
* same model.
|
||||
*/
|
||||
Q_PROPERTY(WidgetModel *widgetModel READ widgetModel CONSTANT)
|
||||
|
||||
/**
|
||||
* @brief Whether a room is currently open in NeoChat.
|
||||
*
|
||||
@@ -160,6 +169,8 @@ public:
|
||||
UserListModel *userListModel() const;
|
||||
Q_INVOKABLE void activateUserModel();
|
||||
|
||||
WidgetModel *widgetModel() const;
|
||||
|
||||
/**
|
||||
* @brief Resolve the given resource.
|
||||
*
|
||||
@@ -326,6 +337,11 @@ Q_SIGNALS:
|
||||
|
||||
void currentSpaceChanged();
|
||||
|
||||
protected:
|
||||
bool m_dontUpdateLastRoom = false; // Don't set directly, use LastRoomBlocker.
|
||||
|
||||
friend class LastRoomBlocker;
|
||||
|
||||
private:
|
||||
bool m_isMobile = false;
|
||||
|
||||
@@ -356,13 +372,28 @@ private:
|
||||
MediaMessageFilterModel *m_mediaMessageFilterModel;
|
||||
|
||||
UserListModel *m_userListModel;
|
||||
WidgetModel *m_widgetModel;
|
||||
|
||||
QPointer<NeoChatConnection> m_connection;
|
||||
|
||||
void setCurrentRoom(const QString &roomId);
|
||||
|
||||
// Space ID, "DM", or empty string
|
||||
void setCurrentSpace(const QString &spaceId, bool setRoom = true);
|
||||
/**
|
||||
* @brief Find the most appropriate space for the currently selected room
|
||||
*
|
||||
* Should be used to figure out what space to switch to after a room change.
|
||||
*
|
||||
* @return The Space ID that the currently set room should be displayed as part of. (or "DM" for DM and "" for Home)
|
||||
*/
|
||||
QString findSpaceIdForCurrentRoom() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the current space.
|
||||
*
|
||||
* @param spaceId The ID of the space, "DM" for direct messages or an empty string for Home.
|
||||
* @param goToLastUsedRoom If true, we will navigate to the last opened room in this space.
|
||||
*/
|
||||
void setCurrentSpace(const QString &spaceId, bool goToLastUsedRoom = true);
|
||||
|
||||
/**
|
||||
* @brief Resolve a user URI.
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <KWindowSystem>
|
||||
|
||||
#include "controller.h"
|
||||
#include "models/roomlistmodel.h"
|
||||
#include "models/sortfilterroomlistmodel.h"
|
||||
#include "roommanager.h"
|
||||
#include "windowcontroller.h"
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
@@ -87,9 +89,15 @@ QQC2.Control {
|
||||
displayHint: Kirigami.DisplayHint.IconOnly
|
||||
|
||||
onTriggered: {
|
||||
let dialog = (Clipboard.hasImage ? attachDialog : openFileDialog).createObject(root.QQC2.Overlay.overlay);
|
||||
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
|
||||
dialog.open();
|
||||
if (Clipboard.hasImage) {
|
||||
let dialog = attachDialog.createObject(root.QQC2.Overlay.overlay) as AttachDialog;
|
||||
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
|
||||
dialog.open();
|
||||
} else {
|
||||
let dialog = openFileDialog.createObject(root.QQC2.Overlay.overlay) as OpenFileDialog;
|
||||
dialog.chosen.connect(path => _private.chatBarCache.attachmentPath = path);
|
||||
dialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
tooltip: text
|
||||
@@ -122,9 +130,9 @@ QQC2.Control {
|
||||
displayHint: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onTriggered: {
|
||||
locationChooser.createObject(QQC2.Overlay.overlay, {
|
||||
(locationChooser.createObject(QQC2.Overlay.overlay, {
|
||||
room: root.currentRoom
|
||||
}).open();
|
||||
}) as LocationChooser).open();
|
||||
}
|
||||
tooltip: text
|
||||
},
|
||||
@@ -136,9 +144,9 @@ QQC2.Control {
|
||||
displayHint: QQC2.AbstractButton.IconOnly
|
||||
|
||||
onTriggered: {
|
||||
newPollDialog.createObject(QQC2.Overlay.overlay, {
|
||||
(newPollDialog.createObject(QQC2.Overlay.overlay, {
|
||||
room: root.currentRoom
|
||||
}).open();
|
||||
}) as NewPollDialog).open();
|
||||
}
|
||||
tooltip: text
|
||||
},
|
||||
@@ -255,6 +263,7 @@ QQC2.Control {
|
||||
wrapMode: TextEdit.Wrap
|
||||
// This has to stay PlainText or else formatting starts breaking in strange ways
|
||||
textFormat: TextEdit.PlainText
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * NeoChatConfig.fontScale
|
||||
|
||||
Accessible.description: placeholderText
|
||||
|
||||
@@ -367,7 +376,9 @@ QQC2.Control {
|
||||
id: actionDelegate
|
||||
required property BusyAction modelData
|
||||
icon.name: modelData.isBusy ? "" : (modelData.icon.name.length > 0 ? modelData.icon.name : modelData.icon.source)
|
||||
onClicked: modelData.trigger()
|
||||
onClicked: if (!pieProgress.visible) {
|
||||
modelData.trigger()
|
||||
}
|
||||
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
|
||||
@@ -375,7 +386,9 @@ QQC2.Control {
|
||||
QQC2.ToolTip.text: modelData.tooltip
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
contentItem: PieProgressBar {
|
||||
PieProgressBar {
|
||||
id: pieProgress
|
||||
anchors.fill: parent
|
||||
visible: actionDelegate.modelData.isBusy
|
||||
progress: root.currentRoom.fileUploadingProgress
|
||||
}
|
||||
@@ -402,7 +415,7 @@ QQC2.Control {
|
||||
ReplyComponent {
|
||||
id: replyComponent
|
||||
replyContentModel: ContentProvider.contentModelForEvent(root.currentRoom, _private.chatBarCache.replyId, true)
|
||||
Message.maxContentWidth: replyLoader.item.width
|
||||
Message.maxContentWidth: (replyLoader.item as Item).width
|
||||
|
||||
// When the user replies to a message and the preview is loaded, make sure the text field is focused again
|
||||
Component.onCompleted: textField.forceActiveFocus(Qt.OtherFocusReason)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.neochat
|
||||
|
||||
QQC2.ItemDelegate {
|
||||
id: root
|
||||
@@ -29,6 +30,7 @@ QQC2.ItemDelegate {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.family: "emoji"
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * NeoChatConfig.fontScale
|
||||
|
||||
Kirigami.Icon {
|
||||
width: Kirigami.Units.gridUnit * 0.5
|
||||
|
||||
@@ -65,7 +65,7 @@ QQC2.Popup {
|
||||
padding: 2
|
||||
|
||||
implicitHeight: Kirigami.Units.gridUnit * 20 + 2 * padding
|
||||
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, QQC2.ApplicationWindow.window.width)
|
||||
width: Math.min(contentItem.categoryIconSize * 11 + 2 * padding, QQC2.ApplicationWindow.window?.width)
|
||||
contentItem: EmojiPicker {
|
||||
id: emojiPicker
|
||||
height: 400
|
||||
|
||||
@@ -148,7 +148,7 @@ ColumnLayout {
|
||||
id: quickReactions
|
||||
Layout.fillWidth: true
|
||||
|
||||
model: ["👍", "👎", "😄", "🎉", "😕", "❤", "🚀", "👀"]
|
||||
model: ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"]
|
||||
|
||||
delegate: EmojiDelegate {
|
||||
required property string modelData
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import QtCore as Core
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kquickimageeditor as KQuickImageEditor
|
||||
|
||||
Kirigami.Page {
|
||||
id: rootEditorView
|
||||
id: root
|
||||
|
||||
property bool resizing: false
|
||||
required property string imagePath
|
||||
@@ -26,7 +25,7 @@ Kirigami.Page {
|
||||
function crop() {
|
||||
const ratioX = editImage.paintedWidth / editImage.nativeWidth;
|
||||
const ratioY = editImage.paintedHeight / editImage.nativeHeight;
|
||||
rootEditorView.resizing = false;
|
||||
root.resizing = false;
|
||||
imageDoc.crop(selectionTool.selectionX / ratioX, selectionTool.selectionY / ratioY, selectionTool.selectionWidth / ratioX, selectionTool.selectionHeight / ratioY);
|
||||
}
|
||||
|
||||
@@ -43,9 +42,9 @@ Kirigami.Page {
|
||||
text: i18nc("@action:button Accept image modification", "Accept")
|
||||
icon.name: "dialog-ok"
|
||||
onTriggered: {
|
||||
let newPath = Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + (new Date()).getTime() + "." + imagePath.split('.').pop();
|
||||
let newPath = Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + (new Date()).getTime() + "." + root.imagePath.split('.').pop();
|
||||
if (imageDoc.saveAs(newPath)) {
|
||||
newPathChanged(newPath);
|
||||
root.newPathChanged(newPath);
|
||||
} else {
|
||||
msg.type = Kirigami.MessageType.Error;
|
||||
msg.text = i18n("Unable to save file. Check if you have the correct permission to edit the cache directory.");
|
||||
@@ -80,12 +79,12 @@ Kirigami.Page {
|
||||
|
||||
KQuickImageEditor.ImageDocument {
|
||||
id: imageDoc
|
||||
path: rootEditorView.imagePath
|
||||
path: root.imagePath
|
||||
}
|
||||
|
||||
KQuickImageEditor.SelectionTool {
|
||||
id: selectionTool
|
||||
visible: rootEditorView.resizing
|
||||
visible: root.resizing
|
||||
width: editImage.paintedWidth
|
||||
height: editImage.paintedHeight
|
||||
x: editImage.horizontalPadding
|
||||
@@ -101,7 +100,7 @@ Kirigami.Page {
|
||||
Connections {
|
||||
target: selectionTool.selectionArea
|
||||
function onDoubleClicked() {
|
||||
rootEditorView.crop();
|
||||
root.crop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,8 +118,8 @@ Kirigami.Page {
|
||||
display: QQC2.Button.TextBesideIcon
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
icon.name: rootEditorView.resizing ? "dialog-cancel" : "transform-crop"
|
||||
text: rootEditorView.resizing ? i18n("Cancel") : i18nc("@action:button Crop an image", "Crop")
|
||||
icon.name: root.resizing ? "dialog-cancel" : "transform-crop"
|
||||
text: root.resizing ? i18n("Cancel") : i18nc("@action:button Crop an image", "Crop")
|
||||
onTriggered: {
|
||||
resizeRectangle.width = editImage.paintedWidth;
|
||||
resizeRectangle.height = editImage.paintedHeight;
|
||||
@@ -130,38 +129,38 @@ Kirigami.Page {
|
||||
resizeRectangle.insideY = 100;
|
||||
resizeRectangle.insideWidth = 100;
|
||||
resizeRectangle.insideHeight = 100;
|
||||
rootEditorView.resizing = !rootEditorView.resizing;
|
||||
root.resizing = !root.resizing;
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "dialog-ok"
|
||||
visible: rootEditorView.resizing
|
||||
visible: root.resizing
|
||||
text: i18nc("@action:button Crop an image", "Crop")
|
||||
onTriggered: rootEditorView.crop()
|
||||
onTriggered: root.crop()
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "object-rotate-left"
|
||||
text: i18nc("@action:button Rotate an image to the left", "Rotate left")
|
||||
onTriggered: imageDoc.rotate(-90)
|
||||
visible: !rootEditorView.resizing
|
||||
visible: !root.resizing
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "object-rotate-right"
|
||||
text: i18nc("@action:button Rotate an image to the right", "Rotate right")
|
||||
onTriggered: imageDoc.rotate(90)
|
||||
visible: !rootEditorView.resizing
|
||||
visible: !root.resizing
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "object-flip-vertical"
|
||||
text: i18nc("@action:button Mirror an image vertically", "Flip")
|
||||
onTriggered: imageDoc.mirror(false, true)
|
||||
visible: !rootEditorView.resizing
|
||||
visible: !root.resizing
|
||||
},
|
||||
Kirigami.Action {
|
||||
icon.name: "object-flip-horizontal"
|
||||
text: i18nc("@action:button Mirror an image horizontally", "Mirror")
|
||||
onTriggered: imageDoc.mirror(true, false)
|
||||
visible: !rootEditorView.resizing
|
||||
visible: !root.resizing
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user