fix(StatusBaseButton): adapt to handle actions when it is disabled

- add an `interactive` property as a drop-in replacement for `enabled`;
the UI looks "disabled" but can still display e.g. a tooltip or some
loading animation
- add the ability to display a tooltip
- remove DisabledTooltipButton and replace it with a regular
`Status(Flat)Button`, using the above new features
- update storybook with the new `interactive` switch

Fixes #10185
This commit is contained in:
Lukáš Tinkl 2024-03-12 16:44:27 +01:00 committed by Lukáš Tinkl
parent ad7f39f91c
commit d25cefcc2e
11 changed files with 76 additions and 113 deletions

View File

@ -51,10 +51,12 @@ SplitView {
size: modelData
text: ctrlText.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -67,10 +69,12 @@ SplitView {
size: modelData
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -84,10 +88,12 @@ SplitView {
text: ctrlText.text
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -101,10 +107,12 @@ SplitView {
size: modelData
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
isRoundIcon: true
radius: height/2
textFillWidth: ctrlFillWidth.checked
@ -125,10 +133,12 @@ SplitView {
size: modelData
text: ctrlText.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -141,10 +151,12 @@ SplitView {
size: modelData
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -158,10 +170,12 @@ SplitView {
text: ctrlText.text
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
textFillWidth: ctrlFillWidth.checked
}
}
@ -175,10 +189,12 @@ SplitView {
size: modelData
icon.name: ctrlIconName.text
asset.emoji: d.effectiveEmoji
tooltip.text: ctrlTooltip.text
textPosition: d.effectiveTextPosition
type: ctrlType.currentIndex
loading: ctrlLoading.checked
enabled: ctrlEnabled.checked
interactive: ctrlInteractive.checked
isRoundIcon: true
radius: height/2
textFillWidth: ctrlFillWidth.checked
@ -234,6 +250,14 @@ SplitView {
text: "enabled"
}
}
RowLayout {
Label { text: "Tooltip:" }
TextField {
id: ctrlTooltip
placeholderText: "Tooltip"
text: "Sample tooltip"
}
}
RowLayout {
Label { text: "Type:" }
ComboBox {
@ -260,6 +284,11 @@ SplitView {
id: ctrlLoading
text: "Loading"
}
Switch {
id: ctrlInteractive
text: "Interactive"
checked: true
}
Switch {
id: ctrlEnabled
text: "Enabled"

View File

@ -33,7 +33,10 @@ Button {
color: d.textColor
}
property alias tooltip: tooltip
property bool loading
property bool interactive: true
property color normalColor
property color hoverColor
@ -56,9 +59,14 @@ Button {
QtObject {
id: d
readonly property color textColor: root.hovered && (root.enabled || root.loading) ? root.textHoverColor :
root.enabled || root.loading ? root.textColor
: root.disabledTextColor
readonly property color textColor: {
if (!root.interactive || !root.enabled)
return root.disabledTextColor
if (root.hovered)
return root.textHoverColor
return root.textColor
}
readonly property bool iconOnly: root.display === AbstractButton.IconOnly || root.text === ""
readonly property int iconSize: {
switch(root.size) {
@ -119,9 +127,9 @@ Button {
radius: root.radius
border.color: root.borderColor
color: {
if (root.enabled)
return !root.loading && (root.hovered || root.highlighted) ? hoverColor : normalColor;
return disabledColor;
if (!root.enabled || !root.interactive)
return disabledColor
return !root.loading && (root.hovered || root.highlighted) ? hoverColor : normalColor
}
}
@ -151,7 +159,7 @@ Button {
id: roundIcon
StatusRoundIcon {
opacity: !root.loading && root.icon.name !== "" && root.display !== AbstractButton.TextOnly
opacity: !root.loading && root.icon.name !== "" && root.display !== AbstractButton.TextOnly
asset.name: root.icon.name
asset.width: d.iconSize
asset.height: d.iconSize
@ -216,14 +224,21 @@ Button {
}
}
// stop the mouse clicks in the "loading" state w/o disabling the whole button
// stop the mouse clicks in the "loading" or non-interactive state w/o disabling the whole button
// as this would make it impossible to have hover events or a tooltip
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.AllButtons
enabled: root.loading
enabled: root.loading || !root.interactive
onPressed: mouse.accepted = true
onWheel: wheel.accepted = true
cursorShape: !root.loading ? Qt.PointingHandCursor: undefined // always works; 'undefined' resets to default cursor
cursorShape: root.interactive && !root.loading ? Qt.PointingHandCursor: undefined // always works; 'undefined' resets to default cursor
}
StatusToolTip {
id: tooltip
visible: tooltip.text !== "" && root.hovered
offset: -(tooltip.x + tooltip.width/2 - root.width/2)
}
}

View File

@ -40,6 +40,6 @@ StatusBaseButton {
disabledTextColor: Theme.palette.baseColor1
borderColor: (type === StatusBaseButton.Type.Normal || hovered) && !loading ? "transparent"
: Theme.palette.baseColor2
borderColor: (type === StatusBaseButton.Type.Normal || hovered) && !loading && interactive ? "transparent"
: Theme.palette.baseColor2
}

View File

@ -139,16 +139,12 @@ StackView {
title: qsTr("Tokens")
buttons: [
DisabledTooltipButton {
readonly property bool buttonEnabled: root.isPrivilegedTokenOwnerProfile && root.arePrivilegedTokensDeployed
buttonType: DisabledTooltipButton.Normal
aliasedObjectName: "addNewItemButton"
StatusButton {
objectName: "addNewItemButton"
text: qsTr("Mint token")
enabled: root.isAdminOnly || buttonEnabled
interactive: buttonEnabled
interactive: root.isPrivilegedTokenOwnerProfile && root.arePrivilegedTokensDeployed
onClicked: root.push(newTokenViewComponent, StackView.Immediate)
tooltipText: qsTr("In order to mint, you must hodl the TokenMaster token for %1").arg(root.communityName)
tooltip.text: root.isAdminOnly ? qsTr("In order to mint, you must hodl the TokenMaster token for %1").arg(root.communityName) : ""
}
]

View File

@ -282,16 +282,15 @@ Item {
}
}
DisabledTooltipButton {
StatusButton {
id: startBtn
interactive: startButtonEnabled
buttonType: DisabledTooltipButton.Normal
aliasedObjectName: "ensStartButton"
objectName: "ensStartButton"
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.padding
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Start")
tooltipText: root.tooltipText
tooltip.text: root.tooltipText
onClicked: startBtnClicked()
}
}

View File

@ -65,8 +65,7 @@ SettingsContentBase {
priv.hasAnyProfileShowcaseChanges
saveChangesButtonEnabled: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid
toast.saveChangesTooltipVisible: root.dirty
toast.saveChangesTooltipText: qsTr("Invalid changes made to Identity")
toast.saveChangesTooltipText: saveChangesButtonEnabled ? "" : qsTr("Invalid changes made to Identity")
autoscrollWhenDirty: profileTabBar.currentIndex === MyProfileView.Identity
onResetChangesClicked: priv.reset()

View File

@ -38,14 +38,13 @@ Rectangle {
height: parent.height
spacing: Style.current.padding
DisabledTooltipButton {
buttonType: DisabledTooltipButton.Flat
aliasedObjectName: "walletFooterSendButton"
icon: "send"
StatusFlatButton {
objectName: "walletFooterSendButton"
icon.name: "send"
text: root.isCommunityOwnershipTransfer ? qsTr("Send Owner token to transfer %1 Community ownership").arg(root.communityName) : qsTr("Send")
interactive: networkConnectionStore.sendBuyBridgeEnabled
onClicked: root.launchSendModal()
tooltipText: networkConnectionStore.sendBuyBridgeToolTipText
tooltip.text: networkConnectionStore.sendBuyBridgeToolTipText
visible: !walletStore.overview.isWatchOnlyAccount && walletStore.overview.canSend
}
@ -57,13 +56,12 @@ Rectangle {
}
}
DisabledTooltipButton {
icon: "bridge"
buttonType: DisabledTooltipButton.Flat
StatusFlatButton {
icon.name: "bridge"
text: qsTr("Bridge")
interactive: networkConnectionStore.sendBuyBridgeEnabled
onClicked: root.launchBridgeModal()
tooltipText: networkConnectionStore.sendBuyBridgeToolTipText
tooltip.text: networkConnectionStore.sendBuyBridgeToolTipText
visible: !walletStore.overview.isWatchOnlyAccount && !root.isCommunityOwnershipTransfer && walletStore.overview.canSend
}

View File

@ -1,62 +0,0 @@
import QtQuick 2.15
import StatusQ.Controls 0.1
Item {
id: root
property string aliasedObjectName
property string text
property string icon
property alias tooltipText: tooltip.text
property int buttonType: DisabledTooltipButton.Normal
property bool interactive: true
property Component buttonComponent: buttonType === DisabledTooltipButton.Normal ? normalButton : flatButton
signal clicked()
enum Type {
Normal, // 0
Flat // 1
}
implicitWidth: !!buttonLoader.item ? buttonLoader.item.width : 0
implicitHeight: !!buttonLoader.item ? buttonLoader.item.height : 0
Loader {
id: buttonLoader
anchors.centerIn: parent
sourceComponent: buttonComponent
active: root.visible
}
HoverHandler {
id: hoverHandler
enabled: !root.interactive
cursorShape: Qt.PointingHandCursor
}
StatusToolTip {
id: tooltip
visible: hoverHandler.hovered && !!text
offset: -(tooltip.x + tooltip.width/2 - root.width/2)
}
Component{
id: flatButton
StatusFlatButton {
objectName: root.aliasedObjectName
icon.name: root.icon
text: root.text
enabled: root.interactive
onClicked: root.clicked()
}
}
Component{
id: normalButton
StatusButton {
objectName: root.aliasedObjectName
icon.name: root.icon
text: root.text
enabled: root.interactive
onClicked: root.clicked()
}
}
}

View File

@ -9,7 +9,6 @@ CopyButton 1.0 CopyButton.qml
CopyButtonWithCircle 1.0 CopyButtonWithCircle.qml
CopyToClipBoardButton 1.0 CopyToClipBoardButton.qml
CurrencyAmountInput 1.0 CurrencyAmountInput.qml
DisabledTooltipButton 1.0 DisabledTooltipButton.qml
EmojiHash 1.0 EmojiHash.qml
EmptyShapeRectangleFooterListView 1.0 EmptyShapeRectangleFooterListView.qml
ErrorDetails 1.0 ErrorDetails.qml

View File

@ -18,8 +18,7 @@ Rectangle {
property bool saveChangesButtonEnabled: false
property bool saveForLaterButtonVisible
property alias saveChangesText: saveChangesButton.text
property alias saveChangesTooltipText: saveChangesButton.tooltipText
property alias saveChangesTooltipVisible: saveChangesButton.enabled
property string saveChangesTooltipText
property alias saveForLaterText: saveForLaterButton.text
property alias cancelChangesText: cancelChangesButton.text
property alias changesDetectedText: changesDetectedTextItem.text
@ -148,13 +147,12 @@ Rectangle {
onClicked: root.saveForLaterClicked()
}
DisabledTooltipButton {
StatusButton {
id: saveChangesButton
objectName: "settingsDirtyToastMessageSaveButton"
buttonType: DisabledTooltipButton.Normal
text: root.defaultSaveChangesText
enabled: root.active && root.saveChangesButtonEnabled
interactive: root.active && root.saveChangesButtonEnabled
tooltip.text: root.saveChangesTooltipText
onClicked: root.saveChangesClicked()
}
}

View File

@ -123,7 +123,8 @@ Pane {
objectName: "editProfileButton"
size: StatusButton.Size.Small
text: qsTr("Edit Profile")
enabled: !root.readOnly
interactive: !root.readOnly
tooltip.text: interactive ? "" : qsTr("Not available in preview mode")
onClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile)
root.closeRequested()
@ -319,15 +320,6 @@ Pane {
Loader {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: menuButton.visible ? menuButton.height : -1
HoverHandler {
id: actionButtonHoverHandler
enabled: root.readOnly
}
StatusToolTip {
text: qsTr("Not available in preview mode")
visible: actionButtonHoverHandler.hovered
}
sourceComponent: {
// current user