Rework HBox-based pages and account settings
- Refactor everything about HBox, and adapt all the pages and popups that used it - Replace HTabContainer by HTabbedBox - Make boxes swippable - Make esc presses in boxes click the cancel button - Make all boxes and popups scrollable when needed - Replace generic apply button icons in popups - Fix tab focus for error and invite popups - Rework (still WIP) the account settings page: - Use the standard tabbed design of other pages - Ditch the horizontal profile layout, hacky and impossible to extend - Add real-time coloring for the display name field - Implement a device list in account settings (Sessions, still WIP)
This commit is contained in:
@@ -4,16 +4,21 @@ import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
|
||||
HFlickableColumnPage {
|
||||
title: qsTr("Add an account")
|
||||
header: HPageHeader {}
|
||||
HPage {
|
||||
id: page
|
||||
|
||||
HTabContainer {
|
||||
tabModel: [
|
||||
qsTr("Sign in"), qsTr("Register"), qsTr("Reset"),
|
||||
]
|
||||
HTabbedBox {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(implicitWidth, page.availableWidth)
|
||||
height: Math.min(implicitHeight, page.availableHeight)
|
||||
|
||||
SignIn { Component.onCompleted: forceActiveFocus() }
|
||||
header: HTabBar {
|
||||
HTabButton { text: qsTr("Sign in") }
|
||||
HTabButton { text: qsTr("Register") }
|
||||
HTabButton { text: qsTr("Reset") }
|
||||
}
|
||||
|
||||
SignIn {}
|
||||
Register {}
|
||||
Reset {}
|
||||
}
|
||||
|
@@ -3,28 +3,30 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/ButtonLayout"
|
||||
|
||||
HBox {
|
||||
id: signInBox
|
||||
clickButtonOnEnter: "ok"
|
||||
HFlickableColumnPage {
|
||||
function takeFocus() { registerButton.forceActiveFocus() }
|
||||
|
||||
buttonModel: [
|
||||
{ name: "ok", text: qsTr("Register from Riot"), iconName: "register" },
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
ok: button => {
|
||||
Qt.openUrlExternally("https://riot.im/app/#/register")
|
||||
footer: ButtonLayout {
|
||||
ApplyButton {
|
||||
id: registerButton
|
||||
text: qsTr("Register from Riot")
|
||||
icon.name: "register"
|
||||
onClicked: Qt.openUrlExternally("https://riot.im/app/#/register")
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
HLabel {
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
text: qsTr(
|
||||
"Not yet implemented\n\nYou can create a new " +
|
||||
"account from another client such as Riot."
|
||||
"Not implemented yet\n\n" +
|
||||
"You can create a new account from another client such as Riot."
|
||||
)
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
@@ -3,32 +3,31 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/ButtonLayout"
|
||||
|
||||
HBox {
|
||||
id: signInBox
|
||||
clickButtonOnEnter: "ok"
|
||||
HFlickableColumnPage {
|
||||
function takeFocus() { resetButton.forceActiveFocus() }
|
||||
|
||||
buttonModel: [
|
||||
{
|
||||
name: "ok",
|
||||
text: qsTr("Reset password from Riot"),
|
||||
iconName: "reset-password"
|
||||
},
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
ok: button => {
|
||||
Qt.openUrlExternally("https://riot.im/app/#/forgot_password")
|
||||
footer: ButtonLayout {
|
||||
ApplyButton {
|
||||
id: resetButton
|
||||
text: qsTr("Reset password from Riot")
|
||||
icon.name: "reset-password"
|
||||
onClicked:
|
||||
Qt.openUrlExternally("https://riot.im/app/#/forgot_password")
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
HLabel {
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
text: qsTr(
|
||||
"Not yet implemented\n\nYou can reset your " +
|
||||
"password using another client such as Riot."
|
||||
"Not implemented yet\n\n" +
|
||||
"You can reset your password from another client such as Riot."
|
||||
)
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
@@ -3,82 +3,10 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../Base"
|
||||
import "../../Base/ButtonLayout"
|
||||
|
||||
HBox {
|
||||
id: signInBox
|
||||
clickButtonOnEnter: "apply"
|
||||
|
||||
onFocusChanged: idField.item.forceActiveFocus()
|
||||
|
||||
buttonModel: [
|
||||
{
|
||||
name: "apply",
|
||||
text: qsTr("Sign in"),
|
||||
enabled: canSignIn,
|
||||
iconName: "sign-in",
|
||||
loading: loginFuture !== null,
|
||||
disableWhileLoading: false,
|
||||
},
|
||||
{ name: "cancel", text: qsTr("Cancel"), iconName: "cancel"},
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
apply: button => {
|
||||
if (loginFuture) loginFuture.cancel()
|
||||
|
||||
signInTimeout.restart()
|
||||
|
||||
errorMessage.text = ""
|
||||
|
||||
const args = [
|
||||
idField.item.text.trim(), passwordField.item.text,
|
||||
undefined, serverField.item.text.trim(),
|
||||
]
|
||||
|
||||
loginFuture = py.callCoro("login_client", args, userId => {
|
||||
signInTimeout.stop()
|
||||
errorMessage.text = ""
|
||||
loginFuture = null
|
||||
|
||||
py.callCoro(
|
||||
rememberAccount.checked ?
|
||||
"saved_accounts.add": "saved_accounts.delete",
|
||||
|
||||
[userId]
|
||||
)
|
||||
|
||||
pageLoader.showPage(
|
||||
"AccountSettings/AccountSettings", {userId}
|
||||
)
|
||||
|
||||
}, (type, args, error, traceback, uuid) => {
|
||||
loginFuture = null
|
||||
signInTimeout.stop()
|
||||
|
||||
let txt = qsTr(
|
||||
"Invalid request, login type or unknown error: %1",
|
||||
).arg(type)
|
||||
|
||||
type === "MatrixForbidden" ?
|
||||
txt = qsTr("Invalid username or password") :
|
||||
|
||||
type === "MatrixUserDeactivated" ?
|
||||
txt = qsTr("This account was deactivated") :
|
||||
|
||||
utils.showError(type, traceback, uuid)
|
||||
|
||||
errorMessage.text = txt
|
||||
})
|
||||
},
|
||||
|
||||
cancel: button => {
|
||||
if (! loginFuture) return
|
||||
|
||||
signInTimeout.stop()
|
||||
loginFuture.cancel()
|
||||
loginFuture = null
|
||||
}
|
||||
})
|
||||
HFlickableColumnPage {
|
||||
id: page
|
||||
|
||||
|
||||
property var loginFuture: null
|
||||
@@ -90,6 +18,83 @@ HBox {
|
||||
passwordField.item.text && ! serverField.item.error
|
||||
|
||||
|
||||
function takeFocus() { idField.item.forceActiveFocus() }
|
||||
|
||||
function signIn() {
|
||||
if (page.loginFuture) page.loginFuture.cancel()
|
||||
|
||||
signInTimeout.restart()
|
||||
|
||||
errorMessage.text = ""
|
||||
|
||||
const args = [
|
||||
idField.item.text.trim(), passwordField.item.text,
|
||||
undefined, serverField.item.text.trim(),
|
||||
]
|
||||
|
||||
page.loginFuture = py.callCoro("login_client", args, userId => {
|
||||
signInTimeout.stop()
|
||||
errorMessage.text = ""
|
||||
page.loginFuture = null
|
||||
|
||||
py.callCoro(
|
||||
rememberAccount.checked ?
|
||||
"saved_accounts.add": "saved_accounts.delete",
|
||||
|
||||
[userId]
|
||||
)
|
||||
|
||||
pageLoader.showPage(
|
||||
"AccountSettings/AccountSettings", {userId}
|
||||
)
|
||||
|
||||
}, (type, args, error, traceback, uuid) => {
|
||||
page.loginFuture = null
|
||||
signInTimeout.stop()
|
||||
|
||||
let txt = qsTr(
|
||||
"Invalid request, login type or unknown error: %1",
|
||||
).arg(type)
|
||||
|
||||
type === "MatrixForbidden" ?
|
||||
txt = qsTr("Invalid username or password") :
|
||||
|
||||
type === "MatrixUserDeactivated" ?
|
||||
txt = qsTr("This account was deactivated") :
|
||||
|
||||
utils.showError(type, traceback, uuid)
|
||||
|
||||
errorMessage.text = txt
|
||||
})
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
if (! page.loginFuture) return
|
||||
|
||||
signInTimeout.stop()
|
||||
page.loginFuture.cancel()
|
||||
page.loginFuture = null
|
||||
}
|
||||
|
||||
|
||||
footer: ButtonLayout {
|
||||
ApplyButton {
|
||||
enabled: page.canSignIn
|
||||
text: qsTr("Sign in")
|
||||
icon.name: "sign-in"
|
||||
loading: page.loginFuture !== null
|
||||
disableWhileLoading: false
|
||||
onClicked: page.signIn()
|
||||
}
|
||||
|
||||
CancelButton {
|
||||
onClicked: page.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: page.cancel()
|
||||
|
||||
|
||||
Timer {
|
||||
id: signInTimeout
|
||||
interval: 30 * 1000
|
||||
@@ -120,10 +125,10 @@ HBox {
|
||||
HButton {
|
||||
icon.name: modelData
|
||||
circle: true
|
||||
checked: signInWith === modelData
|
||||
checked: page.signInWith === modelData
|
||||
enabled: modelData === "username"
|
||||
autoExclusive: true
|
||||
onClicked: signInWith = modelData
|
||||
onClicked: page.signInWith = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,8 +136,8 @@ HBox {
|
||||
HLabeledItem {
|
||||
id: idField
|
||||
label.text: qsTr(
|
||||
signInWith === "email" ? "Email:" :
|
||||
signInWith === "phone" ? "Phone:" :
|
||||
page.signInWith === "email" ? "Email:" :
|
||||
page.signInWith === "phone" ? "Phone:" :
|
||||
"Username:"
|
||||
)
|
||||
|
||||
@@ -157,9 +162,6 @@ HBox {
|
||||
|
||||
HLabeledItem {
|
||||
id: serverField
|
||||
label.text: qsTr("Homeserver:")
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
// 2019-11-11 https://www.hello-matrix.net/public_servers.php
|
||||
readonly property var knownServers: [
|
||||
@@ -182,6 +184,10 @@ HBox {
|
||||
readonly property bool knownServerChosen:
|
||||
knownServers.includes(item.cleanText)
|
||||
|
||||
label.text: qsTr("Homeserver:")
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
HTextField {
|
||||
width: parent.width
|
||||
text: "https://matrix.org"
|
||||
|
Reference in New Issue
Block a user