Compare commits

...

38 Commits

Author SHA1 Message Date
l10n daemon script
eeddf99ca5 GIT_SILENT Sync po/docbooks with svn 2024-04-25 02:59:02 +00:00
Joshua Goins
09a35b1a7e Preserve mx-reply in the edited message if it exists
(cherry picked from commit fa57db8e83)
2024-04-24 15:30:17 -04:00
l10n daemon script
533182ec55 GIT_SILENT Sync po/docbooks with svn 2024-04-24 03:37:34 +00:00
Tobias Fella
70a8842f00 Use escaped title in devtools
(cherry picked from commit 307536c6b6)
2024-04-23 14:04:21 +02:00
Tobias Fella
ab33d1ca88 Work around QML opening dialog in wrong window
(cherry picked from commit 203be8bd35)
2024-04-23 14:04:06 +02:00
Tobias Fella
9e45f22e09 Replace Quotient::Connection with NeoChatConnection where possible
(cherry picked from commit 1e644587b3)
2024-04-23 14:03:51 +02:00
James Graham
6a627dfff0 Refactor the MessageComponentModel component update
(cherry picked from commit 66a60f09e3)
2024-04-23 14:03:37 +02:00
Tobias Fella
a9f05a7f63 Remove search bar; Use QuickSwitcher instead
(cherry picked from commit 69b6f16ec1)
2024-04-23 14:03:26 +02:00
James Graham
4dfd4b68eb Fix Roomlist Shortcuts
Fix the ctrl + pgup/pgdwn shortcuts for the room list so that they work with tree model

BUG: 485949
(cherry picked from commit 28c9d94457)
2024-04-23 14:03:19 +02:00
Tobias Fella
3786710d81 Force author display name in HiddenDelegate to PlainText
(cherry picked from commit d74fd1a560)
2024-04-23 14:03:13 +02:00
James Graham
3967b27352 Make the SpaceDrawer navigable with the keyboard.
(cherry picked from commit 624b1b06c5)
2024-04-23 14:03:05 +02:00
Carl Schwan
714ea8413c Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: Carl Schwan <carl@carlschwan.eu>
(cherry picked from commit 95376c2ccc)
2024-04-23 14:02:53 +02:00
James Graham
4097addae9 Use AvatarButton in UserInfo instead of a custom button. This has the advantage of showing keyboard focus properly
(cherry picked from commit 1eb622165b)
2024-04-23 14:02:42 +02:00
Nate Graham
e9ac9deb40 Use more appropriate icons and tooltips for the room info drawer handles
Right now they use the standard text but left and right arrow icons,
which is a bit odd, and I think fails to convey what will happen when
clicked especially whern the drawer is closed.

Instead, let's use descriptive tooltip text for both, and a descriptive
icon for the the "this will open the drawer" handle button. For the one
to close the drawer, the default icon seems better, so let's stop
overriding it.

(cherry picked from commit 9d6ba324fb)
2024-04-23 14:02:28 +02:00
James Graham
3b858ab7d5 Use new cornerRadius Kirigami unit across the app
(cherry picked from commit ab0c8b8170)
2024-04-23 14:02:19 +02:00
James Graham
08807797a5 Make sure that tab can be used to navigate away from the chatbar
(cherry picked from commit 91d295e0bb)
2024-04-23 14:02:09 +02:00
James Graham
923839d6c7 Add Carl's focus title hack as a devtool option
(cherry picked from commit 125974dd7a)
2024-04-23 14:02:01 +02:00
Tobias Fella
3d4a1d22b0 Improve CodeComponent background
(cherry picked from commit 92895a7d00)
2024-04-23 14:01:53 +02:00
Nate Graham
5aa7f499c0 Make the "add new" menu button a hamburger menu
I know hamburger menus sometimes aren't amazing, but the current icon is
misleading. It's a plus button which generally means "create new".
However the menu is full of actions not related to creating new things,
including:

- Explore Rooms
- Find your Friends
- Scan a QR Code

These actions may technically result in a new room appearing in the
sidebar, but that's not a user's definition of creating a new thing;
these are *joining* a thing, and the fact that a new entry appears in
the sidebar is an implementation detail.

As a result the existing icon is inaccurate, and also holds back the
menu from adding additional items in the future that are even less
related to creating new rooms. An example would be the quick room
switcher, which is not exposed visibly in the UI anywhere, and could not
logically live in the current menu without changing its icon and text.

(cherry picked from commit d9308440e6)
2024-04-23 14:01:45 +02:00
James Graham
40c3519737 Change actionChanged to notificationActionChanged
Change actionChanged to notificationActionChanged to avoid any clashes with ItemDelegate action property signals

(cherry picked from commit 5340142c06)
2024-04-23 14:01:36 +02:00
James Graham
6ec9cc2475 Elide the Hidden delegate text
(cherry picked from commit 012d30ee9f)
2024-04-23 14:01:26 +02:00
James Graham
eba34b19ad Only override the DelegateType when showing hidden messages
(cherry picked from commit 031d69d996)
2024-04-23 14:01:16 +02:00
James Graham
8517636485 Implement devtoool to show hidden timeline messages
(cherry picked from commit 8b63c18f65)
2024-04-23 14:01:07 +02:00
James Graham
4a96dae57d Fancy Effects 2021-2024 gone but never forgotten
Remove fancy effects as it's busted and causing CPU spikes.

(cherry picked from commit dc2f11eb2b)
2024-04-23 14:00:57 +02:00
James Graham
09f433be45 Use 0.8.x for libQuotient flatpak
(cherry picked from commit 13e64a9487)
2024-04-23 14:00:44 +02:00
l10n daemon script
b9901a9167 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-04-23 03:20:13 +00:00
l10n daemon script
8b27d99d82 GIT_SILENT made messages (after extraction) 2024-04-23 02:45:40 +00:00
l10n daemon script
6b53c4d7b1 GIT_SILENT Sync po/docbooks with svn 2024-04-22 03:49:36 +00:00
l10n daemon script
bd28a7f66d SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2024-04-22 03:40:01 +00:00
l10n daemon script
0d1c09696d GIT_SILENT made messages (after extraction) 2024-04-22 03:04:59 +00:00
Albert Astals Cid
aeb4013d26 GIT_SILENT Upgrade release service version to 24.04.80. 2024-04-21 11:39:05 +02:00
l10n daemon script
08a7e324aa GIT_SILENT Sync po/docbooks with svn 2024-04-21 01:23:23 +00:00
James Graham
9202a4525f Make sure the user can get to the navigationtabbar 2024-04-20 17:21:21 +00:00
Carl Schwan
bfc756fb35 rejrejore 2024-04-20 17:21:21 +00:00
Carl Schwan
2a735ff1cc jreojreojr 2024-04-20 17:21:21 +00:00
James Graham
551092a1b4 Make sure the drawer get active focus on open 2024-04-20 17:21:21 +00:00
Carl Schwan
ddd12688aa RoomInformation: allow tabbing on actions 2024-04-20 17:21:21 +00:00
l10n daemon script
71767c4172 GIT_SILENT Sync po/docbooks with svn 2024-04-20 01:23:40 +00:00
129 changed files with 10177 additions and 8308 deletions

View File

@@ -110,7 +110,7 @@
{
"type": "git",
"url": "https://github.com/quotient-im/libQuotient.git",
"branch": "dev",
"branch": "0.8.x",
"disable-submodules": true
}
],

View File

@@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "04")
set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION_MICRO "80")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -204,7 +204,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/InviteUserPage.qml
qml/ImageEditorPage.qml
qml/NeochatMaximizeComponent.qml
qml/FancyEffectsContainer.qml
qml/TypingPane.qml
qml/QuickSwitcher.qml
qml/HoverActions.qml
@@ -281,9 +280,6 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/ConfirmLeaveDialog.qml
qml/CodeMaximizeComponent.qml
qml/EditStateDialog.qml
RESOURCES
qml/confetti.png
qml/glowdot.png
)
add_subdirectory(settings)

View File

@@ -14,6 +14,7 @@
#include "models/actionsmodel.h"
#include "neochatconfig.h"
#include "texthandler.h"
#include "utils.h"
using namespace Quotient;
@@ -145,6 +146,26 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
return;
}
// We want to add back the <mx-reply> if it's in the original message but not in the edit, to preserve the reply.
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
QString originalString;
if (event->content()) {
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
} else {
originalString = event->plainBody();
}
const QRegularExpression exp(TextRegex::removeRichReply);
const auto match = exp.match(originalString);
if (match.hasCaptured(0) && !handledText.contains(TextRegex::removeRichReply)) {
handledText.prepend(match.captured(0));
}
}
}
}
m_room->postMessage(text, handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
}

View File

@@ -19,7 +19,6 @@
#include <signal.h>
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/csapi/logout.h>
#include <Quotient/csapi/notifications.h>
#include <Quotient/eventstats.h>

View File

@@ -117,7 +117,7 @@ private:
Quotient::AccountRegistry m_accountRegistry;
QStringList m_accountsLoading;
QMap<QString, QPointer<Quotient::Connection>> m_connectionsLoading;
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
QString m_endpoint;
private Q_SLOTS:

View File

@@ -15,6 +15,12 @@ FormCard.FormCardPage {
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show hidden events in the timeline")
checked: Config.showAllEvents
onToggled: Config.showAllEvents = checked
}
FormCard.FormCheckDelegate {
id: roomAccountDataVisibleCheck
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
@@ -23,5 +29,14 @@ FormCard.FormCardPage {
onToggled: Config.alwaysVerifyDevice = checked
}
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show focus in window header")
checked: Config.windowTitleFocus
onToggled: {
Config.windowTitleFocus = checked;
Config.save();
}
}
}
}

View File

@@ -25,9 +25,10 @@ ColumnLayout {
text: i18n("Room")
textRole: "escapedDisplayName"
valueRole: "roomId"
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.EscapedDisplayNameRole)
model: RoomManager.roomListModel
currentIndex: 0
displayMode: FormCard.FormComboBoxDelegate.Page
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
}

View File

@@ -21,7 +21,6 @@ public:
* @brief Defines the room list categories a room can be assigned.
*/
enum Types {
Search = 0, /**< So we can show a search delegate if needed, e.g. collapsed mode. */
Invited, /**< The user has been invited to the room. */
Favorite, /**< The room is set as a favourite. */
Direct, /**< The room is a direct chat. */
@@ -68,8 +67,6 @@ public:
return i18n("Low priority");
case NeoChatRoomType::Space:
return i18n("Spaces");
case NeoChatRoomType::Search:
return i18n("Search");
default:
return {};
}
@@ -89,8 +86,6 @@ public:
return QStringLiteral("object-order-lower");
case NeoChatRoomType::Space:
return QStringLiteral("group");
case NeoChatRoomType::Search:
return QStringLiteral("search");
default:
return QStringLiteral("tools-report-bug");
}

View File

@@ -4,7 +4,6 @@
#include "login.h"
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/qt_connection_util.h>
#include "controller.h"
@@ -54,7 +53,7 @@ void LoginHelper::init()
m_connection = new NeoChatConnection();
}
m_connection->resolveServer(m_matrixId);
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
setHomeserverReachable(true);
m_testing = false;
Q_EMIT testingChanged();
@@ -100,7 +99,7 @@ void LoginHelper::init()
Q_EMIT Controller::instance().errorOccured(i18n("Network Error"), std::move(error));
});
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
connectSingleShot(m_connection.get(), &Connection::syncDone, this, [this]() {
Q_EMIT loaded();
});
}
@@ -182,7 +181,7 @@ QUrl LoginHelper::ssoUrl() const
void LoginHelper::loginWithSso()
{
m_connection->resolveServer(m_matrixId);
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
SsoSession *session = m_connection->prepareForSso(m_deviceName);
m_ssoUrl = session->ssoUrl();
Q_EMIT ssoUrlChanged();

View File

@@ -146,7 +146,7 @@ private:
QString m_deviceName;
bool m_supportsSso = false;
bool m_supportsPassword = false;
NeoChatConnection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
QUrl m_ssoUrl;
bool m_testing = false;
bool m_isLoggingIn = false;

View File

@@ -14,8 +14,6 @@
#include "neochatconnection.h"
#include <Quotient/connection.h>
using namespace Quotient;
ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *connection)

View File

@@ -35,7 +35,7 @@ private:
QSize requestedSize;
const QString localFile;
Quotient::MediaThumbnailJob *job = nullptr;
NeoChatConnection *m_connection;
QPointer<NeoChatConnection> m_connection;
QImage image;
QString errorStr;
@@ -75,6 +75,6 @@ public:
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
private:
NeoChatConnection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
MatrixImageProvider() = default;
};

View File

@@ -10,6 +10,8 @@
#include <Quotient/events/eventcontent.h>
#include <qcoro/qcorosignal.h>
#include "neochatconnection.h"
using namespace Quotient;
AccountEmoticonModel::AccountEmoticonModel(QObject *parent)
@@ -77,12 +79,12 @@ QHash<int, QByteArray> AccountEmoticonModel::roleNames() const
};
}
Connection *AccountEmoticonModel::connection() const
NeoChatConnection *AccountEmoticonModel::connection() const
{
return m_connection;
}
void AccountEmoticonModel::setConnection(Connection *connection)
void AccountEmoticonModel::setConnection(NeoChatConnection *connection)
{
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);

View File

@@ -12,7 +12,7 @@
#include <QPointer>
#include <QQmlEngine>
#include <Quotient/connection.h>
class NeoChatConnection;
/**
* @class AccountEmoticonModel
@@ -29,7 +29,7 @@ class AccountEmoticonModel : public QAbstractListModel
/**
* @brief The connection to get emoticons from.
*/
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
enum Roles {
@@ -63,8 +63,8 @@ public:
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
/**
* @brief Deletes the emoticon at the given index.
@@ -96,7 +96,7 @@ Q_SIGNALS:
private:
std::optional<Quotient::ImagePackEventContent> m_images;
QPointer<Quotient::Connection> m_connection;
QPointer<NeoChatConnection> m_connection;
QCoro::Task<void> doSetEmoticonImage(int index, QUrl source);
QCoro::Task<void> doAddEmoticon(QUrl source, QString shortcode, QString description, QString type);

View File

@@ -4,6 +4,7 @@
#include "actionsmodel.h"
#include "chatbarcache.h"
#include "neochatconnection.h"
#include "neochatroom.h"
#include "roommanager.h"
#include <Quotient/events/roommemberevent.h>
@@ -260,7 +261,7 @@ QList<ActionsModel::Action> actions{
return QString();
}
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
auto connection = room->connection();
auto connection = dynamic_cast<NeoChatConnection *>(room->connection());
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
if (parts.length() >= 2) {
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});

View File

@@ -110,7 +110,7 @@ Q_SIGNALS:
private:
explicit CustomEmojiModel(QObject *parent = nullptr);
QList<CustomEmoji> m_emojis;
NeoChatConnection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
void fetchEmojis();
};

View File

@@ -5,7 +5,8 @@
#include "customemojimodel.h"
#include <QRegularExpression>
#include <connection.h>
class NeoChatConnection;
struct CustomEmoji {
QString name; // with :semicolons:
@@ -14,6 +15,6 @@ struct CustomEmoji {
};
struct CustomEmojiModel::Private {
Quotient::Connection *conn = nullptr;
QPointer<NeoChatConnection> connection;
QList<CustomEmoji> emojies;
};

View File

@@ -11,9 +11,10 @@
#include <KLocalizedString>
#include <Quotient/csapi/device_management.h>
#include <Quotient/connection.h>
#include <Quotient/user.h>
#include "neochatconnection.h"
using namespace Quotient;
DevicesModel::DevicesModel(QObject *parent)
@@ -152,12 +153,12 @@ void DevicesModel::setName(const QString &deviceId, const QString &name)
});
}
Connection *DevicesModel::connection() const
NeoChatConnection *DevicesModel::connection() const
{
return m_connection;
}
void DevicesModel::setConnection(Connection *connection)
void DevicesModel::setConnection(NeoChatConnection *connection)
{
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);

View File

@@ -9,10 +9,7 @@
#include <Quotient/csapi/definitions/client_device.h>
namespace Quotient
{
class Connection;
}
class NeoChatConnection;
/**
* @class DevicesModel
@@ -31,7 +28,7 @@ class DevicesModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its devices from.
*/
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
public:
/**
@@ -88,9 +85,8 @@ public:
explicit DevicesModel(QObject *parent = nullptr);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
Q_SIGNALS:
void connectionChanged();
@@ -99,5 +95,5 @@ Q_SIGNALS:
private:
void fetchDevices();
QList<Quotient::Device> m_devices;
QPointer<Quotient::Connection> m_connection;
QPointer<NeoChatConnection> m_connection;
};

View File

@@ -246,70 +246,86 @@ void MessageContentModel::updateComponents(bool isEditing)
if (eventCast<const Quotient::RoomMessageEvent>(m_event)
&& eventCast<const Quotient::RoomMessageEvent>(m_event)->rawMsgtype() == QStringLiteral("m.key.verification.request")) {
m_components += MessageComponent{MessageComponentType::Verification, QString(), {}};
} else {
EventHandler eventHandler(m_room, m_event);
if (eventHandler.hasReply()) {
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
} else {
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
}
}
endResetModel();
return;
}
if (isEditing) {
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
} else if (m_event->isRedacted()) {
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
if (m_event->isRedacted()) {
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
endResetModel();
return;
}
EventHandler eventHandler(m_room, m_event);
if (eventHandler.hasReply()) {
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
} else {
if (eventHandler.messageComponentType() == MessageComponentType::Text) {
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
auto body = EventHandler::rawMessageBody(*event);
m_components.append(TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced()));
} else if (eventHandler.messageComponentType() == MessageComponentType::File) {
m_components += MessageComponent{MessageComponentType::File, QString(), {}};
if (m_emptyItinerary) {
auto fileTransferInfo = fileInfo();
#ifndef Q_OS_ANDROID
KSyntaxHighlighting::Repository repository;
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
QFile file(fileTransferInfo.localPath.path());
file.open(QIODevice::ReadOnly);
m_components += MessageComponent{MessageComponentType::Code,
QString::fromStdString(file.readAll().toStdString()),
{{QStringLiteral("class"), definitionForFile.name()}}};
}
#endif
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
QImageReader reader(fileTransferInfo.localPath.path());
m_components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
}
} else {
updateItineraryModel();
if (m_itineraryModel != nullptr) {
m_components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
}
}
} else {
m_components += MessageComponent{eventHandler.messageComponentType(), QString(), {}};
}
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
}
}
if (m_linkPreviewer != nullptr) {
if (m_linkPreviewer->loaded()) {
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
} else {
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
}
if (isEditing) {
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
} else {
m_components.append(componentsForType(eventHandler.messageComponentType()));
}
if (m_linkPreviewer != nullptr) {
if (m_linkPreviewer->loaded()) {
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
} else {
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
}
}
endResetModel();
}
QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type)
{
switch (type) {
case MessageComponentType::Text: {
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
auto body = EventHandler::rawMessageBody(*event);
return TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced());
}
case MessageComponentType::File: {
QList<MessageComponent> components;
components += MessageComponent{MessageComponentType::File, QString(), {}};
if (m_emptyItinerary) {
auto fileTransferInfo = fileInfo();
#ifndef Q_OS_ANDROID
KSyntaxHighlighting::Repository repository;
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
QFile file(fileTransferInfo.localPath.path());
file.open(QIODevice::ReadOnly);
components += MessageComponent{MessageComponentType::Code,
QString::fromStdString(file.readAll().toStdString()),
{{QStringLiteral("class"), definitionForFile.name()}}};
}
#endif
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
QImageReader reader(fileTransferInfo.localPath.path());
components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
}
} else {
updateItineraryModel();
if (m_itineraryModel != nullptr) {
components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
}
}
return components;
}
default:
return {MessageComponent{type, QString(), {}}};
}
}
void MessageContentModel::updateLinkPreviewer()
{
if (m_room == nullptr || m_event == nullptr) {

View File

@@ -98,6 +98,8 @@ private:
QPointer<LinkPreviewer> m_linkPreviewer;
ItineraryModel *m_itineraryModel = nullptr;
QList<MessageComponent> componentsForType(MessageComponentType::Type type);
void updateLinkPreviewer();
void updateItineraryModel();
bool m_emptyItinerary = false;

View File

@@ -7,7 +7,6 @@
#include "neochatconfig.h"
#include <Quotient/connection.h>
#include <Quotient/csapi/rooms.h>
#include <Quotient/events/redactionevent.h>
#include <Quotient/events/roommessageevent.h>
@@ -117,34 +116,6 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
if (message != nullptr) {
createEventObjects(message);
if (NeoChatConfig::self()->showFancyEffects()) {
QString planBody = message->plainBody();
// snowflake
const QString snowlakeEmoji = QString::fromUtf8("\xE2\x9D\x84");
if (planBody.contains(snowlakeEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("snowflake"));
}
// fireworks
const QString fireworksEmoji = QString::fromUtf8("\xF0\x9F\x8E\x86");
if (planBody.contains(fireworksEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
}
// sparkler
const QString sparklerEmoji = QString::fromUtf8("\xF0\x9F\x8E\x87");
if (planBody.contains(sparklerEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
}
// party pooper
const QString partyEmoji = QString::fromUtf8("\xF0\x9F\x8E\x89");
if (planBody.contains(partyEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
}
// confetti ball
const QString confettiEmoji = QString::fromUtf8("\xF0\x9F\x8E\x8A");
if (planBody.contains(confettiEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
}
}
}
if (event->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get()));

View File

@@ -140,5 +140,4 @@ private:
Q_SIGNALS:
void roomChanged();
void fancyEffectsReasonFound(const QString &fancyEffect);
};

View File

@@ -36,6 +36,14 @@ MessageFilterModel::MessageFilterModel(QObject *parent, TimelineModel *sourceMod
}
bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (NeoChatConfig::self()->showAllEvents()) {
return true;
}
return eventIsVisible(sourceRow, sourceParent);
}
bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const
{
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
@@ -59,9 +67,8 @@ bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
// Don't show state events that are not the first in a consecutive group on the
// same day as they will be grouped as a single delegate.
const bool notLastRow = sourceRow < sourceModel()->rowCount() - 1;
const bool previousEventIsState = notLastRow
? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State
: false;
const bool previousEventIsState =
notLastRow ? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State : false;
const bool newDay = sourceModel()->data(sourceModel()->index(sourceRow, 0), MessageEventModel::ShowSectionRole).toBool();
if (eventType == DelegateType::State && notLastRow && previousEventIsState && !newDay) {
return false;
@@ -72,7 +79,11 @@ bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
QVariant MessageFilterModel::data(const QModelIndex &index, int role) const
{
if (role == AggregateDisplayRole) {
if (role == MessageEventModel::DelegateTypeRole && NeoChatConfig::self()->showAllEvents()) {
if (!eventIsVisible(index.row(), index.parent())) {
return DelegateType::Other;
}
} else if (role == AggregateDisplayRole) {
return aggregateEventToString(mapToSource(index).row());
} else if (role == StateEventsRole) {
return stateEventsList(mapToSource(index).row());

View File

@@ -60,6 +60,8 @@ public:
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
private:
bool eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const;
/**
* @brief Aggregation of the text of consecutive state events starting at row.
*

View File

@@ -3,7 +3,6 @@
#include "notificationsmodel.h"
#include <Quotient/connection.h>
#include <Quotient/events/event.h>
#include <Quotient/uri.h>

View File

@@ -3,8 +3,7 @@
#include "publicroomlistmodel.h"
#include <Quotient/connection.h>
#include "neochatconnection.h"
#include "publicroomlist_logging.h"
using namespace Quotient;
@@ -14,14 +13,14 @@ PublicRoomListModel::PublicRoomListModel(QObject *parent)
{
}
Quotient::Connection *PublicRoomListModel::connection() const
NeoChatConnection *PublicRoomListModel::connection() const
{
return m_connection;
}
void PublicRoomListModel::setConnection(Connection *conn)
void PublicRoomListModel::setConnection(NeoChatConnection *connection)
{
if (m_connection == conn) {
if (m_connection == connection) {
return;
}
@@ -38,7 +37,7 @@ void PublicRoomListModel::setConnection(Connection *conn)
endResetModel();
m_connection = conn;
m_connection = connection;
if (job) {
job->abandon();

View File

@@ -9,10 +9,7 @@
#include <Quotient/csapi/list_public_rooms.h>
namespace Quotient
{
class Connection;
}
class NeoChatConnection;
/**
* @class PublicRoomListModel
@@ -33,7 +30,7 @@ class PublicRoomListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its rooms from.
*/
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
/**
* @brief The server to get the public room list from.
@@ -95,8 +92,8 @@ public:
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *conn);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] QString server() const;
void setServer(const QString &value);
@@ -117,7 +114,7 @@ public:
Q_INVOKABLE void search(int limit = 50);
private:
QPointer<Quotient::Connection> m_connection = nullptr;
QPointer<NeoChatConnection> m_connection = nullptr;
QString m_server;
QString m_searchText;
bool m_showOnlySpaces = false;

View File

@@ -5,13 +5,13 @@
#include <QDebug>
#include <Quotient/connection.h>
#include <Quotient/converters.h>
#include <Quotient/csapi/definitions/push_ruleset.h>
#include <Quotient/csapi/pushrules.h>
#include <Quotient/jobs/basejob.h>
#include "neochatconfig.h"
#include "neochatconnection.h"
#include <KLazyLocalizedString>
@@ -454,7 +454,7 @@ void PushRuleModel::setConnection(NeoChatConnection *connection)
Q_EMIT connectionChanged();
if (m_connection) {
connect(m_connection, &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
connect(m_connection, &NeoChatConnection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
updateNotificationRules(QStringLiteral("m.push_rules"));
}
}

View File

@@ -126,7 +126,7 @@ private Q_SLOTS:
private:
PushRuleAction::Action m_defaultKeywordAction;
QList<Rule> m_rules;
NeoChatConnection *m_connection;
QPointer<NeoChatConnection> m_connection;
void setRules(QList<Quotient::PushRule> rules, PushRuleKind::Kind kind);

View File

@@ -25,12 +25,12 @@ RoomListModel::RoomListModel(QObject *parent)
RoomListModel::~RoomListModel() = default;
Quotient::Connection *RoomListModel::connection() const
NeoChatConnection *RoomListModel::connection() const
{
return m_connection;
}
void RoomListModel::setConnection(Connection *connection)
void RoomListModel::setConnection(NeoChatConnection *connection)
{
if (connection == m_connection) {
return;

View File

@@ -12,10 +12,11 @@ class NeoChatRoom;
namespace Quotient
{
class Connection;
class Room;
}
class NeoChatConnection;
/**
* @class RoomListModel
*
@@ -29,7 +30,7 @@ class RoomListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its rooms from.
*/
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
/**
@@ -60,8 +61,8 @@ public:
explicit RoomListModel(QObject *parent = nullptr);
~RoomListModel() override;
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
/**
* @brief Get the given role value at the given index.
@@ -109,7 +110,7 @@ private Q_SLOTS:
void refresh(NeoChatRoom *room, const QList<int> &roles = {});
private:
Quotient::Connection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
QList<NeoChatRoom *> m_rooms;
QString m_activeSpaceId;

View File

@@ -3,7 +3,6 @@
#include "roomtreemodel.h"
#include <Quotient/connection.h>
#include <Quotient/room.h>
#include "eventhandler.h"
@@ -300,9 +299,6 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
return NeoChatRoomType::typeName(index.row());
}
if (role == DelegateTypeRole) {
if (index.row() == NeoChatRoomType::Search) {
return QStringLiteral("search");
}
if (index.row() == NeoChatRoomType::AddDirect) {
return QStringLiteral("addDirect");
}

View File

@@ -10,7 +10,6 @@
#include <QGuiApplication>
#include <Quotient/connection.h>
#include <Quotient/events/stickerevent.h>
#include <KLocalizedString>

View File

@@ -3,8 +3,6 @@
#include "serverlistmodel.h"
#include <Quotient/connection.h>
#include <QDebug>
#include <KConfig>

View File

@@ -110,7 +110,7 @@ Q_SIGNALS:
private:
QList<Server> m_servers;
QPointer<Quotient::QueryPublicRoomsJob> m_checkServerJob = nullptr;
NeoChatConnection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
void initialize();
};

View File

@@ -5,6 +5,8 @@
#include "roomlistmodel.h"
#include "neochatconnection.h"
SortFilterRoomListModel::SortFilterRoomListModel(RoomListModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{

View File

@@ -129,10 +129,6 @@ QString SortFilterRoomTreeModel::filterText() const
bool SortFilterRoomTreeModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!source_parent.isValid()) {
if (sourceModel()->data(sourceModel()->index(source_row, 0), RoomTreeModel::CategoryRole).toInt() == NeoChatRoomType::Search
&& NeoChatConfig::collapsed()) {
return true;
}
if (sourceModel()->data(sourceModel()->index(source_row, 0), RoomTreeModel::CategoryRole).toInt() == NeoChatRoomType::AddDirect
&& m_mode == DirectChats) {
return true;
@@ -205,4 +201,14 @@ void SortFilterRoomTreeModel::setMode(SortFilterRoomTreeModel::Mode mode)
invalidate();
}
QModelIndex SortFilterRoomTreeModel::currentRoomIndex() const
{
const auto roomModel = dynamic_cast<RoomTreeModel *>(sourceModel());
if (roomModel == nullptr) {
return {};
}
return mapFromSource(roomModel->indexForRoom(RoomManager::instance().currentRoom()));
}
#include "moc_sortfilterroomtreemodel.cpp"

View File

@@ -76,6 +76,8 @@ public:
Mode mode() const;
void setMode(Mode mode);
Q_INVOKABLE QModelIndex currentRoomIndex() const;
protected:
/**
* @brief Returns true if the value of source_left is less than source_right.

View File

@@ -3,7 +3,6 @@
#include "spacechildrenmodel.h"
#include <Quotient/connection.h>
#include <Quotient/jobs/basejob.h>
#include <Quotient/room.h>
@@ -47,7 +46,7 @@ void SpaceChildrenModel::setSpace(NeoChatRoom *space)
}
auto connection = m_space->connection();
connect(connection, &Quotient::Connection::loadedRoomState, this, [this](Quotient::Room *room) {
connect(connection, &NeoChatConnection::loadedRoomState, this, [this](Quotient::Room *room) {
if (m_pendingChildren.contains(room->name())) {
m_pendingChildren.removeAll(room->name());
refreshModel();

View File

@@ -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
#include <QPointer>
#include <Quotient/csapi/space_hierarchy.h>
#include <Quotient/events/stateevent.h>
@@ -149,7 +151,7 @@ public:
bool isSuggested() const;
private:
NeoChatConnection *m_connection;
QPointer<NeoChatConnection> m_connection;
std::vector<std::unique_ptr<SpaceTreeItem>> m_children;
SpaceTreeItem *m_parentItem;

View File

@@ -3,9 +3,10 @@
#include "userdirectorylistmodel.h"
#include <Quotient/connection.h>
#include <Quotient/room.h>
#include "neochatconnection.h"
using namespace Quotient;
UserDirectoryListModel::UserDirectoryListModel(QObject *parent)
@@ -13,14 +14,14 @@ UserDirectoryListModel::UserDirectoryListModel(QObject *parent)
{
}
Quotient::Connection *UserDirectoryListModel::connection() const
NeoChatConnection *UserDirectoryListModel::connection() const
{
return m_connection;
}
void UserDirectoryListModel::setConnection(Connection *conn)
void UserDirectoryListModel::setConnection(NeoChatConnection *connection)
{
if (m_connection == conn) {
if (m_connection == connection) {
return;
}
@@ -35,7 +36,7 @@ void UserDirectoryListModel::setConnection(Connection *conn)
endResetModel();
m_connection = conn;
m_connection = connection;
Q_EMIT connectionChanged();
if (m_job) {

View File

@@ -9,10 +9,7 @@
#include <Quotient/csapi/users.h>
namespace Quotient
{
class Connection;
}
class NeoChatConnection;
/**
* @class UserDirectoryListModel
@@ -32,7 +29,7 @@ class UserDirectoryListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting users from.
*/
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
/**
* @brief The text to search the public room list for.
@@ -57,8 +54,8 @@ public:
explicit UserDirectoryListModel(QObject *parent = nullptr);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *conn);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] QString searchText() const;
void setSearchText(const QString &searchText);
@@ -99,7 +96,7 @@ Q_SIGNALS:
void searchingChanged();
private:
Quotient::Connection *m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
QString m_searchText;
bool attempted = false;

View File

@@ -5,7 +5,6 @@
#include <QGuiApplication>
#include <Quotient/connection.h>
#include <Quotient/events/roompowerlevelsevent.h>
#include "neochatroom.h"

View File

@@ -100,10 +100,6 @@
<label>Minimize to system tray on startup</label>
<default>false</default>
</entry>
<entry name="ShowFancyEffects" type="bool">
<label>Show Fancy Effects</label>
<default>true</default>
</entry>
<entry name="MediaMaxWidth" type="int">
<label>The maximum width any media item in the timeline can be.</label>
<default>540</default>
@@ -161,10 +157,18 @@
</entry>
</group>
<group name="Debug">
<entry name="ShowAllEvents" type="bool">
<label>Don't hide any events in the timeline</label>
<default>false</default>
</entry>
<entry name="AlwaysVerifyDevice" type="bool">
<label>Always allow device verification</label>
<default>false</default>
</entry>
<entry name="WindowTitleFocus" type="bool">
<label>Show the current focus item in the window title</label>
<default>false</default>
</entry>
</group>
<group name="FeatureFlags">
<entry name="Threads" type="bool">

View File

@@ -18,6 +18,7 @@
"Name[nl]": "Tobias Fella",
"Name[pl]": "Tobias Fella",
"Name[sl]": "Tobias Fella",
"Name[ta]": "டோபியாஸ் ஃபெல்லா",
"Name[tr]": "Tobias Fella",
"Name[uk]": "Tobias Fella",
"Name[x-test]": "xxTobias Fellaxx",
@@ -40,6 +41,7 @@
"Description[nl]": "Delen via NeoChat",
"Description[pl]": "Udostępnij przez NeoChat",
"Description[sl]": "Deli prek NeoChat",
"Description[ta]": "நியோச்சாட் மூலம் பகிர்",
"Description[tr]": "NeoChat ile Paylaş",
"Description[uk]": "Оприлюднити за допомогою NeoChat",
"Description[x-test]": "xxShare via NeoChatxx",
@@ -63,6 +65,7 @@
"Name[nl]": "NeoChat",
"Name[pl]": "NeoChat",
"Name[sl]": "NeoChat",
"Name[ta]": "நியோச்சாட்",
"Name[tr]": "NeoChat",
"Name[uk]": "NeoChat",
"Name[x-test]": "xxNeoChatxx",

View File

@@ -278,6 +278,8 @@ QQC2.Control {
Keys.onTabPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else {
contextDrawer.handle.children[0].forceActiveFocus()
}
}
Keys.onPressed: event => {

View File

@@ -48,10 +48,10 @@ QQC2.ItemDelegate {
background: Rectangle {
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
radius: Kirigami.Units.cornerRadius
Rectangle {
radius: Kirigami.Units.smallSpacing
radius: Kirigami.Units.cornerRadius
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: root.hovered && !root.pressed ? 0.2 : 0

View File

@@ -40,7 +40,7 @@ QQC2.Popup {
background: Kirigami.ShadowedRectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.mediumSpacing
radius: Kirigami.Units.cornerRadius
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)

View File

@@ -30,7 +30,7 @@ QQC2.Popup {
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.mediumSpacing
radius: Kirigami.Units.cornerRadius
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)

View File

@@ -17,7 +17,7 @@ RowLayout {
property bool collapsed: false
required property NeoChatConnection connection
property alias roomSearchFieldFocussed: roomSearchField.activeFocus
signal search
property Kirigami.Action exploreAction: Kirigami.Action {
text: i18n("Explore rooms")
@@ -83,15 +83,30 @@ RowLayout {
*/
signal textChanged(string newText)
Kirigami.SearchField {
id: roomSearchField
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing
Item {
Layout.preferredWidth: Kirigami.Units.largeSpacing
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.preferredWidth: root.desiredWidth ? root.desiredWidth - menuButton.width - root.spacing : -1
visible: !root.collapsed
onTextChanged: root.textChanged(text)
KeyNavigation.tab: treeView
text: i18nc("@title", "Rooms")
}
Item {
Layout.fillWidth: true
visible: root.collapsed
}
QQC2.ToolButton {
id: searchButton
display: QQC2.AbstractButton.IconOnly
onClicked: root.search();
icon.name: "search"
text: i18nc("@action", "Search Room")
Shortcut {
sequence: "Ctrl+F"
onActivated: searchButton.clicked()
}
}
QQC2.ToolButton {
@@ -100,8 +115,8 @@ RowLayout {
display: QQC2.AbstractButton.IconOnly
checkable: true
action: Kirigami.Action {
text: i18n("Create rooms and chats")
icon.name: "irc-join-channel"
text: i18nc("@action:button", "Show Menu")
icon.name: "application-menu-symbolic"
onTriggered: {
if (Kirigami.isMobile) {
const menu = mobileMenu.createObject();

View File

@@ -1,304 +0,0 @@
// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
import QtQuick
import QtQuick.Layouts
import QtQuick.Particles
import org.kde.kirigami as Kirigami
Item {
id: root
property bool enabled: false
property int effectInterval: Kirigami.Units.veryLongDuration * 10
property color darkSnowColor: "grey"
property bool isThemeDark: Kirigami.Theme.backgroundColor.hslLightness <= darkSnowColor.hslLightness
function showConfettiEffect() {
confettiTimer.start();
}
function showSnowEffect() {
snowTimer.start();
}
function showFireworksEffect() {
fireworksTimer.start();
}
// Confetti
Timer {
id: confettiTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
confettiSystem.running = !confettiSystem.running;
}
}
}
ParticleSystem {
id: confettiSystem
anchors.fill: parent
running: false
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
ImageParticle {
source: "qrc:/qt/qml/org/kde/neochat/qml/confetti.png"
entryEffect: ImageParticle.Scale
rotationVariation: 360
rotationVelocity: 90
color: Qt.hsla(Math.random(), 0.5, 0.6, 1)
colorVariation: 1
}
Emitter {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
sizeVariation: Kirigami.Units.iconSizes.small / 2
lifeSpan: Kirigami.Units.veryLongDuration * 10
size: Kirigami.Units.iconSizes.small
velocity: AngleDirection {
angle: 90
angleVariation: 42
magnitude: 500
}
}
}
// Snow
Timer {
id: snowTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
snowSystem.running = !snowSystem.running;
}
}
}
ParticleSystem {
id: snowSystem
anchors.fill: parent
running: false
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
ItemParticle {
delegate: Rectangle {
width: 10
height: width
radius: width
color: root.isThemeDark ? "white" : darkSnowColor
scale: Math.random()
opacity: Math.random()
}
}
Emitter {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
sizeVariation: Kirigami.Units.iconSizes.medium
lifeSpan: Kirigami.Units.veryLongDuration * 10
size: Kirigami.Units.iconSizes.large
emitRate: 42
velocity: AngleDirection {
angle: 90
angleVariation: 10
magnitude: 300
}
}
}
// Fireworks
Timer {
id: fireworksTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
fireworksInternalTimer.running = !fireworksInternalTimer.running;
}
}
}
Timer {
id: fireworksInternalTimer
interval: 300
triggeredOnStart: true
running: false
repeat: true
onTriggered: {
var x = Math.random() * parent.width;
var y = Math.random() * parent.height;
customEmit(x, y);
customEmit(x, y);
customEmit(x, y);
}
}
ParticleSystem {
id: fireworksSystem
anchors.fill: parent
running: fireworksInternalTimer.running
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
}
ImageParticle {
id: fireworksParticleA
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["a"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
ImageParticle {
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
color: root.isThemeDark ? "white" : "gold"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["light"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
ImageParticle {
id: fireworksParticleB
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["b"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
Component {
id: emitterComp
Emitter {
id: container
property int life: 23
property real targetX: 0
property real targetY: 0
width: 1
height: 1
system: fireworksSystem
size: 16
endSize: 8
sizeVariation: 5
Timer {
interval: life
running: true
onTriggered: {
container.destroy();
var randomHue = Math.random();
var lightness = root.isThemeDark ? 0.8 : 0.7;
fireworksParticleA.color = Qt.hsla(randomHue, 0.8, lightness, 1);
fireworksParticleB.color = Qt.hsla(1 - randomHue, 0.8, lightness, 1);
}
}
velocity: AngleDirection {
angleVariation: 360
magnitude: 200
}
}
}
function customEmit(x, y) {
var currentSize = Math.round(Math.random() * 200) + 40;
var currentLifeSpan = Math.round(Math.random() * 1000) + 100;
for (var i = 0; i < 8; i++) {
var obj = emitterComp.createObject(parent);
obj.x = x;
obj.y = y;
obj.targetX = Math.random() * currentSize - currentSize / 2 + obj.x;
obj.targetY = Math.random() * currentSize - currentSize / 2 + obj.y;
obj.life = Math.round(Math.random() * 23) + 150;
obj.emitRate = Math.round(Math.random() * 32) + 5;
obj.lifeSpan = currentLifeSpan;
const group = Math.round(Math.random() * 3);
switch (group) {
case 0:
obj.group = "light";
break;
case 1:
obj.group = "a";
break;
case 2:
obj.group = "b";
break;
}
}
}
}

View File

@@ -16,6 +16,8 @@ Kirigami.ApplicationWindow {
property NeoChatConnection connection: Controller.activeConnection
title: Config.windowTitleFocus ? activeFocusItem + " " + (activeFocusItem ? activeFocusItem.Accessible.name : "") : "NeoChat"
minimumWidth: Kirigami.Units.gridUnit * 20
minimumHeight: Kirigami.Units.gridUnit * 15
@@ -96,12 +98,9 @@ Kirigami.ApplicationWindow {
}
}
Loader {
id: quickView
active: !Kirigami.Settings.isMobile
sourceComponent: QuickSwitcher {
connection: root.connection
}
QuickSwitcher {
id: quickSwitcher
connection: root.connection
}
Connections {
@@ -160,8 +159,11 @@ Kirigami.ApplicationWindow {
connection: root.connection
handleOpenIcon.source: "arrow-right"
handleClosedIcon.source: "arrow-left"
handleClosedIcon.source: "documentinfo-symbolic"
handleClosedToolTip: i18nc("@action:button", "Show Room Information")
// Default icon is fine, only need to override the tooltip text
handleOpenToolTip: i18nc("@action:button", "Close Room Information Drawer")
// Connect to the onClicked function of the RoomDrawer handle button
Connections {
@@ -221,6 +223,8 @@ Kirigami.ApplicationWindow {
RoomListPage {
id: roomList
onSearch: quickSwitcher.open()
connection: root.connection
Shortcut {

View File

@@ -6,6 +6,7 @@ import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components
import org.kde.kitemmodels
import org.kde.neochat
@@ -19,10 +20,10 @@ QQC2.Dialog {
width: Math.min(700, parent.width)
height: 400
leftPadding: 0
rightPadding: 0
bottomPadding: 1
topPadding: 0
leftPadding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
topPadding: Kirigami.Units.smallSpacing
anchors.centerIn: applicationWindow().overlay
@@ -40,53 +41,60 @@ QQC2.Dialog {
roomList.currentIndex = 0;
}
header: Kirigami.SearchField {
id: searchField
Keys.onDownPressed: {
roomList.forceActiveFocus();
if (roomList.currentIndex < roomList.count - 1) {
roomList.currentIndex++;
} else {
roomList.currentIndex = 0;
background: DialogRoundedBackground {}
contentItem: ColumnLayout {
Kirigami.SearchField {
id: searchField
Layout.fillWidth: true
Keys.onDownPressed: {
roomList.forceActiveFocus();
if (roomList.currentIndex < roomList.count - 1) {
roomList.currentIndex++;
} else {
roomList.currentIndex = 0;
}
}
}
Keys.onUpPressed: {
if (roomList.currentIndex === 0) {
roomList.currentIndex = roomList.count - 1;
} else {
roomList.currentIndex--;
Keys.onUpPressed: {
if (roomList.currentIndex === 0) {
roomList.currentIndex = roomList.count - 1;
} else {
roomList.currentIndex--;
}
}
Keys.onEnterPressed: {
RoomManager.resolveResource(roomList.currentItem.currentRoom.id);
root.close();
}
Keys.onReturnPressed: {
RoomManager.resolveResource(roomList.currentItem.currentRoom.id);
root.close();
}
focusSequence: ""
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
}
Keys.onEnterPressed: {
RoomManager.resolveResource(roomList.currentItem.currentRoom.id);
root.close();
}
Keys.onReturnPressed: {
RoomManager.resolveResource(roomList.currentItem.currentRoom.id);
root.close();
}
focusSequence: ""
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
}
QQC2.ScrollView {
anchors.fill: parent
clip: true
QQC2.ScrollView {
clip: true
Keys.forwardTo: searchField
ListView {
id: roomList
currentIndex: 0
highlightMoveDuration: 200
Layout.fillWidth: true
Layout.fillHeight: true
Keys.forwardTo: searchField
keyNavigationEnabled: true
model: RoomManager.sortFilterRoomListModel
delegate: RoomDelegate {
connection: root.connection
onClicked: root.close()
ListView {
id: roomList
currentIndex: 0
highlightMoveDuration: 200
Keys.forwardTo: searchField
keyNavigationEnabled: true
model: RoomManager.sortFilterRoomListModel
delegate: RoomDelegate {
connection: root.connection
onClicked: root.close()
showConfigure: false
}
}
}
}

View File

@@ -25,6 +25,8 @@ Delegates.RoundedItemDelegate {
required property string subtitleText
required property string displayName
property bool showConfigure: true
property bool collapsed: false
readonly property bool hasNotifications: contextNotificationCount > 0
@@ -130,7 +132,7 @@ Delegates.RoundedItemDelegate {
QQC2.Button {
id: configButton
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList && !root.collapsed
visible: root.hovered && !Kirigami.Settings.isMobile && !Config.compactRoomList && !root.collapsed && root.showConfigure
text: i18n("Configure room")
display: QQC2.Button.IconOnly

View File

@@ -31,6 +31,8 @@ Kirigami.OverlayDrawer {
}
}
onOpened: forceActiveFocus()
MouseArea {
anchors.left: parent.left
anchors.top: parent.top

View File

@@ -76,6 +76,7 @@ QQC2.ScrollView {
visible: !root.room.isSpace
icon.name: "search"
text: i18n("Search in this room")
activeFocusOnTab: true
Layout.fillWidth: true
@@ -96,6 +97,8 @@ QQC2.ScrollView {
onClicked: root.room.isFavourite ? root.room.removeTag("m.favourite") : root.room.addTag("m.favourite", 1.0)
activeFocusOnTab: true
Layout.fillWidth: true
}
@@ -104,6 +107,7 @@ QQC2.ScrollView {
visible: !root.room.isSpace
icon.name: "map-flat"
text: i18n("Show locations for this room")
activeFocusOnTab: true
onClicked: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'LocationsPage'), {
room: root.room
@@ -118,6 +122,7 @@ QQC2.ScrollView {
id: leaveButton
icon.name: "arrow-left"
text: i18nc("@action:button", "Leave this room")
activeFocusOnTab: true
Layout.fillWidth: true
@@ -193,11 +198,12 @@ QQC2.ScrollView {
model: root.room.isDirectChat() ? 0 : sortedMessageEventModel
clip: true
activeFocusOnTab: true
focus: true
delegate: Delegates.RoundedItemDelegate {
id: userDelegate
required property int index
required property string name
required property string userId
required property string avatar
@@ -208,6 +214,9 @@ QQC2.ScrollView {
text: name
KeyNavigation.tab: navigationBar.tabGroup.checkedButton
KeyNavigation.backtab: index === 0 ? userList.headerItem.userListSearchField : null
onClicked: {
userDelegate.highlighted = true;
RoomManager.resolveResource(userDelegate.userId, "mention");
@@ -260,8 +269,8 @@ QQC2.ScrollView {
}
onRoomChanged: {
if (root.headerItem) {
root.headerItem.userListSearchField.text = "";
if (userList.headerItem) {
userList.headerItem.userListSearchField.text = "";
}
userList.currentIndex = -1;
}

View File

@@ -29,6 +29,8 @@ Kirigami.Page {
readonly property bool collapsed: Config.collapsed
signal search
onCurrentWidthChanged: pageStack.defaultColumnWidth = root.currentWidth
Component.onCompleted: pageStack.defaultColumnWidth = root.currentWidth
@@ -40,41 +42,41 @@ Kirigami.Page {
}
function goToNextRoomFiltered(condition) {
let index = treeView.currentIndex;
while (index++ !== treeView.count - 1) {
if (condition(treeView.itemAtIndex(index))) {
treeView.currentIndex = index;
treeView.currentItem.clicked();
let index = treeView.rowAtIndex(RoomManager.sortFilterRoomTreeModel.currentRoomIndex());
while (index++ < treeView.rows) {
let item = treeView.itemAtIndex(treeView.index(index, 0))
if (condition(item)) {
RoomManager.resolveResource(item.currentRoom.id)
return;
}
}
}
function goToPreviousRoomFiltered(condition) {
let index = treeView.currentIndex;
while (index-- !== 0) {
if (condition(treeView.itemAtIndex(index))) {
treeView.currentIndex = index;
treeView.currentItem.clicked();
let index = treeView.rowAtIndex(RoomManager.sortFilterRoomTreeModel.currentRoomIndex());
while (index-- > 0) {
let item = treeView.itemAtIndex(treeView.index(index, 0))
if (condition(item)) {
RoomManager.resolveResource(item.currentRoom.id)
return;
}
}
}
function goToNextRoom() {
goToNextRoomFiltered(item => item.visible);
goToNextRoomFiltered(item => (item && item instanceof RoomDelegate));
}
function goToPreviousRoom() {
goToPreviousRoomFiltered(item => item.visible);
goToPreviousRoomFiltered(item => (item && item instanceof RoomDelegate));
}
function goToNextUnreadRoom() {
goToNextRoomFiltered(item => (item.visible && item.hasUnread));
goToNextRoomFiltered(item => (item && item instanceof RoomDelegate && item.hasUnread));
}
function goToPreviousUnreadRoom() {
goToPreviousRoomFiltered(item => (item.visible && item.hasUnread));
goToPreviousRoomFiltered(item => (item && item instanceof RoomDelegate && item.hasUnread));
}
titleDelegate: Loader {
@@ -89,6 +91,10 @@ Kirigami.Page {
function onCurrentSpaceChanged() {
treeView.expandRecursively();
}
function onCurrentRoomChanged() {
treeView.positionViewAtIndex(RoomManager.sortFilterRoomTreeModel.currentRoomIndex(), TableView.AlignVCenter)
}
}
RowLayout {
@@ -160,22 +166,6 @@ Kirigami.Page {
}
}
DelegateChoice {
roleValue: "search"
delegate: Delegates.RoundedItemDelegate {
required property TreeView treeView
implicitWidth: treeView.width
onClicked: quickView.item.open()
contentItem: Kirigami.Icon {
width: Kirigami.Units.iconSizes.smallMedium
height: Kirigami.Units.iconSizes.smallMedium
source: "search"
}
}
}
DelegateChoice {
roleValue: "addDirect"
delegate: Delegates.RoundedItemDelegate {
@@ -308,6 +298,8 @@ Kirigami.Page {
collapsed: root.collapsed
connection: root.connection
onSearch: root.search()
onTextChanged: newText => {
RoomManager.sortFilterRoomTreeModel.filterText = newText;
treeView.expandRecursively();

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