Warning, /network/neochat/src/qml/main.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 2.15 0006 import QtQuick.Controls 2.15 as QQC2 0007 import QtQuick.Layouts 1.15 0008 0009 import org.kde.kirigami 2.15 as Kirigami 0010 0011 import org.kde.neochat 1.0 0012 import './RoomList' as RoomList 0013 import './Dialog' as Dialog 0014 0015 Kirigami.ApplicationWindow { 0016 id: root 0017 0018 property int columnWidth: Kirigami.Units.gridUnit * 13 0019 0020 property RoomList.Page roomListPage 0021 property bool roomListLoaded: false 0022 0023 property RoomPage roomPage 0024 0025 minimumWidth: Kirigami.Units.gridUnit * 20 0026 minimumHeight: Kirigami.Units.gridUnit * 15 0027 0028 visible: false // Will be overridden in Component.onCompleted 0029 wideScreen: width > columnWidth * 5 0030 0031 pageStack { 0032 initialPage: LoadingPage {} 0033 globalToolBar.canContainHandles: true 0034 defaultColumnWidth: roomListPage ? roomListPage.currentWidth : 0 0035 globalToolBar { 0036 style: Kirigami.ApplicationHeaderStyle.ToolBar 0037 showNavigationButtons: pageStack.currentIndex > 0 || pageStack.layers.depth > 1 ? Kirigami.ApplicationHeaderStyle.ShowBackButton : 0 0038 } 0039 } 0040 0041 Connections { 0042 target: root.quitAction 0043 function onTriggered() { 0044 Qt.quit() 0045 } 0046 } 0047 0048 Loader { 0049 active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile 0050 source: Qt.resolvedUrl("qrc:/GlobalMenu.qml") 0051 } 0052 0053 // This timer allows to batch update the window size change to reduce 0054 // the io load and also work around the fact that x/y/width/height are 0055 // changed when loading the page and overwrite the saved geometry from 0056 // the previous session. 0057 Timer { 0058 id: saveWindowGeometryTimer 0059 interval: 1000 0060 onTriggered: Controller.saveWindowGeometry() 0061 } 0062 0063 Connections { 0064 id: saveWindowGeometryConnections 0065 enabled: false // Disable on startup to avoid writing wrong values if the window is hidden 0066 target: root 0067 0068 function onClosing() { Controller.saveWindowGeometry(); } 0069 function onWidthChanged() { saveWindowGeometryTimer.restart(); } 0070 function onHeightChanged() { saveWindowGeometryTimer.restart(); } 0071 function onXChanged() { saveWindowGeometryTimer.restart(); } 0072 function onYChanged() { saveWindowGeometryTimer.restart(); } 0073 } 0074 0075 0076 Loader { 0077 id: quickView 0078 active: !Kirigami.Settings.isMobile 0079 sourceComponent: QuickSwitcher { } 0080 } 0081 0082 Connections { 0083 target: RoomManager 0084 0085 function onPushRoom(room, event) { 0086 root.roomPage = pageStack.push("qrc:/RoomPage.qml"); 0087 root.roomPage.forceActiveFocus(); 0088 if (event.length > 0) { 0089 roomPage.goToEvent(event); 0090 } 0091 } 0092 0093 function onReplaceRoom(room, event) { 0094 const roomItem = pageStack.get(pageStack.depth - 1); 0095 pageStack.currentIndex = pageStack.depth - 1; 0096 root.roomPage.forceActiveFocus(); 0097 if (event.length > 0) { 0098 roomItem.goToEvent(event); 0099 } 0100 } 0101 0102 function goToEvent(event) { 0103 if (event.length > 0) { 0104 roomItem.goToEvent(event); 0105 } 0106 roomItem.forceActiveFocus(); 0107 } 0108 0109 function onOpenRoomInNewWindow(room) { 0110 const secondaryWindow = roomWindow.createObject(undefined, {currentRoom: room}); 0111 secondaryWindow.width = root.width - pageStack.get(0).width; 0112 secondaryWindow.show(); 0113 } 0114 0115 function onShowUserDetail(user) { 0116 const roomItem = pageStack.get(pageStack.depth - 1); 0117 roomItem.showUserDetail(user); 0118 } 0119 0120 function onAskDirectChatConfirmation(user) { 0121 askDirectChatConfirmationComponent.createObject(QQC2.ApplicationWindow.overlay, { 0122 user: user, 0123 }).open(); 0124 } 0125 } 0126 0127 function pushReplaceLayer(page, args) { 0128 if (pageStack.layers.depth === 2) { 0129 pageStack.layers.replace(page, args); 0130 } else { 0131 pageStack.layers.push(page, args); 0132 } 0133 } 0134 0135 contextDrawer: RoomDrawer { 0136 id: contextDrawer 0137 0138 // This is a memory for all user initiated actions on the drawer, i.e. clicking the button 0139 // It is used to ensure that user choice is remembered when changing pages and expanding and contracting the window width 0140 property bool drawerUserState: Config.autoRoomInfoDrawer 0141 0142 // Connect to the onClicked function of the RoomDrawer handle button 0143 Connections { 0144 target: contextDrawer.handle.children[0] 0145 function onClicked() { 0146 contextDrawer.drawerUserState = contextDrawer.drawerOpen 0147 } 0148 } 0149 0150 modal: !root.wideScreen || !enabled 0151 onEnabledChanged: drawerOpen = enabled && !modal 0152 onModalChanged: { 0153 if (Config.autoRoomInfoDrawer) { 0154 drawerOpen = !modal && drawerUserState 0155 dim = false 0156 } 0157 } 0158 enabled: RoomManager.hasOpenRoom && pageStack.layers.depth < 2 && pageStack.depth < 3 && (pageStack.visibleItems.length > 1 || pageStack.currentIndex > 0) 0159 handleVisible: enabled 0160 } 0161 0162 Dialog.ConfirmLogout { 0163 id: confirmLogoutDialog 0164 } 0165 0166 Component.onCompleted: { 0167 Controller.setBlur(pageStack, Config.blur && !Config.compactLayout); 0168 if (Config.minimizeToSystemTrayOnStartup && !Kirigami.Settings.isMobile && Controller.supportSystemTray && Config.systemTray) { 0169 restoreWindowGeometryConnections.enabled = true; // To restore window size and position 0170 } else { 0171 visible = true; 0172 saveWindowGeometryConnections.enabled = true; 0173 } 0174 } 0175 Connections { 0176 target: Config 0177 function onBlurChanged() { 0178 Controller.setBlur(pageStack, Config.blur && !Config.compactLayout); 0179 } 0180 function onCompactLayoutChanged() { 0181 Controller.setBlur(pageStack, Config.blur && !Config.compactLayout); 0182 } 0183 } 0184 0185 // blur effect 0186 color: Config.blur && !Config.compactLayout ? "transparent" : Kirigami.Theme.backgroundColor 0187 0188 // we need to apply the translucency effect separately on top of the color 0189 background: Rectangle { 0190 color: Config.blur && !Config.compactLayout ? Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 1 - Config.transparency) : "transparent" 0191 } 0192 0193 Component { 0194 id: roomListComponent 0195 RoomList.Page { 0196 id: roomList 0197 0198 Shortcut { 0199 sequences: ["Ctrl+PgUp", "Ctrl+Backtab", "Alt+Up"] 0200 onActivated: { 0201 roomList.goToPreviousRoom(); 0202 } 0203 } 0204 0205 Shortcut { 0206 sequences: ["Ctrl+PgDown", "Ctrl+Tab", "Alt+Down"] 0207 onActivated: { 0208 roomList.goToNextRoom(); 0209 } 0210 } 0211 0212 Shortcut { 0213 sequence: "Alt+Shift+Up" 0214 onActivated: { 0215 roomList.goToPreviousUnreadRoom(); 0216 } 0217 } 0218 0219 Shortcut { 0220 sequence: "Alt+Shift+Down" 0221 onActivated: { 0222 roomList.goToNextUnreadRoom(); 0223 } 0224 } 0225 } 0226 } 0227 0228 Connections { 0229 target: AccountRegistry 0230 function onRowsRemoved() { 0231 if (AccountRegistry.rowCount() === 0) { 0232 RoomManager.reset(); 0233 pageStack.clear(); 0234 roomListLoaded = false; 0235 pageStack.push("qrc:/WelcomePage.qml"); 0236 } 0237 } 0238 } 0239 0240 Connections { 0241 target: Controller 0242 0243 function onInitiated() { 0244 if (Controller.accountCount === 0) { 0245 pageStack.replace("qrc:/WelcomePage.qml", {}); 0246 } else if (!roomListLoaded) { 0247 pageStack.replace(roomListComponent, { 0248 activeConnection: Controller.activeConnection 0249 }); 0250 roomListLoaded = true; 0251 roomListPage = pageStack.currentItem 0252 RoomManager.loadInitialRoom(); 0253 } 0254 } 0255 0256 function onGlobalErrorOccured(error, detail) { 0257 showPassiveNotification(i18n("%1: %2", error, detail)); 0258 } 0259 0260 function onUserConsentRequired(url) { 0261 let consent = consentSheetComponent.createObject(QQC2.ApplicationWindow.overlay) 0262 consent.url = url 0263 consent.open() 0264 } 0265 } 0266 0267 Connections { 0268 id: restoreWindowGeometryConnections 0269 enabled: false 0270 target: root 0271 0272 function onVisibleChanged() { 0273 if (!visible) { 0274 return; 0275 } 0276 Controller.restoreWindowGeometry(root); 0277 restoreWindowGeometryConnections.enabled = false; // Only restore window geometry for the first time 0278 saveWindowGeometryConnections.enabled = true; 0279 } 0280 } 0281 0282 Component { 0283 id: keyVerificationDialogComponent 0284 KeyVerificationDialog { } 0285 } 0286 0287 Connections { 0288 target: Controller.activeConnection 0289 0290 //TODO Remove this when the E2EE flag in libQuotient goes away 0291 ignoreUnknownSignals: true 0292 function onDirectChatAvailable(directChat) { 0293 RoomManager.enterRoom(Controller.activeConnection.room(directChat.id)); 0294 } 0295 function onNewKeyVerificationSession(session) { 0296 applicationWindow().pageStack.pushDialogLayer(keyVerificationDialogComponent, { 0297 session: session, 0298 }, { 0299 title: i18nc("@title:window", "Session Verification") 0300 }); 0301 } 0302 } 0303 0304 Component { 0305 id: consentSheetComponent 0306 Kirigami.OverlaySheet { 0307 id: consentSheet 0308 0309 property string url: "" 0310 0311 title: i18n("User consent") 0312 0313 QQC2.Label { 0314 id: label 0315 0316 text: i18n("Your homeserver requires you to agree to its terms and conditions before being able to use it. Please click the button below to read them.") 0317 wrapMode: Text.WordWrap 0318 width: parent.width 0319 } 0320 footer: QQC2.Button { 0321 text: i18n("Open") 0322 onClicked: UrlHelper.openUrl(consentSheet.url) 0323 } 0324 } 0325 } 0326 0327 Component { 0328 id: createRoomDialog 0329 0330 CreateRoomDialog {} 0331 } 0332 0333 Component { 0334 id: createSpaceDialog 0335 CreateSpaceDialog {} 0336 } 0337 0338 Component { 0339 id: roomWindow 0340 RoomWindow {} 0341 } 0342 0343 Component { 0344 id: userDialog 0345 UserDetailDialog {} 0346 } 0347 0348 Component { 0349 id: askDirectChatConfirmationComponent 0350 0351 Kirigami.OverlaySheet { 0352 id: askDirectChatConfirmation 0353 required property var user; 0354 0355 parent: QQC2.ApplicationWindow.overlay 0356 title: i18n("Start a chat") 0357 contentItem: QQC2.Label { 0358 text: i18n("Do you want to start a chat with %1?", user.displayName) 0359 wrapMode: Text.WordWrap 0360 } 0361 footer: QQC2.DialogButtonBox { 0362 standardButtons: QQC2.DialogButtonBox.Ok | QQC2.DialogButtonBox.Cancel 0363 onAccepted: { 0364 user.requestDirectChat(); 0365 askDirectChatConfirmation.close(); 0366 } 0367 onRejected: askDirectChatConfirmation.close(); 0368 } 0369 } 0370 } 0371 0372 property Item hoverLinkIndicator: QQC2.Control { 0373 parent: overlay.parent 0374 property string text 0375 opacity: linkText.text.length > 0 ? 1 : 0 0376 0377 z: 20 0378 x: 0 0379 y: parent.height - implicitHeight 0380 contentItem: QQC2.Label { 0381 id: linkText 0382 text: parent.text.startsWith("https://matrix.to/") ? "" : parent.text 0383 } 0384 Kirigami.Theme.colorSet: Kirigami.Theme.View 0385 background: Rectangle { 0386 color: Kirigami.Theme.backgroundColor 0387 } 0388 } 0389 0390 Shortcut { 0391 sequence: "Ctrl+Shift+," 0392 onActivated: { 0393 pageStack.pushDialogLayer("qrc:/SettingsPage.qml", {connection: Controller.activeConnection}, { title: i18n("Configure") }) 0394 } 0395 } 0396 }