Warning, /network/neochat/src/qml/RoomPage.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2018-2020 Black Hat <bhat@encom.eu.org> 0002 // SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu> 0003 // SPDX-License-Identifier: GPL-3.0-only 0004 0005 import QtQuick 0006 import QtQuick.Controls as QQC2 0007 import QtQuick.Layouts 0008 import QtQuick.Window 0009 0010 import org.kde.kirigamiaddons.labs.components as KirigamiComponents 0011 import org.kde.kirigami as Kirigami 0012 import org.kde.kitemmodels 0013 0014 import org.kde.neochat 0015 import org.kde.neochat.config 0016 0017 Kirigami.Page { 0018 id: root 0019 0020 /// Not readonly because of the separate window view. 0021 property NeoChatRoom currentRoom: RoomManager.currentRoom 0022 0023 required property NeoChatConnection connection 0024 0025 /** 0026 * @brief The TimelineModel to use. 0027 * 0028 * Required so that new events can be requested when the end of the current 0029 * local timeline is reached. 0030 * 0031 * @note For loading a room in a different window, override this with a new 0032 * TimelineModel set with the room to be shown. 0033 * 0034 * @sa TimelineModel 0035 */ 0036 property TimelineModel timelineModel: RoomManager.timelineModel 0037 0038 /** 0039 * @brief The MessageFilterModel to use. 0040 * 0041 * This model has the filtered list of events that should be shown in the timeline. 0042 * 0043 * @note For loading a room in a different window, override this with a new 0044 * MessageFilterModel with the new TimelineModel as the source model. 0045 * 0046 * @sa TimelineModel, MessageFilterModel 0047 */ 0048 property MessageFilterModel messageFilterModel: RoomManager.messageFilterModel 0049 0050 /** 0051 * @brief The MediaMessageFilterModel to use. 0052 * 0053 * This model has the filtered list of media events that should be shown in 0054 * the timeline. 0055 * 0056 * @note For loading a room in a different window, override this with a new 0057 * MediaMessageFilterModel with the new MessageFilterModel as the source model. 0058 * 0059 * @sa TimelineModel, MessageFilterModel 0060 */ 0061 property MediaMessageFilterModel mediaMessageFilterModel: RoomManager.mediaMessageFilterModel 0062 0063 /** 0064 * @brief The ActionsHandler object to use. 0065 */ 0066 property ActionsHandler actionsHandler: ActionsHandler { 0067 room: root.currentRoom 0068 } 0069 0070 property bool loading: !root.currentRoom || (root.currentRoom.timelineSize === 0 && !root.currentRoom.allHistoryLoaded) 0071 0072 /// Disable cancel shortcut. Used by the separate window since it provides its own cancel implementation. 0073 property bool disableCancelShortcut: false 0074 0075 title: root.currentRoom.displayName 0076 focus: true 0077 padding: 0 0078 0079 actions: [ 0080 Kirigami.Action { 0081 visible: Kirigami.Settings.isMobile || !applicationWindow().pageStack.wideMode 0082 icon.name: "view-right-new" 0083 onTriggered: applicationWindow().openRoomDrawer() 0084 } 0085 ] 0086 0087 KeyNavigation.left: pageStack.get(0) 0088 0089 onCurrentRoomChanged: { 0090 banner.visible = false; 0091 if (!Kirigami.Settings.isMobile && chatBarLoader.item) { 0092 chatBarLoader.item.forceActiveFocus(); 0093 } 0094 } 0095 0096 Connections { 0097 target: root.connection 0098 function onIsOnlineChanged() { 0099 if (!root.connection.isOnline) { 0100 banner.text = i18n("NeoChat is offline. Please check your network connection."); 0101 banner.visible = true; 0102 banner.type = Kirigami.MessageType.Error; 0103 } else { 0104 banner.visible = false; 0105 } 0106 } 0107 } 0108 0109 header: KirigamiComponents.Banner { 0110 id: banner 0111 0112 showCloseButton: true 0113 visible: false 0114 } 0115 0116 Loader { 0117 id: timelineViewLoader 0118 anchors.fill: parent 0119 active: root.currentRoom && !root.currentRoom.isInvite && !root.loading 0120 sourceComponent: TimelineView { 0121 id: timelineView 0122 currentRoom: root.currentRoom 0123 timelineModel: root.timelineModel 0124 messageFilterModel: root.messageFilterModel 0125 actionsHandler: root.actionsHandler 0126 onFocusChatBar: { 0127 if (chatBarLoader.item) { 0128 chatBarLoader.item.forceActiveFocus(); 0129 } 0130 } 0131 } 0132 } 0133 0134 Loader { 0135 id: invitationLoader 0136 active: root.currentRoom && root.currentRoom.isInvite 0137 anchors.centerIn: parent 0138 sourceComponent: InvitationView { 0139 currentRoom: root.currentRoom 0140 anchors.centerIn: parent 0141 } 0142 } 0143 0144 Loader { 0145 active: root.loading && !invitationLoader.active 0146 anchors.centerIn: parent 0147 sourceComponent: Kirigami.LoadingPlaceholder { 0148 anchors.centerIn: parent 0149 } 0150 } 0151 0152 background: Rectangle { 0153 Kirigami.Theme.colorSet: Kirigami.Theme.View 0154 Kirigami.Theme.inherit: false 0155 color: Config.compactLayout ? Kirigami.Theme.backgroundColor : "transparent" 0156 } 0157 0158 footer: Loader { 0159 id: chatBarLoader 0160 active: timelineViewLoader.active && !root.currentRoom.readOnly 0161 sourceComponent: ChatBar { 0162 id: chatBar 0163 width: parent.width 0164 currentRoom: root.currentRoom 0165 connection: root.connection 0166 actionsHandler: root.actionsHandler 0167 onMessageSent: { 0168 if (!timelineViewLoader.item.atYEnd) { 0169 timelineViewLoader.item.goToLastMessage(); 0170 } 0171 } 0172 } 0173 } 0174 0175 Connections { 0176 target: RoomManager 0177 function onCurrentRoomChanged() { 0178 if (!RoomManager.currentRoom) { 0179 if (pageStack.lastItem === root) { 0180 pageStack.pop(); 0181 } 0182 } else if (root.currentRoom.isInvite) { 0183 root.currentRoom.clearInvitationNotification(); 0184 } 0185 } 0186 0187 function onWarning(title, message) { 0188 root.warning(title, message); 0189 } 0190 } 0191 0192 Shortcut { 0193 sequence: StandardKey.Cancel 0194 onActivated: { 0195 if (!timelineViewLoader.item.atYEnd || root.currentRoom.hasUnreadMessages) { 0196 timelineViewLoader.item.goToLastMessage(); 0197 root.currentRoom.markAllMessagesAsRead(); 0198 } else { 0199 applicationWindow().pageStack.get(0).forceActiveFocus(); 0200 } 0201 } 0202 enabled: !root.disableCancelShortcut 0203 } 0204 0205 Connections { 0206 target: root.connection 0207 function onJoinedRoom(room, invited) { 0208 if (root.currentRoom.id === invited.id) { 0209 RoomManager.resolveResource(room.id); 0210 } 0211 } 0212 } 0213 0214 Keys.onPressed: event => { 0215 if (!(event.modifiers & Qt.ControlModifier) && event.key < Qt.Key_Escape) { 0216 event.accepted = true; 0217 chatBarLoader.item.insertText(event.text); 0218 chatBarLoader.item.forceActiveFocus(); 0219 return; 0220 } else if (event.key === Qt.Key_PageUp) { 0221 event.accepted = true; 0222 timelineViewLoader.item.pageUp(); 0223 } else if (event.key === Qt.Key_PageDown) { 0224 event.accepted = true; 0225 timelineViewLoader.item.pageDown(); 0226 } 0227 } 0228 0229 Connections { 0230 target: root.currentRoom 0231 function onShowMessage(messageType, message) { 0232 banner.text = message; 0233 banner.type = messageType === ActionsHandler.Error ? Kirigami.MessageType.Error : messageType === ActionsHandler.Positive ? Kirigami.MessageType.Positive : Kirigami.MessageType.Information; 0234 banner.visible = true; 0235 } 0236 } 0237 0238 function warning(title, message) { 0239 banner.text = `${title}<br />${message}`; 0240 banner.type = Kirigami.MessageType.Warning; 0241 banner.visible = true; 0242 } 0243 0244 Connections { 0245 target: RoomManager 0246 function onShowUserDetail(user) { 0247 root.showUserDetail(user); 0248 } 0249 0250 function onShowEventSource(eventId) { 0251 applicationWindow().pageStack.pushDialogLayer('qrc:/org/kde/neochat/qml/MessageSourceSheet.qml', { 0252 sourceText: root.currentRoom.getEventJsonSource(eventId) 0253 }, { 0254 title: i18n("Message Source"), 0255 width: Kirigami.Units.gridUnit * 25 0256 }); 0257 } 0258 0259 function onShowMessageMenu(eventId, author, delegateType, plainText, htmlText, selectedText) { 0260 const contextMenu = messageDelegateContextMenu.createObject(root, { 0261 selectedText: selectedText, 0262 author: author, 0263 eventId: eventId, 0264 delegateType: delegateType, 0265 plainText: plainText, 0266 htmlText: htmlText 0267 }); 0268 contextMenu.open(); 0269 } 0270 0271 function onShowFileMenu(eventId, author, delegateType, plainText, mimeType, progressInfo) { 0272 const contextMenu = fileDelegateContextMenu.createObject(root, { 0273 author: author, 0274 eventId: eventId, 0275 delegateType: delegateType, 0276 plainText: plainText, 0277 mimeType: mimeType, 0278 progressInfo: progressInfo 0279 }); 0280 contextMenu.open(); 0281 } 0282 0283 function onShowMaximizedMedia(index) { 0284 var popup = maximizeComponent.createObject(QQC2.Overlay.overlay, { 0285 initialIndex: index 0286 }); 0287 popup.closed.connect(() => { 0288 timelineViewLoader.item.interactive = true; 0289 popup.destroy(); 0290 }); 0291 popup.open(); 0292 } 0293 } 0294 0295 function showUserDetail(user) { 0296 userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, { 0297 room: root.currentRoom, 0298 user: root.currentRoom.getUser(user.id) 0299 }).open(); 0300 } 0301 0302 Component { 0303 id: userDetailDialog 0304 UserDetailDialog {} 0305 } 0306 0307 Component { 0308 id: messageDelegateContextMenu 0309 MessageDelegateContextMenu { 0310 connection: root.connection 0311 } 0312 } 0313 0314 Component { 0315 id: fileDelegateContextMenu 0316 FileDelegateContextMenu { 0317 connection: root.connection 0318 } 0319 } 0320 0321 Component { 0322 id: maximizeComponent 0323 NeochatMaximizeComponent { 0324 currentRoom: root.currentRoom 0325 model: root.mediaMessageFilterModel 0326 } 0327 } 0328 }