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