2020-09-24 09:57:54 +10:00
|
|
|
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
2020-07-24 15:30:35 +10:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
|
|
|
import QtQuick 2.12
|
|
|
|
import QtQuick.Layouts 1.12
|
2020-08-19 14:17:24 +10:00
|
|
|
import "../.."
|
2020-07-24 15:30:35 +10:00
|
|
|
import "../../Base"
|
|
|
|
import "../../Base/Buttons"
|
|
|
|
import "../../PythonBridge"
|
2020-08-19 23:42:10 +10:00
|
|
|
import "../../ShortcutBundles"
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
HBox {
|
2020-08-19 14:17:24 +10:00
|
|
|
id: box
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-23 03:43:09 +10:00
|
|
|
property bool knownHttps: window.getState(box, "knownHttps", false)
|
2020-07-24 15:30:35 +10:00
|
|
|
property string acceptedUserUrl: ""
|
|
|
|
property string acceptedUrl: ""
|
2020-07-26 13:31:13 +10:00
|
|
|
property var loginFlows: []
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
property string saveName: "serverBrowser"
|
2020-08-23 03:43:09 +10:00
|
|
|
property var saveProperties: ["acceptedUserUrl", "knownHttps"]
|
2020-08-19 14:17:24 +10:00
|
|
|
property string loadingIconStep: "server-ping-bad"
|
|
|
|
|
2020-09-29 13:06:50 +10:00
|
|
|
property string connectFutureId: ""
|
|
|
|
property string fetchServersFutureId: ""
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
signal accepted()
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
function takeFocus() { serverField.item.field.forceActiveFocus() }
|
|
|
|
|
|
|
|
function fetchServers() {
|
2020-09-29 13:06:50 +10:00
|
|
|
if (fetchServersFutureId) py.cancelCoro(fetchServersFutureId)
|
2020-08-23 03:19:38 +10:00
|
|
|
|
2020-09-29 13:06:50 +10:00
|
|
|
fetchServersFutureId = py.callCoro("fetch_homeservers", [], () => {
|
|
|
|
fetchServersFutureId = ""
|
2020-08-19 14:17:24 +10:00
|
|
|
}, (type, args, error, traceback) => {
|
2020-09-29 13:06:50 +10:00
|
|
|
fetchServersFutureId = ""
|
2020-08-23 03:19:38 +10:00
|
|
|
print( traceback) // TODO: display error graphically
|
2020-08-19 14:17:24 +10:00
|
|
|
})
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
function connect() {
|
2020-09-29 13:06:50 +10:00
|
|
|
if (connectFutureId) py.cancelCoro(connectFutureId)
|
2020-07-24 15:30:35 +10:00
|
|
|
connectTimeout.restart()
|
|
|
|
|
2020-08-23 03:43:09 +10:00
|
|
|
const typedUrl = serverField.item.field.cleanText
|
|
|
|
const args = [typedUrl]
|
|
|
|
|
|
|
|
if (box.knownHttps)
|
|
|
|
args[0] = args[0].replace(/^(https?:\/\/)?/, "https://")
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-09-29 13:06:50 +10:00
|
|
|
connectFutureId = py.callCoro("server_info", args, ([url, flows]) => {
|
2020-07-24 15:30:35 +10:00
|
|
|
connectTimeout.stop()
|
2020-08-19 14:17:24 +10:00
|
|
|
serverField.errorLabel.text = ""
|
2020-09-29 13:06:50 +10:00
|
|
|
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")
|
|
|
|
)
|
|
|
|
)) {
|
2020-08-19 14:17:24 +10:00
|
|
|
serverField.errorLabel.text =
|
2020-07-26 13:31:13 +10:00
|
|
|
qsTr("No supported sign-in method for this homeserver.")
|
|
|
|
return
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
acceptedUrl = url
|
2020-08-23 03:43:09 +10:00
|
|
|
acceptedUserUrl = typedUrl
|
2020-07-24 15:30:35 +10:00
|
|
|
loginFlows = flows
|
|
|
|
accepted()
|
|
|
|
|
|
|
|
}, (type, args, error, traceback, uuid) => {
|
2020-08-19 16:14:46 +10:00
|
|
|
console.error(traceback)
|
|
|
|
|
2020-07-24 15:30:35 +10:00
|
|
|
connectTimeout.stop()
|
2020-09-29 13:06:50 +10:00
|
|
|
connectFutureId = ""
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
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) :
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-03 15:19:08 +10:00
|
|
|
py.showError(type, traceback, uuid)
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
serverField.errorLabel.text = text
|
2020-07-24 15:30:35 +10:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
padding: 0
|
|
|
|
implicitWidth: theme.controls.box.defaultWidth * 1.25
|
2020-08-19 18:38:29 +10:00
|
|
|
contentHeight: window.height
|
2020-08-19 14:17:24 +10:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
footer: HLabeledItem {
|
|
|
|
id: serverField
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
readonly property bool knownServerChosen:
|
|
|
|
serverList.model.find(item.cleanText) !== null
|
|
|
|
|
|
|
|
label.text: qsTr("Homeserver address:")
|
2020-08-21 23:32:19 +10:00
|
|
|
label.topPadding: theme.spacing / 2
|
2020-08-19 21:23:52 +10:00
|
|
|
label.bottomPadding: label.topPadding / 4
|
2020-08-21 23:32:19 +10:00
|
|
|
label.leftPadding: theme.spacing
|
|
|
|
label.rightPadding: label.leftPadding
|
|
|
|
errorLabel.leftPadding: label.leftPadding
|
|
|
|
errorLabel.rightPadding: label.leftPadding
|
|
|
|
errorLabel.bottomPadding: label.leftPadding
|
2020-08-19 14:17:24 +10:00
|
|
|
|
|
|
|
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
|
2020-08-19 23:36:52 +10:00
|
|
|
defaultText: window.getState(box, "acceptedUserUrl", "")
|
2020-08-19 16:14:46 +10:00
|
|
|
placeholderText: "example.org"
|
2020-08-19 14:17:24 +10:00
|
|
|
|
2020-08-19 21:21:41 +10:00
|
|
|
onTextEdited: {
|
|
|
|
py.callCoro(
|
2020-08-21 02:21:47 +10:00
|
|
|
"set_string_filter", ["filtered_homeservers", text],
|
2020-08-19 21:21:41 +10:00
|
|
|
)
|
2020-08-23 03:43:09 +10:00
|
|
|
knownHttps = false
|
2020-08-19 21:21:41 +10:00
|
|
|
serverList.currentIndex = -1
|
|
|
|
}
|
2020-08-19 18:38:29 +10:00
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2020-08-19 18:38:29 +10:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2020-08-19 14:17:24 +10:00
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
HButton {
|
|
|
|
id: apply
|
|
|
|
enabled: field.cleanText && ! field.error
|
2020-08-19 21:30:30 +10:00
|
|
|
icon.name: "server-connect-to-address"
|
2020-08-19 14:17:24 +10:00
|
|
|
icon.color: theme.colors.positiveBackground
|
2020-09-29 13:06:50 +10:00
|
|
|
loading: box.connectFutureId !== ""
|
2020-08-19 14:17:24 +10:00
|
|
|
disableWhileLoading: false
|
|
|
|
onClicked: box.connect()
|
|
|
|
|
|
|
|
Layout.fillHeight: true
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 19:08:12 +10:00
|
|
|
onKeyboardAccept:
|
|
|
|
if (serverField.item.apply.enabled) serverField.item.apply.clicked()
|
|
|
|
|
2020-07-24 15:30:35 +10:00
|
|
|
onAccepted: window.saveState(this)
|
|
|
|
|
2020-08-21 19:18:08 +10:00
|
|
|
Component.onDestruction:
|
2020-09-29 13:06:50 +10:00
|
|
|
if (fetchServersFutureId) py.cancelCoro(fetchServersFutureId)
|
2020-08-21 19:18:08 +10:00
|
|
|
|
2020-07-24 15:30:35 +10:00
|
|
|
Timer {
|
|
|
|
id: connectTimeout
|
|
|
|
interval: 30 * 1000
|
|
|
|
onTriggered: {
|
2020-08-19 14:17:24 +10:00
|
|
|
serverField.errorLabel.text =
|
2020-07-24 15:30:35 +10:00
|
|
|
serverField.knownServerChosen ?
|
|
|
|
|
|
|
|
qsTr("This homeserver seems unavailable. Verify your inter" +
|
2020-08-19 14:17:24 +10:00
|
|
|
"net connection or try again later.") :
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
qsTr("This homeserver seems unavailable. Verify the " +
|
|
|
|
"entered address, your internet connection or try " +
|
2020-08-19 14:17:24 +10:00
|
|
|
"again later.")
|
2020-07-24 15:30:35 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
Timer {
|
|
|
|
interval: 1000
|
2020-08-19 18:38:29 +10:00
|
|
|
running:
|
2020-09-29 13:06:50 +10:00
|
|
|
fetchServersFutureId === "" &&
|
2020-08-19 18:38:29 +10:00
|
|
|
ModelStore.get("homeservers").count === 0
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
repeat: true
|
|
|
|
triggeredOnStart: true
|
|
|
|
onTriggered: box.fetchServers()
|
2020-07-24 15:30:35 +10:00
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
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"
|
|
|
|
)
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
|
2020-08-19 23:42:10 +10:00
|
|
|
FlickShortcuts {
|
|
|
|
flickable: serverList
|
|
|
|
active: ! mainUI.debugConsole.visible
|
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
HListView {
|
|
|
|
id: serverList
|
2020-08-19 18:38:29 +10:00
|
|
|
|
|
|
|
function setFieldText(fromItemIndex) {
|
2020-08-23 03:43:09 +10:00
|
|
|
const url = model.get(fromItemIndex).id
|
|
|
|
box.knownHttps = /^https:\/\//.test(url)
|
|
|
|
serverField.item.field.text = url.replace(/^https:\/\//, "")
|
2020-08-19 18:38:29 +10:00
|
|
|
}
|
|
|
|
|
2020-08-19 14:17:24 +10:00
|
|
|
clip: true
|
2020-08-19 18:38:29 +10:00
|
|
|
model: ModelStore.get("filtered_homeservers")
|
2020-08-19 14:17:24 +10:00
|
|
|
|
|
|
|
delegate: ServerDelegate {
|
|
|
|
width: serverList.width
|
|
|
|
loadingIconStep: box.loadingIconStep
|
|
|
|
onClicked: {
|
2020-08-21 19:10:32 +10:00
|
|
|
serverList.setFieldText(model.index)
|
2020-08-19 14:17:24 +10:00
|
|
|
serverField.item.apply.clicked()
|
|
|
|
}
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
|
|
|
|
Layout.fillWidth: true
|
2020-08-19 14:17:24 +10:00
|
|
|
Layout.fillHeight: true
|
2020-08-19 21:17:21 +10:00
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
z: -10
|
|
|
|
anchors.fill: parent
|
|
|
|
color: theme.colors.strongBackground
|
|
|
|
}
|
2020-08-20 02:42:42 +10:00
|
|
|
|
|
|
|
HLoader {
|
|
|
|
id: busyIndicatorLoader
|
|
|
|
anchors.centerIn: parent
|
|
|
|
width: 96 * theme.uiScale
|
|
|
|
height: width
|
|
|
|
|
|
|
|
source: "../../Base/HBusyIndicator.qml"
|
2020-09-29 13:06:50 +10:00
|
|
|
active: box.fetchServersFutureId && ! serverList.count
|
2020-08-20 02:42:42 +10:00
|
|
|
opacity: active ? 1 : 0
|
|
|
|
|
|
|
|
Behavior on opacity { HNumberAnimation { factor: 2 } }
|
|
|
|
}
|
2020-07-24 15:30:35 +10:00
|
|
|
}
|
|
|
|
}
|