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:
miruka 2019-08-17 13:01:43 -04:00
parent 3e48d63cf3
commit 1ab79347e9
9 changed files with 205 additions and 90 deletions

13
TODO.md
View File

@ -1,10 +1,12 @@
- Refactoring - Refactoring
- `^property type name$`
- Use [Animators](https://doc.qt.io/qt-5/qml-qtquick-animator.html) - Use [Animators](https://doc.qt.io/qt-5/qml-qtquick-animator.html)
- Choose a better default easing type for animations
- Use overshoot for the scale login thing
- Sendbox - Sendbox
- SignIn/RememberAccount screens - HButton
- SignIn must be in a flickable - Control: hovered, visualFocus, enaled
- Unfinished work in button-refactor branch - Border and pressed color in theme / checkbox theming
- Button can get "hoverEnabled: false" to let HoverHandlers work
- Room Sidepane - Room Sidepane
- Hide when window too small - Hide when window too small
- Also save/load its size - Also save/load its size
@ -88,7 +90,7 @@
- Spinner when loading account, past room events, images or clicking buttons - Spinner when loading account, past room events, images or clicking buttons
- Show account page as loading until profile initially retrieved - Show account page as loading until profile initially retrieved
- Theming - Theming
- Support SVG hue via image provider for icons - Make all icons white/black, since we can now use ColorOverlay
- Don't create additional lines in theme conversion (braces) - Don't create additional lines in theme conversion (braces)
- Recursively merge default and user theme - Recursively merge default and user theme
- Distribute fonts - Distribute fonts
@ -121,6 +123,7 @@
- Links preview - Links preview
- Client improvements - Client improvements
- Logout previous session if adding an account that's already connected
- Image provider: on failed conversion, way to show a "broken image" thumb? - Image provider: on failed conversion, way to show a "broken image" thumb?
- Config file format - Config file format
- Initial sync filter and lazy load, see weechat-matrix `_handle_login()` - Initial sync filter and lazy load, see weechat-matrix `_handle_login()`

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
fill-rule="evenodd"
clip-rule="evenodd"
version="1.1"
id="svg4"
sodipodi:docname="check-mark.svg"
inkscape:version="">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-7.6779661"
inkscape:cy="12"
inkscape:current-layer="svg4" />
<path
d="M21 6.285l-11.16 12.733-6.84-6.018 1.319-1.49 5.341 4.686 9.865-11.196 1.475 1.285z"
id="path2"
style="fill:#ffffff;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View 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
}
}

View File

@ -1,8 +1,20 @@
import QtQuick 2.12 import QtQuick 2.12
import QtGraphicalEffects 1.12
Image { Image {
id: image
asynchronous: true asynchronous: true
cache: true cache: true
mipmap: true
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
property color colorize: "transparent"
layer {
enabled: ! Qt.colorEqual(colorize, "transparent")
effect: ColorOverlay {
color: image.colorize
cached: image.cache
}
}
} }

View File

@ -1,8 +1,23 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
HScalingBox { HRectangle {
id: interfaceBox 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 title: interfaceTitle.text
property alias buttonModel: interfaceButtonsRepeater.model property alias buttonModel: interfaceButtonsRepeater.model
@ -18,25 +33,35 @@ HScalingBox {
} }
} }
Keys.onReturnPressed: clickEnterButtonTarget()
Keys.onEnterPressed: clickEnterButtonTarget()
HColumnLayout { HColumnLayout {
anchors.fill: parent
id: mainColumn id: mainColumn
width: parent.width
spacing: interfaceBox.verticalSpacing
HRowLayout { HLabel {
Layout.alignment: Qt.AlignHCenter id: interfaceTitle
Layout.margins: interfaceBox.margins visible: Boolean(text)
font.pixelSize: theme.fontSize.bigger
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
HLabel { Layout.fillWidth: true
id: interfaceTitle Layout.topMargin: interfaceBox.verticalSpacing
font.pixelSize: theme.fontSize.bigger Layout.leftMargin: interfaceBox.horizontalSpacing
} Layout.rightMargin: interfaceBox.horizontalSpacing
} }
HSpacer {} HColumnLayout {
id: interfaceBody
spacing: interfaceBox.verticalSpacing
HColumnLayout { id: interfaceBody } Layout.fillWidth: true
Layout.leftMargin: interfaceBox.horizontalSpacing
HSpacer {} Layout.rightMargin: interfaceBox.horizontalSpacing
}
HRowLayout { HRowLayout {
Repeater { Repeater {
@ -53,7 +78,7 @@ HScalingBox {
onClicked: buttonCallbacks[modelData.name](button) onClicked: buttonCallbacks[modelData.name](button)
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: theme.controls.avatar.size Layout.preferredHeight: theme.baseElementsHeight
} }
} }
} }

View File

@ -1,6 +1,10 @@
import QtQuick 2.12 import QtQuick 2.12
NumberAnimation { 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 duration: theme.animationDuration * factor
easing.type: overshoot > 1 ? Easing.InOutBack : Easing.Linear
easing.overshoot: overshoot
} }

View File

@ -38,12 +38,13 @@ SwipeView {
implicitWidth: parent ? parent.width : 0 implicitWidth: parent ? parent.width : 0
color: theme.controls.header.background color: theme.controls.header.background
height: ! hideHeaderUnderHeight || height: innerHeaderLabel.text && (
window.height >= ! hideHeaderUnderHeight ||
hideHeaderUnderHeight + window.height >=
theme.baseElementsHeight + hideHeaderUnderHeight +
currentSpacing * 2 ? theme.baseElementsHeight +
theme.baseElementsHeight : 0 currentSpacing * 2
) ? theme.baseElementsHeight : 0
Behavior on height { HNumberAnimation {} } Behavior on height { HNumberAnimation {} }
visible: height > 0 visible: height > 0

View File

@ -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 {}
}
}

View File

@ -2,7 +2,7 @@ import QtQuick 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import "../Base" import "../Base"
Item { HPage {
property string loginWith: "username" property string loginWith: "username"
readonly property bool canLogin: idField.text && passwordField.text readonly property bool canLogin: idField.text && passwordField.text
@ -10,15 +10,16 @@ Item {
HInterfaceBox { HInterfaceBox {
id: signInBox id: signInBox
title: "Sign in" Layout.alignment: Qt.AlignCenter
anchors.centerIn: parent
multiplyWidth: 0.85
title: qsTr("Sign in")
enterButtonTarget: "login" enterButtonTarget: "login"
buttonModel: [ buttonModel: [
{ name: "register", text: qsTr("Register"), enabled: false }, { name: "register", text: qsTr("Register"), enabled: false },
{ name: "login", text: qsTr("Login"), enabled: canLogin }, { name: "login", text: qsTr("Login"), enabled: canLogin },
{ name: "forgot", text: qsTr("Forgot?"), enabled: false } { name: "forgot", text: qsTr("Forgot?"), enabled: false },
] ]
buttonCallbacks: ({ buttonCallbacks: ({
@ -29,14 +30,23 @@ Item {
let args = [idField.text, passwordField.text] let args = [idField.text, passwordField.text]
py.callCoro("login_client", args, ([success, data]) => { py.callCoro("login_client", args, ([success, data]) => {
if (success) { if (! success) {
// data = userId
errorMessage.text = ""
pageStack.showPage("RememberAccount", {loginWith,data})
} else {
errorMessage.text = qsTr(data) 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 { HRowLayout {
spacing: signInBox.margins * 1.25 spacing: signInBox.horizontalSpacing * 1.25
Layout.margins: signInBox.margins
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Layout.topMargin: signInBox.verticalSpacing / 2
Layout.bottomMargin: Layout.topMargin
Repeater { Repeater {
model: ["username", "email", "phone"] model: ["username", "email", "phone"]
@ -70,20 +81,26 @@ Item {
loginWith === "phone" ? "Phone" : loginWith === "phone" ? "Phone" :
"Username" "Username"
) )
onAccepted: signInBox.clickEnterButtonTarget()
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: signInBox.margins
} }
HTextField { HTextField {
id: passwordField id: passwordField
placeholderText: qsTr("Password") placeholderText: qsTr("Password")
echoMode: HTextField.Password echoMode: HTextField.Password
onAccepted: signInBox.clickEnterButtonTarget()
Layout.fillWidth: true 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 { HLabel {
@ -97,7 +114,6 @@ Item {
Behavior on Layout.maximumHeight { HNumberAnimation {} } Behavior on Layout.maximumHeight { HNumberAnimation {} }
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: signInBox.margins
} }
} }
} }