diff --git a/kaidan_qml.qrc b/kaidan_qml.qrc index 48c8f96..664fac1 100644 --- a/kaidan_qml.qrc +++ b/kaidan_qml.qrc @@ -1,36 +1,38 @@ 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/QrScannerPage.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..e545cdb 100644 --- a/src/qml/LoginPage.qml +++ b/src/qml/LoginPage.qml @@ -1,164 +1,172 @@ /* * 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(qrScannerPage) + } + ] + 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 Kirigami.Theme.backgroundColor: Material.accent text: qsTr("Connect") states: [ State { name: "connecting" PropertyChanges { target: connectButton enabled: false text: "" + qsTr("Connecting…") + "" } } ] onClicked: { // connect to given account data kaidan.jid = jidField.text.toLowerCase() kaidan.password = passField.text kaidan.mainConnect() } } // 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/QrScannerPage.qml b/src/qml/QrScannerPage.qml new file mode 100644 index 0000000..9f4dc0c --- /dev/null +++ b/src/qml/QrScannerPage.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 +import org.kde.kirigami 2.2 as Kirigami +import QtMultimedia 5.9 + +Kirigami.Page { + leftPadding: 0 + rightPadding: 0 + topPadding: 0 + bottomPadding: 0 + + title: qsTr("Scan QR code") + + VideoOutput { + id: viewfinder + anchors.fill: parent + source: camera + } + + Camera { + id: camera + captureMode: Camera.CaptureVideo + } +} diff --git a/src/qml/main.qml b/src/qml/main.qml index 4bf541d..9840bc1 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: qrScannerPage; QrScannerPage {}} 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) } }