Compare commits
14 Commits
work/nvrwh
...
work/redst
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49e4fd1b00 | ||
|
|
a1ca768711 | ||
|
|
f0d2c19393 | ||
|
|
67db05a0c3 | ||
|
|
05e932b884 | ||
|
|
763713cd32 | ||
|
|
2687448212 | ||
|
|
d059195e92 | ||
|
|
6ef7acc8e5 | ||
|
|
2cb89807ef | ||
|
|
b5fcad3db0 | ||
|
|
d3fd441c88 | ||
|
|
e9568b50fc | ||
|
|
e7040a518a |
1107
po/ar/neochat.po
1107
po/ar/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1199
po/az/neochat.po
1199
po/az/neochat.po
File diff suppressed because it is too large
Load Diff
1065
po/ca/neochat.po
1065
po/ca/neochat.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1065
po/cs/neochat.po
1065
po/cs/neochat.po
File diff suppressed because it is too large
Load Diff
1135
po/da/neochat.po
1135
po/da/neochat.po
File diff suppressed because it is too large
Load Diff
1125
po/de/neochat.po
1125
po/de/neochat.po
File diff suppressed because it is too large
Load Diff
1153
po/el/neochat.po
1153
po/el/neochat.po
File diff suppressed because it is too large
Load Diff
1116
po/en_GB/neochat.po
1116
po/en_GB/neochat.po
File diff suppressed because it is too large
Load Diff
1107
po/eo/neochat.po
1107
po/eo/neochat.po
File diff suppressed because it is too large
Load Diff
1018
po/es/neochat.po
1018
po/es/neochat.po
File diff suppressed because it is too large
Load Diff
1109
po/eu/neochat.po
1109
po/eu/neochat.po
File diff suppressed because it is too large
Load Diff
1109
po/fi/neochat.po
1109
po/fi/neochat.po
File diff suppressed because it is too large
Load Diff
1113
po/fr/neochat.po
1113
po/fr/neochat.po
File diff suppressed because it is too large
Load Diff
1105
po/gl/neochat.po
1105
po/gl/neochat.po
File diff suppressed because it is too large
Load Diff
1062
po/he/neochat.po
1062
po/he/neochat.po
File diff suppressed because it is too large
Load Diff
1111
po/hi/neochat.po
1111
po/hi/neochat.po
File diff suppressed because it is too large
Load Diff
1122
po/hu/neochat.po
1122
po/hu/neochat.po
File diff suppressed because it is too large
Load Diff
1109
po/ia/neochat.po
1109
po/ia/neochat.po
File diff suppressed because it is too large
Load Diff
1193
po/id/neochat.po
1193
po/id/neochat.po
File diff suppressed because it is too large
Load Diff
1169
po/ie/neochat.po
1169
po/ie/neochat.po
File diff suppressed because it is too large
Load Diff
1117
po/it/neochat.po
1117
po/it/neochat.po
File diff suppressed because it is too large
Load Diff
994
po/ja/neochat.po
994
po/ja/neochat.po
File diff suppressed because it is too large
Load Diff
1059
po/ka/neochat.po
1059
po/ka/neochat.po
File diff suppressed because it is too large
Load Diff
1101
po/ko/neochat.po
1101
po/ko/neochat.po
File diff suppressed because it is too large
Load Diff
1000
po/lt/neochat.po
1000
po/lt/neochat.po
File diff suppressed because it is too large
Load Diff
1111
po/lv/neochat.po
1111
po/lv/neochat.po
File diff suppressed because it is too large
Load Diff
1074
po/nl/neochat.po
1074
po/nl/neochat.po
File diff suppressed because it is too large
Load Diff
1101
po/nn/neochat.po
1101
po/nn/neochat.po
File diff suppressed because it is too large
Load Diff
1199
po/pa/neochat.po
1199
po/pa/neochat.po
File diff suppressed because it is too large
Load Diff
1113
po/pl/neochat.po
1113
po/pl/neochat.po
File diff suppressed because it is too large
Load Diff
1189
po/pt/neochat.po
1189
po/pt/neochat.po
File diff suppressed because it is too large
Load Diff
1199
po/pt_BR/neochat.po
1199
po/pt_BR/neochat.po
File diff suppressed because it is too large
Load Diff
1115
po/ru/neochat.po
1115
po/ru/neochat.po
File diff suppressed because it is too large
Load Diff
1107
po/sa/neochat.po
1107
po/sa/neochat.po
File diff suppressed because it is too large
Load Diff
1181
po/sk/neochat.po
1181
po/sk/neochat.po
File diff suppressed because it is too large
Load Diff
1064
po/sl/neochat.po
1064
po/sl/neochat.po
File diff suppressed because it is too large
Load Diff
1115
po/sv/neochat.po
1115
po/sv/neochat.po
File diff suppressed because it is too large
Load Diff
1099
po/ta/neochat.po
1099
po/ta/neochat.po
File diff suppressed because it is too large
Load Diff
1124
po/tok/neochat.po
1124
po/tok/neochat.po
File diff suppressed because it is too large
Load Diff
1105
po/tr/neochat.po
1105
po/tr/neochat.po
File diff suppressed because it is too large
Load Diff
1081
po/uk/neochat.po
1081
po/uk/neochat.po
File diff suppressed because it is too large
Load Diff
1004
po/zh_CN/neochat.po
1004
po/zh_CN/neochat.po
File diff suppressed because it is too large
Load Diff
1074
po/zh_TW/neochat.po
1074
po/zh_TW/neochat.po
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import QtPositioning
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.neochat.libneochat
|
||||
|
||||
ApplicationWindow {
|
||||
id: root
|
||||
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
74
src/app/qml/UserMenu.qml
Normal file
74
src/app/qml/UserMenu.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
73
src/libneochat/qml/CreateRoomDialog.qml
Normal file
73
src/libneochat/qml/CreateRoomDialog.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/libneochat/qml/CreateSpaceDialog.qml
Normal file
64
src/libneochat/qml/CreateSpaceDialog.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/roominfo/CMakeLists.txt
Normal file
17
src/roominfo/CMakeLists.txt
Normal 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
|
||||
)
|
||||
@@ -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 {
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import QtQuick
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.libneochat
|
||||
import org.kde.neochat.timeline
|
||||
|
||||
/**
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ ecm_add_qml_module(Spaces GENERATE_PLUGIN_SOURCE
|
||||
QML_FILES
|
||||
SpaceHomePage.qml
|
||||
SpaceHierarchyDelegate.qml
|
||||
RemoveChildDialog.qml
|
||||
SelectExistingRoomDialog.qml
|
||||
SOURCES
|
||||
models/spacechildrenmodel.cpp
|
||||
models/spacechildsortfiltermodel.cpp
|
||||
|
||||
@@ -7,7 +7,7 @@ import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.libneochat
|
||||
|
||||
Kirigami.Dialog {
|
||||
id: root
|
||||
@@ -9,124 +9,36 @@ 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
|
||||
import org.kde.neochat.libneochat
|
||||
|
||||
FormCard.FormCardPage {
|
||||
Kirigami.Dialog {
|
||||
id: root
|
||||
|
||||
property string parentId: ""
|
||||
|
||||
property bool isSpace: false
|
||||
|
||||
property bool showChildType: false
|
||||
|
||||
property bool showCreateChoice: false
|
||||
property string parentId
|
||||
|
||||
required property NeoChatConnection connection
|
||||
|
||||
signal addChild(string childId, bool setChildParent, bool canonical)
|
||||
signal newChild(string childName)
|
||||
|
||||
title: isSpace ? i18nc("@title", "Create a Space") : i18nc("@title", "Create a Room")
|
||||
title: i18nc("@title", "Select Existing Room")
|
||||
implicitWidth: Kirigami.Units.gridUnit * 20
|
||||
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
|
||||
|
||||
Component.onCompleted: roomNameField.forceActiveFocus()
|
||||
onAccepted: root.addChild(chosenRoomDelegate.roomId, existingOfficialCheck.checked, makeCanonicalCheck.checked);
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: root.isSpace ? i18n("New Space Information") : i18n("New Room Information")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
FormCard.FormComboBoxDelegate {
|
||||
id: roomTypeCombo
|
||||
property bool isInitialising: true
|
||||
Component.onCompleted: pickRoomDelegate.forceActiveFocus()
|
||||
|
||||
visible: root.showChildType
|
||||
|
||||
text: i18n("Select type")
|
||||
model: ListModel {
|
||||
id: roomTypeModel
|
||||
}
|
||||
textRole: "text"
|
||||
valueRole: "isSpace"
|
||||
|
||||
Component.onCompleted: {
|
||||
currentIndex = indexOfValue(root.isSpace);
|
||||
roomTypeModel.append({
|
||||
"text": i18n("Room"),
|
||||
"isSpace": false
|
||||
});
|
||||
roomTypeModel.append({
|
||||
"text": i18n("Space"),
|
||||
"isSpace": true
|
||||
});
|
||||
roomTypeCombo.currentIndex = 0;
|
||||
roomTypeCombo.isInitialising = false;
|
||||
}
|
||||
onCurrentValueChanged: {
|
||||
if (!isInitialising) {
|
||||
root.isSpace = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
visible: root.showChildType
|
||||
}
|
||||
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: roomNameField
|
||||
label: i18n("Name:")
|
||||
onAccepted: if (roomNameField.text.length > 0) {
|
||||
roomTopicField.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {}
|
||||
|
||||
FormCard.FormTextFieldDelegate {
|
||||
id: roomTopicField
|
||||
label: i18n("Topic:")
|
||||
onAccepted: ok.clicked()
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
visible: root.parentId.length > 0
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: ok
|
||||
text: root.isSpace ? i18nc("@action:button", "Create Space") : i18nc("@action:button", "Create Room")
|
||||
enabled: roomNameField.text.length > 0
|
||||
onClicked: {
|
||||
if (root.isSpace) {
|
||||
root.connection.createSpace(roomNameField.text, roomTopicField.text, root.parentId, newOfficialCheck.checked);
|
||||
} else {
|
||||
root.connection.createRoom(roomNameField.text, roomTopicField.text, root.parentId, newOfficialCheck.checked);
|
||||
}
|
||||
root.newChild(roomNameField.text);
|
||||
root.closeDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
FormCard.FormHeader {
|
||||
visible: root.showChildType
|
||||
title: i18n("Select Existing Room")
|
||||
}
|
||||
FormCard.FormCard {
|
||||
visible: root.showChildType
|
||||
FormCard.FormButtonDelegate {
|
||||
id: pickRoomDelegate
|
||||
|
||||
visible: !chosenRoomDelegate.visible
|
||||
text: i18nc("@action:button", "Pick room")
|
||||
text: i18nc("@action:button", "Pick Room")
|
||||
onClicked: {
|
||||
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage'), {
|
||||
let dialog = pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.libneochat', 'ExploreRoomsPage'), {
|
||||
connection: root.connection
|
||||
}, {
|
||||
title: i18nc("@title", "Explore Rooms")
|
||||
@@ -227,13 +139,15 @@ FormCard.FormCardPage {
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {}
|
||||
FormCard.FormDelegateSeparator {
|
||||
below: existingOfficialCheck
|
||||
}
|
||||
|
||||
FormCard.FormCheckDelegate {
|
||||
id: existingOfficialCheck
|
||||
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")
|
||||
description: enabled ? i18n("You have the required privilege level in the child to set this state") : i18n("You do not have a high enough privilege level in the child to set this state")
|
||||
description: enabled ? i18nc("@info:description", "You have the required privilege level in the child to set this state") : i18n("You do not have a high enough privilege level in the child to set this state")
|
||||
checked: enabled
|
||||
|
||||
enabled: {
|
||||
@@ -250,26 +164,17 @@ FormCard.FormCardPage {
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
visible: root.parentId.length > 0
|
||||
above: existingOfficialCheck
|
||||
below: makeCanonicalCheck
|
||||
}
|
||||
|
||||
FormCard.FormCheckDelegate {
|
||||
id: makeCanonicalCheck
|
||||
text: i18nc("@option:check The canonical parent is the default one if a room has multiple parent spaces.", "Make this space the canonical parent")
|
||||
description: i18nc("@info:description", "The canonical parent is the default one if a room has multiple parent spaces.")
|
||||
checked: enabled
|
||||
|
||||
enabled: existingOfficialCheck.enabled
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
text: i18nc("@action:button", "Ok")
|
||||
enabled: chosenRoomDelegate.visible
|
||||
onClicked: {
|
||||
root.addChild(chosenRoomDelegate.roomId, existingOfficialCheck.checked, makeCanonicalCheck.checked);
|
||||
root.closeDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,7 @@ import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.delegates as Delegates
|
||||
import org.kde.kirigamiaddons.labs.components as Components
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.libneochat as LibNeoChat
|
||||
import org.kde.neochat.libneochat
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -202,7 +201,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
LibNeoChat.DelegateSizeHelper {
|
||||
DelegateSizeHelper {
|
||||
id: sizeHelper
|
||||
parentItem: root
|
||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||
|
||||
@@ -6,20 +6,47 @@ 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.libneochat as LibNeoChat
|
||||
import org.kde.neochat.settings
|
||||
import org.kde.neochat.libneochat
|
||||
import org.kde.neochat.settings as Settings
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
readonly property NeoChatRoom currentRoom: RoomManager.currentRoom
|
||||
/**
|
||||
* @brief The NeoChatRoom the delegate is being displayed in.
|
||||
*/
|
||||
required property NeoChatRoom room
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
spacing: 0
|
||||
|
||||
Component {
|
||||
id: roomMenuComponent
|
||||
|
||||
KirigamiComponents.ConvergentContextMenu {
|
||||
Kirigami.Action {
|
||||
icon.name: "list-add-symbolic"
|
||||
text: i18nc("@action:inmenu", "New Room…")
|
||||
onTriggered: _private.createRoom(root.room.id)
|
||||
}
|
||||
|
||||
Kirigami.Action {
|
||||
icon.name: "list-add-symbolic"
|
||||
text: i18nc("@action:inmenu", "New Space…")
|
||||
onTriggered: _private.createSpace(root.room.id)
|
||||
}
|
||||
|
||||
Kirigami.Action {
|
||||
icon.name: "search-symbolic"
|
||||
text: i18nc("@action:inmenu", "Existing Room…")
|
||||
onTriggered: _private.selectExisting(root.room.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Control {
|
||||
id: headerItem
|
||||
Layout.fillWidth: true
|
||||
@@ -40,32 +67,37 @@ ColumnLayout {
|
||||
GroupChatDrawerHeader {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
room: root.currentRoom
|
||||
room: root.room
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
QQC2.Button {
|
||||
visible: root.currentRoom.canSendState("invite")
|
||||
visible: root.room.canSendState("invite")
|
||||
text: i18nc("@button", "Invite user to space")
|
||||
icon.name: "list-add-user"
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'InviteUserPage'), {
|
||||
room: root.currentRoom
|
||||
onClicked: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat.libneochat', 'InviteUserPage'), {
|
||||
room: root.room
|
||||
}, {
|
||||
title: i18nc("@title", "Invite a User")
|
||||
})
|
||||
}
|
||||
QQC2.Button {
|
||||
visible: root.currentRoom.canSendState("m.space.child")
|
||||
text: i18nc("@button", "Add new room")
|
||||
id: addNewButton
|
||||
|
||||
visible: root.room.canSendState("m.space.child")
|
||||
text: i18nc("@button", "Add to Space")
|
||||
icon.name: "list-add"
|
||||
onClicked: _private.createRoom(root.currentRoom.id)
|
||||
onClicked: {
|
||||
const menu = roomMenuComponent.createObject(addNewButton);
|
||||
menu.popup();
|
||||
}
|
||||
}
|
||||
QQC2.Button {
|
||||
text: i18nc("@action:button", "Leave this space")
|
||||
icon.name: "go-previous"
|
||||
onClicked: RoomManager.leaveRoom(root.currentRoom)
|
||||
onClicked: root.room.forget()
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
@@ -76,7 +108,7 @@ ColumnLayout {
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
text: i18nc("'Space' is a matrix space", "Space Settings")
|
||||
onClicked: {
|
||||
RoomSettingsView.openRoomSettings(root.currentRoom, RoomSettingsView.Space);
|
||||
Settings.RoomSettingsView.openRoomSettings(root.room, Settings.RoomSettingsView.Space);
|
||||
drawer.close();
|
||||
}
|
||||
icon.name: 'settings-configure-symbolic'
|
||||
@@ -94,7 +126,7 @@ ColumnLayout {
|
||||
onTextChanged: spaceChildSortFilterModel.filterText = text
|
||||
}
|
||||
}
|
||||
LibNeoChat.DelegateSizeHelper {
|
||||
DelegateSizeHelper {
|
||||
id: sizeHelper
|
||||
parentItem: root
|
||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||
@@ -125,7 +157,7 @@ ColumnLayout {
|
||||
id: spaceChildSortFilterModel
|
||||
sourceModel: SpaceChildrenModel {
|
||||
id: spaceChildrenModel
|
||||
space: root.currentRoom
|
||||
space: root.room
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,27 +190,43 @@ ColumnLayout {
|
||||
}
|
||||
QtObject {
|
||||
id: _private
|
||||
|
||||
function createRoom(parentId) {
|
||||
let dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'CreateRoomDialog'), {
|
||||
title: i18nc("@title", "Create a Child"),
|
||||
connection: root.currentRoom.connection,
|
||||
parentId: parentId,
|
||||
showChildType: true,
|
||||
showCreateChoice: true
|
||||
}, {
|
||||
title: i18nc("@title", "Create a Child")
|
||||
});
|
||||
dialog.addChild.connect((childId, setChildParent, canonical) => {
|
||||
// We have to get a room object from the connection as we may not
|
||||
// be adding to the top level parent.
|
||||
let parent = root.currentRoom.connection.room(parentId);
|
||||
if (parent) {
|
||||
parent.addChild(childId, setChildParent, canonical);
|
||||
}
|
||||
const dialog = Qt.createComponent('org.kde.neochat.libneochat', 'CreateRoomDialog').createObject(root, {
|
||||
connection: root.room.connection,
|
||||
parentId: parentId
|
||||
});
|
||||
dialog.newChild.connect(childName => {
|
||||
spaceChildrenModel.addPendingChild(childName);
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
function createSpace(parentId) {
|
||||
const dialog = Qt.createComponent('org.kde.neochat.libneochat', 'CreateSpaceDialog').createObject(root, {
|
||||
connection: root.room.connection,
|
||||
parentId: parentId,
|
||||
});
|
||||
dialog.newChild.connect(childName => {
|
||||
spaceChildrenModel.addPendingChild(childName);
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
function selectExisting(parentId) {
|
||||
const dialog = Qt.createComponent('org.kde.neochat.spaces', 'SelectExistingRoomDialog').createObject(root, {
|
||||
connection: root.room.connection,
|
||||
parentId: parentId,
|
||||
});
|
||||
dialog.addChild.connect((childId, setChildParent, canonical) => {
|
||||
// We have to get a room object from the connection as we may not
|
||||
// be adding to the top level parent.
|
||||
let parent = root.room.connection.room(parentId);
|
||||
if (parent) {
|
||||
parent.addChild(childId, setChildParent, canonical);
|
||||
}
|
||||
});
|
||||
dialog.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,21 +41,42 @@ RowLayout {
|
||||
|
||||
implicitHeight: Math.max(nameButton.implicitHeight, timeLabel.implicitHeight)
|
||||
|
||||
QQC2.AbstractButton {
|
||||
QQC2.Label {
|
||||
id: nameButton
|
||||
contentItem: QQC2.Label {
|
||||
text: root.author.disambiguatedName
|
||||
color: root.author.color
|
||||
textFormat: Text.PlainText
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
|
||||
text: root.author.disambiguatedName
|
||||
color: root.author.color
|
||||
textFormat: Text.PlainText
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
|
||||
function openUserMenu(): void {
|
||||
const menu = Qt.createComponent("org.kde.neochat", "UserMenu").createObject(root, {
|
||||
window: QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow,
|
||||
author: root.author,
|
||||
});
|
||||
menu.popup(root.QQC2.Overlay.overlay);
|
||||
}
|
||||
Accessible.name: contentItem.text
|
||||
onClicked: RoomManager.resolveResource(root.author.uri)
|
||||
|
||||
HoverHandler {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
// tapping to open profile
|
||||
TapHandler {
|
||||
onTapped: RoomManager.resolveResource(root.author.uri)
|
||||
}
|
||||
|
||||
// right-clicking/long-press for context menu
|
||||
TapHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
|
||||
acceptedButtons: Qt.RightButton
|
||||
onTapped: nameButton.openUserMenu()
|
||||
}
|
||||
TapHandler {
|
||||
acceptedDevices: PointerDevice.TouchScreen
|
||||
onTapped: nameButton.openUserMenu()
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
@@ -73,16 +94,4 @@ RowLayout {
|
||||
id: timeHoverHandler
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
acceptedDevices: PointerDevice.TouchScreen
|
||||
onLongPressed: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink);
|
||||
}
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
|
||||
gesturePolicy: TapHandler.WithinBounds
|
||||
onTapped: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,14 +142,6 @@ KirigamiComponents.ConvergentContextMenu {
|
||||
}
|
||||
}
|
||||
|
||||
component ShowUserAction: Kirigami.Action {
|
||||
text: i18nc("@action:inmenu", "Show User")
|
||||
icon.name: "username-copy"
|
||||
onTriggered: {
|
||||
RoomManager.resolveResource(author.id)
|
||||
}
|
||||
}
|
||||
|
||||
component PinMessageAction: Kirigami.Action {
|
||||
readonly property bool pinned: currentRoom.isEventPinned(root.eventId)
|
||||
|
||||
@@ -222,10 +214,10 @@ KirigamiComponents.ConvergentContextMenu {
|
||||
dialog.showStickers = false;
|
||||
dialog.chosen.connect(emoji => {
|
||||
root.room.toggleReaction(root.eventId, emoji);
|
||||
root.menuItem.close();
|
||||
root.close();
|
||||
});
|
||||
dialog.closed.connect(() => {
|
||||
root.menuItem.close();
|
||||
root.close();
|
||||
});
|
||||
dialog.open();
|
||||
return;
|
||||
|
||||
@@ -94,8 +94,6 @@ DelegateContextMenu {
|
||||
|
||||
DelegateContextMenu.ReportMessageAction {}
|
||||
|
||||
DelegateContextMenu.ShowUserAction {}
|
||||
|
||||
Kirigami.Action {
|
||||
separator: true
|
||||
visible: viewSourceAction.visible
|
||||
|
||||
@@ -149,6 +149,7 @@ MessageDelegateBase {
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: _private.showMessageMenu()
|
||||
}
|
||||
|
||||
@@ -159,7 +160,7 @@ MessageDelegateBase {
|
||||
}
|
||||
}
|
||||
|
||||
avatarComponent: KirigamiComponents.AvatarButton {
|
||||
avatarComponent: KirigamiComponents.Avatar {
|
||||
id: avatar
|
||||
implicitWidth: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||
implicitHeight: width
|
||||
@@ -170,7 +171,34 @@ MessageDelegateBase {
|
||||
asynchronous: true
|
||||
QQC2.ToolTip.text: root.author.htmlSafeDisambiguatedName
|
||||
|
||||
onClicked: RoomManager.resolveResource(root.author.uri)
|
||||
function openUserMenu(): void {
|
||||
const menu = Qt.createComponent("org.kde.neochat", "UserMenu").createObject(root, {
|
||||
window: QQC2.ApplicationWindow.window as Kirigami.ApplicationWindow,
|
||||
author: root.author,
|
||||
});
|
||||
console.info(Qt.createComponent("org.kde.neochat", "UserMenu").errorString());
|
||||
menu.popup(root.QQC2.Overlay.overlay);
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
// tapping to open profile
|
||||
TapHandler {
|
||||
onTapped: RoomManager.resolveResource(root.author.uri)
|
||||
}
|
||||
|
||||
// right-clicking/long-press for context menu
|
||||
TapHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
|
||||
acceptedButtons: Qt.RightButton
|
||||
onTapped: avatar.openUserMenu()
|
||||
}
|
||||
TapHandler {
|
||||
acceptedDevices: PointerDevice.TouchScreen
|
||||
onTapped: avatar.openUserMenu()
|
||||
}
|
||||
}
|
||||
|
||||
sectionComponent: SectionDelegate {
|
||||
|
||||
@@ -102,7 +102,6 @@ DelegateContextMenu {
|
||||
}
|
||||
DelegateContextMenu.PinMessageAction {}
|
||||
DelegateContextMenu.ReportMessageAction {}
|
||||
DelegateContextMenu.ShowUserAction {}
|
||||
Kirigami.Action {
|
||||
separator: true
|
||||
visible: viewSourceAction.visible
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.kde.kitemmodels
|
||||
|
||||
import org.kde.neochat
|
||||
import org.kde.neochat.timeline
|
||||
import org.kde.neochat.libneochat as LibNeoChat
|
||||
|
||||
QQC2.ScrollView {
|
||||
id: root
|
||||
@@ -261,13 +262,24 @@ QQC2.ScrollView {
|
||||
}
|
||||
}
|
||||
|
||||
TypingPane {
|
||||
id: typingPane
|
||||
LibNeoChat.DelegateSizeHelper {
|
||||
id: typingPaneSizeHelper
|
||||
parentItem: typingPaneContainer
|
||||
startBreakpoint: Kirigami.Units.gridUnit * 46
|
||||
endBreakpoint: Kirigami.Units.gridUnit * 66
|
||||
startPercentWidth: 100
|
||||
endPercentWidth: NeoChatConfig.compactLayout ? 100 : 85
|
||||
maxWidth: NeoChatConfig.compactLayout ? -1 : Kirigami.Units.gridUnit * 60
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: typingPaneContainer
|
||||
visible: root.currentRoom && root.currentRoom.otherMembersTyping.length > 0
|
||||
labelText: visible ? i18ncp("Message displayed when some users are typing", "%2 is typing", "%2 are typing", root.currentRoom.otherMembersTyping.length, root.currentRoom.otherMembersTyping.map(member => member.displayName).join(", ")) : ""
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: visible ? implicitHeight : 0
|
||||
height: visible ? typingPane.implicitHeight : 0
|
||||
z: 2
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
property: "height"
|
||||
@@ -275,7 +287,15 @@ QQC2.ScrollView {
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
z: 2
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: typingPaneSizeHelper.availableWidth
|
||||
TypingPane {
|
||||
id: typingPane
|
||||
labelText: visible ? i18ncp("Message displayed when some users are typing", "%2 is typing", "%2 are typing", root.currentRoom.otherMembersTyping.length, root.currentRoom.otherMembersTyping.map(member => member.displayName).join(", ")) : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function goToEvent(eventID) {
|
||||
|
||||
@@ -48,24 +48,32 @@ Video {
|
||||
*/
|
||||
required property var fileTransferInfo
|
||||
|
||||
/**
|
||||
* @brief Whether the video should be played when downloaded.
|
||||
*/
|
||||
required property bool playOnFinished
|
||||
|
||||
/**
|
||||
* @brief Whether the media has been downloaded.
|
||||
*/
|
||||
readonly property bool downloaded: root.fileTransferInfo && root.fileTransferInfo.completed
|
||||
onDownloadedChanged: {
|
||||
if (downloaded) {
|
||||
root.autoPlay = root.playOnFinished;
|
||||
root.source = root.fileTransferInfo.localPath;
|
||||
}
|
||||
if (downloaded && playOnFinished) {
|
||||
playSavedFile();
|
||||
playOnFinished = false;
|
||||
|
||||
console.info("hasAudio:" + root.hasAudio + " hasVideo:" + root.hasVideo);
|
||||
|
||||
if (playOnFinished) {
|
||||
//playSavedFile();
|
||||
root.Message.contentModel.setPlayOnFinished(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Whether the video should be played when downloaded.
|
||||
*/
|
||||
property bool playOnFinished: false
|
||||
onPaused: console.info("PAUSED")
|
||||
onPlaying: console.info("PLAYING")
|
||||
onStopped: console.info("STOPPED")
|
||||
|
||||
Layout.preferredWidth: mediaSizeHelper.currentSize.width
|
||||
Layout.preferredHeight: mediaSizeHelper.currentSize.height
|
||||
@@ -87,9 +95,13 @@ Video {
|
||||
target: videoLabel
|
||||
visible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
/*PropertyChanges {
|
||||
target: mediaThumbnail
|
||||
visible: true
|
||||
}*/
|
||||
PropertyChanges {
|
||||
target: infoBackground
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
@@ -99,6 +111,14 @@ Video {
|
||||
target: downloadBar
|
||||
visible: true
|
||||
}
|
||||
/*PropertyChanges {
|
||||
target: mediaThumbnail
|
||||
visible: true
|
||||
}*/
|
||||
PropertyChanges {
|
||||
target: infoBackground
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "paused"
|
||||
@@ -136,10 +156,10 @@ Video {
|
||||
target: videoControls
|
||||
stateVisible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
/*PropertyChanges {
|
||||
target: mediaThumbnail
|
||||
visible: true
|
||||
}
|
||||
}*/
|
||||
PropertyChanges {
|
||||
target: videoLabel
|
||||
visible: true
|
||||
@@ -188,41 +208,37 @@ Video {
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
id: videoLabel
|
||||
anchors.centerIn: parent
|
||||
Rectangle {
|
||||
id: infoBackground
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
color: "black"
|
||||
opacity: 0.5
|
||||
visible: false
|
||||
color: "white"
|
||||
text: i18n("Video")
|
||||
font.pixelSize: 16
|
||||
|
||||
padding: 8
|
||||
|
||||
background: Rectangle {
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
color: "black"
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: downloadBar
|
||||
anchors.fill: parent
|
||||
Kirigami.Icon {
|
||||
id: videoLabel
|
||||
|
||||
anchors.centerIn: parent
|
||||
visible: false
|
||||
source: "media-playback-start-symbolic"
|
||||
width: Kirigami.Units.iconSizes.huge
|
||||
height: Kirigami.Units.iconSizes.huge
|
||||
}
|
||||
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
radius: Kirigami.Units.cornerRadius
|
||||
Kirigami.LoadingPlaceholder {
|
||||
id: downloadBar
|
||||
|
||||
QQC2.ProgressBar {
|
||||
anchors.centerIn: parent
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: parent.width * 0.8
|
||||
|
||||
from: 0
|
||||
to: root.fileTransferInfo.total
|
||||
value: root.fileTransferInfo.progress
|
||||
}
|
||||
text: i18nc("@info:placeholder", "Downloading…")
|
||||
visible: false
|
||||
determinate: root.fileTransferInfo.progress > 0
|
||||
progressBar.from: 0
|
||||
progressBar.to: root.fileTransferInfo.total
|
||||
progressBar.value: root.fileTransferInfo.progress
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -407,7 +423,7 @@ Video {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds | TapHandler.WithinBounds
|
||||
onTapped: if (root.fileTransferInfo.completed) {
|
||||
if (root.playbackState == MediaPlayer.PlayingState) {
|
||||
if (root.playbackState === MediaPlayer.PlayingState) {
|
||||
root.pause();
|
||||
} else {
|
||||
MediaManager.startPlayback();
|
||||
@@ -429,14 +445,18 @@ Video {
|
||||
if (root.downloaded) {
|
||||
playSavedFile();
|
||||
} else {
|
||||
playOnFinished = true;
|
||||
//root.Message.contentModel.setPlayOnFinished(true);
|
||||
Message.room.downloadFile(root.eventId, Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + root.eventId.replace(":", "_").replace("/", "_").replace("+", "_") + Message.room.fileNameToDownload(root.eventId));
|
||||
}
|
||||
}
|
||||
|
||||
function playSavedFile() {
|
||||
root.stop();
|
||||
MediaManager.startPlayback();
|
||||
root.play();
|
||||
root.state = "playing";
|
||||
console.info("current state:" + root.state);
|
||||
}
|
||||
|
||||
onStateChanged: console.info("state changed to " + root.state)
|
||||
onErrorOccurred: (error, errorString) => console.info("ERR: " + errorString)
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ void MessageContentModel::initializeModel()
|
||||
});
|
||||
connect(m_room, &NeoChatRoom::fileTransferCompleted, this, [this](const QString &eventId) {
|
||||
if (m_room != nullptr && eventId == m_eventId) {
|
||||
setPlayOnFinished(true);
|
||||
resetContent();
|
||||
Q_EMIT dataChanged(index(0), index(rowCount() - 1), {FileTransferInfoRole});
|
||||
}
|
||||
@@ -377,6 +378,9 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
return QVariant::fromValue<ChatBarCache *>(m_room->editCache());
|
||||
}
|
||||
if (role == PlayOnFinishedrole) {
|
||||
return m_playOnFinished;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -416,6 +420,7 @@ QHash<int, QByteArray> MessageContentModel::roleNamesStatic()
|
||||
roles[MessageContentModel::ThreadRootRole] = "threadRoot";
|
||||
roles[MessageContentModel::LinkPreviewerRole] = "linkPreviewer";
|
||||
roles[MessageContentModel::ChatBarCacheRole] = "chatBarCache";
|
||||
roles[MessageContentModel::PlayOnFinishedrole] = "playOnFinished";
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -559,11 +564,19 @@ QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentT
|
||||
case MessageComponentType::Text: {
|
||||
const auto roomMessageEvent = eventCast<const Quotient::RoomMessageEvent>(event.first);
|
||||
auto body = EventHandler::rawMessageBody(*roomMessageEvent);
|
||||
return TextHandler().textComponents(body,
|
||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||
m_room,
|
||||
roomMessageEvent,
|
||||
roomMessageEvent->isReplaced());
|
||||
if (body.trimmed().isEmpty()) {
|
||||
return TextHandler().textComponents(i18n("<i>This event does not have any content.</i>"),
|
||||
Qt::TextFormat::RichText,
|
||||
m_room,
|
||||
roomMessageEvent,
|
||||
roomMessageEvent->isReplaced());
|
||||
} else {
|
||||
return TextHandler().textComponents(body,
|
||||
EventHandler::messageBodyInputFormat(*roomMessageEvent),
|
||||
m_room,
|
||||
roomMessageEvent,
|
||||
roomMessageEvent->isReplaced());
|
||||
}
|
||||
}
|
||||
case MessageComponentType::File: {
|
||||
QList<MessageComponent> components;
|
||||
@@ -779,4 +792,9 @@ void MessageContentModel::setThreadsEnabled(bool enableThreads)
|
||||
m_threadsEnabled = enableThreads;
|
||||
}
|
||||
|
||||
void MessageContentModel::setPlayOnFinished(bool value)
|
||||
{
|
||||
m_playOnFinished = value;
|
||||
}
|
||||
|
||||
#include "moc_messagecontentmodel.cpp"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user