Compare commits
60 Commits
work/redst
...
v23.01.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebd521e2ee | ||
|
|
9d5303113e | ||
|
|
3850fe15a5 | ||
|
|
5392481d06 | ||
|
|
0ce048517b | ||
|
|
c51e16e16c | ||
|
|
765a95050d | ||
|
|
38dcefffcb | ||
|
|
391b61dcb4 | ||
|
|
d76c9fcbcf | ||
|
|
f7b8ae2af2 | ||
|
|
ddbf9b60d4 | ||
|
|
8948ff5faa | ||
|
|
d270e202a8 | ||
|
|
61e1dd14ba | ||
|
|
eee93e0f1f | ||
|
|
826760a55c | ||
|
|
749398df8f | ||
|
|
150968d226 | ||
|
|
d81df24e7c | ||
|
|
594a5cf6ca | ||
|
|
0af420b824 | ||
|
|
31fed8362a | ||
|
|
dbcf8c6327 | ||
|
|
8012392400 | ||
|
|
3e48578b44 | ||
|
|
d7e656e57f | ||
|
|
8e83b923d9 | ||
|
|
a739f0f09f | ||
|
|
bc74737b0f | ||
|
|
e92fccf904 | ||
|
|
20cbedfff5 | ||
|
|
e0d508d3dd | ||
|
|
af318a2bae | ||
|
|
6b4e81c763 | ||
|
|
dcac63aa04 | ||
|
|
7818747e45 | ||
|
|
7cb1f856ca | ||
|
|
5955c8e7dc | ||
|
|
dee3c279e8 | ||
|
|
94427280d8 | ||
|
|
8b245b1cc9 | ||
|
|
0513cd10c4 | ||
|
|
28b5631d06 | ||
|
|
5f2cd92da7 | ||
|
|
4535125c54 | ||
|
|
8831da956a | ||
|
|
f2ec6e1d4c | ||
|
|
93f7def532 | ||
|
|
782f5517d3 | ||
|
|
f238c18ce8 | ||
|
|
4fe0ea373f | ||
|
|
982d21dd58 | ||
|
|
7002132bde | ||
|
|
1ef931f7e7 | ||
|
|
8797015c6a | ||
|
|
85a562d469 | ||
|
|
f50c62ba12 | ||
|
|
13f05a0995 | ||
|
|
1adddcc0d9 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ compile_commands.json
|
|||||||
kate.project.ctags.*
|
kate.project.ctags.*
|
||||||
*.user
|
*.user
|
||||||
.flatpak-builder/
|
.flatpak-builder/
|
||||||
|
.idea/
|
||||||
|
|||||||
@@ -6,11 +6,14 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(NeoChat)
|
set(PROJECT_VERSION "23.01")
|
||||||
set(PROJECT_VERSION "22.11")
|
project(NeoChat VERSION ${PROJECT_VERSION})
|
||||||
|
|
||||||
set(KF5_MIN_VERSION "5.91.0")
|
set(KF5_MIN_VERSION "5.91.0")
|
||||||
set(QT_MIN_VERSION "5.15.2")
|
set(QT_MIN_VERSION "5.15.2")
|
||||||
|
if (ANDROID)
|
||||||
|
set(QT_MIN_VERSION "5.15.8")
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
|
|
||||||
@@ -122,6 +125,8 @@ set_package_properties(KF5DocTools PROPERTIES DESCRIPTION
|
|||||||
TYPE OPTIONAL
|
TYPE OPTIONAL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
find_package(Sqlite3)
|
||||||
|
|
||||||
if(NOT Quotient_VERSION_MINOR GREATER 6)
|
if(NOT Quotient_VERSION_MINOR GREATER 6)
|
||||||
cmake_policy(SET CMP0063 OLD)
|
cmake_policy(SET CMP0063 OLD)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
0
LICENSES/MIT.txt
Executable file → Normal file
0
LICENSES/MIT.txt
Executable file → Normal file
@@ -14,7 +14,8 @@
|
|||||||
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
android:name="org.qtproject.qt5.android.bindings.QtActivity"
|
||||||
android:label="NeoChat"
|
android:label="NeoChat"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data android:name="android.app.lib_name" android:value="neochat-app"/>
|
<meta-data android:name="android.app.lib_name" android:value="neochat-app"/>
|
||||||
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
|
||||||
<meta-data android:name="android.app.repository" android:value="default"/>
|
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||||
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||||
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||||
@@ -38,8 +38,6 @@
|
|||||||
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||||
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||||
<!-- Messages maps -->
|
<!-- Messages maps -->
|
||||||
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
|
||||||
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
|
||||||
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||||
|
|
||||||
<!-- Splash screen -->
|
<!-- Splash screen -->
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.6.4'
|
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +73,10 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion qtMinSdkVersion
|
minSdkVersion qtMinSdkVersion
|
||||||
targetSdkVersion qtTargetSdkVersion
|
targetSdkVersion qtTargetSdkVersion
|
||||||
|
applicationId "org.kde.neochat"
|
||||||
|
namespace "org.kde.neochat"
|
||||||
|
versionCode timestamp
|
||||||
|
versionName projectVersionFull
|
||||||
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
manifestPlaceholders = [versionName: projectVersionFull, versionCode: timestamp]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,20 @@
|
|||||||
<content_attribute id="social-chat">intense</content_attribute>
|
<content_attribute id="social-chat">intense</content_attribute>
|
||||||
</content_rating>
|
</content_rating>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="23.01" date="2023-01-30">
|
||||||
|
<url>https://plasma-mobile.org/2023/01/30/january-blog-post/</url>
|
||||||
|
<description>
|
||||||
|
<p>New features and bugfixes:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Notifications will now be shown for all accounts, not just the active one</li>
|
||||||
|
<li>There is a new "compact" mode for the room list</li>
|
||||||
|
<li>You can now search in the room history</li>
|
||||||
|
<li>Emojis and Reactions have been significantly improved</li>
|
||||||
|
<li>Fixed several crashes around user invitations</li>
|
||||||
|
<li>Room permission settings can now be configured</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="22.11" date="2022-11-30">
|
<release version="22.11" date="2022-11-30">
|
||||||
<url>https://plasma-mobile.org/2022/11/30/plasma-mobile-gear-22-11/</url>
|
<url>https://plasma-mobile.org/2022/11/30/plasma-mobile-gear-22-11/</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
1485
po/ar/neochat.po
1485
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
1649
po/az/neochat.po
1649
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1477
po/ca/neochat.po
1477
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1533
po/cs/neochat.po
1533
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1486
po/da/neochat.po
1486
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1507
po/de/neochat.po
1507
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
2240
po/el/neochat.po
2240
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1499
po/en_GB/neochat.po
1499
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1483
po/es/neochat.po
1483
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1485
po/eu/neochat.po
1485
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1643
po/fi/neochat.po
1643
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1516
po/fr/neochat.po
1516
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1649
po/hu/neochat.po
1649
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1794
po/ia/neochat.po
1794
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1626
po/id/neochat.po
1626
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1539
po/ie/neochat.po
1539
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1532
po/it/neochat.po
1532
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
1453
po/ja/neochat.po
1453
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1486
po/ka/neochat.po
1486
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1627
po/ko/neochat.po
1627
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1489
po/nl/neochat.po
1489
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1437
po/nn/neochat.po
1437
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1623
po/pa/neochat.po
1623
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1503
po/pl/neochat.po
1503
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1511
po/pt/neochat.po
1511
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1650
po/pt_BR/neochat.po
1650
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1511
po/ru/neochat.po
1511
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1655
po/sk/neochat.po
1655
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1485
po/sl/neochat.po
1485
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1631
po/sv/neochat.po
1631
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1493
po/ta/neochat.po
1493
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1494
po/tok/neochat.po
1494
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1494
po/tr/neochat.po
1494
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1497
po/uk/neochat.po
1497
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1472
po/zh_CN/neochat.po
1472
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1451
po/zh_TW/neochat.po
1451
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -6,47 +6,47 @@
|
|||||||
add_library(neochat STATIC
|
add_library(neochat STATIC
|
||||||
controller.cpp
|
controller.cpp
|
||||||
actionshandler.cpp
|
actionshandler.cpp
|
||||||
emojimodel.cpp
|
models/emojimodel.cpp
|
||||||
emojitones.cpp
|
emojitones.cpp
|
||||||
customemojimodel.cpp
|
models/customemojimodel.cpp
|
||||||
clipboard.cpp
|
clipboard.cpp
|
||||||
matriximageprovider.cpp
|
matriximageprovider.cpp
|
||||||
messageeventmodel.cpp
|
models/messageeventmodel.cpp
|
||||||
messagefiltermodel.cpp
|
models/messagefiltermodel.cpp
|
||||||
roomlistmodel.cpp
|
models/roomlistmodel.cpp
|
||||||
sortfilterspacelistmodel.cpp
|
models/sortfilterspacelistmodel.cpp
|
||||||
spacehierarchycache.cpp
|
spacehierarchycache.cpp
|
||||||
roommanager.cpp
|
roommanager.cpp
|
||||||
neochatroom.cpp
|
neochatroom.cpp
|
||||||
neochatuser.cpp
|
neochatuser.cpp
|
||||||
userlistmodel.cpp
|
models/userlistmodel.cpp
|
||||||
userfiltermodel.cpp
|
models/userfiltermodel.cpp
|
||||||
publicroomlistmodel.cpp
|
models/publicroomlistmodel.cpp
|
||||||
userdirectorylistmodel.cpp
|
models/userdirectorylistmodel.cpp
|
||||||
keywordnotificationrulemodel.cpp
|
models/keywordnotificationrulemodel.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
notificationsmanager.cpp
|
notificationsmanager.cpp
|
||||||
sortfilterroomlistmodel.cpp
|
models/sortfilterroomlistmodel.cpp
|
||||||
chatdocumenthandler.cpp
|
chatdocumenthandler.cpp
|
||||||
devicesmodel.cpp
|
models/devicesmodel.cpp
|
||||||
filetypesingleton.cpp
|
filetypesingleton.cpp
|
||||||
login.cpp
|
login.cpp
|
||||||
stickerevent.cpp
|
stickerevent.cpp
|
||||||
webshortcutmodel.cpp
|
models/webshortcutmodel.cpp
|
||||||
blurhash.cpp
|
blurhash.cpp
|
||||||
blurhashimageprovider.cpp
|
blurhashimageprovider.cpp
|
||||||
joinrulesevent.cpp
|
joinrulesevent.cpp
|
||||||
collapsestateproxymodel.cpp
|
models/collapsestateproxymodel.cpp
|
||||||
urlhelper.cpp
|
urlhelper.cpp
|
||||||
windowcontroller.cpp
|
windowcontroller.cpp
|
||||||
linkpreviewer.cpp
|
linkpreviewer.cpp
|
||||||
completionmodel.cpp
|
models/completionmodel.cpp
|
||||||
completionproxymodel.cpp
|
models/completionproxymodel.cpp
|
||||||
actionsmodel.cpp
|
models/actionsmodel.cpp
|
||||||
serverlistmodel.cpp
|
models/serverlistmodel.cpp
|
||||||
statemodel.cpp
|
models/statemodel.cpp
|
||||||
filetransferpseudojob.cpp
|
filetransferpseudojob.cpp
|
||||||
searchmodel.cpp
|
models/searchmodel.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(neochat-app
|
add_executable(neochat-app
|
||||||
@@ -103,6 +103,9 @@ endif()
|
|||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
target_sources(neochat PRIVATE notifyrc.qrc)
|
target_sources(neochat PRIVATE notifyrc.qrc)
|
||||||
target_link_libraries(neochat PRIVATE Qt::Svg OpenSSL::SSL)
|
target_link_libraries(neochat PRIVATE Qt::Svg OpenSSL::SSL)
|
||||||
|
if(SQLite3_FOUND)
|
||||||
|
target_link_libraries(neochat-app PRIVATE SQLite::SQLite3)
|
||||||
|
endif()
|
||||||
target_sources(neochat-app PRIVATE notifyrc.qrc)
|
target_sources(neochat-app PRIVATE notifyrc.qrc)
|
||||||
target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL)
|
target_link_libraries(neochat PUBLIC Qt::Svg OpenSSL::SSL)
|
||||||
kirigami_package_breeze_icons(ICONS
|
kirigami_package_breeze_icons(ICONS
|
||||||
@@ -159,7 +162,7 @@ if(ANDROID)
|
|||||||
"zoom-out"
|
"zoom-out"
|
||||||
"image-rotate-left-symbolic"
|
"image-rotate-left-symbolic"
|
||||||
"image-rotate-right-symbolic"
|
"image-rotate-right-symbolic"
|
||||||
"channel-insecure-symbolic"
|
"channel-secure-symbolic"
|
||||||
"download"
|
"download"
|
||||||
"smiley"
|
"smiley"
|
||||||
"tools-check-spelling"
|
"tools-check-spelling"
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
|
||||||
#include "actionsmodel.h"
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "customemojimodel.h"
|
#include "models/actionsmodel.h"
|
||||||
|
#include "models/customemojimodel.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "neochatuser.h"
|
#include "neochatuser.h"
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
#include <Sonnet/BackgroundChecker>
|
#include <Sonnet/BackgroundChecker>
|
||||||
#include <Sonnet/Settings>
|
#include <Sonnet/Settings>
|
||||||
|
|
||||||
#include "actionsmodel.h"
|
#include "models/actionsmodel.h"
|
||||||
|
#include "models/roomlistmodel.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "roomlistmodel.h"
|
|
||||||
|
|
||||||
class SyntaxHighlighter : public QSyntaxHighlighter
|
class SyntaxHighlighter : public QSyntaxHighlighter
|
||||||
{
|
{
|
||||||
@@ -105,7 +105,7 @@ ChatDocumentHandler::ChatDocumentHandler(QObject *parent)
|
|||||||
{
|
{
|
||||||
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
connect(this, &ChatDocumentHandler::roomChanged, this, [this]() {
|
||||||
m_completionModel->setRoom(m_room);
|
m_completionModel->setRoom(m_room);
|
||||||
static NeoChatRoom *previousRoom = nullptr;
|
static QPointer<NeoChatRoom> previousRoom = nullptr;
|
||||||
if (previousRoom) {
|
if (previousRoom) {
|
||||||
disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
|
disconnect(previousRoom, &NeoChatRoom::chatBoxTextChanged, this, nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
#include <QQuickTextDocument>
|
#include <QQuickTextDocument>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
#include "completionmodel.h"
|
#include "models/completionmodel.h"
|
||||||
#include "userlistmodel.h"
|
#include "models/userlistmodel.h"
|
||||||
|
|
||||||
class QTextDocument;
|
class QTextDocument;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ QImage Clipboard::image() const
|
|||||||
|
|
||||||
QString Clipboard::saveImage(QString localPath) const
|
QString Clipboard::saveImage(QString localPath) const
|
||||||
{
|
{
|
||||||
if (!QDir().exists(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)))) {
|
QString imageDir(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
|
||||||
QDir().mkdir(QStringLiteral("%1/screenshots").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
|
|
||||||
|
if (!QDir().exists(imageDir)) {
|
||||||
|
QDir().mkdir(imageDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localPath.isEmpty()) {
|
if (localPath.isEmpty()) {
|
||||||
localPath = QStringLiteral("file://%1/screenshots/%2.png")
|
localPath = QStringLiteral("file://%1/%2.png").arg(imageDir, QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd-hh-mm-ss")));
|
||||||
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation),
|
|
||||||
QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd-hh-mm-ss")));
|
|
||||||
}
|
}
|
||||||
QUrl url(localPath);
|
QUrl url(localPath);
|
||||||
if (!url.isLocalFile()) {
|
if (!url.isLocalFile()) {
|
||||||
@@ -51,14 +52,11 @@ QString Clipboard::saveImage(QString localPath) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir;
|
if (image.save(url.toLocalFile())) {
|
||||||
if (!dir.exists(localPath)) {
|
return localPath;
|
||||||
dir.mkpath(localPath);
|
} else {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
image.save(url.toLocalFile());
|
|
||||||
|
|
||||||
return localPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clipboard::saveText(QString message)
|
void Clipboard::saveText(QString message)
|
||||||
|
|||||||
@@ -128,16 +128,7 @@ Controller::Controller(QObject *parent)
|
|||||||
if (AccountRegistry::instance().size() > oldAccountCount) {
|
if (AccountRegistry::instance().size() > oldAccountCount) {
|
||||||
auto connection = AccountRegistry::instance().accounts()[AccountRegistry::instance().size() - 1];
|
auto connection = AccountRegistry::instance().accounts()[AccountRegistry::instance().size() - 1];
|
||||||
connect(connection, &Connection::syncDone, this, [=]() {
|
connect(connection, &Connection::syncDone, this, [=]() {
|
||||||
bool changes = false;
|
handleNotifications(connection);
|
||||||
for (const auto &room : connection->allRooms()) {
|
|
||||||
if (m_notificationCounts[room] != room->unreadStats().notableCount) {
|
|
||||||
m_notificationCounts[room] = room->unreadStats().notableCount;
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changes) {
|
|
||||||
handleNotifications();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
oldAccountCount = AccountRegistry::instance().size();
|
oldAccountCount = AccountRegistry::instance().size();
|
||||||
@@ -146,19 +137,16 @@ Controller::Controller(QObject *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QUOTIENT_07
|
#ifdef QUOTIENT_07
|
||||||
void Controller::handleNotifications()
|
void Controller::handleNotifications(QPointer<Quotient::Connection> connection)
|
||||||
{
|
{
|
||||||
static bool initial = true;
|
static QStringList initial;
|
||||||
static QStringList oldNotifications;
|
static QStringList oldNotifications;
|
||||||
if (!m_connection) {
|
auto job = connection->callApi<GetNotificationsJob>();
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto job = m_connection->callApi<GetNotificationsJob>();
|
|
||||||
|
|
||||||
connect(job, &BaseJob::success, this, [this, job]() {
|
connect(job, &BaseJob::success, this, [job, connection]() {
|
||||||
const auto notifications = job->jsonData()["notifications"].toArray();
|
const auto notifications = job->jsonData()["notifications"].toArray();
|
||||||
if (initial) {
|
if (!initial.contains(connection->user()->id())) {
|
||||||
initial = false;
|
initial.append(connection->user()->id());
|
||||||
for (const auto &n : notifications) {
|
for (const auto &n : notifications) {
|
||||||
oldNotifications += n.toObject()["event"].toObject()["event_id"].toString();
|
oldNotifications += n.toObject()["event"].toObject()["event_id"].toString();
|
||||||
}
|
}
|
||||||
@@ -174,7 +162,7 @@ void Controller::handleNotifications()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
oldNotifications += notification["event"].toObject()["event_id"].toString();
|
oldNotifications += notification["event"].toObject()["event_id"].toString();
|
||||||
auto room = m_connection->room(notification["room_id"].toString());
|
auto room = connection->room(notification["room_id"].toString());
|
||||||
|
|
||||||
// If room exists, room is NOT active OR the application is NOT active, show notification
|
// If room exists, room is NOT active OR the application is NOT active, show notification
|
||||||
if (room && !(room->id() == RoomManager::instance().currentRoom()->id() && QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
if (room && !(room->id() == RoomManager::instance().currentRoom()->id() && QGuiApplication::applicationState() == Qt::ApplicationActive)) {
|
||||||
@@ -196,7 +184,7 @@ void Controller::handleNotifications()
|
|||||||
|
|
||||||
if (notification["event"]["type"] == "m.room.encrypted") {
|
if (notification["event"]["type"] == "m.room.encrypted") {
|
||||||
#ifdef Quotient_E2EE_ENABLED
|
#ifdef Quotient_E2EE_ENABLED
|
||||||
auto decrypted = m_connection->decryptNotification(notification);
|
auto decrypted = connection->decryptNotification(notification);
|
||||||
body = decrypted["content"].toObject()["body"].toString();
|
body = decrypted["content"].toObject()["body"].toString();
|
||||||
#endif
|
#endif
|
||||||
if (body.isEmpty()) {
|
if (body.isEmpty()) {
|
||||||
@@ -381,6 +369,11 @@ void Controller::invokeLogin()
|
|||||||
if (error == "Unrecognised access token") {
|
if (error == "Unrecognised access token") {
|
||||||
Q_EMIT errorOccured(i18n("Login Failed: Access Token invalid or revoked"));
|
Q_EMIT errorOccured(i18n("Login Failed: Access Token invalid or revoked"));
|
||||||
logout(connection, false);
|
logout(connection, false);
|
||||||
|
} else if (error == "Connection closed") {
|
||||||
|
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
|
||||||
|
// Failed due to network connection issue. This might happen when the homeserver is
|
||||||
|
// temporary down, or the user trying to re-launch NeoChat in a network that cannot
|
||||||
|
// connect to the homeserver. In this case, we don't want to do logout().
|
||||||
} else {
|
} else {
|
||||||
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
|
Q_EMIT errorOccured(i18n("Login Failed: %1", error));
|
||||||
logout(connection, true);
|
logout(connection, true);
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ private:
|
|||||||
|
|
||||||
bool hasWindowSystem() const;
|
bool hasWindowSystem() const;
|
||||||
#ifdef QUOTIENT_07
|
#ifdef QUOTIENT_07
|
||||||
void handleNotifications();
|
void handleNotifications(QPointer<Quotient::Connection> connection);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
|
||||||
#include "emojitones.h"
|
#include "emojitones.h"
|
||||||
#include "emojimodel.h"
|
#include "models/emojimodel.h"
|
||||||
|
|
||||||
QMultiHash<QString, QVariant> EmojiTones::_tones = {
|
QMultiHash<QString, QVariant> EmojiTones::_tones = {
|
||||||
#include "emojitones_data.h"
|
#include "emojitones_data.h"
|
||||||
|
|||||||
38
src/main.cpp
38
src/main.cpp
@@ -42,39 +42,39 @@
|
|||||||
#include "blurhashimageprovider.h"
|
#include "blurhashimageprovider.h"
|
||||||
#include "chatdocumenthandler.h"
|
#include "chatdocumenthandler.h"
|
||||||
#include "clipboard.h"
|
#include "clipboard.h"
|
||||||
#include "collapsestateproxymodel.h"
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "customemojimodel.h"
|
|
||||||
#include "devicesmodel.h"
|
|
||||||
#include "emojimodel.h"
|
|
||||||
#include "filetypesingleton.h"
|
#include "filetypesingleton.h"
|
||||||
#include "joinrulesevent.h"
|
#include "joinrulesevent.h"
|
||||||
#include "linkpreviewer.h"
|
#include "linkpreviewer.h"
|
||||||
#include "keywordnotificationrulemodel.h"
|
|
||||||
#include "login.h"
|
#include "login.h"
|
||||||
#include "matriximageprovider.h"
|
#include "matriximageprovider.h"
|
||||||
#include "messageeventmodel.h"
|
#include "models/collapsestateproxymodel.h"
|
||||||
#include "messagefiltermodel.h"
|
#include "models/customemojimodel.h"
|
||||||
|
#include "models/devicesmodel.h"
|
||||||
|
#include "models/emojimodel.h"
|
||||||
|
#include "models/keywordnotificationrulemodel.h"
|
||||||
|
#include "models/messageeventmodel.h"
|
||||||
|
#include "models/messagefiltermodel.h"
|
||||||
|
#include "models/publicroomlistmodel.h"
|
||||||
|
#include "models/roomlistmodel.h"
|
||||||
|
#include "models/searchmodel.h"
|
||||||
|
#include "models/serverlistmodel.h"
|
||||||
|
#include "models/sortfilterroomlistmodel.h"
|
||||||
|
#include "models/sortfilterspacelistmodel.h"
|
||||||
|
#include "models/userdirectorylistmodel.h"
|
||||||
|
#include "models/userfiltermodel.h"
|
||||||
|
#include "models/userlistmodel.h"
|
||||||
|
#include "models/webshortcutmodel.h"
|
||||||
#include "neochatconfig.h"
|
#include "neochatconfig.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "neochatuser.h"
|
#include "neochatuser.h"
|
||||||
#include "notificationsmanager.h"
|
#include "notificationsmanager.h"
|
||||||
#include "searchmodel.h"
|
|
||||||
#ifdef QUOTIENT_07
|
#ifdef QUOTIENT_07
|
||||||
#include "pollhandler.h"
|
#include "pollhandler.h"
|
||||||
#endif
|
#endif
|
||||||
#include "publicroomlistmodel.h"
|
|
||||||
#include "roomlistmodel.h"
|
|
||||||
#include "roommanager.h"
|
#include "roommanager.h"
|
||||||
#include "serverlistmodel.h"
|
|
||||||
#include "sortfilterroomlistmodel.h"
|
|
||||||
#include "sortfilterspacelistmodel.h"
|
|
||||||
#include "spacehierarchycache.h"
|
#include "spacehierarchycache.h"
|
||||||
#include "urlhelper.h"
|
#include "urlhelper.h"
|
||||||
#include "userdirectorylistmodel.h"
|
|
||||||
#include "userfiltermodel.h"
|
|
||||||
#include "userlistmodel.h"
|
|
||||||
#include "webshortcutmodel.h"
|
|
||||||
#include "windowcontroller.h"
|
#include "windowcontroller.h"
|
||||||
#ifdef QUOTIENT_07
|
#ifdef QUOTIENT_07
|
||||||
#include <keyverificationsession.h>
|
#include <keyverificationsession.h>
|
||||||
@@ -82,9 +82,9 @@
|
|||||||
#ifdef HAVE_COLORSCHEME
|
#ifdef HAVE_COLORSCHEME
|
||||||
#include "colorschemer.h"
|
#include "colorschemer.h"
|
||||||
#endif
|
#endif
|
||||||
#include "completionmodel.h"
|
#include "models/completionmodel.h"
|
||||||
|
#include "models/statemodel.h"
|
||||||
#include "neochatuser.h"
|
#include "neochatuser.h"
|
||||||
#include "statemodel.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_RUNNER
|
#ifdef HAVE_RUNNER
|
||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|||||||
@@ -158,11 +158,12 @@ QVector<ActionsModel::Action> actions{
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
#ifdef QUOTIENT_07
|
#ifdef QUOTIENT_07
|
||||||
if (room->currentState().get<RoomMemberEvent>(text)->membership() == Membership::Invite) {
|
const RoomMemberEvent *roomMemberEvent = room->currentState().get<RoomMemberEvent>(text);
|
||||||
|
if (roomMemberEvent && roomMemberEvent->membership() == Membership::Invite) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already invited to this room.", "%1 is already invited to this room.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already invited to this room.", "%1 is already invited to this room.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (room->currentState().get<RoomMemberEvent>(text)->membership() == Membership::Ban) {
|
if (roomMemberEvent && roomMemberEvent->membership() == Membership::Ban) {
|
||||||
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <memory>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
struct CustomEmoji {
|
struct CustomEmoji {
|
||||||
QString name; // with :semicolons:
|
QString name; // with :semicolons:
|
||||||
@@ -439,7 +439,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
|
|||||||
case EventTypeRole:
|
case EventTypeRole:
|
||||||
return DelegateType::ReadMarker;
|
return DelegateType::ReadMarker;
|
||||||
case TimeRole: {
|
case TimeRole: {
|
||||||
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime();
|
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime();
|
||||||
const KFormat format;
|
const KFormat format;
|
||||||
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ class Connection;
|
|||||||
class UserDirectoryListModel : public QAbstractListModel
|
class UserDirectoryListModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||||
Q_PROPERTY(QString keyword READ keyword WRITE setKeyword NOTIFY keywordChanged)
|
Q_PROPERTY(QString keyword READ keyword WRITE setKeyword NOTIFY keywordChanged)
|
||||||
Q_PROPERTY(bool limited READ limited NOTIFY limitedChanged)
|
Q_PROPERTY(bool limited READ limited NOTIFY limitedChanged)
|
||||||
|
|
||||||
@@ -95,48 +95,35 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == ObjectRole) {
|
if (role == ObjectRole) {
|
||||||
return QVariant::fromValue(user);
|
return QVariant::fromValue(user);
|
||||||
}
|
}
|
||||||
if (role == PermRole) {
|
|
||||||
auto pl = m_currentRoom->getCurrentState<RoomPowerLevelsEvent>();
|
|
||||||
auto userPl = pl->powerLevelForUser(user->id());
|
|
||||||
|
|
||||||
if (userPl == pl->content().usersDefault) { // Shortcut
|
|
||||||
return UserType::Member;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userPl < pl->powerLevelForEvent("m.room.message")) {
|
|
||||||
return UserType::Muted;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto userPls = pl->users();
|
|
||||||
|
|
||||||
int highestPl = pl->usersDefault();
|
|
||||||
QHash<QString, int>::const_iterator i = userPls.constBegin();
|
|
||||||
while (i != userPls.constEnd()) {
|
|
||||||
if (i.value() > highestPl) {
|
|
||||||
highestPl = i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userPl == highestPl) {
|
|
||||||
return UserType::Owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userPl >= pl->powerLevelForState("m.room.power_levels")) {
|
|
||||||
return UserType::Admin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userPl >= pl->ban() || userPl >= pl->kick() || userPl >= pl->redact()) {
|
|
||||||
return UserType::Moderator;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UserType::Member;
|
|
||||||
}
|
|
||||||
if (role == PowerLevelRole) {
|
if (role == PowerLevelRole) {
|
||||||
auto pl = m_currentRoom->getCurrentState<RoomPowerLevelsEvent>();
|
auto pl = m_currentRoom->getCurrentState<RoomPowerLevelsEvent>();
|
||||||
return pl->powerLevelForUser(user->id());
|
return pl->powerLevelForUser(user->id());
|
||||||
}
|
}
|
||||||
|
if (role == PowerLevelStringRole) {
|
||||||
|
#ifdef QUOTIENT_07
|
||||||
|
auto pl = m_currentRoom->currentState().get<RoomPowerLevelsEvent>();
|
||||||
|
#else
|
||||||
|
auto pl = m_currentRoom->getCurrentState<RoomPowerLevelsEvent>();
|
||||||
|
#endif
|
||||||
|
// User might not in the room yet, in this case pl can be nullptr.
|
||||||
|
// e.g. When invited but user not accepted or denied the invitation.
|
||||||
|
if (!pl) {
|
||||||
|
return QStringLiteral("Not Available");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto userPl = pl->powerLevelForUser(user->id());
|
||||||
|
|
||||||
|
switch (userPl) {
|
||||||
|
case 0:
|
||||||
|
return QStringLiteral("Member");
|
||||||
|
case 50:
|
||||||
|
return QStringLiteral("Moderator");
|
||||||
|
case 100:
|
||||||
|
return QStringLiteral("Admin");
|
||||||
|
default:
|
||||||
|
return QStringLiteral("Custom");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -241,8 +228,8 @@ QHash<int, QByteArray> UserListModel::roleNames() const
|
|||||||
roles[UserIdRole] = "userId";
|
roles[UserIdRole] = "userId";
|
||||||
roles[AvatarRole] = "avatar";
|
roles[AvatarRole] = "avatar";
|
||||||
roles[ObjectRole] = "user";
|
roles[ObjectRole] = "user";
|
||||||
roles[PermRole] = "perm";
|
|
||||||
roles[PowerLevelRole] = "powerLevel";
|
roles[PowerLevelRole] = "powerLevel";
|
||||||
|
roles[PowerLevelStringRole] = "powerLevelString";
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ public:
|
|||||||
Moderator,
|
Moderator,
|
||||||
Member,
|
Member,
|
||||||
Muted,
|
Muted,
|
||||||
|
Custom,
|
||||||
};
|
};
|
||||||
Q_ENUM(Types)
|
Q_ENUM(Types)
|
||||||
};
|
};
|
||||||
@@ -41,8 +43,8 @@ public:
|
|||||||
UserIdRole,
|
UserIdRole,
|
||||||
AvatarRole,
|
AvatarRole,
|
||||||
ObjectRole,
|
ObjectRole,
|
||||||
PermRole,
|
|
||||||
PowerLevelRole,
|
PowerLevelRole,
|
||||||
|
PowerLevelStringRole,
|
||||||
};
|
};
|
||||||
|
|
||||||
UserListModel(QObject *parent = nullptr);
|
UserListModel(QObject *parent = nullptr);
|
||||||
@@ -57,8 +59,6 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
// Q_INVOKABLE
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void roomChanged();
|
void roomChanged();
|
||||||
void usersRefreshed();
|
void usersRefreshed();
|
||||||
@@ -71,7 +71,7 @@ private Q_SLOTS:
|
|||||||
void avatarChanged(Quotient::User *user, const Quotient::Room *context);
|
void avatarChanged(Quotient::User *user, const Quotient::Room *context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoChatRoom *m_currentRoom;
|
QPointer<NeoChatRoom> m_currentRoom;
|
||||||
QList<Quotient::User *> m_users;
|
QList<Quotient::User *> m_users;
|
||||||
|
|
||||||
int findUserPos(Quotient::User *user) const;
|
int findUserPos(Quotient::User *user) const;
|
||||||
@@ -25,10 +25,6 @@
|
|||||||
<label>Background transparency value</label>
|
<label>Background transparency value</label>
|
||||||
<default>0.3</default>
|
<default>0.3</default>
|
||||||
</entry>
|
</entry>
|
||||||
<entry name="ShowNotifications" type="bool">
|
|
||||||
<label>Show notifications</label>
|
|
||||||
<default>true</default>
|
|
||||||
</entry>
|
|
||||||
<entry name="MergeRoomList" type="bool">
|
<entry name="MergeRoomList" type="bool">
|
||||||
<label>Merge Room Lists</label>
|
<label>Merge Room Lists</label>
|
||||||
<default>false</default>
|
<default>false</default>
|
||||||
|
|||||||
@@ -11,6 +11,12 @@
|
|||||||
#include <KNotification>
|
#include <KNotification>
|
||||||
#include <KNotificationReplyAction>
|
#include <KNotificationReplyAction>
|
||||||
|
|
||||||
|
#ifdef QUOTIENT_07
|
||||||
|
#include <accountregistry.h>
|
||||||
|
#else
|
||||||
|
#include "neochataccountregistry.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <connection.h>
|
#include <connection.h>
|
||||||
#include <csapi/pushrules.h>
|
#include <csapi/pushrules.h>
|
||||||
#include <jobs/basejob.h>
|
#include <jobs/basejob.h>
|
||||||
@@ -49,10 +55,6 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
|||||||
const QString &replyEventId,
|
const QString &replyEventId,
|
||||||
bool canReply)
|
bool canReply)
|
||||||
{
|
{
|
||||||
if (!NeoChatConfig::self()->showNotifications()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap img;
|
QPixmap img;
|
||||||
img.convertFromImage(icon);
|
img.convertFromImage(icon);
|
||||||
KNotification *notification = new KNotification("message");
|
KNotification *notification = new KNotification("message");
|
||||||
@@ -68,8 +70,15 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
|||||||
|
|
||||||
notification->setDefaultAction(i18n("Open NeoChat in this room"));
|
notification->setDefaultAction(i18n("Open NeoChat in this room"));
|
||||||
connect(notification, &KNotification::defaultActivated, this, [=]() {
|
connect(notification, &KNotification::defaultActivated, this, [=]() {
|
||||||
RoomManager::instance().enterRoom(room);
|
|
||||||
WindowController::instance().showAndRaiseWindow(notification->xdgActivationToken());
|
WindowController::instance().showAndRaiseWindow(notification->xdgActivationToken());
|
||||||
|
if (room->localUser()->id() != Controller::instance().activeConnection()->userId()) {
|
||||||
|
#ifdef QUOTIENT_07
|
||||||
|
Controller::instance().setActiveConnection(Accounts.get(room->localUser()->id()));
|
||||||
|
#else
|
||||||
|
Controller::instance().setActiveConnection(AccountRegistry::instance().get(room->localUser()->id()));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
RoomManager::instance().enterRoom(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (canReply) {
|
if (canReply) {
|
||||||
@@ -90,9 +99,6 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
|
|||||||
|
|
||||||
void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QString &title, const QString &sender, const QImage &icon)
|
void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QString &title, const QString &sender, const QImage &icon)
|
||||||
{
|
{
|
||||||
if (!NeoChatConfig::self()->showNotifications()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QPixmap img;
|
QPixmap img;
|
||||||
img.convertFromImage(icon);
|
img.convertFromImage(icon);
|
||||||
KNotification *notification = new KNotification("invite");
|
KNotification *notification = new KNotification("invite");
|
||||||
@@ -102,9 +108,9 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *room, const QStri
|
|||||||
notification->setFlags(KNotification::Persistent);
|
notification->setFlags(KNotification::Persistent);
|
||||||
notification->setDefaultAction(i18n("Open this invitation in NeoChat"));
|
notification->setDefaultAction(i18n("Open this invitation in NeoChat"));
|
||||||
connect(notification, &KNotification::defaultActivated, this, [=]() {
|
connect(notification, &KNotification::defaultActivated, this, [=]() {
|
||||||
|
WindowController::instance().showAndRaiseWindow(notification->xdgActivationToken());
|
||||||
notification->close();
|
notification->close();
|
||||||
RoomManager::instance().enterRoom(room);
|
RoomManager::instance().enterRoom(room);
|
||||||
WindowController::instance().showAndRaiseWindow(notification->xdgActivationToken());
|
|
||||||
});
|
});
|
||||||
notification->setActions({i18n("Accept Invitation"), i18n("Reject Invitation")});
|
notification->setActions({i18n("Accept Invitation"), i18n("Reject Invitation")});
|
||||||
connect(notification, &KNotification::action1Activated, this, [room, notification]() {
|
connect(notification, &KNotification::action1Activated, this, [room, notification]() {
|
||||||
@@ -271,7 +277,9 @@ void NotificationsManager::updateNotificationRules(const QString &type)
|
|||||||
if (overrideRule["rule_id"] == ".m.rule.master") {
|
if (overrideRule["rule_id"] == ".m.rule.master") {
|
||||||
bool ruleEnabled = overrideRule["enabled"].toBool();
|
bool ruleEnabled = overrideRule["enabled"].toBool();
|
||||||
m_globalNotificationsEnabled = !ruleEnabled;
|
m_globalNotificationsEnabled = !ruleEnabled;
|
||||||
NeoChatConfig::self()->setShowNotifications(m_globalNotificationsEnabled);
|
if (!m_globalNotificationsSet) {
|
||||||
|
m_globalNotificationsSet = true;
|
||||||
|
}
|
||||||
Q_EMIT globalNotificationsEnabledChanged(m_globalNotificationsEnabled);
|
Q_EMIT globalNotificationsEnabledChanged(m_globalNotificationsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class NotificationsManager : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool globalNotificationsEnabled MEMBER m_globalNotificationsEnabled WRITE setGlobalNotificationsEnabled NOTIFY globalNotificationsEnabledChanged)
|
Q_PROPERTY(bool globalNotificationsEnabled MEMBER m_globalNotificationsEnabled WRITE setGlobalNotificationsEnabled NOTIFY globalNotificationsEnabledChanged)
|
||||||
|
Q_PROPERTY(bool globalNotificationsSet MEMBER m_globalNotificationsSet NOTIFY globalNotificationsSetChanged)
|
||||||
Q_PROPERTY(PushNotificationAction::Action oneToOneNotificationAction MEMBER m_oneToOneNotificationAction WRITE setOneToOneNotificationAction NOTIFY
|
Q_PROPERTY(PushNotificationAction::Action oneToOneNotificationAction MEMBER m_oneToOneNotificationAction WRITE setOneToOneNotificationAction NOTIFY
|
||||||
oneToOneNotificationActionChanged)
|
oneToOneNotificationActionChanged)
|
||||||
Q_PROPERTY(PushNotificationAction::Action encryptedOneToOneNotificationAction MEMBER m_encryptedOneToOneNotificationAction WRITE
|
Q_PROPERTY(PushNotificationAction::Action encryptedOneToOneNotificationAction MEMBER m_encryptedOneToOneNotificationAction WRITE
|
||||||
@@ -73,7 +74,8 @@ private:
|
|||||||
QMultiMap<QString, KNotification *> m_notifications;
|
QMultiMap<QString, KNotification *> m_notifications;
|
||||||
QHash<QString, QPointer<KNotification>> m_invitations;
|
QHash<QString, QPointer<KNotification>> m_invitations;
|
||||||
|
|
||||||
bool m_globalNotificationsEnabled;
|
bool m_globalNotificationsEnabled = false;
|
||||||
|
bool m_globalNotificationsSet = false;
|
||||||
PushNotificationAction::Action m_oneToOneNotificationAction = PushNotificationAction::Unknown;
|
PushNotificationAction::Action m_oneToOneNotificationAction = PushNotificationAction::Unknown;
|
||||||
PushNotificationAction::Action m_encryptedOneToOneNotificationAction = PushNotificationAction::Unknown;
|
PushNotificationAction::Action m_encryptedOneToOneNotificationAction = PushNotificationAction::Unknown;
|
||||||
PushNotificationAction::Action m_groupChatNotificationAction = PushNotificationAction::Unknown;
|
PushNotificationAction::Action m_groupChatNotificationAction = PushNotificationAction::Unknown;
|
||||||
@@ -107,6 +109,7 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void globalNotificationsEnabledChanged(bool newState);
|
void globalNotificationsEnabledChanged(bool newState);
|
||||||
|
void globalNotificationsSetChanged(bool newState);
|
||||||
void oneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
void oneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
||||||
void encryptedOneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
void encryptedOneToOneNotificationActionChanged(PushNotificationAction::Action action);
|
||||||
void groupChatNotificationActionChanged(PushNotificationAction::Action action);
|
void groupChatNotificationActionChanged(PushNotificationAction::Action action);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ Comment[nl]=Rooms zoeken in NeoChat
|
|||||||
Comment[pl]=Znajdź pokoje w NeoChat
|
Comment[pl]=Znajdź pokoje w NeoChat
|
||||||
Comment[pt]=Procurar salas no NeoChat
|
Comment[pt]=Procurar salas no NeoChat
|
||||||
Comment[pt_BR]=Encontrar salas no NeoChat
|
Comment[pt_BR]=Encontrar salas no NeoChat
|
||||||
Comment[ru]=Поиск комнаты NeoChat
|
Comment[ru]=Поиск комнат NeoChat
|
||||||
Comment[sl]=Najdi sobe v NeoChatu
|
Comment[sl]=Najdi sobe v NeoChatu
|
||||||
Comment[sv]=Sök efter rum i NeoChat
|
Comment[sv]=Sök efter rum i NeoChat
|
||||||
Comment[ta]=நியோச்சாட்டில் அரங்குகளை கண்டுபிடிக்கும்
|
Comment[ta]=நியோச்சாட்டில் அரங்குகளை கண்டுபிடிக்கும்
|
||||||
|
|||||||
@@ -10,188 +10,115 @@ import org.kde.kirigami 2.15 as Kirigami
|
|||||||
|
|
||||||
import org.kde.neochat 1.0
|
import org.kde.neochat 1.0
|
||||||
|
|
||||||
Loader {
|
ColumnLayout {
|
||||||
id: attachmentPaneLoader
|
id: root
|
||||||
|
|
||||||
readonly property var attachmentMimetype: FileType.mimeTypeForUrl(attachmentPaneLoader.attachmentPath)
|
signal attachmentCancelled()
|
||||||
|
|
||||||
|
property string attachmentPath
|
||||||
|
|
||||||
|
readonly property var attachmentMimetype: FileType.mimeTypeForUrl(attachmentPath)
|
||||||
readonly property bool hasImage: attachmentMimetype.valid && FileType.supportedImageFormats.includes(attachmentMimetype.preferredSuffix)
|
readonly property bool hasImage: attachmentMimetype.valid && FileType.supportedImageFormats.includes(attachmentMimetype.preferredSuffix)
|
||||||
readonly property string attachmentPath: currentRoom.chatBoxAttachmentPath
|
|
||||||
readonly property string baseFileName: attachmentPath.substring(attachmentPath.lastIndexOf('/') + 1, attachmentPath.length)
|
readonly property string baseFileName: attachmentPath.substring(attachmentPath.lastIndexOf('/') + 1, attachmentPath.length)
|
||||||
|
|
||||||
active: visible
|
RowLayout {
|
||||||
sourceComponent: Component {
|
spacing: Kirigami.Units.smallSpacing
|
||||||
QQC2.Pane {
|
|
||||||
id: attachmentPane
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
|
|
||||||
contentItem: Item {
|
QQC2.Label {
|
||||||
property real spacing: attachmentPane.spacing > 0 ? attachmentPane.spacing : toolBar.spacing
|
Layout.fillWidth: true
|
||||||
implicitWidth: Math.max(image.implicitWidth, imageBusyIndicator.implicitWidth, fileInfoLayout.implicitWidth, toolBar.implicitWidth)
|
Layout.alignment: Qt.AlignLeft
|
||||||
implicitHeight: Math.max(
|
text: i18n("Attachment:")
|
||||||
(hasImage ? Math.max(image.preferredHeight, imageBusyIndicator.implicitHeight) + spacing : 0)
|
horizontalAlignment: Text.AlignLeft
|
||||||
+ fileInfoLayout.implicitHeight,
|
verticalAlignment: Text.AlignVCenter
|
||||||
toolBar.implicitHeight
|
}
|
||||||
)
|
QQC2.ToolButton {
|
||||||
|
id: editImageButton
|
||||||
|
visible: hasImage
|
||||||
|
icon.name: "document-edit"
|
||||||
|
text: i18n("Edit")
|
||||||
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
|
||||||
Image {
|
Component {
|
||||||
id: image
|
id: imageEditorPage
|
||||||
property real preferredHeight: Math.min(implicitHeight, Kirigami.Units.gridUnit * 8)
|
ImageEditorPage {
|
||||||
height: preferredHeight
|
imagePath: root.attachmentPath
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
bottom: fileInfoLayout.top
|
|
||||||
bottomMargin: parent.spacing
|
|
||||||
}
|
|
||||||
width: Math.min(implicitWidth, attachmentPane.availableWidth)
|
|
||||||
asynchronous: true
|
|
||||||
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
|
|
||||||
smooth: height === preferredHeight && parent.height === parent.implicitHeight // Don't smooth until height animation stops
|
|
||||||
source: hasImage ? attachmentPaneLoader.attachmentPath : ""
|
|
||||||
visible: hasImage
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
|
|
||||||
onSourceChanged: {
|
|
||||||
// Reset source size height, which affect implicitHeight
|
|
||||||
sourceSize.height = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
onSourceSizeChanged: {
|
|
||||||
if (implicitHeight > Kirigami.Units.gridUnit * 8) {
|
|
||||||
// This can save a lot of RAM when loading large images.
|
|
||||||
// It also improves visual quality for large images.
|
|
||||||
sourceSize.height = Kirigami.Units.gridUnit * 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
NumberAnimation {
|
|
||||||
property: "height"
|
|
||||||
duration: Kirigami.Units.shortDuration
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.BusyIndicator {
|
|
||||||
id: imageBusyIndicator
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
top: parent.top
|
|
||||||
bottom: fileInfoLayout.top
|
|
||||||
bottomMargin: parent.spacing
|
|
||||||
}
|
|
||||||
visible: running
|
|
||||||
running: image.visible && image.progress < 1
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: fileInfoLayout
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.verticalCenter: undefined
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
spacing: parent.spacing
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
id: mimetypeIcon
|
|
||||||
implicitHeight: Kirigami.Units.fontMetrics.roundedIconSize(fileLabel.implicitHeight)
|
|
||||||
implicitWidth: implicitHeight
|
|
||||||
source: attachmentMimetype.iconName
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Label {
|
|
||||||
id: fileLabel
|
|
||||||
text: baseFileName
|
|
||||||
}
|
|
||||||
|
|
||||||
states: State {
|
|
||||||
when: !hasImage
|
|
||||||
AnchorChanges {
|
|
||||||
target: fileInfoLayout
|
|
||||||
anchors.bottom: undefined
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Using a toolbar to get a button spacing consistent with what the QQC2 style normally has
|
|
||||||
// Also has some accessibility info
|
|
||||||
QQC2.ToolBar {
|
|
||||||
id: toolBar
|
|
||||||
width: parent.width
|
|
||||||
anchors.top: parent.top
|
|
||||||
|
|
||||||
leftPadding: 0
|
|
||||||
rightPadding: 0
|
|
||||||
topPadding: 0
|
|
||||||
bottomPadding: 0
|
|
||||||
|
|
||||||
Kirigami.Theme.inherit: true
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
||||||
|
|
||||||
contentItem: RowLayout {
|
|
||||||
spacing: parent.spacing
|
|
||||||
QQC2.Label {
|
|
||||||
Layout.leftMargin: -attachmentPane.leftPadding
|
|
||||||
Layout.topMargin: -attachmentPane.topPadding
|
|
||||||
leftPadding: cancelAttachmentButton.leftPadding + 1 + attachmentPane.leftPadding
|
|
||||||
rightPadding: cancelAttachmentButton.rightPadding + 1
|
|
||||||
topPadding: cancelAttachmentButton.topPadding + attachmentPane.topPadding
|
|
||||||
bottomPadding: cancelAttachmentButton.bottomPadding
|
|
||||||
text: i18n("Attachment:")
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
background: Kirigami.ShadowedRectangle {
|
|
||||||
property real cornerRadius: cancelAttachmentButton.background.hasOwnProperty("radius") ?
|
|
||||||
Math.min(cancelAttachmentButton.background.radius, height/2) : 0
|
|
||||||
corners.bottomLeftRadius: toolBar.mirrored ? cornerRadius : 0
|
|
||||||
corners.bottomRightRadius: toolBar.mirrored ? 0 : cornerRadius
|
|
||||||
color: Kirigami.Theme.backgroundColor
|
|
||||||
opacity: 0.75
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
QQC2.ToolButton {
|
|
||||||
id: editImageButton
|
|
||||||
visible: hasImage
|
|
||||||
icon.name: "document-edit"
|
|
||||||
text: i18n("Edit")
|
|
||||||
display: QQC2.AbstractButton.IconOnly
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: imageEditorPage
|
|
||||||
ImageEditorPage {
|
|
||||||
imagePath: attachmentPaneLoader.attachmentPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClicked: {
|
|
||||||
let imageEditor = applicationWindow().pageStack.layers.push(imageEditorPage);
|
|
||||||
imageEditor.newPathChanged.connect(function(newPath) {
|
|
||||||
applicationWindow().pageStack.layers.pop();
|
|
||||||
attachmentPaneLoader.attachmentPath = newPath;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
QQC2.ToolTip.text: text
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
}
|
|
||||||
QQC2.ToolButton {
|
|
||||||
id: cancelAttachmentButton
|
|
||||||
icon.name: "dialog-close"
|
|
||||||
text: i18n("Cancel sending Image")
|
|
||||||
display: QQC2.AbstractButton.IconOnly
|
|
||||||
onClicked: currentRoom.chatBoxAttachmentPath = "";
|
|
||||||
QQC2.ToolTip.text: text
|
|
||||||
QQC2.ToolTip.visible: hovered
|
|
||||||
}
|
|
||||||
}
|
|
||||||
background: null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
onClicked: {
|
||||||
color: Kirigami.Theme.backgroundColor
|
let imageEditor = applicationWindow().pageStack.layers.push(imageEditorPage);
|
||||||
|
imageEditor.newPathChanged.connect(function(newPath) {
|
||||||
|
applicationWindow().pageStack.layers.pop();
|
||||||
|
root.attachmentPath = newPath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
QQC2.ToolTip.text: text
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
}
|
||||||
|
QQC2.ToolButton {
|
||||||
|
id: cancelAttachmentButton
|
||||||
|
display: QQC2.AbstractButton.IconOnly
|
||||||
|
action: Kirigami.Action {
|
||||||
|
text: i18n("Cancel sending attachment")
|
||||||
|
icon.name: "dialog-close"
|
||||||
|
onTriggered: attachmentCancelled();
|
||||||
|
shortcut: "Escape"
|
||||||
|
}
|
||||||
|
QQC2.ToolTip.text: text
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
asynchronous: true
|
||||||
|
cache: false // Cache is not needed. Images will rarely be shown repeatedly.
|
||||||
|
source: hasImage ? root.attachmentPath : ""
|
||||||
|
visible: hasImage
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
||||||
|
onSourceChanged: {
|
||||||
|
// Reset source size height, which affect implicitHeight
|
||||||
|
sourceSize.height = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
onSourceSizeChanged: {
|
||||||
|
if (implicitHeight > Kirigami.Units.gridUnit * 8) {
|
||||||
|
// This can save a lot of RAM when loading large images.
|
||||||
|
// It also improves visual quality for large images.
|
||||||
|
sourceSize.height = Kirigami.Units.gridUnit * 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Kirigami.Units.shortDuration
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QQC2.BusyIndicator {
|
||||||
|
id: imageBusyIndicator
|
||||||
|
|
||||||
|
visible: running
|
||||||
|
running: image.visible && image.progress < 1
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
id: fileInfoLayout
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: parent.spacing
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
id: mimetypeIcon
|
||||||
|
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
source: attachmentMimetype.iconName
|
||||||
|
}
|
||||||
|
QQC2.Label {
|
||||||
|
id: fileLabel
|
||||||
|
text: baseFileName
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user