Compare commits

..

14 Commits

Author SHA1 Message Date
Joshua Goins
49e4fd1b00 Overhaul video player 2025-05-20 18:08:23 -04:00
James Graham
a1ca768711 Use the forget function to leave a room everywhere
Use the forget function to leave a room everywhere this is both for consistency and to reduce dependencies. This way no dependency on RoomManager is required to leave a room and since in all cases they have an object they can just call the function.
2025-05-20 17:35:34 +01:00
l10n daemon script
f0d2c19393 GIT_SILENT Sync po/docbooks with svn 2025-05-20 01:39:59 +00:00
Carl Schwan
67db05a0c3 Adapt API to ConvergentContextMenu change
Use close instead of using internal menuItem
2025-05-19 18:59:45 +02:00
Ritchie Frodomar
05e932b884 Move typing indicators closer to messages
This merge request addresses a minor papercut in NeoChat's layout when using a screen magnifier.

If you are zoomed in on a conversation, typing indicators are generally invisible. This merge request moves them to align with actual messages, making them more visible to screen magnifier users like myself. That way, you can do the text chat equivalent of waiting for someone else to finish talking before you ramble on.

### Before
![Screenshot of NeoChat in a test conversation. A user is typing. The typing pane is very far off to the left, not visible when zoomed in.](https://cdn.acidiclight.dev/images/2025/04/03/31d836b18875.png)

### After
![Screenshot of the typing indicator in a conversation. The typing pane now aligns with the chatbar and messages.](https://cdn.acidiclight.dev/images/2025/04/03/870ace40ce86.png)
2025-05-19 12:07:02 -04:00
l10n daemon script
763713cd32 GIT_SILENT Sync po/docbooks with svn 2025-05-19 01:42:11 +00:00
Joshua Goins
2687448212 Add header to UserMenu for mobile which has the user info
To give a little bit more context, and it also matches the message
context menu which does the same.
2025-05-18 20:00:21 -04:00
Joshua Goins
d059195e92 Add user menu that is opened via right-clicking/long-tapped on avatar
We can un-clutter our message context menu, which we had to share
with user actions. (Even though we only had one so far.) I added one new
user-specific action which allows you to quickly mention the user in
chat. Otherwise you would've had to copy their username or use the
completion menu.

It's convergent on mobile, it still has the hover indicator and it also
is available through the AuthorComponent.

BUG: 486252
2025-05-18 20:00:20 -04:00
James Graham
6ef7acc8e5 Remove any dependencies on App from the spaces module.
Remove any dependencies on App from the spaces module. This requires moving some dialogs either to spaces, or libneochat if they're used more generically.
2025-05-18 14:38:57 +01:00
l10n daemon script
2cb89807ef GIT_SILENT Sync po/docbooks with svn 2025-05-18 01:40:43 +00:00
Joshua Goins
b5fcad3db0 Fix multiple Global menu issues
See individual commits. When backporting, I'll create a separate patchset just for the we-broke-something-bugs without the strings.
2025-05-17 21:21:38 -04:00
Joshua Goins
d3fd441c88 Improve the "Create a Room/Space" and "Select Existing Room" dialog
First of all, these are now all separate dialogs instead of shoving all
of these functions (which are only marginally related) into one single
dialog. We also convert these to in-app Kirigami Dialogs, which look a
bit nicer. I also touched up the UX in some places, such as adding
descriptions which were previously available to translators. I also hid
some not oft used options like setting a topic, which almost nobody does
before creating a room/space.
2025-05-17 21:09:43 -04:00
Joshua Goins
e9568b50fc If the message body is empty, say so
Normally if a malformed event is empty it will just be empty space - but
that looks buggy. Instead, we can add a message saying "This event does
not have any content."

BUG: 494093
2025-05-17 21:09:25 -04:00
James Graham
e7040a518a Create a new module for the room info drawer QML.
Create a new module for the room info drawer QML. This also requires moving some QML to LibNeoChat common with other modules. Finally all QML in roominfo is modifed to not depend on app.
2025-05-17 14:27:38 +01:00
119 changed files with 28722 additions and 22412 deletions

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

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

@@ -8,6 +8,7 @@ endif()
add_subdirectory(libneochat)
add_subdirectory(login)
add_subdirectory(rooms)
add_subdirectory(roominfo)
add_subdirectory(timeline)
add_subdirectory(spaces)
add_subdirectory(chatbar)

View File

@@ -8,8 +8,6 @@ add_library(neochat STATIC
controller.h
roommanager.cpp
roommanager.h
models/userfiltermodel.cpp
models/userfiltermodel.h
models/userdirectorylistmodel.cpp
models/userdirectorylistmodel.h
notificationsmanager.cpp
@@ -58,10 +56,8 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/AccountMenu.qml
qml/CollapsedRoomDelegate.qml
qml/RoomPage.qml
qml/ExploreRoomsPage.qml
qml/ManualRoomDialog.qml
qml/ExplorerDelegate.qml
qml/InviteUserPage.qml
qml/ImageEditorPage.qml
qml/NeochatMaximizeComponent.qml
qml/TypingPane.qml
@@ -69,7 +65,6 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/AttachmentPane.qml
qml/QuickFormatBar.qml
qml/UserDetailDialog.qml
qml/CreateRoomDialog.qml
qml/OpenFileDialog.qml
qml/KeyVerificationDialog.qml
qml/ConfirmLogoutDialog.qml
@@ -79,26 +74,14 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/EmojiSas.qml
qml/VerificationCanceled.qml
qml/MessageSourceSheet.qml
qml/RoomSearchPage.qml
qml/RoomPinnedMessagesPage.qml
qml/LocationChooser.qml
qml/InvitationView.qml
qml/AvatarTabButton.qml
qml/OsmLocationPlugin.qml
qml/FullScreenMap.qml
qml/LocationsPage.qml
qml/LocationMapItem.qml
qml/RoomDrawer.qml
qml/RoomDrawerPage.qml
qml/DirectChatDrawerHeader.qml
qml/GroupChatDrawerHeader.qml
qml/RoomInformation.qml
qml/RoomMedia.qml
qml/ChooseRoomDialog.qml
qml/RemoveChildDialog.qml
qml/QrCodeMaximizeComponent.qml
qml/NotificationsView.qml
qml/SearchPage.qml
qml/ServerComboBox.qml
qml/UserSearchPage.qml
qml/ManualUserDialog.qml
@@ -118,12 +101,14 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/AvatarNotification.qml
qml/ReasonDialog.qml
qml/NewPollDialog.qml
qml/UserMenu.qml
DEPENDENCIES
QtCore
QtQuick
IMPORTS
org.kde.neochat.libneochat
org.kde.neochat.rooms
org.kde.neochat.roominfo
org.kde.neochat.timeline
org.kde.neochat.spaces
org.kde.neochat.settings
@@ -189,7 +174,7 @@ else()
endif()
target_include_directories(neochat PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/models)
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
target_link_libraries(neochat PRIVATE Loginplugin Roomsplugin RoomInfoplugin Timelineplugin Spacesplugin Chatbarplugin Settingsplugin Devtoolsplugin)
target_link_libraries(neochat PUBLIC
LibNeoChat
Timeline

View File

@@ -32,6 +32,7 @@
#include "neochatroom.h"
#include "notificationsmanager.h"
#include "proxycontroller.h"
#include "roommanager.h"
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
#include "trayicon.h"
@@ -230,6 +231,7 @@ void Controller::initConnection(NeoChatConnection *connection)
m_notificationsManager.handleNotifications(connection);
});
connect(this, &Controller::globalUrlPreviewDefaultChanged, connection, &NeoChatConnection::globalUrlPreviewEnabledChanged);
connect(connection, &NeoChatConnection::roomAboutToBeLeft, &RoomManager::instance(), &RoomManager::roomLeft);
Q_EMIT connectionAdded(connection);
}

View File

@@ -276,7 +276,7 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *rawRoom)
if (inAnyOfOurRooms) {
doPostInviteNotification(room);
} else {
room->leaveRoom();
room->forget();
}
}
});
@@ -330,14 +330,14 @@ void NotificationsManager::doPostInviteNotification(QPointer<NeoChatRoom> room)
if (!room) {
return;
}
RoomManager::instance().leaveRoom(room);
room->forget();
notification->close();
});
connect(rejectAndIgnoreAction, &KNotificationAction::activated, this, [room, notification]() {
if (!room) {
return;
}
RoomManager::instance().leaveRoom(room);
room->forget();
room->connection()->addToIgnoredUsers(room->invitingUserId());
notification->close();
});

View File

@@ -92,7 +92,7 @@ KirigamiComponents.ConvergentContextMenu {
const dialog = Qt.createComponent("org.kde.kirigami", "PromptDialog").createObject(QQC2.Overlay.overlay, {
title: i18nc("@title", "Verification Request Sent"),
subtitle: i18nc("@info:label", "To proceed, accept the verification request on another device."),
standardButtons: QQC2.Dialog.Ok
standardButtons: Kirigami.Dialog.Ok
})
dialog.open();
root.connection.onNewKeyVerificationSession.connect(() => {

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
@@ -12,7 +11,7 @@ import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
required property NeoChatConnection connection
@@ -24,7 +23,7 @@ QQC2.Dialog {
topPadding: 0
bottomPadding: 0
standardButtons: QQC2.Dialog.NoButton
standardButtons: Kirigami.Dialog.NoButton
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title: dialog to switch between logged in accounts", "Switch Account")

View File

@@ -8,30 +8,33 @@ import org.kde.kirigami as Kirigami
import org.kde.neochat
Kirigami.PromptDialog {
Kirigami.Dialog {
id: root
required property var user
title: i18nc("@title:dialog", "Start a chat")
subtitle: i18n("Do you want to start a chat with %1?", root.user.displayName)
dialogType: Kirigami.PromptDialog.Warning
width: Math.min(Kirigami.Units.gridUnit * 24, QQC2.ApplicationWindow.window.width)
height: Kirigami.Units.gridUnit * 8
onRejected: {
root.close();
standardButtons: QQC2.Dialog.Close
title: i18nc("@title:dialog", "Start a chat")
contentItem: QQC2.Label {
text: i18n("Do you want to start a chat with %1?", root.user.displayName)
textFormat: Text.PlainText
wrapMode: Text.Wrap
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
}
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
customFooterActions: [
Kirigami.Action {
text: i18nc("@action:button", "Start Chat")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "im-user"
onClicked: {
onTriggered: {
root.user.requestDirectChat();
root.close();
}
}
}
]
}

View File

@@ -28,7 +28,7 @@ Kirigami.PromptDialog {
text: i18nc("@action:button", "Leave Room")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "arrow-left-symbolic"
onClicked: RoomManager.leaveRoom(root.room)
onClicked: root.room.forget();
}
}
}

View File

@@ -8,30 +8,32 @@ import org.kde.kirigami as Kirigami
import org.kde.neochat
Kirigami.PromptDialog {
Kirigami.Dialog {
id: root
required property string url
width: Math.min(Kirigami.Units.gridUnit * 24, QQC2.ApplicationWindow.window.width)
height: Kirigami.Units.gridUnit * 8
leftPadding: Kirigami.Units.largeSpacing
rightPadding: Kirigami.Units.largeSpacing
title: i18nc("@title:dialog", "User Consent")
subtitle: i18nc("@info", "Your homeserver requires you to agree to its terms and conditions before being able to use it. Please click the button below to read them.")
dialogType: Kirigami.PromptDialog.Warning
onRejected: {
root.close();
contentItem: QQC2.Label {
text: i18nc("@info", "Your homeserver requires you to agree to its terms and conditions before being able to use it. Please click the button below to read them.")
wrapMode: Text.WordWrap
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
}
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
customFooterActions: [
Kirigami.Action {
text: i18nc("@action:button", "Open")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "internet-services"
onClicked: {
onTriggered: {
UrlHelper.openUrl(root.url);
root.close();
}
}
}
]
}

View File

@@ -8,6 +8,8 @@ import QtPositioning
import org.kde.kirigami as Kirigami
import org.kde.neochat.libneochat
ApplicationWindow {
id: root

View File

@@ -15,7 +15,7 @@ import org.kde.neochat.settings
Labs.MenuBar {
id: root
property NeoChatConnection connection
required property NeoChatConnection connection
Labs.Menu {
title: i18nc("menu", "NeoChat")
@@ -38,25 +38,31 @@ Labs.MenuBar {
title: i18nc("menu", "File")
Labs.MenuItem {
text: i18nc("menu", "Find your friends")
icon.name: "list-add-user"
text: i18nc("@action:inmenu", "Find your Friends")
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
onTriggered: pushReplaceLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage'), {
connection: root.connection
}, {
title: i18nc("@title", "Find your friends")
})
}
Labs.MenuItem {
text: i18nc("menu", "New Group…")
icon.name: "system-users-symbolic"
text: i18nc("@action:inmenu", "Create a Room…")
enabled: pageStack.layers.currentItem.title !== i18n("Find your friends") && AccountRegistry.accountCount > 0
shortcut: StandardKey.New
onTriggered: {
const dialog = createRoomDialog.createObject(root.overlay);
dialog.open();
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
connection: root.connection
}, {
title: i18nc("@title", "Create a Room")
});
}
}
Labs.MenuItem {
text: i18nc("menu", "Browse Chats…")
icon.name: "compass-symbolic"
text: i18nc("@action:inmenu", "Explore Rooms")
onTriggered: {
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
connection: root.connection
@@ -77,7 +83,8 @@ Labs.MenuBar {
title: i18nc("menu", "View")
Labs.MenuItem {
text: i18nc("menu item that opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Open Quick Switcher")
icon.name: "search-symbolic"
text: i18nc("@action:inmenu opens a UI element called the 'Quick Switcher', which offers a fast keyboard-based interface for switching in between chats.", "Search Rooms")
onTriggered: quickSwitcher.open()
}
}
@@ -85,6 +92,7 @@ Labs.MenuBar {
title: i18nc("menu", "Window")
Labs.MenuItem {
icon.name: "view-fullscreen-symbolic"
text: root.visibility === Window.FullScreen ? i18nc("menu", "Exit Full Screen") : i18nc("menu", "Enter Full Screen")
onTriggered: root.visibility === Window.FullScreen ? root.showNormal() : root.showFullScreen()
}
@@ -93,14 +101,12 @@ Labs.MenuBar {
title: i18nc("menu", "Help")
Labs.MenuItem {
text: i18nc("menu", "About Matrix")
onTriggered: UrlHelper.openUrl("https://matrix.org/docs/chat_basics/matrix-for-im/")
}
Labs.MenuItem {
icon.name: "help-about-symbolic"
text: i18nc("menu", "About NeoChat")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutPage"))
}
Labs.MenuItem {
icon.name: "kde-symbolic"
text: i18nc("menu", "About KDE")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent("org.kde.kirigamiaddons.formcard", "AboutKDEPage"))
}

View File

@@ -108,7 +108,7 @@ ColumnLayout {
icon.name: "dialog-cancel-symbolic"
text: i18nc("@action:button Reject this invite", "Reject Invite")
onClicked: RoomManager.leaveRoom(root.currentRoom)
onClicked: root.currentRoom.forget()
}
}
@@ -123,7 +123,7 @@ ColumnLayout {
text: i18nc("@action:button Block the user", "Block %1", root.invitingMember.displayName)
onClicked: {
RoomManager.leaveRoom(root.currentRoom);
root.currentRoom.forget()
root.currentRoom.connection.addToIgnoredUsers(root.currentRoom.invitingUserId);
}
}

View File

@@ -12,7 +12,7 @@ import org.kde.prison
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
required property string room
@@ -23,7 +23,7 @@ QQC2.Dialog {
topPadding: 0
bottomPadding: 0
standardButtons: QQC2.Dialog.NoButton
standardButtons: Kirigami.Dialog.NoButton
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title:dialog", "Join Room")

View File

@@ -80,9 +80,8 @@ Kirigami.ApplicationWindow {
Loader {
active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile
sourceComponent: Qt.createComponent("org.kde.neochat", "GlobalMenu")
onActiveChanged: if (active) {
item.connection = root.connection;
sourceComponent: GlobalMenu {
connection: root.connection
}
}
@@ -149,9 +148,13 @@ Kirigami.ApplicationWindow {
}
function openRoomDrawer() {
pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomDrawerPage'), {
connection: root.connection
const page = pageStack.push(Qt.createComponent('org.kde.neochat', 'RoomDrawerPage'), {
connection: root.connection,
room: RoomManager.currentRoom,
userListModel: RoomManager.userListModel,
mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
});
page.resolveResource.connect((idOrUri, action) => RoomManager.resolveResource(idOrUri, action))
}
contextDrawer: RoomDrawer {
@@ -161,7 +164,18 @@ Kirigami.ApplicationWindow {
// It is used to ensure that user choice is remembered when changing pages and expanding and contracting the window width
property bool drawerUserState: NeoChatConfig.autoRoomInfoDrawer
room: RoomManager.currentRoom
connection: root.connection
userListModel: RoomManager.userListModel
mediaMessageFilterModel: RoomManager.mediaMessageFilterModel
onResolveResource: (idOrUri, action) => RoomManager.resolveResource(idOrUri, action)
roomDrawerWidth: NeoChatConfig.roomDrawerWidth
onRoomDrawerWidthChanged: {
NeoChatConfig.roomDrawerWidth = actualWidth;
NeoChatConfig.save();
}
handleClosedIcon.source: "documentinfo-symbolic"
handleClosedToolTip: i18nc("@action:button", "Show Room Information")

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Window
import QtQuick.Layouts
@@ -11,7 +10,7 @@ import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
/**
@@ -32,41 +31,35 @@ QQC2.Dialog {
topPadding: 0
bottomPadding: 0
footer: QQC2.DialogButtonBox {
QQC2.Button {
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
standardButtons: Kirigami.Dialog.Cancel
customFooterActions: [
Kirigami.Action {
enabled: roomIdAliasText.isValidText
text: i18n("OK")
icon.name: "dialog-ok"
onTriggered: {
// We don't necessarily have all the info so fill out the best we can.
let roomId = roomIdAliasText.isAlias() ? "" : roomIdAliasText.text;
let displayName = "";
let avatarUrl = "";
let alias = roomIdAliasText.isAlias() ? roomIdAliasText.text : "";
let topic = "";
let memberCount = -1;
let isJoined = false;
if (roomIdAliasText.room) {
roomId = roomIdAliasText.room.id;
displayName = roomIdAliasText.room.displayName;
avatarUrl = roomIdAliasText.room.avatarUrl.toString().length > 0 ? connection.makeMediaUrl(roomIdAliasText.room.avatarUrl) : "";
alias = roomIdAliasText.room.canonicalAlias;
topic = roomIdAliasText.room.topic;
memberCount = roomIdAliasText.room.joinedCount;
isJoined = true;
}
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.close();
}
}
QQC2.Button {
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
text: i18n("Cancel")
icon.name: "dialog-cancel"
}
}
onAccepted: {
// We don't necessarily have all the info so fill out the best we can.
let roomId = roomIdAliasText.isAlias() ? "" : roomIdAliasText.text;
let displayName = "";
let avatarUrl = "";
let alias = roomIdAliasText.isAlias() ? roomIdAliasText.text : "";
let topic = "";
let memberCount = -1;
let isJoined = false;
if (roomIdAliasText.room) {
roomId = roomIdAliasText.room.id;
displayName = roomIdAliasText.room.displayName;
avatarUrl = roomIdAliasText.room.avatarUrl.toString().length > 0 ? connection.makeMediaUrl(roomIdAliasText.room.avatarUrl) : "";
alias = roomIdAliasText.room.canonicalAlias;
topic = roomIdAliasText.room.topic;
memberCount = roomIdAliasText.room.joinedCount;
isJoined = true;
}
root.roomSelected(roomId, displayName, avatarUrl, alias, topic, memberCount, isJoined);
root.close();
}
]
contentItem: ColumnLayout {
spacing: 0

View File

@@ -10,7 +10,7 @@ import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
/**
@@ -31,6 +31,19 @@ QQC2.Dialog {
topPadding: 0
bottomPadding: 0
standardButtons: Kirigami.Dialog.Cancel
customFooterActions: [
Kirigami.Action {
enabled: userIdText.isValidText
text: i18n("OK")
icon.name: "dialog-ok"
onTriggered: {
root.connection.requestDirectChat(userIdText.text);
root.accept();
}
}
]
contentItem: ColumnLayout {
spacing: 0
FormCard.FormTextFieldDelegate {
@@ -62,21 +75,6 @@ QQC2.Dialog {
}
}
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
enabled: userIdText.isValidText
text: i18n("OK")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "dialog-ok"
onClicked: {
root.connection.requestDirectChat(userIdText.text);
root.accept();
}
}
}
onVisibleChanged: {
userIdText.forceActiveFocus();
timer.restart();

View File

@@ -15,18 +15,27 @@ import Quotient
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
required property NeoChatRoom room
title: i18nc("@title: create new poll in the room", "Create Poll")
standardButtons: Kirigami.Dialog.Cancel
customFooterActions: [
Kirigami.Action {
enabled: optionModel.allValuesSet && questionTextField.text.length > 0
text: i18nc("@action:button", "Send")
icon.name: "document-send"
onTriggered: {
root.room.postPoll(pollTypeCombo.currentValue, questionTextField.text, optionModel.values())
root.close()
}
}
]
width: Math.min(applicationWindow().width, Kirigami.Units.gridUnit * 24)
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
title: i18nc("@title: create new poll in the room", "Create Poll")
contentItem: ColumnLayout {
spacing: 0
@@ -144,19 +153,4 @@ QQC2.Dialog {
onClicked: optionModel.append({optionText: ""})
}
}
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
enabled: optionModel.allValuesSet && questionTextField.text.length > 0
text: i18nc("@action:button", "Send")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "document-send"
onClicked: {
root.room.postPoll(pollTypeCombo.currentValue, questionTextField.text, optionModel.values())
root.close()
}
}
}
}

View File

@@ -10,11 +10,13 @@ import org.kde.kirigamiaddons.components
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
property var connection
parent: applicationWindow().overlay
leftPadding: 0
rightPadding: 0
topPadding: 0

View File

@@ -137,7 +137,9 @@ Kirigami.Page {
id: spaceLoader
active: root.currentRoom && root.currentRoom.isSpace
anchors.fill: parent
sourceComponent: SpaceHomePage {}
sourceComponent: SpaceHomePage {
room: root.currentRoom
}
}
Loader {

View File

@@ -102,7 +102,7 @@ QQC2.ComboBox {
}
}
QQC2.Dialog {
Kirigami.Dialog {
id: addServerSheet
width: Math.min(Kirigami.Units.gridUnit * 15, QQC2.ApplicationWindow.window.width)
@@ -182,19 +182,15 @@ QQC2.ComboBox {
}
}
footer: QQC2.DialogButtonBox {
QQC2.Button {
enabled: serverUrlField.acceptableInput && serverUrlField.isValidServer
text: i18nc("@action:button", "Ok")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "dialog-ok"
onClicked: {
serverListModel.addServer(serverUrlField.text);
root.currentIndex = root.indexOfValue(serverUrlField.text);
root.server = root.currentValue;
serverUrlField.text = "";
addServerSheet.close();
}
customFooterActions: Kirigami.Action {
text: i18nc("@action:button", "Ok")
enabled: serverUrlField.acceptableInput && serverUrlField.isValidServer
onTriggered: {
serverListModel.addServer(serverUrlField.text);
root.currentIndex = root.indexOfValue(serverUrlField.text);
root.server = root.currentValue;
serverUrlField.text = "";
addServerSheet.close();
}
}
}

View File

@@ -13,7 +13,7 @@ import org.kde.prison
import org.kde.neochat
QQC2.Dialog {
Kirigami.Dialog {
id: root
// This dialog is sometimes used outside the context of a room, e.g., when scanning a user's QR code.
@@ -28,7 +28,7 @@ QQC2.Dialog {
topPadding: 0
bottomPadding: 0
standardButtons: QQC2.Dialog.NoButton
standardButtons: Kirigami.Dialog.NoButton
width: Math.min(QQC2.ApplicationWindow.window.width, Kirigami.Units.gridUnit * 24)
title: i18nc("@title:menu Account details dialog", "Account Details")

74
src/app/qml/UserMenu.qml Normal file
View File

@@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.components as KirigamiComponents
import org.kde.neochat
import org.kde.neochat.settings
import org.kde.neochat.devtools
KirigamiComponents.ConvergentContextMenu {
id: root
required property Kirigami.ApplicationWindow window
required property var author
headerContentItem: RowLayout {
id: detailRow
spacing: Kirigami.Units.largeSpacing
KirigamiComponents.Avatar {
id: avatar
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
name: root.author.displayName
source: root.author.avatarUrl
color: root.author.color
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
Kirigami.Heading {
level: 1
Layout.fillWidth: true
font.bold: true
elide: Text.ElideRight
wrapMode: Text.NoWrap
text: root.author.displayName
textFormat: Text.PlainText
}
QQC2.Label {
id: idLabel
textFormat: TextEdit.PlainText
text: root.author.id
elide: Qt.ElideRight
}
}
}
QQC2.Action {
text: i18nc("@action:button", "Open Profile")
icon.name: "im-user-symbolic"
onTriggered: RoomManager.resolveResource(root.author.uri)
}
QQC2.Action {
text: i18nc("@action:button", "Mention")
icon.name: "username-copy-symbolic"
onTriggered: {
RoomManager.currentRoom.mainCache.mentionAdded(root.author.id);
}
}
}

View File

@@ -448,29 +448,27 @@ void RoomManager::knockRoom(NeoChatConnection *account, const QString &roomAlias
Qt::SingleShotConnection);
}
void RoomManager::roomLeft(const QString &id)
{
if (id.isEmpty()) {
return;
}
if (m_currentRoom && m_currentRoom->id() == id) {
setCurrentRoom({});
}
if (m_currentSpaceId == id) {
setCurrentSpace({});
}
}
bool RoomManager::visitNonMatrix(const QUrl &url)
{
UrlHelper().openUrl(url);
return true;
}
void RoomManager::leaveRoom(NeoChatRoom *room)
{
if (!room) {
return;
}
if (m_currentRoom && m_currentRoom->id() == room->id()) {
setCurrentRoom({});
}
if (m_currentSpaceId == room->id()) {
setCurrentSpace({});
}
room->forget();
}
ChatDocumentHandler *RoomManager::chatDocumentHandler() const
{
return m_chatDocumentHandler;

View File

@@ -195,11 +195,6 @@ public:
*/
Q_INVOKABLE void loadInitialRoom();
/**
* @brief Leave the room and close it if it is open.
*/
Q_INVOKABLE void leaveRoom(NeoChatRoom *room);
/**
* @brief Knock a room.
*
@@ -208,6 +203,13 @@ public:
*/
void knockRoom(NeoChatConnection *account, const QString &roomAliasOrId, const QString &reason, const QStringList &viaServers);
/**
* @brief Cleanup after the given room is left.
*
* This ensures that the current room and space are not set to the left room.
*/
void roomLeft(const QString &id);
/**
* @brief Show a media item maximized.
*

View File

@@ -55,6 +55,19 @@ QQC2.Control {
}
}
Connections {
target: currentRoom.mainCache
function onMentionAdded(mention: string): void {
// add mention text
textField.append(mention + " ");
// move cursor to the end
textField.cursorPosition = textField.text.length;
// move the focus back to the chat bar
textField.forceActiveFocus(Qt.OtherFocusReason);
}
}
/**
* @brief The list of actions in the ChatBar.
*
@@ -123,7 +136,7 @@ QQC2.Control {
displayHint: QQC2.AbstractButton.IconOnly
onTriggered: {
newPollDialog.createObject(root.QQC2.Overlay.overlay, {
newPollDialog.createObject(QQC2.Overlay.overlay, {
room: root.currentRoom
}).open();
}

View File

@@ -41,12 +41,21 @@ target_sources(LibNeoChat PRIVATE
models/locationsmodel.cpp
models/roomlistmodel.cpp
models/stickermodel.cpp
models/userfiltermodel.cpp
models/userlistmodel.cpp
)
ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
URI org.kde.neochat.libneochat
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/libneochat
QML_FILES
qml/GroupChatDrawerHeader.qml
qml/LocationMapItem.qml
qml/InviteUserPage.qml
qml/ExploreRoomsPage.qml
qml/SearchPage.qml
qml/CreateRoomDialog.qml
qml/CreateSpaceDialog.qml
)
ecm_qt_declare_logging_category(LibNeoChat

View File

@@ -195,6 +195,7 @@ Q_SIGNALS:
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
void attachmentPathChanged();
void mentionAdded(const QString &mention);
private:
QString m_text = QString();

View File

@@ -29,7 +29,7 @@ QStringList rainbowColors{"#ff2b00"_L1, "#ff5500"_L1, "#ff8000"_L1, "#ffaa00"_L1
auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *) {
if (text.isEmpty()) {
Q_EMIT room->showMessage(MessageType::Information, i18n("Leaving this room."));
room->connection()->leaveRoom(room);
room->forget();
} else {
QRegularExpression roomRegex(uR"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)"_s);
auto regexMatch = roomRegex.match(text);
@@ -38,13 +38,13 @@ auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room, ChatBarCache *
i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text));
return QString();
}
auto leaving = room->connection()->room(text);
auto leaving = dynamic_cast<NeoChatRoom *>(room->connection()->room(text));
if (!leaving) {
leaving = room->connection()->roomByAlias(text);
leaving = dynamic_cast<NeoChatRoom *>(room->connection()->roomByAlias(text));
}
if (leaving) {
Q_EMIT room->showMessage(MessageType::Information, i18nc("Leaving room <roomname>.", "Leaving room %1.", text));
room->connection()->leaveRoom(leaving);
leaving->forget();
} else {
Q_EMIT room->showMessage(MessageType::Information, i18nc("Room <roomname> not found", "Room %1 not found.", text));
}

View File

@@ -9,6 +9,7 @@
#include "neochatroom.h"
#include "spacehierarchycache.h"
#include <Quotient/connection.h>
#include <Quotient/jobs/basejob.h>
#include <Quotient/quotient_common.h>
#include <qt6keychain/keychain.h>
@@ -386,6 +387,13 @@ void NeoChatConnection::createSpace(const QString &name, const QString &topic, c
});
}
Quotient::ForgetRoomJob *NeoChatConnection::forgetRoom(const QString &id)
{
Q_EMIT roomAboutToBeLeft(id);
return Connection::forgetRoom(id);
}
bool NeoChatConnection::directChatExists(Quotient::User *user)
{
return directChats().contains(user);

View File

@@ -150,6 +150,14 @@ public:
*/
Q_INVOKABLE void createSpace(const QString &name, const QString &topic, const QString &parent = {}, bool setChildParent = false);
/**
* @brief Send /forget to the server and delete room locally.
*
* @note This wraps around the Quotient::Connection::forgetRoom() to allow
* roomAboutToBeLeft() to be emitted.
*/
Quotient::ForgetRoomJob *forgetRoom(const QString &id);
/**
* @brief Whether a direct chat with the user exists.
*/
@@ -224,6 +232,11 @@ Q_SIGNALS:
*/
void errorOccured(const QString &error);
/**
* @brief The given room ID is about to be forgotten.
*/
void roomAboutToBeLeft(const QString &id);
private:
static bool m_globalUrlPreviewDefault;
static PushRuleAction::Action m_defaultAction;

View File

@@ -305,8 +305,9 @@ void NeoChatRoom::forget()
roomIds += predecessor->id();
}
const auto neochatConnection = dynamic_cast<NeoChatConnection *>(connection());
for (const auto &id : roomIds) {
connection()->forgetRoom(id);
neochatConnection->forgetRoom(id);
}
}

View File

@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.labs.components as Components
import org.kde.neochat
Kirigami.Dialog {
id: root
property string parentId
required property NeoChatConnection connection
signal newChild(string childName)
title: i18nc("@title", "Create Room")
implicitWidth: Kirigami.Units.gridUnit * 20
standardButtons: Kirigami.Dialog.Cancel
customFooterActions: [
Kirigami.Action {
icon.name: "list-add-symbolic"
text: i18nc("@action:button Create new room", "Create")
enabled: roomNameField.text.length > 0
onTriggered: {
root.connection.createRoom(roomNameField.text, "", root.parentId, false);
root.newChild(roomNameField.text);
root.close();
}
}
]
Component.onCompleted: roomNameField.forceActiveFocus()
ColumnLayout {
spacing: Kirigami.Units.largeSpacing
FormCard.FormRadioDelegate {
id: privateTypeDelegate
text: i18nc("@info:label", "Private")
description: i18nc("@info:description", "This room can only be joined with an invite.")
checked: true
}
FormCard.FormRadioDelegate {
id: publicTypeDelegate
text: i18nc("@info:label", "Public")
description: i18nc("@info:description", "This room can be found and joined by anyone.")
}
FormCard.FormDelegateSeparator {}
FormCard.FormTextFieldDelegate {
id: roomNameField
label: i18nc("@info:label Name of the room", "Name:")
placeholderText: i18nc("@info:placeholder Placeholder for room name", "New Room")
}
FormCard.FormTextFieldDelegate {
id: roomAddressField
label: i18nc("@info:label Address or alias to refer to the room by", "Address:")
placeholderText: i18nc("@info:placeholder Placeholder address for the room", "new-room")
visible: publicTypeDelegate.checked
}
}
}

View File

@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.labs.components as Components
import org.kde.neochat
Kirigami.Dialog {
id: root
property string parentId
required property NeoChatConnection connection
signal newChild(string childName)
title: i18nc("@title", "Create a Space")
implicitWidth: Kirigami.Units.gridUnit * 20
standardButtons: Kirigami.Dialog.Cancel
Component.onCompleted: roomNameField.forceActiveFocus()
customFooterActions: [
Kirigami.Action {
icon.name: "list-add-symbolic"
text: i18nc("@action:button Create new space", "Create")
enabled: roomNameField.text.length > 0
onTriggered: {
root.connection.createSpace(roomNameField.text, "", root.parentId, newOfficialCheck.checked);
root.newChild(roomNameField.text);
root.close();
}
}
]
ColumnLayout {
spacing: Kirigami.Units.largeSpacing
FormCard.FormTextFieldDelegate {
id: roomNameField
label: i18nc("@info:label Name of the space", "Name:")
placeholderText: i18nc("@info:placeholder", "New Space")
}
FormCard.FormDelegateSeparator {
above: roomNameField
below: newOfficialCheck
visible: newOfficialCheck.visible
}
FormCard.FormCheckDelegate {
id: newOfficialCheck
visible: root.parentId.length > 0
text: i18nc("@option:check As in make the space from which this dialog was created an official parent.", "Make this parent official")
checked: true
}
}
}

View File

@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2025 James Graham <james.h.graham@protonmail.com>
# SPDX-License-Identifier: BSD-2-Clause
qt_add_library(RoomInfo STATIC)
ecm_add_qml_module(RoomInfo GENERATE_PLUGIN_SOURCE
URI org.kde.neochat.roominfo
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/roominfo
QML_FILES
RoomDrawer.qml
RoomDrawerPage.qml
RoomInformation.qml
RoomMedia.qml
DirectChatDrawerHeader.qml
LocationsPage.qml
RoomPinnedMessagesPage.qml
RoomSearchPage.qml
)

View File

@@ -8,7 +8,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.neochat
import org.kde.neochat.libneochat
ColumnLayout {
id: root
@@ -18,6 +18,8 @@ ColumnLayout {
*/
required property NeoChatRoom room
signal resolveResource(string idOrUri, string action)
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
spacing: 0
@@ -33,7 +35,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter
onClicked: {
RoomManager.resolveResource(root.room.directChatRemoteMember.uri)
root.resolveResource(root.room.directChatRemoteMember.uri, "")
}
contentItem: KirigamiComponents.Avatar {

View File

@@ -6,12 +6,13 @@ import QtLocation
import QtPositioning
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.neochat.libneochat
Kirigami.Page {
id: root
required property var room
required property NeoChatRoom room
title: i18nc("Locations on a map", "Locations")

View File

@@ -9,14 +9,19 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kitemmodels
import org.kde.neochat
import org.kde.neochat.settings
import org.kde.neochat.libneochat
import org.kde.neochat.timeline as Timeline
import org.kde.neochat.settings as Settings
Kirigami.OverlayDrawer {
id: root
readonly property NeoChatRoom room: RoomManager.currentRoom
required property NeoChatRoom room
required property NeoChatConnection connection
required property UserListModel userListModel
required property Timeline.MediaMessageFilterModel mediaMessageFilterModel
signal resolveResource(string idOrUri, string action)
width: actualWidth
interactive: modal
@@ -24,11 +29,12 @@ Kirigami.OverlayDrawer {
readonly property int minWidth: Kirigami.Units.gridUnit * 15
readonly property int maxWidth: Kirigami.Units.gridUnit * 25
readonly property int defaultWidth: Kirigami.Units.gridUnit * 20
property int roomDrawerWidth
property int actualWidth: {
if (NeoChatConfig.roomDrawerWidth === -1) {
if (root.roomDrawerWidth === -1) {
return Kirigami.Units.gridUnit * 20;
} else {
return NeoChatConfig.roomDrawerWidth;
return root.roomDrawerWidth;
}
}
@@ -46,8 +52,7 @@ Kirigami.OverlayDrawer {
visible: true
onPressed: _lastX = mapToGlobal(mouseX, mouseY).x
onReleased: {
NeoChatConfig.roomDrawerWidth = root.actualWidth;
NeoChatConfig.save();
root.roomDrawerWidth = root.actualWidth;
}
property real _lastX: -1
@@ -56,9 +61,9 @@ Kirigami.OverlayDrawer {
return;
}
if (Qt.application.layoutDirection === Qt.RightToLeft) {
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, NeoChatConfig.roomDrawerWidth - _lastX + mapToGlobal(mouseX, mouseY).x));
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, root.roomDrawerWidth - _lastX + mapToGlobal(mouseX, mouseY).x));
} else {
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, NeoChatConfig.roomDrawerWidth + _lastX - mapToGlobal(mouseX, mouseY).x));
root.actualWidth = Math.min(root.maxWidth, Math.max(root.minWidth, root.roomDrawerWidth + _lastX - mapToGlobal(mouseX, mouseY).x));
}
}
}
@@ -121,7 +126,7 @@ Kirigami.OverlayDrawer {
QQC2.ToolTip.visible: hovered
onClicked: {
RoomSettingsView.openRoomSettings(root.room, RoomSettingsView.Room);
Settings.RoomSettingsView.openRoomSettings(root.room, Settings.RoomSettingsView.Room);
}
}
}
@@ -138,15 +143,17 @@ Kirigami.OverlayDrawer {
id: roomInformation
RoomInformation {
room: root.room
connection: root.connection
userListModel: root.userListModel
onResolveResource: (idOrUri, action) => root.resolveResource(idOrUri, action)
}
}
Component {
id: roomMedia
RoomMedia {
currentRoom: root.room
connection: root.connection
room: root.room
mediaMessageFilterModel: root.mediaMessageFilterModel
}
}

View File

@@ -7,7 +7,8 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kitemmodels
import org.kde.neochat
import org.kde.neochat.libneochat
import org.kde.neochat.timeline as Timeline
/**
* @brief Page for holding a room drawer component.
@@ -24,8 +25,12 @@ Kirigami.Page {
/**
* @brief The current room that user is viewing.
*/
readonly property NeoChatRoom room: RoomManager.currentRoom
required property NeoChatRoom room
required property NeoChatConnection connection
required property UserListModel userListModel
required property Timeline.MediaMessageFilterModel mediaMessageFilterModel
signal resolveResource(string idOrUri, string action)
title: drawerItemLoader.item ? drawerItemLoader.item.title : ""
@@ -61,15 +66,17 @@ Kirigami.Page {
id: roomInformation
RoomInformation {
room: root.room
connection: root.connection
userListModel: root.userListModel
onResolveResource: (idOrUri, action) => root.resolveResource(idOrUri, action)
}
}
Component {
id: roomMedia
RoomMedia {
currentRoom: root.room
connection: root.connection
room: root.room
mediaMessageFilterModel: root.mediaMessageFilterModel
}
}

View File

@@ -12,7 +12,7 @@ import org.kde.kirigamiaddons.delegates as Delegates
import org.kde.kirigamiaddons.labs.components as KirigamiComponents
import org.kde.kitemmodels
import org.kde.neochat
import org.kde.neochat.libneochat
/**
* @brief Component for visualising the room information.
@@ -34,13 +34,15 @@ QQC2.ScrollView {
*/
required property NeoChatRoom room
required property NeoChatConnection connection
required property UserListModel userListModel
/**
* @brief The title that should be displayed for this component if available.
*/
readonly property string title: root.room.isSpace ? i18nc("@action:title", "Space Members") : i18nc("@action:title", "Room Information")
signal resolveResource(string idOrUri, string action)
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
@@ -216,7 +218,7 @@ QQC2.ScrollView {
UserFilterModel {
id: userFilterModel
sourceModel: RoomManager.userListModel
sourceModel: root.userListModel
allowEmpty: true
}
@@ -249,7 +251,7 @@ QQC2.ScrollView {
KeyNavigation.backtab: index === 0 ? userList.headerItem.userListSearchField : null
onClicked: {
RoomManager.resolveResource(userDelegate.userId, "mention");
root.resolveResource(userDelegate.userId, "mention");
}
contentItem: RowLayout {
@@ -286,6 +288,8 @@ QQC2.ScrollView {
id: directChatDrawerHeader
DirectChatDrawerHeader {
room: root.room
onResolveResource: (idOrUri, action) => root.resolveResource(idOrUri, action)
}
}

View File

@@ -6,8 +6,8 @@ import QtQuick.Controls as QQC2
import QtQuick.Layouts
import Qt.labs.qmlmodels
import org.kde.neochat
import org.kde.neochat.timeline
import org.kde.neochat.libneochat
import org.kde.neochat.timeline as Timeline
/**
* @brief Component for visualising the loaded media items in the room.
@@ -31,9 +31,9 @@ QQC2.ScrollView {
/**
* @brief The current room that user is viewing.
*/
required property NeoChatRoom currentRoom
required property NeoChatRoom room
required property NeoChatConnection connection
required property Timeline.MediaMessageFilterModel mediaMessageFilterModel
// HACK: Hide unnecessary horizontal scrollbar (https://bugreports.qt.io/browse/QTBUG-83890)
QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
@@ -42,26 +42,26 @@ QQC2.ScrollView {
clip: true
verticalLayoutDirection: ListView.BottomToTop
model: RoomManager.mediaMessageFilterModel
model: root.mediaMessageFilterModel
delegate: DelegateChooser {
role: "type"
DelegateChoice {
roleValue: MediaMessageFilterModel.Image
delegate: MessageDelegate {
roleValue: Timeline.MediaMessageFilterModel.Image
delegate: Timeline.MessageDelegate {
alwaysFillWidth: true
cardBackground: false
room: root.currentRoom
room: root.room
}
}
DelegateChoice {
roleValue: MediaMessageFilterModel.Video
delegate: MessageDelegate {
roleValue: Timeline.MediaMessageFilterModel.Video
delegate: Timeline.MessageDelegate {
alwaysFillWidth: true
cardBackground: false
room: root.currentRoom
room: root.room
}
}
}

View File

@@ -6,7 +6,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.neochat
import org.kde.neochat.libneochat
import org.kde.neochat.timeline
/**

View File

@@ -3,7 +3,7 @@
import QtQuick
import org.kde.neochat
import org.kde.neochat.libneochat
import org.kde.neochat.timeline
/**

View File

@@ -90,29 +90,13 @@ RowLayout {
action: QQC2.Action {
shortcut: StandardKey.New
onTriggered: {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
Qt.createComponent('org.kde.neochat', 'CreateRoomDialog').createObject(root, {
connection: root.connection
}, {
title: i18nc("@title", "Create a Room")
});
}).open();
}
}
}
QQC2.MenuItem {
text: i18n("Create a Space")
icon.name: "list-add"
onTriggered: {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
connection: root.connection,
isSpace: true,
title: i18nc("@title", "Create a Space")
}, {
title: i18nc("@title", "Create a Space")
});
}
}
QQC2.MenuItem {
text: i18n("Scan a QR Code")
icon.name: "view-barcode-qr"

View File

@@ -159,13 +159,9 @@ Kirigami.NavigationTabBar {
text: i18n("Create a Space")
icon.name: "list-add"
onTriggered: {
pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
connection: root.connection,
isSpace: true,
title: i18nc("@title", "Create a Space")
}, {
title: i18nc("@title", "Create a Space")
});
Qt.createComponent('org.kde.neochat', 'CreateSpaceDialog').createObject(root, {
connection: root.connection
}).open();
explorePopup.close();
}
}

View File

@@ -268,13 +268,11 @@ QQC2.Control {
activeFocusOnTab: true
onSelected: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
connection: root.connection,
isSpace: true,
title: i18nc("@title", "Create a Space")
}, {
title: i18nc("@title", "Create a Space")
})
onSelected: {
Qt.createComponent('org.kde.neochat', 'CreateSpaceDialog').createObject(root, {
connection: root.connection
}).open();
}
}
AvatarTabButton {

View File

@@ -72,6 +72,6 @@ KirigamiComponents.ConvergentContextMenu {
QQC2.Action {
text: i18nc("'Space' is a matrix space", "Leave Space")
icon.name: "go-previous"
onTriggered: RoomManager.leaveRoom(room)
onTriggered: root.room.forget()
}
}

View File

@@ -65,7 +65,7 @@ FormCard.FormCardPage {
visible: !root.connection
}
property QQC2.Dialog passwordSheet: QQC2.Dialog {
property Kirigami.Dialog passwordSheet: Kirigami.Dialog {
id: passwordSheet
property string deviceId
@@ -74,6 +74,7 @@ FormCard.FormCardPage {
title: i18n("Remove device")
standardButtons: QQC2.Dialog.Cancel
FormCard.FormCard {
FormCard.FormTextFieldDelegate {
id: passwordField
@@ -81,19 +82,16 @@ FormCard.FormCardPage {
echoMode: TextInput.Password
}
}
footer: QQC2.DialogButtonBox {
standardButtons: QQC2.Dialog.Cancel
QQC2.Button {
customFooterActions: [
Kirigami.Action {
text: i18nc("As in 'Remove this device'", "Remove")
QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
icon.name: "delete"
onClicked: {
onTriggered: {
devicesModel.logout(passwordSheet.deviceId, passwordField.text);
passwordField.text = "";
passwordSheet.close();
}
}
}
]
}
}

View File

@@ -8,7 +8,7 @@ import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
QQC2.Dialog {
Kirigami.Dialog {
id: root
signal submitPassword(string password)

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