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 connection: root.connection 0132 } 0133 } 0134 0135 Loader { 0136 id: invitationLoader 0137 active: root.currentRoom && root.currentRoom.isInvite 0138 anchors.centerIn: parent 0139 sourceComponent: InvitationView { 0140 currentRoom: root.currentRoom 0141 anchors.centerIn: parent 0142 } 0143 } 0144 0145 Loader { 0146 active: root.loading && !invitationLoader.active 0147 anchors.centerIn: parent 0148 sourceComponent: Kirigami.LoadingPlaceholder { 0149 anchors.centerIn: parent 0150 } 0151 } 0152 0153 background: Rectangle { 0154 Kirigami.Theme.colorSet: Kirigami.Theme.View 0155 Kirigami.Theme.inherit: false 0156 color: Config.compactLayout ? Kirigami.Theme.backgroundColor : "transparent" 0157 } 0158 0159 footer: Loader { 0160 id: chatBarLoader 0161 active: timelineViewLoader.active && !root.currentRoom.readOnly 0162 sourceComponent: ChatBar { 0163 id: chatBar 0164 width: parent.width 0165 currentRoom: root.currentRoom 0166 connection: root.connection 0167 actionsHandler: root.actionsHandler 0168 onMessageSent: { 0169 if (!timelineViewLoader.item.atYEnd) { 0170 timelineViewLoader.item.goToLastMessage(); 0171 } 0172 } 0173 } 0174 } 0175 0176 Connections { 0177 target: RoomManager 0178 function onCurrentRoomChanged() { 0179 if(!RoomManager.currentRoom) { 0180 if(pageStack.lastItem === root) { 0181 pageStack.pop() 0182 } 0183 } else if (root.currentRoom.isInvite) { 0184 root.currentRoom.clearInvitationNotification(); 0185 } 0186 } 0187 0188 function onWarning(title, message) { 0189 root.warning(title, message); 0190 } 0191 } 0192 0193 Shortcut { 0194 sequence: StandardKey.Cancel 0195 onActivated: { 0196 if (!timelineViewLoader.item.atYEnd || root.currentRoom.hasUnreadMessages) { 0197 timelineViewLoader.item.goToLastMessage(); 0198 root.currentRoom.markAllMessagesAsRead(); 0199 } else { 0200 applicationWindow().pageStack.get(0).forceActiveFocus(); 0201 } 0202 } 0203 enabled: !root.disableCancelShortcut 0204 } 0205 0206 Connections { 0207 target: root.connection 0208 function onJoinedRoom(room, invited) { 0209 if(root.currentRoom.id === invited.id) { 0210 RoomManager.enterRoom(room); 0211 } 0212 } 0213 } 0214 0215 Keys.onPressed: event => { 0216 if (!(event.modifiers & Qt.ControlModifier) && event.key < Qt.Key_Escape) { 0217 event.accepted = true; 0218 chatBarLoader.item.insertText(event.text); 0219 chatBarLoader.item.forceActiveFocus(); 0220 return; 0221 } else if (event.key === Qt.Key_PageUp) { 0222 event.accepted = true; 0223 timelineViewLoader.item.pageUp() 0224 } else if (event.key === Qt.Key_PageDown) { 0225 event.accepted = true; 0226 timelineViewLoader.item.pageDown() 0227 } 0228 } 0229 0230 Connections { 0231 target: root.currentRoom 0232 function onShowMessage(messageType, message) { 0233 banner.text = message; 0234 banner.type = messageType === ActionsHandler.Error ? Kirigami.MessageType.Error : messageType === ActionsHandler.Positive ? Kirigami.MessageType.Positive : Kirigami.MessageType.Information; 0235 banner.visible = true; 0236 } 0237 } 0238 0239 function warning(title, message) { 0240 banner.text = `${title}<br />${message}`; 0241 banner.type = Kirigami.MessageType.Warning; 0242 banner.visible = true; 0243 } 0244 0245 Connections { 0246 target: RoomManager 0247 function onShowUserDetail(user) { 0248 root.showUserDetail(user) 0249 } 0250 0251 function onShowEventSource(eventId) { 0252 applicationWindow().pageStack.pushDialogLayer('qrc:/org/kde/neochat/qml/MessageSourceSheet.qml', { 0253 sourceText: root.currentRoom.getEventJsonSource(eventId) 0254 }, { 0255 title: i18n("Message Source"), 0256 width: Kirigami.Units.gridUnit * 25 0257 }); 0258 } 0259 0260 function onShowMessageMenu(eventId, author, delegateType, plainText, htmlText, selectedText) { 0261 const contextMenu = messageDelegateContextMenu.createObject(root, { 0262 selectedText: selectedText, 0263 author: author, 0264 eventId: eventId, 0265 delegateType: delegateType, 0266 plainText: plainText, 0267 htmlText: htmlText 0268 }); 0269 contextMenu.open(); 0270 } 0271 0272 function onShowFileMenu(eventId, author, delegateType, plainText, mimeType, progressInfo) { 0273 const contextMenu = fileDelegateContextMenu.createObject(root, { 0274 author: author, 0275 eventId: eventId, 0276 delegateType: delegateType, 0277 plainText: plainText, 0278 mimeType: mimeType, 0279 progressInfo: progressInfo 0280 }); 0281 contextMenu.open(); 0282 } 0283 0284 function onShowMaximizedMedia(index) { 0285 var popup = maximizeComponent.createObject(QQC2.Overlay.overlay, { 0286 initialIndex: index 0287 }) 0288 popup.closed.connect(() => { 0289 timelineViewLoader.item.interactive = true 0290 popup.destroy() 0291 }) 0292 popup.open() 0293 } 0294 } 0295 0296 function showUserDetail(user) { 0297 userDetailDialog.createObject(QQC2.ApplicationWindow.overlay, { 0298 room: root.currentRoom, 0299 user: root.currentRoom.getUser(user.id), 0300 }).open(); 0301 } 0302 0303 Component { 0304 id: userDetailDialog 0305 UserDetailDialog {} 0306 } 0307 0308 Component { 0309 id: messageDelegateContextMenu 0310 MessageDelegateContextMenu { 0311 connection: root.connection 0312 } 0313 } 0314 0315 Component { 0316 id: fileDelegateContextMenu 0317 FileDelegateContextMenu { 0318 connection: root.connection 0319 } 0320 } 0321 0322 Component { 0323 id: maximizeComponent 0324 NeochatMaximizeComponent { 0325 currentRoom: root.currentRoom 0326 model: root.mediaMessageFilterModel 0327 } 0328 } 0329 }