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:
parent
3e48d63cf3
commit
1ab79347e9
13
TODO.md
13
TODO.md
|
@ -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()`
|
||||||
|
|
52
src/icons/light-thin/check-mark.svg
Normal file
52
src/icons/light-thin/check-mark.svg
Normal 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 |
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HColumnLayout {
|
Keys.onReturnPressed: clickEnterButtonTarget()
|
||||||
anchors.fill: parent
|
Keys.onEnterPressed: clickEnterButtonTarget()
|
||||||
id: mainColumn
|
|
||||||
|
|
||||||
HRowLayout {
|
HColumnLayout {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
id: mainColumn
|
||||||
Layout.margins: interfaceBox.margins
|
width: parent.width
|
||||||
|
spacing: interfaceBox.verticalSpacing
|
||||||
|
|
||||||
HLabel {
|
HLabel {
|
||||||
id: interfaceTitle
|
id: interfaceTitle
|
||||||
|
visible: Boolean(text)
|
||||||
font.pixelSize: theme.fontSize.bigger
|
font.pixelSize: theme.fontSize.bigger
|
||||||
}
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
|
||||||
|
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 }
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 && (
|
||||||
|
! hideHeaderUnderHeight ||
|
||||||
window.height >=
|
window.height >=
|
||||||
hideHeaderUnderHeight +
|
hideHeaderUnderHeight +
|
||||||
theme.baseElementsHeight +
|
theme.baseElementsHeight +
|
||||||
currentSpacing * 2 ?
|
currentSpacing * 2
|
||||||
theme.baseElementsHeight : 0
|
) ? theme.baseElementsHeight : 0
|
||||||
|
|
||||||
Behavior on height { HNumberAnimation {} }
|
Behavior on height { HNumberAnimation {} }
|
||||||
visible: height > 0
|
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 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,13 +30,22 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
py.callCoro(
|
||||||
|
"saved_accounts." +
|
||||||
|
(rememberAccount.checked ? "add": "delete"),
|
||||||
|
[data]
|
||||||
|
)
|
||||||
|
pageStack.showPage(
|
||||||
|
"EditAccount/EditAccount", {userId: data}
|
||||||
|
)
|
||||||
|
|
||||||
|
errorMessage.text = ""
|
||||||
button.loading = false
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user