feat(@desktop/wallet): Implement loading animation

This commit is contained in:
Khushboo Mehta 2023-01-04 18:21:24 +01:00 committed by Khushboo-dev-cpp
parent 5e2fa14cd6
commit 5df7416fd9
16 changed files with 273 additions and 113 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -0,0 +1,68 @@
import QtQuick 2.14
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
Column {
spacing: 10
StatusCheckBox {
id: loadingButton
text: checked ? "loaded": "loading"
checkState: Qt.Unchecked
}
StatusTextWithLoadingState {
font.pixelSize: 15
text: "Text is big"
loading: loadingButton.checked
width: 100
}
StatusTextWithLoadingState {
font.pixelSize: 22
text: "Text is big"
loading: loadingButton.checked
width: 200
}
StatusListItem {
title: "Nokia 3310"
subTitle: "Incoming device"
asset.width: 40
asset.height: 40
asset.emoji: "😁"
asset.color: "hotpink"
asset.letterSize: 14
asset.isLetterIdenticon: true
statusListItemSubTitle.loading: loadingButton.checked
}
StatusListItem {
title: "Nokia 3310"
subTitle: "Incoming device"
asset.width: 40
asset.height: 40
asset.emoji: "😁"
asset.color: "hotpink"
asset.letterSize: 14
asset.isLetterIdenticon: true
statusListItemSubTitle.loading: loadingButton.checked
statusListItemIcon.loading: loadingButton.checked
}
StatusListItem {
title: "Nokia 3310"
subTitle: "Incoming device"
asset.width: 40
asset.height: 40
asset.emoji: "😁"
asset.color: "hotpink"
asset.letterSize: 14
asset.isLetterIdenticon: true
statusListItemTitle.loading: loadingButton.checked
statusListItemSubTitle.loading: loadingButton.checked
statusListItemIcon.loading: loadingButton.checked
}
}

View File

@ -357,6 +357,11 @@ StatusWindow {
selected: viewLoader.source.toString().includes(title) selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.page(title); onClicked: mainPageView.page(title);
} }
StatusNavigationListItem {
title: "LoadingStates"
selected: viewLoader.source.toString().includes(title)
onClicked: mainPageView.control(title);
}
} }
} }

View File

@ -1,30 +0,0 @@
import QtQuick 2.14
import QtGraphicalEffects 1.14
Item {
id: root
property Item mask
property color color: "#F6F8FA"
Rectangle {
id: gradient
anchors.fill: parent
visible: false
gradient: Gradient {
orientation: Gradient.Horizontal
SkeletonGradientStop { color: "transparent"; from: -3; }
SkeletonGradientStop { color: "transparent"; from: -2; }
SkeletonGradientStop { color: root.color; from: -1 ; }
SkeletonGradientStop { color: "transparent"; from: 0; }
SkeletonGradientStop { color: "transparent"; from: 1; }
}
}
OpacityMask {
anchors.fill: parent
source: gradient
maskSource: root.mask
}
}

View File

@ -1,24 +0,0 @@
import QtQuick 2.14
import QtGraphicalEffects 1.14
/*
TODO: This component should be implemented as inline component of `SkeletonAnimation.qml`
when we use Qt > 5.15
*/
GradientStop {
id: root
property real from: 0
color: "transparent"
NumberAnimation on position {
easing.type: Easing.Linear
loops: Animation.Infinite
running: visible
from: root.from
to: from + 4
duration: 2000
}
}

View File

@ -1,4 +0,0 @@
module StatusQ.Animations
SkeletonAnimation 0.1 SkeletonAnimation.qml
SkeletonGradientStop 0.1 SkeletonGradientStop.qml

View File

@ -0,0 +1,89 @@
import QtQuick 2.13
import QtQuick.Controls 2.12
import StatusQ.Core.Theme 0.1
import QtGraphicalEffects 1.12
/*!
\qmltype LoadingComponent
\inherits Control
\inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1
\brief A componet that can be used to adding a loading state to a widget
Example:
\qml
StatusBaseText {
id: root
LoadingComponent {
anchors.fill: parent
radius: 8
}
}
\endqml
For a list of components available see StatusQ.
*/
Control {
id: root
/*!
\qmlproperty bool LoadingComponent::radius
This property lets user set custom radius
*/
property int radius: 4
background: null
contentItem: Item {
property real contentItemWidth: 0
onWidthChanged: {
contentItemWidth = width
animation.restart()
}
Rectangle {
id: rect
anchors.fill: parent
color: Theme.palette.statusLoadingHighlight
radius: root.radius
visible: false
LinearGradient {
id: gradient
width: 100
height: 2*parent.height
x: -width
y: -height/4
start: Qt.point(0, height)
end: Qt.point(width, height)
gradient: Gradient {
GradientStop { position: 0.2; color: "transparent"}
GradientStop { position: 0.5; color: Theme.palette.statusLoadingHighlight2 }
GradientStop { position: 0.8; color: "transparent"}
}
rotation: 20
NumberAnimation on x {
id: animation
easing.type: Easing.Linear
loops: Animation.Infinite
running: root.visible
from: -gradient.width
to: contentItem.contentItemWidth + gradient.width
duration: 800
easing.period: 2
}
}
}
OpacityMask {
anchors.fill: rect
source: rect
maskSource: Rectangle {
width: root.width
height: root.height
radius: root.radius
}
}
}
}

View File

@ -5,7 +5,6 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Animations 0.1
import QtGraphicalEffects 1.14 import QtGraphicalEffects 1.14
import "private" import "private"
@ -139,7 +138,6 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: statusListItem.leftPadding anchors.leftMargin: statusListItem.leftPadding
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !iconOrImageLoadingOverlay.visible
asset: statusListItem.asset asset: statusListItem.asset
name: statusListItem.title name: statusListItem.title
active: statusListItem.asset.isLetterIdenticon || active: statusListItem.asset.isLetterIdenticon ||
@ -147,20 +145,7 @@ Rectangle {
!!statusListItem.asset.emoji !!statusListItem.asset.emoji
badge.border.color: statusListItem.color badge.border.color: statusListItem.color
ringSettings: statusListItem.ringSettings ringSettings: statusListItem.ringSettings
} loading: statusListItem.loading
Rectangle {
id: iconOrImageLoadingOverlay
visible: statusListItem.loading || statusListItem.loadingFailed
anchors.fill: iconOrImage
radius: width / 2
color: statusListItem.loadingFailed ? Theme.palette.dangerColor2 : Theme.palette.baseColor1
SkeletonAnimation {
anchors.fill: parent
mask: parent
visible: statusListItem.loading && !statusListItem.loadingFailed
}
} }
Item { Item {
@ -182,29 +167,8 @@ Rectangle {
height: childrenRect.height height: childrenRect.height
Rectangle { StatusTextWithLoadingState {
id: titleLoadingOverlay
visible: statusListItem.loading || statusListItem.loadingFailed
anchors {
left: statusListItemTitle.left
top: statusListItemTitle.top
bottom: statusListItemTitle.bottom
}
width: Math.max(95, statusListItemTitle.width)
radius: 4
color: statusListItem.loadingFailed ? Theme.palette.dangerColor2 : Theme.palette.baseColor1
SkeletonAnimation {
anchors.fill: parent
mask: parent
visible: statusListItem.loading && !statusListItem.loadingFailed
}
}
StatusBaseText {
id: statusListItemTitle id: statusListItemTitle
opacity: titleLoadingOverlay.visible ? 0 : 1
text: statusListItem.title text: statusListItem.title
font.pixelSize: 15 font.pixelSize: 15
height: visible ? contentHeight : 0 height: visible ? contentHeight : 0
@ -213,7 +177,7 @@ Rectangle {
anchors.top: bottomModel.length === 0 ? undefined: parent.top anchors.top: bottomModel.length === 0 ? undefined: parent.top
anchors.topMargin: bottomModel.length === 0 ? undefined : 20 anchors.topMargin: bottomModel.length === 0 ? undefined : 20
width: Math.min(implicitWidth, parent.width) width: Math.min(implicitWidth, parent.width)
color: { customColor: {
if (!statusListItem.enabled) { if (!statusListItem.enabled) {
return Theme.palette.baseColor1 return Theme.palette.baseColor1
} }
@ -226,6 +190,7 @@ Rectangle {
return Theme.palette.dangerColor1 return Theme.palette.dangerColor1
} }
} }
loading: statusListItem.loading
StatusIcon { StatusIcon {
width: visible ? 12 : 0 width: visible ? 12 : 0
@ -258,7 +223,7 @@ Rectangle {
} }
} }
StatusBaseText { StatusTextWithLoadingState {
id: statusListItemTitleAsideText id: statusListItemTitleAsideText
anchors.left: statusListItemTitle.right anchors.left: statusListItemTitle.right
anchors.leftMargin: 4 anchors.leftMargin: 4
@ -267,8 +232,9 @@ Rectangle {
anchors.topMargin: bottomModel.length === 0 ? undefined : 20 anchors.topMargin: bottomModel.length === 0 ? undefined : 20
text: statusListItem.titleAsideText text: statusListItem.titleAsideText
font.pixelSize: 10 font.pixelSize: 10
color: Theme.palette.baseColor1 customColor: Theme.palette.baseColor1
visible: !!statusListItem.titleAsideText visible: !!statusListItem.titleAsideText
loading: statusListItem.loading
} }
Loader { Loader {
@ -287,7 +253,7 @@ Rectangle {
width: parent.width width: parent.width
spacing: 4 spacing: 4
StatusBaseText { StatusTextWithLoadingState {
id: statusListItemSubTitle id: statusListItemSubTitle
objectName: "statusListItemSubTitle" objectName: "statusListItemSubTitle"
@ -296,26 +262,26 @@ Rectangle {
text: statusListItem.subTitle text: statusListItem.subTitle
font.pixelSize: 15 font.pixelSize: 15
color: statusListItem.loadingFailed ? Theme.palette.dangerColor1 customColor: !statusListItem.enabled || !statusListItem.tertiaryTitle ?
: !statusListItem.enabled || !statusListItem.tertiaryTitle Theme.palette.baseColor1 : Theme.palette.directColor1
? Theme.palette.baseColor1
: Theme.palette.directColor1
visible: !!statusListItem.subTitle visible: !!statusListItem.subTitle
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
loading: statusListItem.loading
} }
StatusBaseText { StatusTextWithLoadingState {
id: dot id: dot
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.topMargin: -48 Layout.topMargin: -48
text: "." text: "."
font.pixelSize: 40 font.pixelSize: 40
color: Theme.palette.baseColor1 customColor: Theme.palette.baseColor1
lineHeightMode: Text.FixedHeight lineHeightMode: Text.FixedHeight
lineHeight: 24 lineHeight: 24
visible: inlineTagModelRepeater.count > 0 visible: inlineTagModelRepeater.count > 0
loading: statusListItem.loading
} }
StatusScrollView { StatusScrollView {
@ -340,16 +306,17 @@ Rectangle {
} }
} }
StatusBaseText { StatusTextWithLoadingState {
id: statusListItemTertiaryTitle id: statusListItemTertiaryTitle
anchors.top: statusListItemSubtitleTagsRow.bottom anchors.top: statusListItemSubtitleTagsRow.bottom
width: parent.width width: parent.width
height: visible ? contentHeight : 0 height: visible ? contentHeight : 0
text: statusListItem.tertiaryTitle text: statusListItem.tertiaryTitle
color: Theme.palette.baseColor1 customColor: Theme.palette.baseColor1
font.pixelSize: 13 font.pixelSize: 13
visible: !!statusListItem.tertiaryTitle visible: !!statusListItem.tertiaryTitle
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
loading: statusListItem.loading
} }
StatusListItemBadge { StatusListItemBadge {
@ -397,7 +364,7 @@ Rectangle {
} }
} }
StatusBaseText { StatusTextWithLoadingState {
id: statusListItemLabel id: statusListItemLabel
anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined anchors.verticalCenter: bottomModel.length === 0 ? parent.verticalCenter : undefined
anchors.top: bottomModel.length === 0 ? undefined: parent.top anchors.top: bottomModel.length === 0 ? undefined: parent.top
@ -407,8 +374,9 @@ Rectangle {
text: statusListItem.label text: statusListItem.label
font.pixelSize: 15 font.pixelSize: 15
color: Theme.palette.baseColor1 customColor: Theme.palette.baseColor1
visible: !!statusListItem.label visible: !!statusListItem.label
loading: statusListItem.loading
} }
Row { Row {

View File

@ -23,9 +23,11 @@ Loader {
distinctiveColors: Theme.palette.identiconRingColors distinctiveColors: Theme.palette.identiconRingColors
} }
sourceComponent: (root.asset.isLetterIdenticon || root.asset.name === "") ? letterIdenticon : sourceComponent: root.loading ? loadingComp : (root.asset.isLetterIdenticon || root.asset.name === "") ? letterIdenticon :
!root.asset.isImage ? roundedIcon : roundedImage !root.asset.isImage ? roundedIcon : roundedImage
property bool loading: false
Component { Component {
id: roundedImage id: roundedImage
@ -110,4 +112,14 @@ Loader {
implicitWidth: 15 implicitWidth: 15
z: root.dZ z: root.dZ
} }
Component {
id: loadingComp
LoadingComponent {
anchors.centerIn: parent
radius: width/2
height: root.asset.height
width: root.asset.width
}
}
} }

View File

@ -46,4 +46,5 @@ StatusCard 0.1 StatusCard.qml
StatusDatePicker 0.1 StatusDatePicker.qml StatusDatePicker 0.1 StatusDatePicker.qml
StatusChart 0.1 StatusChart.qml StatusChart 0.1 StatusChart.qml
StatusChartPanel 0.1 StatusChartPanel.qml StatusChartPanel 0.1 StatusChartPanel.qml
StatusStepper 0.1 StatusStepper.qml StatusStepper 0.1 StatusStepper.qml
LoadingComponent 0.1 LoadingComponent.qml

View File

@ -0,0 +1,63 @@
import QtQuick 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
/*!
\qmltype StatusTextWithLoadingState
\inherits StatusBaseText
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief A text control with support for loading state
Example:
\qml
StatusTextWithLoadingState {
title: "Account %1 of %2".arg(completedSteps).arg(totalSteps)
loading: isLoading
customColor: Theme.palette.directColor1
}
\endqml
\image statusLoadingText.png
For a list of components available see StatusQ.
*/
StatusBaseText {
id: root
/*!
\qmlproperty bool StatusTextWithLoadingState::loading
This property sets if the text is loading.
*/
property bool loading: false
/*!
\qmlproperty bool StatusTextWithLoadingState::customColor
This property sets the user defined color for the text and handles
transparency in loading state.
*/
property color customColor: Theme.palette.directColor1
color: loading ? "transparent" : customColor
Loader {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
active: root.loading
sourceComponent: LoadingComponent {
anchors.centerIn: parent
radius: textMetrics.font.pixelSize === 15 ? 4 : 8
height: textMetrics.tightBoundingRect.height
width: Math.min(root.width, 140)
}
}
TextMetrics {
id: textMetrics
font: root.font
text: root.text
}
}

View File

@ -53,3 +53,4 @@ StatusItemDelegate 0.1 StatusItemDelegate.qml
StatusTextArea 0.1 StatusTextArea.qml StatusTextArea 0.1 StatusTextArea.qml
StatusBackButton 0.1 StatusBackButton.qml StatusBackButton 0.1 StatusBackButton.qml
StatusPasswordInput 0.1 StatusPasswordInput.qml StatusPasswordInput 0.1 StatusPasswordInput.qml
StatusTextWithLoadingState 0.1 StatusTextWithLoadingState.qml

View File

@ -64,7 +64,9 @@ QtObject {
'yellow': '#FFCA0F', 'yellow': '#FFCA0F',
'yellow2': '#EAD27B', 'yellow2': '#EAD27B',
'blueHijab': '#CDF2FB' 'blueHijab': '#CDF2FB',
'lightPattensBlue': '#D7DEE4',
} }
} }

View File

@ -62,6 +62,9 @@ ThemePalette {
statusFloatingButtonHighlight: getColor('blue4', 0.3) statusFloatingButtonHighlight: getColor('blue4', 0.3)
statusLoadingHighlight: getColor('white', 0.03)
statusLoadingHighlight2: getColor('white', 0.07)
userCustomizationColors: [ userCustomizationColors: [
"#AAC6FF", "#AAC6FF",
"#887AF9", "#887AF9",

View File

@ -60,6 +60,9 @@ ThemePalette {
statusFloatingButtonHighlight: getColor('blueHijab') statusFloatingButtonHighlight: getColor('blueHijab')
statusLoadingHighlight: getColor('lightPattensBlue', 0.5)
statusLoadingHighlight2: indirectColor3
userCustomizationColors: [ userCustomizationColors: [
"#2946C4", "#2946C4",
"#887AF9", "#887AF9",

View File

@ -166,6 +166,9 @@ QtObject {
property color statusFloatingButtonHighlight property color statusFloatingButtonHighlight
property color statusLoadingHighlight
property color statusLoadingHighlight2
property var userCustomizationColors: [] property var userCustomizationColors: []
property var identiconRingColors: [] property var identiconRingColors: []