diff --git a/src/apps/qml/Desktop.qml b/src/apps/qml/Desktop.qml index 2a64237d..5b305117 100644 --- a/src/apps/qml/Desktop.qml +++ b/src/apps/qml/Desktop.qml @@ -1,502 +1,503 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2019 Montel Laurent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 as QQC2 import KDE.Ruqola.RuqolaUtils 1.0 import KDE.Ruqola.Ruqola 1.0 import KDE.Ruqola.DDPClient 1.0 import KDE.Ruqola.RoomFilterProxyModel 1.0 import org.kde.kirigami 2.7 as Kirigami import KDE.Ruqola.DebugCategory 1.0 import KDE.Ruqola.Channel 1.0 import KDE.Ruqola.AccountManager 1.0 Kirigami.ApplicationWindow { id: appid readonly property int margin: 11 property string selectedRoomID: ""; property QtObject selectedRoom property QtObject messageModel property QtObject userModel property QtObject rocketChatAccount: accountManager.currentAccount() property QtObject filesModel: appid.rocketChatAccount.filesForRoomFilterProxyModel() property QtObject discussionsModel: appid.rocketChatAccount.discussionsFilterProxyModel() property QtObject mentionsModel: appid.rocketChatAccount.mentionsFilterProxyModel() property QtObject accountManager: Ruqola.accountManager() property QtObject accountManagerModel: accountManager.rocketChatAccountModel() property QtObject searchMessageModel: rocketChatAccount.searchMessageFilterProxyModel() property QtObject emojiModel: rocketChatAccount.emoticonModel() property QtObject threadsModel: rocketChatAccount.threadsFilterProxyModel() property QtObject threadMessagesModel: rocketChatAccount.threadMessageModel() + property QtObject pinnedMessagesModel: rocketChatAccount.pinnedMessageModel() property string userInputMessageText: ""; width: Kirigami.Units.gridUnit * 55 height: Kirigami.Units.gridUnit * 40 title: i18n("Ruqola") function switchToRoom(roomID) { if (roomID === selectedRoomID) { return; } appid.rocketChatAccount.switchingToRoom(roomID) appid.rocketChatAccount.setUserCurrentMessage(appid.userInputMessageText, selectedRoomID) appid.selectedRoomID = roomID; appid.messageModel = appid.rocketChatAccount.messageModelForRoom(roomID) appid.selectedRoom = appid.rocketChatAccount.getRoomWrapper(roomID) appid.userModel = appid.rocketChatAccount.usersForRoomFilterProxyModel(roomID) } pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.None pageStack.initialPage: [roomsComponent, mainComponent] pageStack.visible: rocketChatAccount.loginStatus === DDPClient.LoggedIn globalDrawer: Kirigami.GlobalDrawer { drawerOpen: false handleVisible: true resetMenuOnTriggered: true topContent: [ QQC2.Label { text: rocketChatAccount.userName === "" ? "" : i18n("Hello, %1", rocketChatAccount.userName) textFormat: Text.PlainText } ] actions: [ Kirigami.Action { text: i18n("About") iconName: ":/icons/systray.png" onTriggered: { aboutDataDialogLoader.active = true } }, Kirigami.Action { text: i18n("Report a Bug") iconName: "tools-report-bug" onTriggered: { Qt.openUrlExternally("https://bugs.kde.org/report.cgi"); } }, Kirigami.Action { text: i18n("Configure Account") iconName: "settings-configure" onTriggered: { configureServerList.visible = true pageStack.visible = false } }, Kirigami.Action { text: i18n("Handbook") iconName: "system-help" onTriggered: { rocketChatAccount.openDocumentation(); } }, Kirigami.Action { separator: true }, Kirigami.Action { text: i18n("Log out") iconName: "system-log-out" onTriggered: { rocketChatAccount.logOut(); appid.globalDrawer.drawerOpen = false; } }, Kirigami.Action { separator: true }, Kirigami.Action { shortcut: StandardKey.Quit text: i18n("Quit") iconName: "application-exit" onTriggered: { Qt.quit(); } } ] } ConfigureServerList { id: configureServerList accountModel: accountManagerModel visible: false onCloseConfigureServer: { configureServerList.visible = false pageStack.visible = true } } LoginPage { id: loginTab rcAccount: rocketChatAccount } Loader { id: aboutDataDialogLoader active: false sourceComponent: AboutDialog { id: aboutDataDialog parent: appid.pageStack applicationData: Ruqola.applicationData() Component.onCompleted: { open() } onOpenurl: { RuqolaUtils.openUrl(link); } onRejected: { aboutDataDialogLoader.active = false } } } Loader { id: privateChannelInfoDialogLoader active: false sourceComponent: PrivateChannelInfoDialog { id: privateChannelInfoDialog roomInfo: appid.selectedRoom parent: appid.pageStack onBlockUser: { rocketChatAccount.blockUser(rid, block) } onRejected: { privateChannelInfoDialogLoader.active = false } onAccepted: { privateChannelInfoDialogLoader.active = false } Component.onCompleted: { initializeAndOpen() } } } Loader { id: notificationsDialogLoader active: false sourceComponent: NotificationOptionsDialog { id: notificationsDialog parent: appid.pageStack onModifyNotificationsSetting: { rocketChatAccount.changeNotificationsSettings(roomId, type, newVal) } Component.onCompleted: { rid = (appid && appid.selectedRoomID) ? appid.selectedRoomID : "" roomInfo = appid ? appid.selectedRoom : "" initializeAndOpen() } onRejected: { notificationsDialogLoader.active = false } onAccepted: { notificationsDialogLoader.active = false } } } Loader { id: channelInfoDialogLoader active: false sourceComponent: ChannelInfoDialog { id: channelInfoDialog parent: appid.pageStack roomInfo: appid.selectedRoom channelName: (appid && appid.selectedRoomID) ? appid.selectedRoomID : "" onDeleteRoom: { rocketChatAccount.eraseRoom(roomId, appid.selectedRoom.channelType) } onModifyChannelSetting: { rocketChatAccount.changeChannelSettings(roomId, type, newVal, channelType) } onRejected: { channelInfoDialogLoader.active = false } onAccepted: { channelInfoDialogLoader.active = false } Component.onCompleted: { initializeAndOpen() } } } Loader { id: leaveChannelDialogLoader active: false property string rid property string roomType sourceComponent: LeaveChannelDialog { id: leaveChannelDialog parent: appid.pageStack onLeaveChannel: { rocketChatAccount.leaveRoom(roomId, channelType) } onRejected: { leaveChannelDialogLoader.active = false } onAccepted: { leaveChannelDialogLoader.active = false } Component.onCompleted: { leaveChannelDialog.rId = leaveChannelDialogLoader.rid leaveChannelDialog.channelType = leaveChannelDialogLoader.roomType open() } } } Loader { id: addUserDialogLoader active: false sourceComponent: AddUserDialog { id: addUserDialog parent: appid.pageStack completerModel: rocketChatAccount.userCompleterFilterModelProxy() roomInfo: appid.selectedRoom roomId: appid.selectedRoomID onSearchUserName: { rocketChatAccount.userAutocomplete(pattern, ""); } onAddUser: { rocketChatAccount.addUserToRoom(userId, rid, channelType) } onRejected: { addUserDialogLoader.active = false } onAccepted: { addUserDialogLoader.active = false } Component.onCompleted: { initializeAndOpen() } } } Loader { id: searchMessageDialogLoader active: false sourceComponent: ShowSearchMessageDialog { id: searchMessageDialog roomId: appid.selectedRoomID parent: appid.pageStack searchMessageModel: appid.searchMessageModel onSearchMessage: { rocketChatAccount.messageSearch(pattern, rid) } onGoToMessage: { console.log(RuqolaDebugCategorySingleton.category, "Show history to message: " + messageId) } onRejected: { rocketChatAccount.clearSearchModel() searchMessageDialogLoader.active = false } onAccepted: { rocketChatAccount.clearSearchModel() searchMessageDialogLoader.active = false } Component.onCompleted: { roomId = appid.selectedRoomID initializeAndOpen() } } } Loader { id: jobErrorMessageDialogLoader property string jobMessageError active: false sourceComponent: JobErrorMessageDialog { id: jobErrorMessageDialog parent: appid.pageStack Component.onCompleted: { jobErrorMessageDialog.jobMessageError = jobErrorMessageDialogLoader.jobMessageError open() } onRejected: { jobErrorMessageDialogLoader.active = false } onAccepted: { jobErrorMessageDialogLoader.active = false } } } Loader { id: createNewChannelDialogLoader active: false sourceComponent: CreateNewChannelDialog { parent: appid.pageStack Component.onCompleted: { encryptedRoomEnabled = appid.rocketChatAccount.encryptedEnabled() initializeAndOpen() } onRejected: { createNewChannelDialogLoader.active = false } onAccepted: { createNewChannelDialogLoader.active = false } onCreateNewChannel: { rocketChatAccount.createNewChannel(name, readOnly, privateRoom, usernames, encryptedRoom, password, broadcast); } } } Loader { id: serverinfodialogLoader active: false sourceComponent: ServerInfoDialog { rcAccount: appid.rocketChatAccount parent: appid.pageStack Component.onCompleted: { open() } onRejected: { serverinfodialogLoader.active = false } } } SearchChannelDialog { id: searchChannelDialog searchChannelModel: rocketChatAccount.searchChannelFilterProxyModel() onSearchChannel: { rocketChatAccount.channelAndPrivateAutocomplete(pattern); } onOpenChannel: { if (channeltype === Channel.Room) { rocketChatAccount.openChannel(channelid) } else if (channeltype === Channel.PrivateChannel) { if (rocketChatAccount.userName !== channelid) { rocketChatAccount.openDirectChannel(channelid) } } else { console.log(RuqolaDebugCategorySingleton.category, "Unknown open channel type : " + channeltype + " channelid : " + channelid + " channelname : " + channelname) } } } Loader { id: takeVideoMessageLoader active: false sourceComponent: TakeVideoMessageDialog { id: takeVideoMessage parent: appid.pageStack rcAccount: rocketChatAccount Component.onCompleted: { open() } onRejected: { takeVideoMessageLoader.active = false } onAccepted: { takeVideoMessageLoader.active = false } } } QQC2.BusyIndicator { id: busy anchors.centerIn: parent visible: rocketChatAccount.loginStatus === DDPClient.LoggingIn } RoomsComponent { id: roomsComponent } MainComponent { id: mainComponent } Loader { id: channelPasswordDialogLoader active: false property string roomId sourceComponent: ChannelPasswordDialog { id: channelPasswordDialog parent: appid.pageStack onJoinRoom: { rocketChatAccount.joinRoom(roomId, password) } Component.onCompleted: { roomId = channelPasswordDialogLoader.roomId initializeAndOpen() } onRejected: { channelPasswordDialogLoader.active = false } onAccepted: { channelPasswordDialogLoader.active = false } } } Connections { target: rocketChatAccount onMissingChannelPassword: { channelPasswordDialogLoader.roomId = roomId channelPasswordDialogLoader.active = true } onJobFailed: { jobErrorMessageDialogLoader.jobMessageError = message jobErrorMessageDialogLoader.active = true } } onClosing: { Qt.quit(); } function toggleShow() { if (visible) { hide(); } else { show(); raise(); requestActivate(); } } Component.onCompleted: { systrayIcon.activateRequested.connect(toggleShow); } } diff --git a/src/apps/qml/MainComponent.qml b/src/apps/qml/MainComponent.qml index 4534c357..652ae31b 100644 --- a/src/apps/qml/MainComponent.qml +++ b/src/apps/qml/MainComponent.qml @@ -1,808 +1,831 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (C) 2017-2019 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 as QQC2 import KDE.Ruqola.RuqolaUtils 1.0 import KDE.Ruqola.Ruqola 1.0 import KDE.Ruqola.Clipboard 1.0 import KDE.Ruqola.RoomFilterProxyModel 1.0 import org.kde.kirigami 2.7 as Kirigami import KDE.Ruqola.DebugCategory 1.0 import KDE.Ruqola.ReceiveTypingNotificationManager 1.0 import KDE.Ruqola.DebugCategory 1.0 Component { id: mainComponent Kirigami.Page { id: mainWidget title: appid.selectedRoom ? appid.selectedRoom.displayRoomName : "" leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 actions { left: Kirigami.Action { icon.name: "preferences-desktop-notification" icon.color: "transparent" visible: appid.selectedRoom onTriggered: { notificationsDialogLoader.active = true; } } main: Kirigami.Action { id: showUsersAction icon.name: "system-users" visible: appid.selectedRoom checkable: true } right: Kirigami.Action { icon.name: "edit-find" visible: appid.selectedRoom onTriggered: { searchMessageDialogLoader.active = true; } } contextualActions: [ Kirigami.Action { visible: appid.selectedRoom text: i18n("Channel Info") onTriggered: { var channelType = appid.selectedRoom.channelType; if (channelType === "c" || channelType === "p") { //Only for debug // if (channelType === "c") { // appid.rocketChatAccount.channelInfo(appid.selectedRoom.rid); // } else { // appid.rocketChatAccount.groupInfo(appid.selectedRoom.rid); // } //For testing channelInfoDialogLoader.active = true } else if (channelType === "d") { privateChannelInfoDialogLoader.active = true } else { console.log(RuqolaDebugCategorySingleton.category,"channel type " + appid.selectedRoom.channelType) } } }, Kirigami.Action { visible: appid.selectedRoom text: i18n("Mentions") onTriggered: { appid.rocketChatAccount.channelGetAllUserMentions(appid.selectedRoomID); showMentionsInRoomDialogLoader.active = true; } }, Kirigami.Action { visible: appid.selectedRoom && appid.rocketChatAccount.hasPinnedMessagesSupport() text: i18n("Pinned Messages") onTriggered: { appid.rocketChatAccount.getPinnedMessages(appid.selectedRoomID); + showPinnedMessageDialogLoader.active = true; } }, Kirigami.Action { visible: appid.selectedRoom && appid.rocketChatAccount.discussionEnabled() text: i18n("Discussions") onTriggered: { appid.rocketChatAccount.discussionsInRoom(appid.selectedRoomID); showDiscussionsInRoomDialogLoader.active = true; } }, Kirigami.Action { visible: appid.selectedRoom && appid.rocketChatAccount.threadsEnabled() text: i18n("Threads") onTriggered: { appid.rocketChatAccount.threadsInRoom(appid.selectedRoomID); showThreadsInRoomDialogLoader.active = true } }, Kirigami.Action { id: menuVideoChatAction property bool shouldBeVisible: false visible: shouldBeVisible && appid.selectedRoom text: i18n("Video Chat") onTriggered: { appid.rocketChatAccount.createJitsiConfCall(appid.selectedRoomID); } }, Kirigami.Action { text: i18n("Add User In Room") visible: appid.selectedRoom ? appid.selectedRoom.canBeModify : false onTriggered: { var channelType = appid.selectedRoom.channelType; if (channelType === "c" || channelType === "p") { addUserDialogLoader.active = true } } }, Kirigami.Action { visible: appid.selectedRoom text: i18n("Take a Video Message") onTriggered: { takeVideoMessageLoader.active = true; } }, Kirigami.Action { visible: appid.selectedRoom text: i18n("Load Recent History") onTriggered: { appid.rocketChatAccount.loadHistory(appid.selectedRoomID); } }, Kirigami.Action { visible: appid.selectedRoom text: i18n("Show Files Attachment In Room") onTriggered: { showFilesInRoomDialogLoader.active = true } } ] } onContextualActionsAboutToShow: { menuVideoChatAction.shouldBeVisible = appid.rocketChatAccount.jitsiEnabled() } globalToolBarStyle: Kirigami.ApplicationHeaderStyle.ToolBar titleDelegate: RowLayout { QQC2.ToolButton { icon.name: "favorite" checkable: true visible: appid.selectedRoom && !appid.selectedRoom.isDiscussionRoom Accessible.onPressAction: onClicked Binding on checked { value: appid.selectedRoom && appid.selectedRoom.favorite } onToggled: { appid.rocketChatAccount.changeFavorite(appid.selectedRoomID, checked) } } QQC2.ToolButton { icon.name: "draw-arrow-back" Accessible.onPressAction: onClicked visible: appid.selectedRoom && appid.selectedRoom.isDiscussionRoom onClicked: { appid.switchToRoom(appid.selectedRoom.parentRid) } } Kirigami.Icon { source: "encrypted" //FIXME height: Kirigami.Units.iconSizes.medium width: height visible: appid.selectedRoom && appid.selectedRoom.encrypted } Kirigami.Heading { text: appid.selectedRoom ? appid.selectedRoom.displayRoomName : "" level: 3 Component.onCompleted: { font.bold = true } } Item { Layout.fillWidth: true } } header: Column { spacing: Kirigami.Units.smallSpacing QQC2.Label { visible: appid.selectedRoom && (appid.selectedRoom.topic !== "") text: appid.selectedRoom ? appid.selectedRoom.topic : "" font.italic: true anchors.right: parent.right anchors.left: parent.left anchors.margins: 2*Kirigami.Units.smallSpacing wrapMode: QQC2.Label.Wrap } QQC2.Label { visible: appid.selectedRoom && (appid.selectedRoom.announcement !== "") text: appid.selectedRoom ? appid.selectedRoom.announcement : "" anchors.right: parent.right anchors.left: parent.left anchors.margins: 2*Kirigami.Units.smallSpacing wrapMode: QQC2.Label.Wrap onLinkActivated: { RuqolaUtils.openUrl(link); } } QQC2.Label { visible: appid.selectedRoom && (appid.selectedRoom.description !== "") text: appid.selectedRoom ? appid.selectedRoom.description : "" font.italic: true anchors.right: parent.right anchors.left: parent.left anchors.margins: 2*Kirigami.Units.smallSpacing wrapMode: QQC2.Label.Wrap } Kirigami.Separator { anchors.right: parent.right anchors.left: parent.left visible: appid.selectedRoom } Flow { id: topBarUserList readonly property bool isActive: showUsersAction.checked anchors { left: parent.left right: parent.right margins: Kirigami.Units.smallSpacing } opacity: topBarUserList.isActive ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 650; easing.type: Easing.InOutQuad } } Repeater { id: repeaterUser model: parent.opacity > 0.5 ? appid.userModel : 0 RowLayout { Kirigami.Icon { source: model.iconstatus //FIXME height: Kirigami.Units.iconSizes.small width: height } Loader { id: userMenuLoader active: false property var posX property var posY sourceComponent: UserMenu { id: userMenu x: userMenuLoader.posX y: userMenuLoader.posY userId: model.userid can_manage_users: appid.selectedRoom.canChangeRoles ownUserId: appid.rocketChatAccount.userID isAdirectChannel: appid.selectedRoom.channelType === "d" onKickUser: { appid.rocketChatAccount.kickUser(appid.selectedRoomID, userId, appid.selectedRoom.channelType) } onChangeRole: { appid.rocketChatAccount.changeRoles(appid.selectedRoomID, userId, appid.selectedRoom.channelType, type) } onIgnoreUser: { if (userId !== appid.rocketChatAccount.userID) { appid.rocketChatAccount.ignoreUser(appid.selectedRoomID, userId, ignore) } } onOpenConversation: { if (userId !== appid.rocketChatAccount.userID) { //console.log("userId " + userId) openDirectChannelDialog.username = model.username; openDirectChannelDialog.open() } } onAboutToShow: { hasLeaderRole = appid.selectedRoom.userHasLeaderRole(model.userid) hasModeratorRole = appid.selectedRoom.userHasModeratorRole(model.userid) hasOwnerRole = appid.selectedRoom.userHasOwnerRole(model.userid) } Component.onCompleted: { open() } onAboutToHide: { userMenuLoader.active = false } } } QQC2.Label { text: model.displayname onLinkActivated: { if (model.userid !== appid.rocketChatAccount.userID) { openDirectChannelDialog.username = link; openDirectChannelDialog.open() } } MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { userMenuLoader.posX = mouse.x userMenuLoader.posY = mouse.y if (userMenuLoader.active) userMenuLoader.active = false else userMenuLoader.active = true } } } } } } SearchLabel { width: parent.width hasFullList: appid.userModel ? appid.userModel.hasFullList : false numberOfElements: repeaterUser.count onLoadMoreElements: { appid.rocketChatAccount.loadMoreUsersInRoom(appid.selectedRoomID, appid.selectedRoom.channelType) } } Item { width: parent.width height: topBarUserList.isActive ? 1 : 0 Kirigami.Separator { height: parent.height width: height > 0 ? parent.width : 0 anchors.centerIn: parent Behavior on width { NumberAnimation { duration: 650; easing.type: Easing.InOutQuad } } } } } } Clipboard { id: clipboard } ActiveChat { id: activeChat model: appid.messageModel rcAccount: appid.rocketChatAccount roomId: appid.selectedRoomID anchors.fill: parent clip: true useMenuMessage: true QQC2.ScrollBar.vertical: QQC2.ScrollBar { } onDragEnded : { if (roomId !== "" && activeChat.atYBeginning) { rcAccount.loadHistory(roomId) } } onPinMessage: { appid.rocketChatAccount.pinMessage(messageId, pinned) } onEditMessage: { userInputMessage.messageId = messageId; userInputMessage.setOriginalMessage(messageStr) //console.log(RuqolaDebugCategorySingleton.category, "edit! messageId : " + messageId + " messageStr " + messageStr) } onCopyMessage: { clipboard.text = messageStr //console.log(RuqolaDebugCategorySingleton.category, "copy! messageId : " + messageId + " messageStr " + messageStr) } onReplyMessage: { console.log(RuqolaDebugCategorySingleton.category, "Not implemented reply message : " + messageId) userInputMessage.messageId = messageId; } onSetFavoriteMessage: { appid.rocketChatAccount.starMessage(messageId, starred) } onIgnoreUser: { appid.rocketChatAccount.ignoreUser(roomId, userId, ignored) } onCreateDiscussion: { createDiscussionDialogLoader.roomId = roomId createDiscussionDialogLoader.messageId = messageId createDiscussionDialogLoader.originalMessage = originalMessage createDiscussionDialogLoader.active = true //TODO add message text too } onOpenChannel: { openChannelDialogLoader.channelName = channel openChannelDialogLoader.active = true; } onOpenDirectChannel: { openDirectChannelDialog.username = userName; openDirectChannelDialog.open() } onJitsiCallConfActivated: { appid.rocketChatAccount.joinJitsiConfCall(roomId) } onReportMessage: { reportMessageDialogLoader.messageId = messageId reportMessageDialogLoader.active = true } onDeleteMessage: { deleteMessageDialogLoader.messageId = messageId deleteMessageDialogLoader.active = true } onDownloadAttachment: { downloadFileDialog.fileToSaveUrl = url downloadFileDialog.open() } onDisplayImage: { displayImageDialog.iUrl = imageUrl displayImageDialog.title = title displayImageDialog.isAnimatedImage = isAnimatedImage displayImageDialog.clearScaleAndOpen(); } onDeleteReaction: { appid.rocketChatAccount.reactOnMessage(messageId, emoji, false) } onAddReaction: { appid.rocketChatAccount.reactOnMessage(messageId, emoji, true) } onOpenThread: { appid.rocketChatAccount.getThreadMessages(threadMessageId) showThreadMessageDialogLoader.threadMessageId = threadMessageId; showThreadMessageDialogLoader.threadPreviewText = threadPreviewText showThreadMessageDialogLoader.active = true } onOpenDiscussion: { //console.log(RuqolaDebugCategorySingleton.category, "Open discussion " + discussionRoomId) appid.switchToRoom(discussionRoomId) } onReplyInThread: { //console.log(RuqolaDebugCategorySingleton.category,"reply in thread " + messageId) userInputMessage.threadmessageId = messageId; } Loader { id: openChannelDialogLoader active: false property string channelName sourceComponent: OpenChannelDialog { id: openChannelDialog parent: appid.pageStack onOpenChannel: { appid.rocketChatAccount.openChannel(channelName); } onRejected: { reportMessageDialogLoader.active = false } onAccepted: { reportMessageDialogLoader.active = false } Component.onCompleted: { channelName = openChannelDialogLoader.channelName open() } } } OpenDirectChannelDialog { id: openDirectChannelDialog parent: appid.pageStack onOpenDirectChannel: { if (appid.rocketChatAccount.userName !== userName) { appid.rocketChatAccount.openDirectChannel(userName); } } } Loader { id: createDiscussionDialogLoader active: false property string roomId property string messageId property string originalMessage sourceComponent: CreateDiscussionDialog { id: createDiscussionDialog parent: appid.pageStack onRejected: { createDiscussionDialogLoader.active = false } onAccepted: { createDiscussionDialogLoader.active = false } Component.onCompleted: { roomName = appid.selectedRoom.displayRoomName roomId = createDiscussionDialogLoader.roomId messageId = createDiscussionDialogLoader.messageId originalMessage = createDiscussionDialogLoader.originalMessage clearAndOpen() } onCreateNewDiscussion: { appid.rocketChatAccount.createDiscussion(parentRoomName, discussionTitle, replyMessage, msgId); } } } Loader { id: reportMessageDialogLoader active: false property string messageId sourceComponent: ReportMessageDialog { parent: appid.pageStack id: reportMessageDialog onReportMessage: { appid.rocketChatAccount.deleteMessage(messageId, message) } onRejected: { reportMessageDialogLoader.active = false } onAccepted: { reportMessageDialogLoader.active = false } Component.onCompleted: { msgId = reportMessageDialogLoader.messageId initializeAndOpen() } } } Loader { id: deleteMessageDialogLoader active: false property string messageId sourceComponent: DeleteMessageDialog { id: deleteMessageDialog parent: appid.pageStack onDeleteMessage: { appid.rocketChatAccount.deleteMessage(messageId, appid.selectedRoomID) } Component.onCompleted: { msgId = deleteMessageDialogLoader.messageId open() } onRejected: { deleteMessageDialogLoader.active = false } onAccepted: { deleteMessageDialogLoader.active = false } } } DownloadFileDialog { id: downloadFileDialog onAccepted: { if (fileUrl != "") { console.log(RuqolaDebugCategorySingleton.category, "You chose: " + fileUrl) appid.rocketChatAccount.downloadFile(fileToSaveUrl, fileUrl) } else { console.log(RuqolaDebugCategorySingleton.category, "No file selected"); } } } DisplayImageDialog { id: displayImageDialog parent: appid.pageStack } Loader { id: uploadFileDialogLoader active: false sourceComponent: UploadFileDialog { id: uploadFileDialog parent: appid.pageStack onUploadFile: { appid.rocketChatAccount.uploadFile(appid.selectedRoomID, description, messageText, filename) } Component.onCompleted: { initializeAndOpen() } onRejected: { uploadFileDialogLoader.active = false } onAccepted: { uploadFileDialogLoader.active = false } } } Loader { id: showMentionsInRoomDialogLoader active: false sourceComponent: ShowMentionsInRoomDialog { id: showMentionsInRoomDialog parent: appid.pageStack roomId: appid.selectedRoomID mentionsModel: appid.mentionsModel onGoToMessage: { console.log(RuqolaDebugCategorySingleton.category, "Go to Message not implemented yet") } onRejected: { showMentionsInRoomDialogLoader.active = false } onAccepted: { showMentionsInRoomDialogLoader.active = false } Component.onCompleted: { initializeAndOpen() } } } Loader { id: showDiscussionsInRoomDialogLoader active: false sourceComponent: ShowDiscussionsInRoomDialog { id: showDiscussionsInRoomDialog parent: appid.pageStack discussionsModel: appid.discussionsModel roomId: appid.selectedRoomID Component.onCompleted: { initializeAndOpen() } onOpenDiscussion: { appid.switchToRoom(discussionId) showDiscussionsInRoomDialogLoader.active = false } onRejected: { showDiscussionsInRoomDialogLoader.active = false } onAccepted: { showDiscussionsInRoomDialogLoader.active = false } } } Loader { id: showThreadsInRoomDialogLoader active: false sourceComponent: ShowThreadsInRoomDialog { id: showThreadsInRoomDialog parent: appid.pageStack threadsModel: appid.threadsModel roomId: appid.selectedRoomID onOpenThread: { appid.rocketChatAccount.getThreadMessages(threadMessageId) showThreadMessageDialogLoader.threadMessageId = threadMessageId showThreadMessageDialogLoader.threadPreviewText = threadPreviewText showThreadsInRoomDialogLoader.active = false showThreadMessageDialogLoader.active = true } onRejected: { showThreadsInRoomDialogLoader.active = false } onAccepted: { showThreadsInRoomDialogLoader.active = false } Component.onCompleted: { initializeAndOpen() } } } Loader { id: showFilesInRoomDialogLoader active: false sourceComponent: ShowFilesInRoomDialog { id: showFilesInRoomDialog parent: appid.pageStack filesModel: appid.filesModel roomId: appid.selectedRoomID channelType: appid.selectedRoom.channelType onDownloadFile: { downloadFileDialog.fileToSaveUrl = file downloadFileDialog.open() } Component.onCompleted: { appid.rocketChatAccount.roomFiles(appid.selectedRoomID, appid.selectedRoom.channelType); initializeAndOpen() } onDeleteFile: { appid.rocketChatAccount.deleteFileMessage(appid.selectedRoomID, fileid, appid.selectedRoom.channelType) } onRejected: { showFilesInRoomDialogLoader.active = false } onAccepted: { showFilesInRoomDialogLoader.active = false } } } + Loader { + id: showPinnedMessageDialogLoader + active: false + property string threadMessageId + property string threadPreviewText + sourceComponent: ShowPinnedMessagesDialog { + id: showPinnedMessageDialog + parent: appid.pageStack + pinnedMessagesModel: appid.pinnedMessagesModel + onAccepted: { + showPinnedMessageDialogLoader.active = false + } + onRejected: { + showPinnedMessageDialogLoader.active = false + } + Component.onCompleted: { + showPinnedMessageDialogLoader.open() + } + } + } + + Loader { id: showThreadMessageDialogLoader active: false property string threadMessageId property string threadPreviewText sourceComponent: ShowThreadMessagesDialog { id: showThreadMessageDialog parent: appid.pageStack threadMessagesModel: appid.threadMessagesModel onAccepted: { showThreadMessageDialogLoader.active = false } onRejected: { showThreadMessageDialogLoader.active = false } Component.onCompleted: { showThreadMessageDialog.threadMessageId = showThreadMessageDialogLoader.threadMessageId; showThreadMessageDialog.threadPreviewText = showThreadMessageDialogLoader.threadPreviewText showThreadMessageDialog.open() } } } } Keys.onEscapePressed: { appid.rocketChatAccount.clearUnreadMessages(appid.selectedRoomID); } footer: QQC2.ToolBar { position: QQC2.ToolBar.Footer visible: appid.selectedRoom ColumnLayout { anchors.fill: parent QQC2.Label { id: channelInfo font.bold: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft visible: appid.selectedRoom && appid.selectedRoom.roomMessageInfo.length > 0 text: appid.selectedRoom ? appid.selectedRoom.roomMessageInfo : "" } QQC2.Label { id: typingInfo visible: text.length > 0 } UserInput { id: userInputMessage rcAccount: appid.rocketChatAccount inputCompleterModel: rcAccount.inputCompleterModel() visible: appid.selectedRoom && (appid.selectedRoom.roomMessageInfo.length === 0) messageLineText: rcAccount.getUserCurrentMessage(appid.selectedRoomID) selectedRoomId: appid.selectedRoomID onTextEditing: { rcAccount.textEditing(appid.selectedRoomID, str) appid.userInputMessageText = str; } onClearUnreadMessages: { rcAccount.clearUnreadMessages(appid.selectedRoomID) } onUploadFile: { uploadFileDialogLoader.active = true } } Connections { target: appid.rocketChatAccount.receiveTypingNotificationManager() onNotificationChanged: { //console.log(RuqolaDebugCategorySingleton.category, "Typing in roomId: " + roomId + " str " + notificationStr); if (appid.selectedRoomID === roomId) { var wasAtEnd = activeChat.atYEnd; typingInfo.text = notificationStr; if (wasAtEnd) { activeChat.positionViewAtEnd(); } } } onClearNotification: { typingInfo.text = ""; } } } } }// mainWidget Item } diff --git a/src/apps/qml/ShowPinnedMessagesDialog.qml b/src/apps/qml/ShowPinnedMessagesDialog.qml index abdc3afc..437920d8 100644 --- a/src/apps/qml/ShowPinnedMessagesDialog.qml +++ b/src/apps/qml/ShowPinnedMessagesDialog.qml @@ -1,99 +1,99 @@ /* Copyright (c) 2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 as QQC2 import QtQuick.Window 2.2 import QtQuick 2.9 import org.kde.kirigami 2.7 as Kirigami QQC2.Dialog { id: showPinnedMessagesDialog title: i18n("Pinned Messages") - property QtObject pinnedmessagesModel + property QtObject pinnedMessagesModel property string roomId width: parent.width * 9 / 10 height: parent.height * 9 / 10 anchors.centerIn: parent modal: true focus: true standardButtons: QQC2.Dialog.Close function initializeAndOpen() { pinnedmessagesModel.clearFilter(); searchField.text = ""; searchField.forceActiveFocus(); open(); } contentItem: ColumnLayout { LineEditWithClearButton { id: searchField placeholderText: i18n("Search Pinned Messages...") Layout.fillWidth: true onTextChanged: { pinnedmessagesModel.setFilterString(text); } } SearchLabel { hasFullList: pinnedmessagesModel.hasFullList numberOfElements: listview.count labelText: listview.count === 0 ? i18n("No Pinned Messages found") : i18np("%1 Pinned Message in room (Total: %2)", "%1 Pinned Messages in room (Total: %2)", listview.count, pinnedmessagesModel.total()) onLoadMoreElements: { //appid.rocketChatAccount.loadMoreDiscussions(roomId) } } ListView { id: listview Layout.fillWidth: true Layout.fillHeight: true clip: true // Scrollars QQC2.ScrollIndicator.vertical: QQC2.ScrollIndicator { } QQC2.ScrollIndicator.horizontal: QQC2.ScrollIndicator { } onDragEnded : { if (roomId !== "" && listview.atYBeginning ) { //appid.rocketChatAccount.loadMoreDiscussions(roomId) } } model: pinnedmessagesModel delegate: DiscussionMessageDelegate { anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: Kirigami.Units.largeSpacing anchors.leftMargin: Kirigami.Units.largeSpacing i_numberofmessages: numberofmessages i_lastmessage: lastmessage i_discussionid: discussionid i_description: description i_timestamp: timestamp onOpenDiscussion: { showDiscussionsInRoomDialog.openDiscussion(messageDiscussionId) } } } } } diff --git a/src/ruqolacore/model/pinnedmessagemodel.cpp b/src/ruqolacore/model/pinnedmessagemodel.cpp index 0e23d82e..2a8579d2 100644 --- a/src/ruqolacore/model/pinnedmessagemodel.cpp +++ b/src/ruqolacore/model/pinnedmessagemodel.cpp @@ -1,82 +1,82 @@ /* Copyright (c) 2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "pinnedmessagemodel.h" #include "listmessages.h" PinnedMessageModel::PinnedMessageModel(const QString &roomID, RocketChatAccount *account, Room *room, QObject *parent) : MessageModel(roomID, account, room, parent) { } PinnedMessageModel::~PinnedMessageModel() { } QString PinnedMessageModel::roomId() const { return mRoomId; } void PinnedMessageModel::setRoomId(const QString &threadMessageId) { mRoomId = threadMessageId; } void PinnedMessageModel::parse(const QJsonObject &obj) { - ListMessages threadmessages; - threadmessages.parseMessages(obj); - for (int i = 0, total = threadmessages.count(); i < total; ++i) { - addMessage(threadmessages.at(i)); + ListMessages messages; + messages.parseMessages(obj); + for (int i = 0, total = messages.count(); i < total; ++i) { + addMessage(messages.at(i)); } } void PinnedMessageModel::parsePinnedMessages(const QJsonObject &obj) { clear(); parse(obj); } void PinnedMessageModel::loadMorePinnedMessages(const QJsonObject &obj) { parse(obj); } int PinnedMessageModel::total() const { return mTotal; } void PinnedMessageModel::setTotal(int total) { mTotal = total; } bool PinnedMessageModel::loadMorePinnedMessageInProgress() const { return mLoadingInProgress; } void PinnedMessageModel::setLoadMorePinnedMessageInProgress(bool inProgress) { mLoadingInProgress = inProgress; }