diff --git a/src/Gui/Login/InstanceInput.qml b/src/Gui/Login/InstanceInput.qml new file mode 100644 index 0000000..4774edc --- /dev/null +++ b/src/Gui/Login/InstanceInput.qml @@ -0,0 +1,69 @@ +import QtQuick +import QtQuick.Layouts + +import "../PStyle" + +ColumnLayout { + id: root + + signal tryInstance(url: string) + + Timer { + id: focusTimer + running: true + onTriggered: instanceInput.pTf.forceActiveFocus() + repeat: false + interval: 250 + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("QutePleroma") + font: PStyle.getFont(36) + } + + RowLayout { + PText { + Layout.alignment: Qt.AlignBottom + Layout.bottomMargin: 8 + text: "https://" + } + + PInputField { + id: instanceInput + Layout.preferredWidth: 200 + label: qsTr("Instance URL") + placeholderText: "ak.gensokyo.shop" + + onTfChanged: (text) => { + let url; + + try { + url = new URL(`https://${text}`) + } catch (_) { + btn.enabled = false + return + } + + btn.enabled = true + } + + onTfAccepted: getInstanceInfo() + } + + PIconButton { + id: btn + Layout.alignment: Qt.AlignBottom + pIcon.name: "arrow-right" + enabled: false + + onPressed: getInstanceInfo() + } + } + + function getInstanceInfo() { + btn.enabled = false + const instanceUrl = `https://${instanceInput.tfText}` + tryInstance(instanceUrl) + } +} \ No newline at end of file diff --git a/src/Gui/Login/LoadingInfo.qml b/src/Gui/Login/LoadingInfo.qml new file mode 100644 index 0000000..89d3c89 --- /dev/null +++ b/src/Gui/Login/LoadingInfo.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import "../PStyle" + +ColumnLayout { + spacing: 32 + + PBusyIndicator { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: 48 + running: true + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Loading instance information...") + } +} \ No newline at end of file diff --git a/src/Gui/Login/Login.qml b/src/Gui/Login/Login.qml new file mode 100644 index 0000000..efb77bf --- /dev/null +++ b/src/Gui/Login/Login.qml @@ -0,0 +1,125 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQml + +import Util +import "../PStyle" + +PStackView { + id: login + initialItem: instanceInput + + property var instanceInfo + + Component { + id: instanceInput + + Rectangle { + InstanceInput { + anchors.centerIn: parent + + onTryInstance: (instanceUrl) => { + login.push(loadInstance) + + Http.getRequest( + `${instanceUrl}/api/v1/instance`, + (body) => { + const json = JSON.parse(body) + print(`Instance name: ${json.title}`) + print(`Instance description: ${json.description}`) + instanceInfo = json + login.replace(infoScreen) + }, + (err) => { + print(err) + login.pop() + }) + } + } + } + } + + Component { + id: loadInstance + + Rectangle { + LoadingInfo { + anchors.centerIn: parent + } + } + } + + Component { + id: infoScreen + + Rectangle { + ColumnLayout { + id: info + anchors.centerIn: parent + + PText { + Layout.alignment: Qt.AlignHCenter + text: instanceInfo.title + font: PStyle.getFont(36) + } + + Image { + id: instanceLogo + + source: instanceInfo.thumbnail + + Layout.alignment: Qt.AlignHCenter + Layout.maximumWidth: 120 + Layout.maximumHeight: Layout.maximumWidth + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: instanceInfo.description + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `uri: ${instanceInfo.uri}` + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `version: ${instanceInfo.version}` + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `known domains: ${instanceInfo.stats.domain_count}` + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `known users: ${instanceInfo.stats.remote_user_count}` + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `status count: ${instanceInfo.stats.status_count}` + } + + PText { + Layout.alignment: Qt.AlignHCenter + text: `user count: ${instanceInfo.stats.user_count}` + } + + PTextButton { + text: qsTr("Back") + enabled: true + + Layout.alignment: Qt.AlignHCenter + + onClicked: { + login.pop() + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Gui/Splash.qml b/src/Gui/Splash.qml index e63ca11..eab8ae0 100644 --- a/src/Gui/Splash.qml +++ b/src/Gui/Splash.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts import QtQuick.Controls import Util +import "Login" import "PStyle" Window { @@ -15,28 +16,8 @@ Window { PBackground { anchors.fill: parent - ColumnLayout { + Login { anchors.centerIn: parent - - PText { - Layout.alignment: Qt.AlignHCenter - text: qsTr("QutePleroma") - font: PStyle.getFont(36) - } - - RowLayout { - PInputField { - Layout.preferredWidth: 200 - label: qsTr("Instance URL") - placeholderText: "ak.gensokyo.shop" - } - - PIconButton { - id: btn - Layout.alignment: Qt.AlignBottom - pIcon.name: "arrow-right" - } - } } } } \ No newline at end of file diff --git a/src/Gui/Style/PStyle/PBusyIndicator.qml b/src/Gui/Style/PStyle/PBusyIndicator.qml new file mode 100644 index 0000000..016218c --- /dev/null +++ b/src/Gui/Style/PStyle/PBusyIndicator.qml @@ -0,0 +1,66 @@ +import QtQuick +import QtQuick.Controls + +import "." + +BusyIndicator { + id: control + + contentItem: Item { + width: height + height: control.height + + Item { + id: item + + x: 0 + y: 0 + width: parent.width + height: parent.height + opacity: control.running ? 1 : 0 + + Behavior on opacity { + OpacityAnimator { + duration: PStyle.animationDuration + } + } + + RotationAnimator { + target: item + running: control.running && control.visible + from: 0 + to: 360 + loops: Animation.Infinite + duration: PStyle.animationDuration * 12 + } + + Repeater { + id: repeater + model: 5 + + Rectangle { + id: delegate + x: item.width / 2 - width / 2 + y: item.height / 2 - height / 2 + implicitWidth: 8 + implicitHeight: 8 + radius: width / 2 + color: Qt.darker(PStyle.foreColor, 1.2) + + required property int index + + transform: [ + Translate { + y: -Math.min(item.width, item.height) * 0.5 + 5 + }, + Rotation { + angle: delegate.index / repeater.count * 360 + origin.x: 5 + origin.y: 5 + } + ] + } + } + } + } +} diff --git a/src/Gui/Style/PStyle/PInputField.qml b/src/Gui/Style/PStyle/PInputField.qml index 88850f0..f9a3e1e 100644 --- a/src/Gui/Style/PStyle/PInputField.qml +++ b/src/Gui/Style/PStyle/PInputField.qml @@ -4,8 +4,13 @@ import "." ColumnLayout { property alias label: lbl.text property alias placeholderText: tf.placeholderText + property alias tfText: tf.text + property alias pTf: tf spacing: 2 + signal tfChanged(text: string) + signal tfAccepted() + PText { id: lbl font.pointSize: 10 @@ -14,5 +19,8 @@ ColumnLayout { PTextField { id: tf Layout.fillWidth: true + + onTextEdited: tfChanged(text) + onAccepted: tfAccepted() } } \ No newline at end of file diff --git a/src/Gui/Style/PStyle/PRawButton.qml b/src/Gui/Style/PStyle/PRawButton.qml index fd10f2b..02a8e8b 100644 --- a/src/Gui/Style/PStyle/PRawButton.qml +++ b/src/Gui/Style/PStyle/PRawButton.qml @@ -9,10 +9,10 @@ Button { background: PBackground { id: background - color: Qt.darker(PStyle.backColor, 1.8) + color: btn.enabled ? Qt.darker(PStyle.backColor, 1.8) : Qt.lighter(PStyle.backColor, 2.4) border.width: 1 - border.color: PStyle.foreColor + border.color: btn.enabled ? PStyle.foreColor : Qt.darker(PStyle.foreColor, 1.4) // Qt.hsva(0, 1, 0.5, 1) } states: [ @@ -66,6 +66,7 @@ Button { } MouseArea { + enabled: btn.enabled hoverEnabled: true anchors.fill: btn onEntered: { diff --git a/src/Gui/Style/PStyle/PStackView.qml b/src/Gui/Style/PStyle/PStackView.qml new file mode 100644 index 0000000..b3a7416 --- /dev/null +++ b/src/Gui/Style/PStyle/PStackView.qml @@ -0,0 +1,41 @@ +import QtQuick +import QtQuick.Controls +import "." + +StackView { + pushEnter: Transition { + PropertyAnimation { + property: "opacity" + from: 0 + to: 1 + duration: PStyle.animationDuration + } + } + + pushExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to: 0 + duration: PStyle.animationDuration + } + } + + popEnter: Transition { + PropertyAnimation { + property: "opacity" + from: 0 + to: 1 + duration: PStyle.animationDuration + } + } + + popExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to: 0 + duration: PStyle.animationDuration + } + } +} \ No newline at end of file diff --git a/src/Gui/Style/resources.qrc b/src/Gui/Style/resources.qrc index 8bf25de..0afd4e2 100644 --- a/src/Gui/Style/resources.qrc +++ b/src/Gui/Style/resources.qrc @@ -10,5 +10,7 @@ PStyle/PRawButton.qml PStyle/PIconButton.qml PStyle/PIcon.qml + PStyle/PBusyIndicator.qml + PStyle/PStackView.qml \ No newline at end of file diff --git a/src/resources.qrc b/src/resources.qrc index 17ebe5c..63bd332 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -2,9 +2,16 @@ Gui/Splash.qml + Gui/Util/Http.qml Gui/Util/qmldir + + Gui/Login/Login.qml + Gui/Login/InstanceInput.qml + Gui/Login/LoadingInfo.qml + + Icons/arrow-right.svg \ No newline at end of file