Refactor HInterfaceBox and SignIn page
- Cleaned up code - Sizes are standardized - New HCheckBox component - Replace RememberAccount page by a checkbox on the SignIn page - The page can now be flicked if it's not tall enough to display everything - HNumberAnimation now has an overshoot property that will set the right easing type, overshoot and adapt the animation factor/duration. - HImage can now be colorized
This commit is contained in:
48
src/qml/Base/HCheckBox.qml
Normal file
48
src/qml/Base/HCheckBox.qml
Normal file
@@ -0,0 +1,48 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import "../utils.js" as Utils
|
||||
|
||||
CheckBox {
|
||||
id: box
|
||||
spacing: theme.spacing
|
||||
|
||||
property bool highlight: enabled && (hovered || visualFocus)
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: implicitHeight
|
||||
implicitHeight: box.contentItem.font.pixelSize * 1.5
|
||||
x: box.leftPadding
|
||||
y: box.topPadding + box.availableHeight / 2 - height / 2
|
||||
radius: theme.radius / 1.5
|
||||
|
||||
color: theme.controls.button.background
|
||||
border.color: Utils.hsluv(
|
||||
180, highlight ? 80 : 0, highlight ? 80 : 40, highlight ? 1 : 0.7
|
||||
)
|
||||
|
||||
Behavior on border.color { HColorAnimation { factor: 0.5 } }
|
||||
|
||||
HIcon {
|
||||
anchors.centerIn: parent
|
||||
dimension: parent.width - 2
|
||||
svgName: "check-mark"
|
||||
colorize: theme.colors.accentText
|
||||
|
||||
visible: scale > 0
|
||||
scale: box.checked ? 1 : 0
|
||||
Behavior on scale { HNumberAnimation { overshoot: 4 } }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: HLabel {
|
||||
text: box.text
|
||||
color: box.enabled ?
|
||||
theme.controls.button.text :
|
||||
theme.controls.button.disabledText
|
||||
|
||||
// Set a width on CheckBox for wrapping to work, e.g. Layout.fillWidth
|
||||
wrapMode: Text.Wrap
|
||||
leftPadding: box.indicator.width + box.spacing
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
@@ -1,8 +1,20 @@
|
||||
import QtQuick 2.12
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
Image {
|
||||
id: image
|
||||
asynchronous: true
|
||||
cache: true
|
||||
mipmap: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
property color colorize: "transparent"
|
||||
|
||||
layer {
|
||||
enabled: ! Qt.colorEqual(colorize, "transparent")
|
||||
effect: ColorOverlay {
|
||||
color: image.colorize
|
||||
cached: image.cache
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,8 +1,23 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
HScalingBox {
|
||||
HRectangle {
|
||||
id: interfaceBox
|
||||
color: theme.controls.box.background
|
||||
implicitWidth: Math.min(
|
||||
parent.width, theme.minimumSupportedWidthPlusSpacing * multiplyWidth
|
||||
)
|
||||
implicitHeight: childrenRect.height
|
||||
|
||||
property real multiplyWidth: 1.0
|
||||
property real multiplyHorizontalSpacing: 1.5
|
||||
property real multiplyVerticalSpacing: 1.5
|
||||
|
||||
property int horizontalSpacing:
|
||||
Math.min(theme.spacing * width / 400, theme.spacing) *
|
||||
multiplyHorizontalSpacing
|
||||
|
||||
property int verticalSpacing: theme.spacing * multiplyVerticalSpacing
|
||||
|
||||
property alias title: interfaceTitle.text
|
||||
property alias buttonModel: interfaceButtonsRepeater.model
|
||||
@@ -18,25 +33,35 @@ HScalingBox {
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: clickEnterButtonTarget()
|
||||
Keys.onEnterPressed: clickEnterButtonTarget()
|
||||
|
||||
HColumnLayout {
|
||||
anchors.fill: parent
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
spacing: interfaceBox.verticalSpacing
|
||||
|
||||
HRowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.margins: interfaceBox.margins
|
||||
HLabel {
|
||||
id: interfaceTitle
|
||||
visible: Boolean(text)
|
||||
font.pixelSize: theme.fontSize.bigger
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
HLabel {
|
||||
id: interfaceTitle
|
||||
font.pixelSize: theme.fontSize.bigger
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: interfaceBox.verticalSpacing
|
||||
Layout.leftMargin: interfaceBox.horizontalSpacing
|
||||
Layout.rightMargin: interfaceBox.horizontalSpacing
|
||||
}
|
||||
|
||||
HSpacer {}
|
||||
HColumnLayout {
|
||||
id: interfaceBody
|
||||
spacing: interfaceBox.verticalSpacing
|
||||
|
||||
HColumnLayout { id: interfaceBody }
|
||||
|
||||
HSpacer {}
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: interfaceBox.horizontalSpacing
|
||||
Layout.rightMargin: interfaceBox.horizontalSpacing
|
||||
}
|
||||
|
||||
HRowLayout {
|
||||
Repeater {
|
||||
@@ -53,7 +78,7 @@ HScalingBox {
|
||||
onClicked: buttonCallbacks[modelData.name](button)
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: theme.controls.avatar.size
|
||||
Layout.preferredHeight: theme.baseElementsHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
import QtQuick 2.12
|
||||
|
||||
NumberAnimation {
|
||||
property real factor: 1.0
|
||||
property real factor: Math.max(overshoot / 1.75, 1.0)
|
||||
property real overshoot: 1.0
|
||||
|
||||
duration: theme.animationDuration * factor
|
||||
easing.type: overshoot > 1 ? Easing.InOutBack : Easing.Linear
|
||||
easing.overshoot: overshoot
|
||||
}
|
||||
|
@@ -38,12 +38,13 @@ SwipeView {
|
||||
implicitWidth: parent ? parent.width : 0
|
||||
color: theme.controls.header.background
|
||||
|
||||
height: ! hideHeaderUnderHeight ||
|
||||
window.height >=
|
||||
hideHeaderUnderHeight +
|
||||
theme.baseElementsHeight +
|
||||
currentSpacing * 2 ?
|
||||
theme.baseElementsHeight : 0
|
||||
height: innerHeaderLabel.text && (
|
||||
! hideHeaderUnderHeight ||
|
||||
window.height >=
|
||||
hideHeaderUnderHeight +
|
||||
theme.baseElementsHeight +
|
||||
currentSpacing * 2
|
||||
) ? theme.baseElementsHeight : 0
|
||||
|
||||
Behavior on height { HNumberAnimation {} }
|
||||
visible: height > 0
|
||||
|
@@ -1,46 +0,0 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../Base"
|
||||
|
||||
Item {
|
||||
property string loginWith: "username"
|
||||
property string userId: ""
|
||||
|
||||
HInterfaceBox {
|
||||
id: rememberBox
|
||||
title: "Sign in"
|
||||
anchors.centerIn: parent
|
||||
|
||||
enterButtonTarget: "yes"
|
||||
|
||||
buttonModel: [
|
||||
{ name: "yes", text: qsTr("Yes") },
|
||||
{ name: "no", text: qsTr("No") },
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
yes: button => {
|
||||
py.callCoro("saved_accounts.add", [userId])
|
||||
pageStack.showPage("EditAccount/EditAccount", {userId})
|
||||
},
|
||||
no: button => {
|
||||
py.callCoro("saved_accounts.delete", [userId])
|
||||
pageStack.showPage("EditAccount/EditAccount", {userId})
|
||||
},
|
||||
})
|
||||
|
||||
HLabel {
|
||||
text: qsTr(
|
||||
"Do you want to remember this account?\n\n" +
|
||||
"If yes, the " + loginWith + " and an access token will be " +
|
||||
"stored to automatically sign in on this device."
|
||||
)
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
Layout.margins: rememberBox.margins
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HSpacer {}
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@ import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../Base"
|
||||
|
||||
Item {
|
||||
HPage {
|
||||
property string loginWith: "username"
|
||||
readonly property bool canLogin: idField.text && passwordField.text
|
||||
|
||||
@@ -10,15 +10,16 @@ Item {
|
||||
|
||||
HInterfaceBox {
|
||||
id: signInBox
|
||||
title: "Sign in"
|
||||
anchors.centerIn: parent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
multiplyWidth: 0.85
|
||||
title: qsTr("Sign in")
|
||||
enterButtonTarget: "login"
|
||||
|
||||
buttonModel: [
|
||||
{ name: "register", text: qsTr("Register"), enabled: false },
|
||||
{ name: "login", text: qsTr("Login"), enabled: canLogin },
|
||||
{ name: "forgot", text: qsTr("Forgot?"), enabled: false }
|
||||
{ name: "forgot", text: qsTr("Forgot?"), enabled: false },
|
||||
]
|
||||
|
||||
buttonCallbacks: ({
|
||||
@@ -29,14 +30,23 @@ Item {
|
||||
let args = [idField.text, passwordField.text]
|
||||
|
||||
py.callCoro("login_client", args, ([success, data]) => {
|
||||
if (success) {
|
||||
// data = userId
|
||||
errorMessage.text = ""
|
||||
pageStack.showPage("RememberAccount", {loginWith,data})
|
||||
} else {
|
||||
if (! success) {
|
||||
errorMessage.text = qsTr(data)
|
||||
button.loading = false
|
||||
return
|
||||
}
|
||||
button.loading = false
|
||||
|
||||
py.callCoro(
|
||||
"saved_accounts." +
|
||||
(rememberAccount.checked ? "add": "delete"),
|
||||
[data]
|
||||
)
|
||||
pageStack.showPage(
|
||||
"EditAccount/EditAccount", {userId: data}
|
||||
)
|
||||
|
||||
errorMessage.text = ""
|
||||
button.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
@@ -44,9 +54,10 @@ Item {
|
||||
})
|
||||
|
||||
HRowLayout {
|
||||
spacing: signInBox.margins * 1.25
|
||||
Layout.margins: signInBox.margins
|
||||
spacing: signInBox.horizontalSpacing * 1.25
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: signInBox.verticalSpacing / 2
|
||||
Layout.bottomMargin: Layout.topMargin
|
||||
|
||||
Repeater {
|
||||
model: ["username", "email", "phone"]
|
||||
@@ -70,20 +81,26 @@ Item {
|
||||
loginWith === "phone" ? "Phone" :
|
||||
"Username"
|
||||
)
|
||||
onAccepted: signInBox.clickEnterButtonTarget()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: signInBox.margins
|
||||
}
|
||||
|
||||
HTextField {
|
||||
id: passwordField
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: HTextField.Password
|
||||
onAccepted: signInBox.clickEnterButtonTarget()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: signInBox.margins
|
||||
}
|
||||
|
||||
HCheckBox {
|
||||
id: rememberAccount
|
||||
text: qsTr("Automatically sign in")
|
||||
checked: true
|
||||
spacing: signInBox.horizontalSpacing
|
||||
|
||||
Layout.maximumWidth: parent.width
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
HLabel {
|
||||
@@ -97,7 +114,6 @@ Item {
|
||||
Behavior on Layout.maximumHeight { HNumberAnimation {} }
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: signInBox.margins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user