mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Functional login page
This commit is contained in:
parent
aaae72a4f2
commit
4a80fdc951
13 changed files with 573 additions and 494 deletions
|
@ -8,29 +8,131 @@ import QtQuick.Controls 2.12
|
|||
import QtQuick.Layouts 1.12
|
||||
import im.nheko 1.0
|
||||
|
||||
TextField {
|
||||
id: input
|
||||
|
||||
property alias backgroundColor: backgroundRect.color
|
||||
ColumnLayout {
|
||||
id: c
|
||||
property color backgroundColor: Nheko.colors.base
|
||||
property alias color: labelC.color
|
||||
property alias textPadding: input.padding
|
||||
property alias text: input.text
|
||||
property alias label: labelC.text
|
||||
property alias placeholderText: input.placeholderText
|
||||
property alias font: input.font
|
||||
property alias echoMode: input.echoMode
|
||||
property alias selectByMouse: input.selectByMouse
|
||||
|
||||
palette: Nheko.colors
|
||||
color: Nheko.colors.text
|
||||
signal textEdited
|
||||
signal accepted
|
||||
signal editingFinished
|
||||
|
||||
function forceActiveFocus() {
|
||||
input.forceActiveFocus();
|
||||
}
|
||||
|
||||
ToolTip.delay: Nheko.tooltipDelay
|
||||
ToolTip.visible: hover.hovered
|
||||
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: labelC.contentHeight
|
||||
Layout.margins: input.padding
|
||||
Layout.bottomMargin: Nheko.paddingSmall
|
||||
visible: labelC.text
|
||||
|
||||
z: 1
|
||||
|
||||
Label {
|
||||
id: labelC
|
||||
|
||||
y: contentHeight + input.padding + Nheko.paddingSmall
|
||||
enabled: false
|
||||
|
||||
palette: Nheko.colors
|
||||
color: Nheko.colors.text
|
||||
font.pixelSize: input.font.pixelSize
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: input.font.pixelSize * 0.02
|
||||
width: parent.width
|
||||
|
||||
state: labelC.text && (input.activeFocus == true || input.text) ? "focused" : ""
|
||||
|
||||
states: State {
|
||||
name: "focused"
|
||||
|
||||
PropertyChanges {
|
||||
target: labelC
|
||||
y: 0
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: input
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
from: ""
|
||||
to: "focused"
|
||||
reversible: true
|
||||
|
||||
NumberAnimation {
|
||||
target: labelC
|
||||
properties: "y"
|
||||
duration: 210
|
||||
easing.type: Easing.InCubic
|
||||
alwaysRunToEnd: true
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: input
|
||||
properties: "opacity"
|
||||
duration: 210
|
||||
easing.type: Easing.InCubic
|
||||
alwaysRunToEnd: true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: input
|
||||
Layout.fillWidth: true
|
||||
|
||||
palette: Nheko.colors
|
||||
color: labelC.color
|
||||
opacity: labelC.text ? 0 : 1
|
||||
|
||||
onTextEdited: c.textEdited()
|
||||
onAccepted: c.accepted()
|
||||
onEditingFinished: c.editingFinished()
|
||||
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
color: labelC.text ? "transparent" : backgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: blueBar
|
||||
|
||||
anchors.top: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
color: Nheko.colors.highlight
|
||||
height: 1
|
||||
width: parent.width
|
||||
|
||||
Rectangle {
|
||||
id: blackBar
|
||||
|
||||
anchors.verticalCenter: blueBar.verticalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: parent.height + 1
|
||||
height: parent.height*2
|
||||
width: 0
|
||||
color: Nheko.colors.text
|
||||
|
||||
|
@ -50,11 +152,12 @@ TextField {
|
|||
to: "focused"
|
||||
reversible: true
|
||||
|
||||
|
||||
NumberAnimation {
|
||||
target: blackBar
|
||||
properties: "width"
|
||||
duration: 500
|
||||
easing.type: Easing.InOutQuad
|
||||
duration: 310
|
||||
easing.type: Easing.InCubic
|
||||
alwaysRunToEnd: true
|
||||
}
|
||||
|
||||
|
@ -64,10 +167,8 @@ TextField {
|
|||
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
color: Nheko.colors.base
|
||||
HoverHandler {
|
||||
id: hover
|
||||
enabled: c.ToolTip.text
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ Popup {
|
|||
id: quickSwitcher
|
||||
|
||||
property int textHeight: Math.round(Qt.application.font.pixelSize * 2.4)
|
||||
property int textMargin: Math.round(textHeight / 8)
|
||||
|
||||
background: null
|
||||
width: Math.round(parent.width / 2)
|
||||
|
@ -34,7 +33,6 @@ Popup {
|
|||
|
||||
anchors.fill: parent
|
||||
font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6)
|
||||
padding: textMargin
|
||||
color: Nheko.colors.text
|
||||
onTextEdited: {
|
||||
completerPopup.completer.searchString = text;
|
||||
|
@ -60,7 +58,7 @@ Popup {
|
|||
id: completerPopup
|
||||
|
||||
x: roomTextInput.x
|
||||
y: roomTextInput.y + quickSwitcher.textHeight + quickSwitcher.textMargin
|
||||
y: roomTextInput.y + roomTextInput.height
|
||||
visible: roomTextInput.length > 0
|
||||
width: parent.width
|
||||
completerName: "room"
|
||||
|
|
|
@ -155,6 +155,11 @@ Pane {
|
|||
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.Quit
|
||||
onActivated: Qt.quit()
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Ctrl+K"
|
||||
onActivated: {
|
||||
|
@ -366,8 +371,13 @@ Pane {
|
|||
id: mainWindow
|
||||
|
||||
anchors.fill: parent
|
||||
initialItem: WelcomePage {
|
||||
//anchors.fill: parent
|
||||
initialItem: welcomePage
|
||||
}
|
||||
|
||||
Component {
|
||||
id: welcomePage
|
||||
|
||||
WelcomePage {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,10 +388,19 @@ Pane {
|
|||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: loginPage
|
||||
|
||||
LoginPage {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onSwitchToChatPage() {
|
||||
console.log("AAAA");
|
||||
mainWindow.replace(chatPage);
|
||||
mainWindow.replace(null, chatPage);
|
||||
}
|
||||
function onSwitchToLoginPage(error) {
|
||||
mainWindow.replace(welcomePage, {}, loginPage, {"error": error}, StackView.PopTransition);
|
||||
}
|
||||
target: MainWindow
|
||||
}
|
||||
|
|
|
@ -173,39 +173,37 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
visible: imagePack.roomid
|
||||
text: qsTr("State key")
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: statekeyField
|
||||
|
||||
visible: imagePack.roomid
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
label: qsTr("State key")
|
||||
text: imagePack.statekey
|
||||
onTextEdited: imagePack.statekey = text
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Packname")
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
label: qsTr("Packname")
|
||||
text: imagePack.packname
|
||||
onTextEdited: imagePack.packname = text
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Attribution")
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
label: qsTr("Attribution")
|
||||
text: imagePack.attribution
|
||||
onTextEdited: imagePack.attribution = text
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
Layout.margins: statekeyField.textPadding
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: font.pixelSize * 0.02
|
||||
text: qsTr("Use as Emoji")
|
||||
}
|
||||
|
||||
|
@ -216,6 +214,9 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
MatrixText {
|
||||
Layout.margins: statekeyField.textPadding
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: font.pixelSize * 0.02
|
||||
text: qsTr("Use as Sticker")
|
||||
}
|
||||
|
||||
|
@ -251,27 +252,28 @@ ApplicationWindow {
|
|||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Shortcode")
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
label: qsTr("Shortcode")
|
||||
text: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.ShortCode)
|
||||
onTextEdited: imagePack.setData(imagePack.index(currentImageIndex, 0), text, SingleImagePackModel.ShortCode)
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
text: qsTr("Body")
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: bodyField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
label: qsTr("Body")
|
||||
text: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.Body)
|
||||
onTextEdited: imagePack.setData(imagePack.index(currentImageIndex, 0), text, SingleImagePackModel.Body)
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
Layout.margins: bodyField.textPadding
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: font.pixelSize * 0.02
|
||||
text: qsTr("Use as Emoji")
|
||||
}
|
||||
|
||||
|
@ -282,6 +284,9 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
MatrixText {
|
||||
Layout.margins: bodyField.textPadding
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: font.pixelSize * 0.02
|
||||
text: qsTr("Use as Sticker")
|
||||
}
|
||||
|
||||
|
@ -292,6 +297,9 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
MatrixText {
|
||||
Layout.margins: bodyField.textPadding
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: font.pixelSize * 0.02
|
||||
text: qsTr("Remove from pack")
|
||||
}
|
||||
|
||||
|
|
|
@ -188,7 +188,6 @@ ApplicationWindow {
|
|||
Layout.fillWidth: true
|
||||
selectByMouse: true
|
||||
font.pixelSize: fontMetrics.font.pixelSize
|
||||
padding: Nheko.paddingMedium
|
||||
color: Nheko.colors.text
|
||||
placeholderText: qsTr("Search for public rooms")
|
||||
onTextChanged: searchTimer.restart()
|
||||
|
@ -199,7 +198,6 @@ ApplicationWindow {
|
|||
|
||||
Layout.minimumWidth: 0.3 * header.width
|
||||
Layout.maximumWidth: 0.3 * header.width
|
||||
padding: Nheko.paddingMedium
|
||||
color: Nheko.colors.text
|
||||
placeholderText: qsTr("Choose custom homeserver")
|
||||
onTextChanged: publicRooms.setMatrixServer(text)
|
||||
|
|
178
resources/qml/pages/LoginPage.qml
Normal file
178
resources/qml/pages/LoginPage.qml
Normal file
|
@ -0,0 +1,178 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Window 2.15
|
||||
import im.nheko 1.0
|
||||
import "../components/"
|
||||
import "../ui/"
|
||||
import "../"
|
||||
|
||||
Item {
|
||||
id: loginPage
|
||||
property int maxExpansion: 800
|
||||
|
||||
property string error: login.error
|
||||
|
||||
Login {
|
||||
id: login
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: scroll
|
||||
|
||||
clip: false
|
||||
palette: Nheko.colors
|
||||
ScrollBar.horizontal.visible: false
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: Math.min(loginPage.height, col.implicitHeight)
|
||||
anchors.margins: Nheko.paddingLarge
|
||||
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
|
||||
spacing: Nheko.paddingMedium
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: Math.min(loginPage.maxExpansion, scroll.width- Nheko.paddingLarge*2)
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
source: "qrc:/logos/login.png"
|
||||
height: 128
|
||||
width: 128
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Nheko.paddingLarge
|
||||
|
||||
Layout.fillWidth: true
|
||||
MatrixTextField {
|
||||
id: matrixIdLabel
|
||||
label: qsTr("Matrix ID")
|
||||
placeholderText: qsTr("e.g @joe:matrix.org")
|
||||
onEditingFinished: login.mxid = text
|
||||
|
||||
ToolTip.text: qsTr("Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :.\nYou can also put your homeserver address there, if your server doesn't support .well-known lookup.\nExample: @user:server.my\nIf Nheko fails to discover your homeserver, it will show you a field to enter the server manually.")
|
||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
||||
}
|
||||
|
||||
|
||||
Spinner {
|
||||
height: matrixIdLabel.height/2
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
|
||||
visible: running
|
||||
running: login.lookingUpHs
|
||||
foreground: Nheko.colors.mid
|
||||
}
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
textFormat: Text.PlainText
|
||||
color: Nheko.theme.error
|
||||
text: login.mxidError
|
||||
visible: text
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: passwordLabel
|
||||
Layout.fillWidth: true
|
||||
label: qsTr("Password")
|
||||
echoMode: TextInput.Password
|
||||
ToolTip.text: qsTr("Your password.")
|
||||
visible: login.passwordSupported
|
||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: deviceNameLabel
|
||||
Layout.fillWidth: true
|
||||
label: qsTr("Device name")
|
||||
placeholderText: login.initialDeviceName()
|
||||
ToolTip.text: qsTr("A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.")
|
||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
||||
}
|
||||
|
||||
MatrixTextField {
|
||||
id: hsLabel
|
||||
enabled: visible
|
||||
visible: login.homeserverNeeded
|
||||
|
||||
Layout.fillWidth: true
|
||||
label: qsTr("Homeserver address")
|
||||
placeholderText: qsTr("server.my:8787")
|
||||
text: login.homeserver
|
||||
onEditingFinished: login.homeserver = text
|
||||
ToolTip.text: qsTr("The address that can be used to contact you homeservers client API.\nExample: https://server.my:8787")
|
||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Nheko.avatarSize
|
||||
Layout.fillWidth: true
|
||||
|
||||
Spinner {
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
|
||||
visible: running
|
||||
running: login.loggingIn
|
||||
foreground: Nheko.colors.mid
|
||||
}
|
||||
}
|
||||
|
||||
MatrixText {
|
||||
textFormat: Text.PlainText
|
||||
color: Nheko.theme.error
|
||||
text: loginPage.error
|
||||
visible: text
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
id: pwBtn
|
||||
visible: login.passwordSupported
|
||||
enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("LOGIN")
|
||||
function pwLogin() {
|
||||
login.onLoginButtonClicked(Login.Password, matrixIdLabel.text, passwordLabel.text, deviceNameLabel.text)
|
||||
}
|
||||
onClicked: pwBtn.pwLogin()
|
||||
Keys.onEnterPressed: pwBtn.pwLogin()
|
||||
Keys.onReturnPressed: pwBtn.pwLogin()
|
||||
Keys.enabled: pwBtn.enabled && login.passwordSupported
|
||||
}
|
||||
FlatButton {
|
||||
id: ssoBtn
|
||||
visible: login.ssoSupported
|
||||
enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("SSO LOGIN")
|
||||
function ssoLogin() {
|
||||
login.onLoginButtonClicked(Login.SSO, matrixIdLabel.text, passwordLabel.text, deviceNameLabel.text)
|
||||
}
|
||||
onClicked: ssoBtn.ssoLogin()
|
||||
Keys.onEnterPressed: ssoBtn.ssoLogin()
|
||||
Keys.onReturnPressed: ssoBtn.ssoLogin()
|
||||
Keys.enabled: ssoBtn.enabled && !login.passwordSupported
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ImageButton {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Nheko.paddingMedium
|
||||
width: Nheko.avatarSize
|
||||
height: Nheko.avatarSize
|
||||
image: ":/icons/icons/ui/angle-arrow-left.svg"
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Back")
|
||||
onClicked: mainWindow.pop()
|
||||
}
|
||||
}
|
|
@ -6,15 +6,6 @@ import im.nheko 1.0
|
|||
import "../components/"
|
||||
|
||||
ColumnLayout {
|
||||
FontMetrics {
|
||||
id: fontMetrics
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.Quit
|
||||
onActivated: Qt.quit()
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
@ -49,27 +40,28 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
FlatButton {
|
||||
Layout.margins: Nheko.paddingLarge
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("REGISTER")
|
||||
onClicked: {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
FlatButton {
|
||||
Layout.margins: Nheko.paddingLarge
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("REGISTER")
|
||||
onClicked: {
|
||||
}
|
||||
}
|
||||
FlatButton {
|
||||
Layout.margins: Nheko.paddingLarge
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("LOGIN")
|
||||
onClicked: {
|
||||
mainWindow.push(loginPage);
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
FlatButton {
|
||||
Layout.margins: Nheko.paddingLarge
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: qsTr("LOGIN")
|
||||
onClicked: {
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
<file>qml/NotificationWarning.qml</file>
|
||||
<file>qml/pages/UserSettingsPage.qml</file>
|
||||
<file>qml/pages/WelcomePage.qml</file>
|
||||
<file>qml/pages/LoginPage.qml</file>
|
||||
<file>qml/components/AdaptiveLayout.qml</file>
|
||||
<file>qml/components/AdaptiveLayoutElement.qml</file>
|
||||
<file>qml/components/AvatarListTile.qml</file>
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QFontMetrics>
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
#include <QtMath>
|
||||
|
||||
#include <mtx/identifiers.hpp>
|
||||
#include <mtx/requests.hpp>
|
||||
|
@ -18,247 +13,94 @@
|
|||
#include "Config.h"
|
||||
#include "Logging.h"
|
||||
#include "LoginPage.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "SSOHandler.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/LoadingIndicator.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/RaisedButton.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
Q_DECLARE_METATYPE(LoginPage::LoginMethod)
|
||||
|
||||
using namespace mtx::identifiers;
|
||||
|
||||
LoginPage::LoginPage(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
LoginPage::LoginPage(QObject *parent)
|
||||
: QObject(parent)
|
||||
, inferredServerAddress_()
|
||||
{
|
||||
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
||||
|
||||
top_layout_ = new QVBoxLayout();
|
||||
|
||||
top_bar_layout_ = new QHBoxLayout();
|
||||
top_bar_layout_->setSpacing(0);
|
||||
top_bar_layout_->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
back_button_ = new FlatButton(this);
|
||||
back_button_->setMinimumSize(QSize(30, 30));
|
||||
|
||||
top_bar_layout_->addWidget(back_button_, 0, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
top_bar_layout_->addStretch(1);
|
||||
|
||||
QIcon icon;
|
||||
icon.addFile(QStringLiteral(":/icons/icons/ui/angle-arrow-left.svg"));
|
||||
|
||||
back_button_->setIcon(icon);
|
||||
back_button_->setIconSize(QSize(32, 32));
|
||||
|
||||
QIcon logo;
|
||||
logo.addFile(QStringLiteral(":/logos/login.png"));
|
||||
|
||||
logo_ = new QLabel(this);
|
||||
logo_->setPixmap(logo.pixmap(128));
|
||||
|
||||
logo_layout_ = new QHBoxLayout();
|
||||
logo_layout_->setContentsMargins(0, 0, 0, 20);
|
||||
logo_layout_->addWidget(logo_, 0, Qt::AlignHCenter);
|
||||
|
||||
form_wrapper_ = new QHBoxLayout();
|
||||
form_widget_ = new QWidget();
|
||||
form_widget_->setMinimumSize(QSize(350, 200));
|
||||
|
||||
form_layout_ = new QVBoxLayout();
|
||||
form_layout_->setSpacing(20);
|
||||
form_layout_->setContentsMargins(0, 0, 0, 30);
|
||||
form_widget_->setLayout(form_layout_);
|
||||
|
||||
form_wrapper_->addStretch(1);
|
||||
form_wrapper_->addWidget(form_widget_);
|
||||
form_wrapper_->addStretch(1);
|
||||
|
||||
matrixid_input_ = new TextField(this);
|
||||
matrixid_input_->setLabel(tr("Matrix ID"));
|
||||
matrixid_input_->setRegexp(QRegularExpression(QStringLiteral("@.+?:.{3,}")));
|
||||
matrixid_input_->setPlaceholderText(tr("e.g @joe:matrix.org"));
|
||||
matrixid_input_->setToolTip(
|
||||
tr("Your login name. A mxid should start with @ followed by the user id. After the user "
|
||||
"id you need to include your server name after a :.\nYou can also put your homeserver "
|
||||
"address there, if your server doesn't support .well-known lookup.\nExample: "
|
||||
"@user:server.my\nIf Nheko fails to discover your homeserver, it will show you a "
|
||||
"field to enter the server manually."));
|
||||
|
||||
spinner_ = new LoadingIndicator(this);
|
||||
spinner_->setFixedHeight(40);
|
||||
spinner_->setFixedWidth(40);
|
||||
spinner_->hide();
|
||||
|
||||
errorIcon_ = new QLabel(this);
|
||||
errorIcon_->setPixmap(QPixmap(QStringLiteral(":/icons/icons/error.png")));
|
||||
errorIcon_->hide();
|
||||
|
||||
matrixidLayout_ = new QHBoxLayout();
|
||||
matrixidLayout_->addWidget(matrixid_input_, 0, Qt::AlignVCenter);
|
||||
|
||||
QFont font;
|
||||
|
||||
error_matrixid_label_ = new QLabel(this);
|
||||
error_matrixid_label_->setFont(font);
|
||||
error_matrixid_label_->setWordWrap(true);
|
||||
|
||||
password_input_ = new TextField(this);
|
||||
password_input_->setLabel(tr("Password"));
|
||||
password_input_->setEchoMode(QLineEdit::Password);
|
||||
password_input_->setToolTip(tr("Your password."));
|
||||
|
||||
deviceName_ = new TextField(this);
|
||||
deviceName_->setLabel(tr("Device name"));
|
||||
deviceName_->setToolTip(
|
||||
tr("A name for this device, which will be shown to others, when verifying your devices. "
|
||||
"If none is provided a default is used."));
|
||||
|
||||
serverInput_ = new TextField(this);
|
||||
serverInput_->setLabel(tr("Homeserver address"));
|
||||
serverInput_->setPlaceholderText(tr("server.my:8787"));
|
||||
serverInput_->setToolTip(tr("The address that can be used to contact you homeservers "
|
||||
"client API.\nExample: https://server.my:8787"));
|
||||
serverInput_->hide();
|
||||
|
||||
serverLayout_ = new QHBoxLayout();
|
||||
serverLayout_->addWidget(serverInput_, 0, Qt::AlignVCenter);
|
||||
|
||||
form_layout_->addLayout(matrixidLayout_);
|
||||
form_layout_->addWidget(error_matrixid_label_, 0, Qt::AlignHCenter);
|
||||
form_layout_->addWidget(password_input_);
|
||||
form_layout_->addWidget(deviceName_, Qt::AlignHCenter);
|
||||
form_layout_->addLayout(serverLayout_);
|
||||
|
||||
error_matrixid_label_->hide();
|
||||
|
||||
button_layout_ = new QHBoxLayout();
|
||||
button_layout_->setSpacing(20);
|
||||
button_layout_->setContentsMargins(0, 0, 0, 30);
|
||||
|
||||
login_button_ = new RaisedButton(tr("LOGIN"), this);
|
||||
login_button_->setMinimumSize(150, 65);
|
||||
login_button_->setFontSize(20);
|
||||
login_button_->setCornerRadius(3);
|
||||
|
||||
sso_login_button_ = new RaisedButton(tr("SSO LOGIN"), this);
|
||||
sso_login_button_->setMinimumSize(150, 65);
|
||||
sso_login_button_->setFontSize(20);
|
||||
sso_login_button_->setCornerRadius(3);
|
||||
sso_login_button_->setVisible(false);
|
||||
|
||||
button_layout_->addStretch(1);
|
||||
button_layout_->addWidget(login_button_);
|
||||
button_layout_->addWidget(sso_login_button_);
|
||||
button_layout_->addStretch(1);
|
||||
|
||||
error_label_ = new QLabel(this);
|
||||
error_label_->setFont(font);
|
||||
error_label_->setWordWrap(true);
|
||||
|
||||
top_layout_->addLayout(top_bar_layout_);
|
||||
top_layout_->addStretch(1);
|
||||
top_layout_->addLayout(logo_layout_);
|
||||
top_layout_->addLayout(form_wrapper_);
|
||||
top_layout_->addStretch(1);
|
||||
top_layout_->addLayout(button_layout_);
|
||||
top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter);
|
||||
top_layout_->addStretch(1);
|
||||
|
||||
setLayout(top_layout_);
|
||||
[[maybe_unused]] static auto ignored =
|
||||
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
||||
|
||||
connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection);
|
||||
connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection);
|
||||
connect(
|
||||
this,
|
||||
&LoginPage::loginOk,
|
||||
this,
|
||||
[this](const mtx::responses::Login &res) {
|
||||
loggingIn_ = false;
|
||||
emit loggingInChanged();
|
||||
|
||||
connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked()));
|
||||
connect(login_button_, &RaisedButton::clicked, this, [this]() {
|
||||
onLoginButtonClicked(passwordSupported ? LoginMethod::Password : LoginMethod::SSO);
|
||||
});
|
||||
connect(sso_login_button_, &RaisedButton::clicked, this, [this]() {
|
||||
onLoginButtonClicked(LoginMethod::SSO);
|
||||
});
|
||||
connect(this,
|
||||
&LoginPage::showErrorMessage,
|
||||
this,
|
||||
static_cast<void (LoginPage::*)(QLabel *, const QString &)>(&LoginPage::showError),
|
||||
Qt::QueuedConnection);
|
||||
connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
|
||||
connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
|
||||
connect(deviceName_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
|
||||
connect(serverInput_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
|
||||
connect(matrixid_input_, SIGNAL(editingFinished()), this, SLOT(onMatrixIdEntered()));
|
||||
connect(serverInput_, SIGNAL(editingFinished()), this, SLOT(onServerAddressEntered()));
|
||||
http::client()->set_user(res.user_id);
|
||||
MainWindow::instance()->showChatPage();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
void
|
||||
LoginPage::showError(const QString &msg)
|
||||
{
|
||||
auto rect = QFontMetrics(font()).boundingRect(msg);
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
error_label_->setFixedHeight((int)qCeil(width / 200.0) * height);
|
||||
error_label_->setText(msg);
|
||||
loggingIn_ = false;
|
||||
emit loggingInChanged();
|
||||
|
||||
error_ = msg;
|
||||
emit errorOccurred();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::showError(QLabel *label, const QString &msg)
|
||||
LoginPage::setHomeserver(QString hs)
|
||||
{
|
||||
auto rect = QFontMetrics(font()).boundingRect(msg);
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
label->setFixedHeight((int)qCeil(width / 200.0) * height);
|
||||
label->setText(msg);
|
||||
if (hs != homeserver_) {
|
||||
homeserver_ = hs;
|
||||
homeserverValid_ = false;
|
||||
emit homeserverChanged();
|
||||
http::client()->set_server(hs.toStdString());
|
||||
checkHomeserverVersion();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::onMatrixIdEntered()
|
||||
{
|
||||
error_label_->setText(QLatin1String(""));
|
||||
clearErrors();
|
||||
|
||||
homeserverValid_ = false;
|
||||
emit homeserverChanged();
|
||||
|
||||
User user;
|
||||
try {
|
||||
user = parse<User>(mxid_.toStdString());
|
||||
} catch (const std::exception &) {
|
||||
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
||||
emit mxidErrorChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!matrixid_input_->isValid()) {
|
||||
error_matrixid_label_->show();
|
||||
showError(error_matrixid_label_,
|
||||
tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"));
|
||||
if (user.hostname().empty() || user.localpart().empty()) {
|
||||
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
||||
emit mxidErrorChanged();
|
||||
return;
|
||||
} else {
|
||||
error_matrixid_label_->setText(QLatin1String(""));
|
||||
error_matrixid_label_->hide();
|
||||
nhlog::net()->debug("hostname: {}", user.hostname());
|
||||
}
|
||||
|
||||
try {
|
||||
user = parse<User>(matrixid_input_->text().toStdString());
|
||||
} catch (const std::exception &) {
|
||||
showError(error_matrixid_label_,
|
||||
tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString homeServer = QString::fromStdString(user.hostname());
|
||||
if (homeServer != inferredServerAddress_) {
|
||||
serverInput_->hide();
|
||||
serverLayout_->removeWidget(errorIcon_);
|
||||
errorIcon_->hide();
|
||||
if (serverInput_->isVisible()) {
|
||||
matrixidLayout_->removeWidget(spinner_);
|
||||
serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
|
||||
spinner_->start();
|
||||
} else {
|
||||
serverLayout_->removeWidget(spinner_);
|
||||
matrixidLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
|
||||
spinner_->start();
|
||||
}
|
||||
|
||||
inferredServerAddress_ = homeServer;
|
||||
serverInput_->setText(homeServer);
|
||||
if (user.hostname() != inferredServerAddress_.toStdString()) {
|
||||
homeserverNeeded_ = false;
|
||||
lookingUpHs_ = true;
|
||||
emit lookingUpHsChanged();
|
||||
|
||||
http::client()->set_server(user.hostname());
|
||||
http::client()->verify_certificates(
|
||||
!UserSettings::instance()->disableCertificateValidation());
|
||||
homeserver_ = QString::fromStdString(user.hostname());
|
||||
emit homeserverChanged();
|
||||
|
||||
http::client()->well_known(
|
||||
[this](const mtx::responses::WellKnown &res, mtx::http::RequestErr err) {
|
||||
|
@ -286,6 +128,7 @@ LoginPage::onMatrixIdEntered()
|
|||
|
||||
nhlog::net()->info("Autodiscovery: Discovered '" + res.homeserver.base_url + "'");
|
||||
http::client()->set_server(res.homeserver.base_url);
|
||||
emit homeserverChanged();
|
||||
checkHomeserverVersion();
|
||||
});
|
||||
}
|
||||
|
@ -294,6 +137,16 @@ LoginPage::onMatrixIdEntered()
|
|||
void
|
||||
LoginPage::checkHomeserverVersion()
|
||||
{
|
||||
clearErrors();
|
||||
|
||||
try {
|
||||
User user = parse<User>(mxid_.toStdString());
|
||||
} catch (const std::exception &) {
|
||||
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
||||
emit mxidErrorChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
http::client()->versions([this](const mtx::responses::Versions &, mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
if (err->status_code == 404) {
|
||||
|
@ -332,93 +185,64 @@ LoginPage::checkHomeserverVersion()
|
|||
});
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::onServerAddressEntered()
|
||||
{
|
||||
error_label_->setText(QLatin1String(""));
|
||||
http::client()->verify_certificates(!UserSettings::instance()->disableCertificateValidation());
|
||||
http::client()->set_server(serverInput_->text().toStdString());
|
||||
checkHomeserverVersion();
|
||||
|
||||
serverLayout_->removeWidget(errorIcon_);
|
||||
errorIcon_->hide();
|
||||
serverLayout_->addWidget(spinner_, 0, Qt::AlignVCenter | Qt::AlignRight);
|
||||
spinner_->start();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::versionError(const QString &error)
|
||||
{
|
||||
showError(error_label_, error);
|
||||
serverInput_->show();
|
||||
showError(error);
|
||||
|
||||
spinner_->stop();
|
||||
serverLayout_->removeWidget(spinner_);
|
||||
serverLayout_->addWidget(errorIcon_, 0, Qt::AlignVCenter | Qt::AlignRight);
|
||||
errorIcon_->show();
|
||||
matrixidLayout_->removeWidget(spinner_);
|
||||
homeserverNeeded_ = true;
|
||||
lookingUpHs_ = false;
|
||||
homeserverValid_ = false;
|
||||
emit lookingUpHsChanged();
|
||||
emit versionLookedUp();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::versionOk(bool passwordSupported_, bool ssoSupported_)
|
||||
LoginPage::versionOk(bool passwordSupported, bool ssoSupported)
|
||||
{
|
||||
passwordSupported = passwordSupported_;
|
||||
ssoSupported = ssoSupported_;
|
||||
passwordSupported_ = passwordSupported;
|
||||
ssoSupported_ = ssoSupported;
|
||||
|
||||
serverLayout_->removeWidget(spinner_);
|
||||
matrixidLayout_->removeWidget(spinner_);
|
||||
spinner_->stop();
|
||||
|
||||
password_input_->setVisible(passwordSupported);
|
||||
password_input_->setEnabled(passwordSupported);
|
||||
sso_login_button_->setVisible(ssoSupported);
|
||||
login_button_->setVisible(passwordSupported);
|
||||
|
||||
if (serverInput_->isVisible())
|
||||
serverInput_->hide();
|
||||
lookingUpHs_ = false;
|
||||
homeserverValid_ = true;
|
||||
emit homeserverChanged();
|
||||
emit lookingUpHsChanged();
|
||||
emit versionLookedUp();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
|
||||
LoginPage::onLoginButtonClicked(LoginMethod loginMethod,
|
||||
QString userid,
|
||||
QString password,
|
||||
QString deviceName)
|
||||
{
|
||||
error_label_->setText(QLatin1String(""));
|
||||
clearErrors();
|
||||
|
||||
User user;
|
||||
|
||||
if (!matrixid_input_->isValid()) {
|
||||
error_matrixid_label_->show();
|
||||
showError(error_matrixid_label_,
|
||||
tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"));
|
||||
return;
|
||||
} else {
|
||||
error_matrixid_label_->setText(QLatin1String(""));
|
||||
error_matrixid_label_->hide();
|
||||
}
|
||||
|
||||
try {
|
||||
user = parse<User>(matrixid_input_->text().toStdString());
|
||||
user = parse<User>(userid.toStdString());
|
||||
} catch (const std::exception &) {
|
||||
showError(error_matrixid_label_,
|
||||
tr("You have entered an invalid Matrix ID e.g @joe:matrix.org"));
|
||||
mxidError_ = tr("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
||||
emit mxidErrorChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginMethod == LoginMethod::Password) {
|
||||
if (password_input_->text().isEmpty())
|
||||
return showError(error_label_, tr("Empty password"));
|
||||
if (password.isEmpty())
|
||||
return showError(tr("Empty password"));
|
||||
|
||||
http::client()->login(
|
||||
user.localpart(),
|
||||
password_input_->text().toStdString(),
|
||||
deviceName_->text().trimmed().isEmpty() ? initialDeviceName()
|
||||
: deviceName_->text().toStdString(),
|
||||
password.toStdString(),
|
||||
deviceName.trimmed().isEmpty() ? initialDeviceName_() : deviceName.toStdString(),
|
||||
[this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
auto error = err->matrix_error.error;
|
||||
if (error.empty())
|
||||
error = err->parse_error;
|
||||
|
||||
showErrorMessage(error_label_, QString::fromStdString(error));
|
||||
emit errorOccurred();
|
||||
showError(QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -432,34 +256,33 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
|
|||
});
|
||||
} else {
|
||||
auto sso = new SSOHandler();
|
||||
connect(sso, &SSOHandler::ssoSuccess, this, [this, sso](std::string token) {
|
||||
mtx::requests::Login req{};
|
||||
req.token = token;
|
||||
req.type = mtx::user_interactive::auth_types::token;
|
||||
req.device_id = deviceName_->text().trimmed().isEmpty()
|
||||
? initialDeviceName()
|
||||
: deviceName_->text().toStdString();
|
||||
http::client()->login(
|
||||
req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
showErrorMessage(error_label_,
|
||||
QString::fromStdString(err->matrix_error.error));
|
||||
emit errorOccurred();
|
||||
return;
|
||||
}
|
||||
connect(
|
||||
sso, &SSOHandler::ssoSuccess, this, [this, sso, userid, deviceName](std::string token) {
|
||||
mtx::requests::Login req{};
|
||||
req.token = token;
|
||||
req.type = mtx::user_interactive::auth_types::token;
|
||||
req.device_id =
|
||||
deviceName.trimmed().isEmpty() ? initialDeviceName_() : deviceName.toStdString();
|
||||
http::client()->login(
|
||||
req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
showError(QString::fromStdString(err->matrix_error.error));
|
||||
emit errorOccurred();
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.well_known) {
|
||||
http::client()->set_server(res.well_known->homeserver.base_url);
|
||||
nhlog::net()->info("Login requested to user server: " +
|
||||
res.well_known->homeserver.base_url);
|
||||
}
|
||||
if (res.well_known) {
|
||||
http::client()->set_server(res.well_known->homeserver.base_url);
|
||||
nhlog::net()->info("Login requested to user server: " +
|
||||
res.well_known->homeserver.base_url);
|
||||
}
|
||||
|
||||
emit loginOk(res);
|
||||
});
|
||||
sso->deleteLater();
|
||||
});
|
||||
emit loginOk(res);
|
||||
});
|
||||
sso->deleteLater();
|
||||
});
|
||||
connect(sso, &SSOHandler::ssoFailed, this, [this, sso]() {
|
||||
showErrorMessage(error_label_, tr("SSO login failed"));
|
||||
showError(tr("SSO login failed"));
|
||||
emit errorOccurred();
|
||||
sso->deleteLater();
|
||||
});
|
||||
|
@ -468,37 +291,6 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod)
|
|||
QString::fromStdString(http::client()->login_sso_redirect(sso->url())));
|
||||
}
|
||||
|
||||
emit loggingIn();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::reset()
|
||||
{
|
||||
matrixid_input_->clear();
|
||||
password_input_->clear();
|
||||
password_input_->show();
|
||||
serverInput_->clear();
|
||||
|
||||
spinner_->stop();
|
||||
errorIcon_->hide();
|
||||
serverLayout_->removeWidget(spinner_);
|
||||
serverLayout_->removeWidget(errorIcon_);
|
||||
matrixidLayout_->removeWidget(spinner_);
|
||||
|
||||
inferredServerAddress_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::onBackButtonClicked()
|
||||
{
|
||||
emit backButtonClicked();
|
||||
}
|
||||
|
||||
void
|
||||
LoginPage::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.initFrom(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
loggingIn_ = true;
|
||||
emit loggingInChanged();
|
||||
}
|
||||
|
|
132
src/LoginPage.h
132
src/LoginPage.h
|
@ -6,16 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class FlatButton;
|
||||
class LoadingIndicator;
|
||||
class OverlayModal;
|
||||
class RaisedButton;
|
||||
class TextField;
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
class QHBoxLayout;
|
||||
#include <QObject>
|
||||
|
||||
namespace mtx {
|
||||
namespace responses {
|
||||
|
@ -23,24 +14,61 @@ struct Login;
|
|||
}
|
||||
}
|
||||
|
||||
class LoginPage : public QWidget
|
||||
class LoginPage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString mxid READ mxid WRITE setMxid NOTIFY matrixIdChanged)
|
||||
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
|
||||
|
||||
Q_PROPERTY(QString mxidError READ mxidError NOTIFY mxidErrorChanged)
|
||||
Q_PROPERTY(QString error READ error NOTIFY errorOccurred)
|
||||
Q_PROPERTY(bool lookingUpHs READ lookingUpHs NOTIFY lookingUpHsChanged)
|
||||
Q_PROPERTY(bool homeserverValid READ homeserverValid NOTIFY lookingUpHsChanged)
|
||||
Q_PROPERTY(bool loggingIn READ loggingIn NOTIFY loggingInChanged)
|
||||
Q_PROPERTY(bool passwordSupported READ passwordSupported NOTIFY versionLookedUp)
|
||||
Q_PROPERTY(bool ssoSupported READ ssoSupported NOTIFY versionLookedUp)
|
||||
Q_PROPERTY(bool homeserverNeeded READ homeserverNeeded NOTIFY versionLookedUp)
|
||||
|
||||
public:
|
||||
enum class LoginMethod
|
||||
{
|
||||
Password,
|
||||
SSO,
|
||||
};
|
||||
Q_ENUM(LoginMethod)
|
||||
|
||||
LoginPage(QWidget *parent = nullptr);
|
||||
LoginPage(QObject *parent = nullptr);
|
||||
|
||||
void reset();
|
||||
Q_INVOKABLE QString initialDeviceName() const
|
||||
{
|
||||
return QString::fromStdString(initialDeviceName_());
|
||||
}
|
||||
|
||||
bool lookingUpHs() const { return lookingUpHs_; }
|
||||
bool loggingIn() const { return loggingIn_; }
|
||||
bool passwordSupported() const { return passwordSupported_; }
|
||||
bool ssoSupported() const { return ssoSupported_; }
|
||||
bool homeserverNeeded() const { return homeserverNeeded_; }
|
||||
bool homeserverValid() const { return homeserverValid_; }
|
||||
|
||||
QString homeserver() { return homeserver_; }
|
||||
QString mxid() { return mxid_; }
|
||||
|
||||
QString error() { return error_; }
|
||||
QString mxidError() { return mxidError_; }
|
||||
|
||||
void setHomeserver(QString hs);
|
||||
void setMxid(QString id)
|
||||
{
|
||||
if (id != mxid_) {
|
||||
mxid_ = id;
|
||||
emit matrixIdChanged();
|
||||
onMatrixIdEntered();
|
||||
}
|
||||
}
|
||||
signals:
|
||||
void backButtonClicked();
|
||||
void loggingIn();
|
||||
void loggingInChanged();
|
||||
void errorOccurred();
|
||||
|
||||
//! Used to trigger the corresponding slot outside of the main thread.
|
||||
|
@ -48,28 +76,26 @@ signals:
|
|||
void versionOkCb(bool passwordSupported, bool ssoSupported);
|
||||
|
||||
void loginOk(const mtx::responses::Login &res);
|
||||
void showErrorMessage(QLabel *label, const QString &msg);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void onServerAddressEntered();
|
||||
|
||||
void matrixIdChanged();
|
||||
void homeserverChanged();
|
||||
|
||||
void mxidErrorChanged();
|
||||
void lookingUpHsChanged();
|
||||
void versionLookedUp();
|
||||
void versionLookupFinished();
|
||||
|
||||
public slots:
|
||||
// Displays errors produced during the login.
|
||||
void showError(const QString &msg);
|
||||
void showError(QLabel *label, const QString &msg);
|
||||
|
||||
private slots:
|
||||
// Callback for the back button.
|
||||
void onBackButtonClicked();
|
||||
|
||||
// Callback for the login button.
|
||||
void onLoginButtonClicked(LoginMethod loginMethod);
|
||||
|
||||
// Callback for probing the server found in the mxid
|
||||
void onMatrixIdEntered();
|
||||
|
||||
// Callback for probing the manually entered server
|
||||
void onServerAddressEntered();
|
||||
void onLoginButtonClicked(LoginMethod loginMethod,
|
||||
QString userid,
|
||||
QString password,
|
||||
QString deviceName);
|
||||
|
||||
// Callback for errors produced during server probing
|
||||
void versionError(const QString &error_message);
|
||||
|
@ -78,7 +104,8 @@ private slots:
|
|||
|
||||
private:
|
||||
void checkHomeserverVersion();
|
||||
std::string initialDeviceName()
|
||||
void onMatrixIdEntered();
|
||||
std::string initialDeviceName_() const
|
||||
{
|
||||
#if defined(Q_OS_MAC)
|
||||
return "Nheko on macOS";
|
||||
|
@ -92,34 +119,27 @@ private:
|
|||
return "Nheko";
|
||||
#endif
|
||||
}
|
||||
void clearErrors()
|
||||
{
|
||||
error_.clear();
|
||||
mxidError_.clear();
|
||||
emit errorOccurred();
|
||||
emit mxidErrorChanged();
|
||||
}
|
||||
|
||||
QVBoxLayout *top_layout_;
|
||||
|
||||
QHBoxLayout *top_bar_layout_;
|
||||
QHBoxLayout *logo_layout_;
|
||||
QHBoxLayout *button_layout_;
|
||||
|
||||
QLabel *logo_;
|
||||
QLabel *error_label_;
|
||||
QLabel *error_matrixid_label_;
|
||||
|
||||
QHBoxLayout *serverLayout_;
|
||||
QHBoxLayout *matrixidLayout_;
|
||||
LoadingIndicator *spinner_;
|
||||
QLabel *errorIcon_;
|
||||
QString inferredServerAddress_;
|
||||
|
||||
FlatButton *back_button_;
|
||||
RaisedButton *login_button_, *sso_login_button_;
|
||||
QString mxid_;
|
||||
QString homeserver_;
|
||||
|
||||
QWidget *form_widget_;
|
||||
QHBoxLayout *form_wrapper_;
|
||||
QVBoxLayout *form_layout_;
|
||||
QString mxidError_;
|
||||
QString error_;
|
||||
|
||||
TextField *matrixid_input_;
|
||||
TextField *password_input_;
|
||||
TextField *deviceName_;
|
||||
TextField *serverInput_;
|
||||
bool passwordSupported = true;
|
||||
bool ssoSupported = false;
|
||||
bool passwordSupported_ = true;
|
||||
bool ssoSupported_ = false;
|
||||
|
||||
bool lookingUpHs_ = false;
|
||||
bool loggingIn_ = false;
|
||||
bool homeserverNeeded_ = false;
|
||||
bool homeserverValid_ = false;
|
||||
};
|
||||
|
|
|
@ -87,7 +87,6 @@ MainWindow::MainWindow(QWindow *parent)
|
|||
setSource(QUrl(QStringLiteral("qrc:///qml/Root.qml")));
|
||||
// modal_ = new OverlayModal(this);
|
||||
|
||||
|
||||
// QFont font;
|
||||
// font.setStyleStrategy(QFont::PreferAntialias);
|
||||
// setFont(font);
|
||||
|
@ -95,31 +94,19 @@ MainWindow::MainWindow(QWindow *parent)
|
|||
trayIcon_ = new TrayIcon(QStringLiteral(":/logos/nheko.svg"), this);
|
||||
|
||||
// welcome_page_ = new WelcomePage(this);
|
||||
// login_page_ = new LoginPage(this);
|
||||
// register_page_ = new RegisterPage(this);
|
||||
|
||||
//// Initialize sliding widget manager.
|
||||
|
||||
// connect(welcome_page_, SIGNAL(userLogin()), this, SLOT(showLoginPage()));
|
||||
// connect(welcome_page_, SIGNAL(userRegister()), this, SLOT(showRegisterPage()));
|
||||
|
||||
// connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
|
||||
// connect(login_page_, &LoginPage::loggingIn, this, &MainWindow::showOverlayProgressBar);
|
||||
// connect(register_page_, &RegisterPage::registering, this,
|
||||
// &MainWindow::showOverlayProgressBar); connect(login_page_, &LoginPage::errorOccurred, this,
|
||||
// [this]() { removeOverlayProgressBar(); }); connect(
|
||||
// register_page_, &RegisterPage::errorOccurred, this, [this]() { removeOverlayProgressBar();
|
||||
// });
|
||||
// connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
|
||||
|
||||
connect(chat_page_, &ChatPage::closing, this, &MainWindow::showWelcomePage);
|
||||
connect(chat_page_, &ChatPage::closing, this, [this] { switchToLoginPage(""); });
|
||||
// connect(
|
||||
// chat_page_, &ChatPage::showOverlayProgressBar, this, &MainWindow::showOverlayProgressBar);
|
||||
connect(chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle);
|
||||
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int)));
|
||||
connect(chat_page_, &ChatPage::showLoginPage, this, [this](const QString &msg) {
|
||||
login_page_->showError(msg);
|
||||
showLoginPage();
|
||||
switchToLoginPage(msg);
|
||||
});
|
||||
|
||||
connect(userSettings_.get(), &UserSettings::trayChanged, trayIcon_, &TrayIcon::setVisible);
|
||||
|
@ -210,6 +197,7 @@ MainWindow::registerQmlTypes()
|
|||
qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage");
|
||||
qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia");
|
||||
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
|
||||
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
||||
qmlRegisterUncreatableType<DeviceVerificationFlow>(
|
||||
"im.nheko",
|
||||
1,
|
||||
|
@ -375,9 +363,7 @@ MainWindow::removeOverlayProgressBar()
|
|||
QTimer *timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
|
||||
connect(timer, &QTimer::timeout, this, [this, timer]() {
|
||||
timer->deleteLater();
|
||||
});
|
||||
connect(timer, &QTimer::timeout, this, [this, timer]() { timer->deleteLater(); });
|
||||
|
||||
// FIXME: Snackbar doesn't work if it's initialized in the constructor.
|
||||
// QTimer::singleShot(0, this, [this]() {
|
||||
|
@ -404,7 +390,6 @@ MainWindow::showChatPage()
|
|||
|
||||
showOverlayProgressBar();
|
||||
|
||||
// login_page_->reset();
|
||||
chat_page_->bootstrap(userid, homeserver, token);
|
||||
connect(cache::client(), &Cache::databaseReady, this, &MainWindow::secretsChanged);
|
||||
connect(cache::client(), &Cache::secretChanged, this, &MainWindow::secretsChanged);
|
||||
|
@ -463,8 +448,7 @@ MainWindow::hasActiveUser()
|
|||
|
||||
void
|
||||
MainWindow::showOverlayProgressBar()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void
|
||||
MainWindow::openCreateRoomDialog(
|
||||
|
@ -485,8 +469,7 @@ MainWindow::showTransparentOverlayModal(QWidget *, QFlags<Qt::AlignmentFlag>)
|
|||
|
||||
void
|
||||
MainWindow::showSolidOverlayModal(QWidget *, QFlags<Qt::AlignmentFlag>)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
bool
|
||||
MainWindow::hasActiveDialogs() const
|
||||
|
@ -503,8 +486,7 @@ MainWindow::pageSupportsTray() const
|
|||
|
||||
void
|
||||
MainWindow::hideOverlay()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
inline void
|
||||
MainWindow::showDialog(QWidget *dialog)
|
||||
|
@ -520,11 +502,6 @@ MainWindow::showWelcomePage()
|
|||
removeOverlayProgressBar();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showLoginPage()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showRegisterPage()
|
||||
{}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
class ChatPage;
|
||||
class RegisterPage;
|
||||
class LoginPage;
|
||||
class WelcomePage;
|
||||
|
||||
class LoadingIndicator;
|
||||
|
@ -65,6 +64,9 @@ public:
|
|||
|
||||
MxcImageProvider *imageProvider() { return imgProvider; }
|
||||
|
||||
//! Show the chat page and start communicating with the given access token.
|
||||
void showChatPage();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
bool event(QEvent *event) override;
|
||||
|
@ -76,15 +78,9 @@ private slots:
|
|||
//! Show the welcome page in the main window.
|
||||
void showWelcomePage();
|
||||
|
||||
//! Show the login page in the main window.
|
||||
void showLoginPage();
|
||||
|
||||
//! Show the register page in the main window.
|
||||
void showRegisterPage();
|
||||
|
||||
//! Show the chat page and start communicating with the given access token.
|
||||
void showChatPage();
|
||||
|
||||
void showOverlayProgressBar();
|
||||
void removeOverlayProgressBar();
|
||||
|
||||
|
@ -96,6 +92,7 @@ signals:
|
|||
|
||||
void switchToChatPage();
|
||||
void switchToWelcomePage();
|
||||
void switchToLoginPage(QString error);
|
||||
|
||||
private:
|
||||
void showDialog(QWidget *dialog);
|
||||
|
@ -112,8 +109,6 @@ private:
|
|||
|
||||
//! The initial welcome screen.
|
||||
WelcomePage *welcome_page_;
|
||||
//! The login screen.
|
||||
LoginPage *login_page_;
|
||||
//! The register page.
|
||||
RegisterPage *register_page_;
|
||||
//! The main chat area.
|
||||
|
|
|
@ -110,7 +110,7 @@ public slots:
|
|||
RoomlistModel *rooms() { return rooms_; }
|
||||
|
||||
private:
|
||||
bool isInitialSync_ = true;
|
||||
bool isInitialSync_ = true;
|
||||
|
||||
RoomlistModel *rooms_ = nullptr;
|
||||
CommunitiesModel *communities_ = nullptr;
|
||||
|
|
Loading…
Reference in a new issue