diff --git a/kaidan_qml.qrc b/kaidan_qml.qrc index 48c8f96..933e8d2 100644 --- a/kaidan_qml.qrc +++ b/kaidan_qml.qrc @@ -1,36 +1,34 @@ src/qml/main.qml src/qml/RosterPage.qml src/qml/LoginPage.qml src/qml/ChatPage.qml src/qml/AboutDialog.qml src/qml/GlobalDrawer.qml src/qml/EmptyChatPage.qml - + src/qml/QrCodeScannerPage.qml src/qml/elements/SubRequestAcceptSheet.qml src/qml/elements/RosterAddContactSheet.qml src/qml/elements/RosterRemoveContactSheet.qml src/qml/elements/RosterListItem.qml src/qml/elements/MessageCounter.qml src/qml/elements/ChatMessage.qml src/qml/elements/ChatMessageImage.qml src/qml/elements/RoundImage.qml src/qml/elements/IconButton.qml src/qml/elements/FileChooser.qml src/qml/elements/FileChooserDesktop.qml src/qml/elements/FileChooserMobile.qml src/qml/elements/SendMediaSheet.qml src/qml/elements/MediaPreviewImage.qml src/qml/elements/MediaPreviewOther.qml src/qml/elements/EmojiPicker.qml src/qml/elements/TextAvatar.qml - src/qml/settings/SettingsItem.qml src/qml/settings/SettingsPage.qml src/qml/settings/SettingsSheet.qml src/qml/settings/ChangePassword.qml - misc/qtquickcontrols2.conf diff --git a/src/qml/LoginPage.qml b/src/qml/LoginPage.qml index ec5b973..5ffa5fe 100644 --- a/src/qml/LoginPage.qml +++ b/src/qml/LoginPage.qml @@ -1,164 +1,175 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan 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 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan 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 Kaidan. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.0 as Controls import QtQuick.Controls.Material 2.0 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.5 as Kirigami import im.kaidan.kaidan 1.0 Kirigami.Page { title: qsTr("Log in") + actions.contextualActions: [ + Kirigami.Action { + text: qsTr("Log in using a QR-Code") + icon.name: "view-barcode" + onTriggered: pageStack.layers.push(qrCodeScannerPage) + } + ] + ColumnLayout { anchors.fill: parent Kirigami.Heading { text: qsTr("Log in to your XMPP account") wrapMode: Text.WordWrap Layout.fillWidth: true horizontalAlignment: Qt.AlignHCenter } ColumnLayout { width: parent.width Layout.fillWidth: true // For desktop or tablet devices Layout.alignment: Qt.AlignCenter Layout.maximumWidth: Kirigami.Units.gridUnit * 25 // JID field Controls.Label { id: jidLabel text: qsTr("Your Jabber-ID:") } Controls.TextField { id: jidField text: kaidan.jid placeholderText: qsTr("user@example.org") Layout.fillWidth: true selectByMouse: true inputMethodHints: Qt.ImhEmailCharactersOnly } // Password field Controls.Label { text: qsTr("Your Password:") } Controls.TextField { id: passField text: kaidan.password echoMode: TextInput.Password selectByMouse: true Layout.fillWidth: true } // Connect button Controls.Button { id: connectButton Layout.fillWidth: true + highlighted: true Kirigami.Theme.backgroundColor: Material.accent - text: qsTr("Connect") + state: kaidan.connectionState !== Enums.StateDisconnected ? "connecting" : "" states: [ State { name: "connecting" PropertyChanges { target: connectButton enabled: false + } + PropertyChanges { + target: connectLabel text: "" + qsTr("Connecting…") + "" + color: "black" } } ] onClicked: { // connect to given account data - kaidan.jid = jidField.text.toLowerCase() + kaidan.jid = jidField.text kaidan.password = passField.text kaidan.mainConnect() } + + Controls.Label { + id: connectLabel + anchors.centerIn: connectButton + text: qsTr("Connect") + color: Kirigami.Theme.highlightedTextColor + textFormat: Text.StyledText + } } // connect when return was pressed Keys.onPressed: { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { connectButton.clicked() } } } // placeholder Item { Layout.preferredHeight: Kirigami.Units.gridUnit * 3 } } - function handleConnectionState(state) { - if (state === Enums.StateConnecting) { - connectButton.state = "connecting" - } else { - connectButton.state = "" - } - } - function handleConnectionError() { var error = kaidan.disconnReason if (error === Enums.ConnAuthenticationFailed) { passiveNotification(qsTr("Invalid username or password.")) } else if (error === Enums.ConnNotConnected) { passiveNotification(qsTr("Cannot connect to the server. Please check your internet connection.")) } else if (error === Enums.ConnTlsNotAvailable) { passiveNotification(qsTr("The server doesn't support secure connections.")) } else if (error === Enums.ConnTlsFailed) { passiveNotification(qsTr("Error while trying to connect securely.")) } else if (error === Enums.ConnDnsError) { passiveNotification(qsTr("Could not resolve the server's address. Please check your JID again.")) } else if (error === Enums.ConnConnectionRefused) { passiveNotification(qsTr("Could not connect to the server.")) } else if (error === Enums.ConnNoSupportedAuth) { passiveNotification(qsTr("Authentification protocol not supported by the server.")) } else { passiveNotification(qsTr("An unknown error occured; see log for details.")) } } Component.onCompleted: { - kaidan.connectionStateChanged.connect(handleConnectionState) kaidan.disconnReasonChanged.connect(handleConnectionError) } Component.onDestruction: { - kaidan.connectionStateChanged.disconnect(handleConnectionState) kaidan.disconnReasonChanged.disconnect(handleConnectionError) } } diff --git a/src/qml/QrCodeScannerPage.qml b/src/qml/QrCodeScannerPage.qml new file mode 100644 index 0000000..9d1fe18 --- /dev/null +++ b/src/qml/QrCodeScannerPage.qml @@ -0,0 +1,95 @@ +/* + * Kaidan - A user-friendly XMPP client for every device! + * + * Copyright (C) 2016-2019 Kaidan developers and contributors + * (see the LICENSE file for a full list of copyright authors) + * + * Kaidan 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 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the author of Kaidan gives + * permission to link the code of its release with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License in + * all respects for all of the code used other than "OpenSSL". If you + * modify this file, you may extend this exception to your version of + * the file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + * + * Kaidan 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 Kaidan. If not, see . + */ + +import QtQuick 2.0 +import QtQuick.Controls 2.3 as Controls +import QtMultimedia 5.9 +import org.kde.kirigami 2.4 as Kirigami +import im.kaidan.kaidan 1.0 + +// QR code scanner output and decoding for logging in by a decoded XMPP URI +Kirigami.Page { + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + + title: qsTr("Scan QR code") + + // message to be shown if no camera can be found + Kirigami.InlineMessage { + visible: { + camera.availability === Camera.Unavailable || + camera.availability === Camera.ResourceMissing + } + anchors.centerIn: parent + width: 300 + height: 60 + text: qsTr("There is no camera available.") + } + + // message to be shown if the found camera is not usable + Kirigami.InlineMessage { + visible: camera.availability === Camera.Busy + anchors.centerIn: parent + width: 300 + height: 60 + text: qsTr("Your camera is busy.\nTry to close other applications using the camera.") + } + + // video output from the camera which is shown on the screen and decoded by a filter + VideoOutput { + id: viewfinder + anchors.fill: parent + fillMode: VideoOutput.PreserveAspectCrop + source: camera + autoOrientation: true + filters: [scannerFilter] + } + + // filter which converst the video frames to images and decodes a containing QR code + QrCodeScannerFilter { + id: scannerFilter + onScanningSucceeded: { + pageStack.layers.pop() + // login by the data from the decoded QR code + kaidan.loginByUri(result) + } + } + + // camera with continuous focus in the center of the video + Camera { + id: camera + focus { + focusMode: Camera.FocusContinuous + focusPointMode: Camera.FocusPointCenter + } + } +} diff --git a/src/qml/main.qml b/src/qml/main.qml index 4bf541d..7349daa 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -1,131 +1,132 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan 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 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan 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 Kaidan. If not, see . */ import QtQuick 2.7 import QtQuick.Controls.Material 2.0 import org.kde.kirigami 2.3 as Kirigami import StatusBar 0.1 import im.kaidan.kaidan 1.0 import "elements" import "settings" Kirigami.ApplicationWindow { id: root StatusBar { color: Material.color(Material.Green, Material.Shade700) } // Global and Contextual Drawers globalDrawer: GlobalDrawer {} contextDrawer: Kirigami.ContextDrawer { id: contextDrawer } AboutDialog { id: aboutDialog focus: true x: (parent.width - width) / 2 y: (parent.height - height) / 2 } SubRequestAcceptSheet { id: subReqAcceptSheet } // when the window was closed, disconnect from jabber server onClosing: { kaidan.mainDisconnect() } // load all pages Component {id: chatPage; ChatPage {}} Component {id: loginPage; LoginPage {}} Component {id: rosterPage; RosterPage {}} Component {id: emptyChatPage; EmptyChatPage {}} Component {id: settingsPage; SettingsPage {}} + Component {id: qrCodeScannerPage; QrCodeScannerPage {}} function passiveNotification(text) { showPassiveNotification(text, "long") } function openLogInPage() { // close all pages (we don't know on which page we're on, // thus we don't use replace) while (pageStack.depth > 0) pageStack.pop() // toggle global drawer globalDrawer.enabled = false globalDrawer.visible = false // push new page pageStack.push(loginPage) } function closeLogInPage() { // toggle global drawer globalDrawer.enabled = true // replace page with roster page pageStack.replace(rosterPage) if (!Kirigami.Settings.isMobile) pageStack.push(emptyChatPage) } function handleSubRequest(from, message) { kaidan.vCardRequested(from) subReqAcceptSheet.from = from subReqAcceptSheet.message = message subReqAcceptSheet.open() } Component.onCompleted: { kaidan.passiveNotificationRequested.connect(passiveNotification) kaidan.newCredentialsNeeded.connect(openLogInPage) kaidan.logInWorked.connect(closeLogInPage) kaidan.subscriptionRequestReceived.connect(handleSubRequest) // push roster page (trying normal start up) pageStack.push(rosterPage) if (!Kirigami.Settings.isMobile) pageStack.push(emptyChatPage) // Annouce that we're ready and the back-end can start with connecting kaidan.start() } Component.onDestruction: { kaidan.passiveNotificationRequested.disconnect(passiveNotification) kaidan.newCredentialsNeeded.disconnect(openLogInPage) kaidan.logInWorked.disconnect(closeLogInPage) kaidan.subscriptionRequestReceived.disconnect(handleSubRequest) } }