moment/src/gui/Pages/AddAccount/ServerBrowser.qml

301 lines
9.0 KiB
QML
Raw Normal View History

// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Layouts 1.12
import "../.."
import "../../Base"
import "../../Base/Buttons"
import "../../PythonBridge"
import "../../ShortcutBundles"
HBox {
id: box
property bool knownHttps: window.getState(box, "knownHttps", false)
property string acceptedUserUrl: ""
property string acceptedUrl: ""
2020-07-26 13:31:13 +10:00
property var loginFlows: []
property string saveName: "serverBrowser"
property var saveProperties: ["acceptedUserUrl", "knownHttps"]
property string loadingIconStep: "server-ping-bad"
property string connectFutureId: ""
property string fetchServersFutureId: ""
signal accepted()
function takeFocus() { serverField.item.field.forceActiveFocus() }
function fetchServers() {
if (fetchServersFutureId) py.cancelCoro(fetchServersFutureId)
fetchServersFutureId = py.callCoro("fetch_homeservers", [], () => {
fetchServersFutureId = ""
}, (type, args, error, traceback) => {
fetchServersFutureId = ""
print( traceback) // TODO: display error graphically
})
}
function connect() {
if (connectFutureId) py.cancelCoro(connectFutureId)
connectTimeout.restart()
const typedUrl = serverField.item.field.cleanText
const args = [typedUrl]
if (box.knownHttps)
args[0] = args[0].replace(/^(https?:\/\/)?/, "https://")
connectFutureId = py.callCoro("server_info", args, ([url, flows]) => {
connectTimeout.stop()
serverField.errorLabel.text = ""
connectFutureId = ""
2020-07-26 13:31:13 +10:00
if (! (
flows.includes("m.login.password") ||
(
flows.includes("m.login.sso") &&
flows.includes("m.login.token")
)
)) {
serverField.errorLabel.text =
2020-07-26 13:31:13 +10:00
qsTr("No supported sign-in method for this homeserver.")
return
}
acceptedUrl = url
acceptedUserUrl = typedUrl
loginFlows = flows
accepted()
}, (type, args, error, traceback, uuid) => {
2020-08-19 16:14:46 +10:00
console.error(traceback)
connectTimeout.stop()
connectFutureId = ""
let text = qsTr("Unexpected error: %1 [%2]").arg(type).arg(args)
type === "MatrixNotFound" ?
text = qsTr("Invalid homeserver address") :
type.startsWith("Matrix") ?
2020-08-19 16:14:46 +10:00
text = qsTr("Connection failed: %1(%2)").arg(type).arg(args) :
py.showError(type, traceback, uuid)
serverField.errorLabel.text = text
})
}
padding: 0
implicitWidth: theme.controls.box.defaultWidth * 1.25
contentHeight: window.height
2020-08-22 00:09:58 +10:00
header: HColumnLayout {
HLabel {
text: qsTr(
"Choose a homeserver to create an account on, or the " +
"homeserver where you have an account to sign in to:"
)
wrapMode: HLabel.Wrap
padding: theme.spacing
Layout.fillWidth: true
}
HRowLayout {
Repeater {
model: [
qsTr("Ping"),
qsTr("Name & location"),
qsTr("Stability"),
qsTr("Site"),
]
HLabel {
text: modelData
elide: HLabel.ElideRight
topPadding: theme.spacing / 2
bottomPadding: topPadding
leftPadding: theme.spacing / (model.index === 0 ? 2 : 3)
rightPadding: theme.spacing / (model.index === 3 ? 1.5 : 3)
background: Rectangle {
color: theme.controls.button.background
}
Layout.fillWidth: model.index === 1
}
}
}
}
footer: HLabeledItem {
id: serverField
readonly property bool knownServerChosen:
serverList.model.find(item.cleanText) !== null
label.text: qsTr("Homeserver address:")
label.topPadding: theme.spacing / 2
label.bottomPadding: label.topPadding / 4
label.leftPadding: theme.spacing
label.rightPadding: label.leftPadding
errorLabel.leftPadding: label.leftPadding
errorLabel.rightPadding: label.leftPadding
errorLabel.bottomPadding: label.leftPadding
HRowLayout {
readonly property alias field: field
readonly property alias apply: apply
width: parent.width
HTextField {
id: field
readonly property string cleanText:
text.toLowerCase().trim().replace(/\/+$/, "")
2020-08-19 16:14:46 +10:00
inputMethodHints: Qt.ImhUrlCharactersOnly
defaultText: window.getState(box, "acceptedUserUrl", "")
2020-08-19 16:14:46 +10:00
placeholderText: "example.org"
onTextEdited: {
py.callCoro(
2020-08-21 02:21:47 +10:00
"set_string_filter", ["filtered_homeservers", text],
)
knownHttps = false
serverList.currentIndex = -1
}
Layout.fillWidth: true
Layout.fillHeight: true
Keys.onBacktabPressed: ev => Keys.onUpPressed(ev)
Keys.onTabPressed: ev => Keys.onDownPressed(ev)
Keys.onUpPressed: {
serverList.decrementCurrentIndex()
serverList.setFieldText(serverList.currentIndex)
}
Keys.onDownPressed: {
serverList.incrementCurrentIndex()
serverList.setFieldText(serverList.currentIndex)
}
}
HButton {
id: apply
enabled: field.cleanText && ! field.error
2020-08-19 21:30:30 +10:00
icon.name: "server-connect-to-address"
icon.color: theme.colors.positiveBackground
loading: box.connectFutureId !== ""
disableWhileLoading: false
onClicked: box.connect()
Layout.fillHeight: true
}
}
}
onKeyboardAccept:
if (serverField.item.apply.enabled) serverField.item.apply.clicked()
onAccepted: window.saveState(this)
Component.onDestruction:
if (fetchServersFutureId) py.cancelCoro(fetchServersFutureId)
Timer {
id: connectTimeout
interval: 30 * 1000
onTriggered: {
serverField.errorLabel.text =
serverField.knownServerChosen ?
qsTr("This homeserver seems unavailable. Verify your inter" +
"net connection or try again later.") :
qsTr("This homeserver seems unavailable. Verify the " +
"entered address, your internet connection or try " +
"again later.")
}
}
Timer {
interval: 1000
running:
fetchServersFutureId === "" &&
ModelStore.get("homeservers").count === 0
repeat: true
triggeredOnStart: true
onTriggered: box.fetchServers()
}
Timer {
interval: theme.animationDuration * 2
running: true
repeat: true
onTriggered:
box.loadingIconStep = "server-ping-" + (
box.loadingIconStep === "server-ping-bad" ? "medium" :
box.loadingIconStep === "server-ping-medium" ? "good" :
"bad"
)
}
FlickShortcuts {
flickable: serverList
active: ! mainUI.debugConsole.visible
}
HListView {
id: serverList
function setFieldText(fromItemIndex) {
const url = model.get(fromItemIndex).id
box.knownHttps = /^https:\/\//.test(url)
serverField.item.field.text = url.replace(/^https:\/\//, "")
}
clip: true
model: ModelStore.get("filtered_homeservers")
delegate: ServerDelegate {
width: serverList.width
loadingIconStep: box.loadingIconStep
onClicked: {
serverList.setFieldText(model.index)
serverField.item.apply.clicked()
}
}
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
z: -10
anchors.fill: parent
color: theme.colors.strongBackground
}
HLoader {
id: busyIndicatorLoader
anchors.centerIn: parent
width: 96 * theme.uiScale
height: width
source: "../../Base/HBusyIndicator.qml"
active: box.fetchServersFutureId && ! serverList.count
opacity: active ? 1 : 0
Behavior on opacity { HNumberAnimation { factor: 2 } }
}
}
}