chore(AppMain): unify the global banner

- extract to a separate component, based on simple properties and
signals
- fix some layout issues in the underlying ModuleWarning component
- removed a duplicate seedphrase banner from the wallet section itself
- add to storybook, covered with QML tests

Fixes #18339
This commit is contained in:
Lukáš Tinkl
2025-08-04 11:36:18 +02:00
committed by Lukáš Tinkl
parent ce662c0f41
commit 5712df2d1b
15 changed files with 410 additions and 363 deletions
@@ -39,9 +39,6 @@ proc init*(self: Controller) =
proc getCurrency*(self: Controller): string =
return self.settingsService.getCurrency()
proc isMnemonicBackedUp*(self: Controller): bool =
return self.settingsService.getMnemonic().len > 0
proc getTotalCurrencyBalance*(self: Controller, addresses: seq[string], chainIds: seq[int]): CurrencyAmount =
return currencyAmountToItem(self.walletAccountService.getTotalCurrencyBalance(addresses, chainIds), self.currencyService.getCurrencyFormat(self.getCurrency()))
@@ -399,8 +399,6 @@ proc checkIfModuleDidLoad(self: Module) =
if(not self.networksModule.isLoaded()):
return
let mnemonicBackedUp = self.controller.isMnemonicBackedUp()
self.view.setData(mnemonicBackedUp)
self.setTotalCurrencyBalance()
self.filter.setAddresses(self.getWalletAddressesNotHidden())
self.filter.load()
@@ -15,7 +15,6 @@ QtObject:
View* = ref object of QObject
delegate: io_interface.AccessInterface
totalCurrencyBalance: CurrencyAmount
isMnemonicBackedUp: bool
tmpAmount: float # shouldn't be used anywhere except in prepare*/getPrepared* procs
tmpSymbol: string # shouldn't be used anywhere except in prepare*/getPrepared* procs
activityController: activityc.Controller
@@ -79,12 +78,6 @@ QtObject:
read = getTotalCurrencyBalance
notify = totalCurrencyBalanceChanged
proc getIsMnemonicBackedUp(self: View): QVariant {.slot.} =
return newQVariant(self.isMnemonicBackedUp)
QtProperty[QVariant] isMnemonicBackedUp:
read = getIsMnemonicBackedUp
proc addressFiltersChanged*(self: View) {.signal.}
proc setAddressFilters*(self: View, address: string) =
self.addressFilters = address
@@ -122,9 +115,6 @@ QtObject:
self.tmpSymbol = "ERROR"
return newQVariant(currencyAmount)
proc setData*(self: View, mnemonicBackedUp: bool) =
self.isMnemonicBackedUp = mnemonicBackedUp
proc runAddAccountPopup*(self: View, addingWatchOnlyAccount: bool) {.slot.} =
self.delegate.runAddAccountPopup(addingWatchOnlyAccount)
+102
View File
@@ -0,0 +1,102 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Storybook
import utils
import mainui
SplitView {
Logs { id: logs }
orientation: Qt.Vertical
SplitView.fillWidth: true
QtObject {
id: d
property bool userDeclinedBackupBanner
property bool testnetEnabled
}
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
ColumnLayout {
width: ctrlWidth.value
anchors.centerIn: parent
Label {
text: "Online > Testnet > Seedphrase"
}
Label {
text: "Width: %1; visible: %2".arg(parent.width).arg(banner.visible ? "true" : "false")
}
GlobalBanner {
id: banner
Tracer { border.color: "blue" }
Layout.fillWidth: true
isOnline: ctrlIsOnline.checked
testnetEnabled: d.testnetEnabled
seedphraseBackedUp: d.userDeclinedBackupBanner
onOpenTestnetPopupRequested: {
logs.logEvent("onOpenTestnetPopupRequested")
d.testnetEnabled = false
}
onOpenBackUpSeedPopupRequested: {
logs.logEvent("onOpenBackUpSeedPopupRequested")
}
onUserDeclinedBackupBannerRequested: {
logs.logEvent("onUserDeclinedBackupBannerRequested")
d.userDeclinedBackupBanner = true
}
}
}
}
LogsAndControlsPanel {
SplitView.minimumHeight: 150
SplitView.preferredHeight: 150
logsView.logText: logs.logText
RowLayout {
Switch {
id: ctrlIsOnline
text: "Online"
checked: true
}
Switch {
id: ctrlTestnetEnabled
text: "Testnet"
checked: d.testnetEnabled
onToggled: d.testnetEnabled = checked
}
Switch {
id: ctrlUserDeclinedBackupBanner
text: "Seedphrase backed up"
checked: d.userDeclinedBackupBanner
onToggled: d.userDeclinedBackupBanner = checked
}
ToolSeparator {}
Label { text: "Width:" }
Slider {
id: ctrlWidth
from: 100
to: 1000
value: 600
}
}
}
}
// category: Components
// status: good
@@ -0,0 +1,123 @@
import QtQuick
import QtTest
import mainui
Item {
id: root
width: 800
height: 600
Component {
id: componentUnderTest
GlobalBanner {
anchors.centerIn: parent
width: 600
isOnline: false
testnetEnabled: false
seedphraseBackedUp: false
}
}
SignalSpy {
id: testNetButtonSignalSpy
target: controlUnderTest
signalName: "openTestnetPopupRequested"
}
SignalSpy {
id: seedphraseButtonSignalSpy
target: controlUnderTest
signalName: "openBackUpSeedPopupRequested"
}
SignalSpy {
id: seedphraseCloseButtonSignalSpy
target: controlUnderTest
signalName: "userDeclinedBackupBannerRequested"
}
property GlobalBanner controlUnderTest: null
TestCase {
name: "GlobalBanner"
when: windowShown
function init() {
testNetButtonSignalSpy.clear()
seedphraseButtonSignalSpy.clear()
seedphraseCloseButtonSignalSpy.clear()
}
function test_basicGeometry() {
controlUnderTest = createTemporaryObject(componentUnderTest, root)
verify(!!controlUnderTest)
tryVerify(() => controlUnderTest.width > 0)
tryVerify(() => controlUnderTest.height > 0)
}
// assert that at most 1 banner is displayed at any given time, and it's the correct one
// "1. Offline/online > 2. Testnet > 3. Seedphrase"
function test_variations_data() {
return [
// offline/online banner
{isOnline: false, testnetEnabled: false, seedphraseBackedUp: false, banner: "connectionInfoBanner"},
{isOnline: false, testnetEnabled: true, seedphraseBackedUp: false, banner: "connectionInfoBanner"},
{isOnline: false, testnetEnabled: false, seedphraseBackedUp: true, banner: "connectionInfoBanner"},
{isOnline: false, testnetEnabled: true, seedphraseBackedUp: true, banner: "connectionInfoBanner"},
// testnet banner
{isOnline: true, testnetEnabled: true, seedphraseBackedUp: false, banner: "testnetBanner"},
{isOnline: true, testnetEnabled: true, seedphraseBackedUp: true, banner: "testnetBanner"},
// seedphrase banner
{isOnline: true, testnetEnabled: false, seedphraseBackedUp: false, banner: "secureYourSeedPhraseBanner"},
// no banner
{isOnline: true, testnetEnabled: false, seedphraseBackedUp: true, banner: ""},
]
}
function test_variations(data) {
controlUnderTest = createTemporaryObject(componentUnderTest, root, data)
verify(!!controlUnderTest)
if (!!data.banner) {
tryCompare(controlUnderTest.item, "objectName", data.banner)
tryCompare(controlUnderTest.item, "visible", true)
} else {
tryVerify(() => controlUnderTest.item === null) // no banner, not visible at all
}
}
// test that the testnet banner's button emits the right signal to open the resp. popup
function test_testnet_button() {
controlUnderTest = createTemporaryObject(componentUnderTest, root,
{isOnline: true, testnetEnabled: true, seedphraseBackedUp: false})
verify(!!controlUnderTest)
tryCompare(controlUnderTest.item, "objectName", "testnetBanner")
const btn = findChild(controlUnderTest.item, "actionButton")
verify(!!btn)
mouseClick(btn)
compare(testNetButtonSignalSpy.count, 1)
}
// test that the seedphrase banner's buttons emit the right signals to open the resp. popup
function test_seedphrase_buttons() {
controlUnderTest = createTemporaryObject(componentUnderTest, root,
{isOnline: true, testnetEnabled: false, seedphraseBackedUp: false})
verify(!!controlUnderTest)
tryCompare(controlUnderTest.item, "objectName", "secureYourSeedPhraseBanner")
const btn = findChild(controlUnderTest.item, "actionButton")
verify(!!btn)
mouseClick(btn)
compare(seedphraseButtonSignalSpy.count, 1)
const closeBtn = findChild(controlUnderTest.item, "closeButton")
verify(!!closeBtn)
mouseClick(closeBtn)
compare(seedphraseCloseButtonSignalSpy.count, 1)
}
}
}
@@ -7,7 +7,7 @@ QtObject {
property var privacyModule
// Module Properties
property bool mnemonicBackedUp: privacyModule.mnemonicBackedUp
readonly property bool mnemonicBackedUp: privacyModule.mnemonicBackedUp
readonly property string keyUid: userProfile.keyUid
// The following properties wrap Privacy and Security View related properties:
@@ -24,7 +24,7 @@ QtObject {
property string preferredName: userProfile.preferredName
property string profileLargeImage: userProfile.largeImage
property string icon: userProfile.icon
property bool userDeclinedBackupBanner: Global.appIsReady? localAccountSensitiveSettings.userDeclinedBackupBanner : false
readonly property bool userDeclinedBackupBanner: Global.appIsReady? localAccountSensitiveSettings.userDeclinedBackupBanner : false
readonly property string keyUid: userProfile.keyUid
readonly property bool isKeycardUser: userProfile.isKeycardUser
readonly property int currentUserStatus: userProfile.currentUserStatus
@@ -143,9 +143,7 @@ QtObject {
root.profileModule.setIsFirstShowcaseInteraction()
}
onUserDeclinedBackupBannerChanged: {
if (userDeclinedBackupBanner !== localAccountSensitiveSettings.userDeclinedBackupBanner) {
localAccountSensitiveSettings.userDeclinedBackupBanner = userDeclinedBackupBanner
}
function setUserDeclinedBackupBanner(value = true) {
localAccountSensitiveSettings.userDeclinedBackupBanner = value
}
}
+1 -9
View File
@@ -213,12 +213,6 @@ Item {
}
}
SeedPhraseBackupWarning {
id: seedPhraseWarning
width: parent.width
anchors.top: parent.top
}
Component {
id: cmpSavedAddresses
SavedAddressesView {
@@ -281,9 +275,7 @@ Item {
StatusSectionLayout {
id: walletSectionLayout
navBar: root.navBar
anchors.top: seedPhraseWarning.bottom
height: root.height - seedPhraseWarning.height
width: root.width
anchors.fill: parent
backButtonName: RootStore.backButtonName
notificationCount: activityCenterStore.unreadNotificationsCount
hasUnseenNotifications: activityCenterStore.hasUnseenNotifications
@@ -1,88 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import StatusQ.Core
import StatusQ.Core.Theme
import utils
import shared
import shared.panels
import "../stores"
Rectangle {
id: root
height: visible ? 32 : 0
visible: !RootStore.mnemonicBackedUp
color: Theme.palette.dangerColor1
Row {
spacing: Theme.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: qsTr("Back up your recovery phrase")
font.pixelSize: Theme.additionalTextSize
anchors.verticalCenter: parent.verticalCenter
color: Theme.palette.white
}
Button {
width: 58
height: 24
contentItem: Item {
anchors.fill: parent
Text {
text: qsTr("Back up")
font.pixelSize: Theme.additionalTextSize
font.weight: Font.Medium
font.family: Theme.baseFont.name
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: Theme.palette.white
}
}
background: Rectangle {
radius: 4
anchors.fill: parent
border.color: Theme.palette.white
color: "#19FFFFFF"
}
StatusMouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: Global.openBackUpSeedPopup()
}
}
}
SVGImage {
id: closeImg
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 18
source: Theme.svg("close-white")
height: 20
width: 20
}
ColorOverlay {
anchors.fill: closeImg
source: closeImg
color: Theme.palette.white
opacity: 0.7
}
StatusMouseArea {
anchors.fill: closeImg
cursorShape: Qt.PointingHandCursor
onClicked: ParallelAnimation {
PropertyAnimation { target: root; property: "visible"; to: false; }
PropertyAnimation { target: root; property: "y"; to: -1 * root.height }
}
}
}
@@ -35,7 +35,6 @@ QtObject {
/* This property holds address of currently selected account in Wallet Main layout */
readonly property var addressFilters: walletSectionInst.addressFilters
readonly property var keypairImportModule: walletSectionInst.keypairImportModule
readonly property string mnemonicBackedUp: walletSectionInst.isMnemonicBackedUp
readonly property var transactionActivityStatus: walletSectionInst.activityController.status
+20 -163
View File
@@ -3,7 +3,6 @@ import QtQml
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Layouts
import QtQml.Models
@@ -827,6 +826,8 @@ Item {
property var activityCenterPopupObj: null
readonly property int activeSectionType: appMain.rootStore.activeSectionType
function openActivityCenterPopup() {
if (!activityCenterPopupObj) {
activityCenterPopupObj = activityCenterPopupComponent.createObject(appMain)
@@ -1449,78 +1450,31 @@ Item {
id: bannersLayout
enabled: !localAppSettings.testEnvironment
&& appMain.rootStore.activeSectionType !== Constants.appSection.homePage
&& d.activeSectionType !== Constants.appSection.homePage
&& !SQUtils.Utils.isMobile // Temp disable until we have proper way to handle banners on mobile
visible: enabled
property var updateBanner: null
property var connectedBanner: null
readonly property bool isConnected: appMain.rootStore.isOnline
function processUpdateAvailable() {
if (!updateBanner)
updateBanner = updateBannerComponent.createObject(this)
}
function processConnected() {
if (!connectedBanner)
connectedBanner = connectedBannerComponent.createObject(this)
}
Layout.fillWidth: true
// apply left/right margins when we remove the window titlebar
Layout.leftMargin: Qt.platform.os === SQUtils.Utils.mac ? appMain.Window.SafeArea.margins.left : 0
Layout.rightMargin: Qt.platform.os === SQUtils.Utils.mac ? appMain.Window.SafeArea.margins.right : 0
Layout.maximumHeight: implicitHeight
spacing: 1
onIsConnectedChanged: {
processConnected()
}
Component.onCompleted: {
if (!isConnected)
processConnected()
}
Connections {
target: rootStore.aboutModuleInst
function onAppVersionFetched(available: bool, version: string, url: string) {
rootStore.setLatestVersionInfo(available, version, url);
// TODO when we re-implement check for updates, uncomment this
// bannersLayout.processUpdateAvailable()
}
}
ModuleWarning {
id: testnetBanner
objectName: "testnetBanner"
GlobalBanner {
Layout.fillWidth: true
text: qsTr("Testnet mode enabled. All balances, transactions and dApp interactions will be on testnets.")
buttonText: qsTr("Turn off")
type: ModuleWarning.Warning
iconName: "warning"
active: appMain.networksStore.areTestNetworksEnabled
delay: false
onClicked: Global.openTestnetPopup()
closeBtnVisible: false
isOnline: appMain.rootStore.isOnline
testnetEnabled: appMain.networksStore.areTestNetworksEnabled
seedphraseBackedUp: appMain.privacyStore.mnemonicBackedUp || appMain.profileStore.userDeclinedBackupBanner
onOpenTestnetPopupRequested: Global.openTestnetPopup()
onOpenBackUpSeedPopupRequested: popups.openBackUpSeedPopup()
onUserDeclinedBackupBannerRequested: appMain.profileStore.setUserDeclinedBackupBanner()
}
ModuleWarning {
id: secureYourSeedPhrase
objectName: "secureYourSeedPhraseBanner"
Layout.fillWidth: true
active: !appMain.profileStore.userDeclinedBackupBanner
&& !appMain.privacyStore.mnemonicBackedUp
type: ModuleWarning.Danger
text: qsTr("Secure your recovery phrase")
buttonText: qsTr("Back up now")
delay: false
onClicked: popups.openBackUpSeedPopup()
onCloseClicked: {
appMain.profileStore.userDeclinedBackupBanner = true
}
}
ModuleWarning {
Layout.fillWidth: true
readonly property int progress: appMain.communitiesStore.discordImportProgress
@@ -1576,16 +1530,6 @@ Item {
onCloseClicked: hide()
}
ModuleWarning {
id: downloadingArchivesBanner
Layout.fillWidth: true
active: appMain.communitiesStore.downloadingCommunityHistoryArchives
type: ModuleWarning.Danger
text: qsTr("Downloading message history archives, DO NOT CLOSE THE APP until this banner disappears.")
closeBtnVisible: false
delay: false
}
ModuleWarning {
id: mailserverConnectionBanner
type: ModuleWarning.Warning
@@ -1594,91 +1538,6 @@ Item {
Layout.fillWidth: true
}
Component {
id: connectedBannerComponent
ModuleWarning {
id: connectedBanner
property bool isConnected: true
objectName: "connectionInfoBanner"
Layout.fillWidth: true
text: isConnected ? qsTr("You are back online") : qsTr("Internet connection lost. Reconnect to ensure everything is up to date.")
type: isConnected ? ModuleWarning.Success : ModuleWarning.Danger
function updateState() {
if (isConnected)
showFor()
else
show();
}
Component.onCompleted: {
connectedBanner.isConnected = Qt.binding(() => bannersLayout.isConnected);
}
onIsConnectedChanged: {
updateState();
}
onCloseClicked: {
hide();
}
onHideFinished: {
destroy()
bannersLayout.connectedBanner = null
}
}
}
Component {
id: updateBannerComponent
ModuleWarning {
readonly property string version: appMain.rootStore.latestVersion
readonly property bool updateAvailable: appMain.rootStore.newVersionAvailable
objectName: "appVersionUpdateBanner"
Layout.fillWidth: true
type: ModuleWarning.Success
delay: false
text: updateAvailable ? qsTr("A new version of Status (%1) is available").arg(version)
: qsTr("Your version is up to date")
buttonText: updateAvailable ? qsTr("Update")
: qsTr("Close")
function updateState() {
if (updateAvailable)
show()
else
showFor(5000)
}
Component.onCompleted: {
updateState()
}
onUpdateAvailableChanged: {
updateState();
}
onClicked: {
if (updateAvailable)
Global.openDownloadModal(appMain.rootStore.newVersionAvailable,
appMain.rootStore.latestVersion,
appMain.rootStore.downloadURL)
else
close()
}
onCloseClicked: {
if (updateAvailable)
appMain.rootStore.resetLastVersion();
hide()
}
onHideFinished: {
destroy()
bannersLayout.updateBanner = null
}
}
}
ConnectionWarnings {
id: walletBlockchainConnectionBanner
objectName: "walletBlockchainConnectionBanner"
@@ -1810,8 +1669,7 @@ Item {
anchors.fill: parent
currentIndex: {
const activeSectionType = appMain.rootStore.activeSectionType
switch (activeSectionType) {
switch (d.activeSectionType) {
case Constants.appSection.homePage:
return Constants.appViewStackIndex.homePage
case Constants.appSection.chat:
@@ -1824,7 +1682,7 @@ Item {
}
}
// Should never be here, correct index must be returned from the for loop above
console.error("Wrong section type:", activeSectionType,
console.error("Wrong section type:", d.activeSectionType,
"or section id: ", appMain.rootStore.activeSectionId)
return Constants.appViewStackIndex.community
case Constants.appSection.communitiesPortal:
@@ -1843,8 +1701,7 @@ Item {
}
}
onCurrentIndexChanged: {
const sectionType = appMain.rootStore.activeSectionType
if (sectionType !== Constants.appSection.profile && sectionType !== Constants.appSection.wallet) {
if (d.activeSectionType !== Constants.appSection.profile && d.activeSectionType !== Constants.appSection.wallet) {
d.maybeDisplayIntroduceYourselfPopup()
}
}
+99
View File
@@ -0,0 +1,99 @@
import QtQuick
import shared.panels
Loader {
id: root
required property bool isOnline
required property bool testnetEnabled
required property bool seedphraseBackedUp
signal openTestnetPopupRequested()
signal openBackUpSeedPopupRequested()
signal userDeclinedBackupBannerRequested()
sourceComponent: {
if (d.showConnectedBanner)
return connectedBannerComponent
if (testnetEnabled)
return testnetBannerComponent
if (!seedphraseBackedUp)
return secureYourSeedPhraseComponent
}
visible: !!item
onLoaded: item.show()
QtObject {
id: d
property bool showConnectedBanner: !root.isOnline // initially, we don't want to show the "You are online" banner
}
Connections {
target: root
function onIsOnlineChanged() {
if (!root.isOnline) {
d.showConnectedBanner = !root.isOnline // show the banner again if we are offline
}
}
}
Component {
id: connectedBannerComponent
ModuleWarning {
id: connectedBanner
objectName: "connectionInfoBanner"
text: root.isOnline ? qsTr("You are back online") : qsTr("Internet connection lost. Reconnect to ensure everything is up to date.")
type: root.isOnline ? ModuleWarning.Success : ModuleWarning.Danger
Connections {
target: root
function onIsOnlineChanged() {
if (root.isOnline) { // keep showing the connectedBanner for 3 more seconds
d.showConnectedBanner = true
connectedBanner.showFor(3000)
}
}
}
delay: false
onCloseClicked: {
d.showConnectedBanner = true // keep showing the connectedBanner until the hide animation is done
hide()
}
onHideFinished: d.showConnectedBanner = false // close the banner until the next offline event
}
}
Component {
id: testnetBannerComponent
ModuleWarning {
objectName: "testnetBanner"
text: qsTr("Testnet mode enabled. All balances, transactions and dApp interactions will be on testnets.")
buttonText: qsTr("Turn off")
type: ModuleWarning.Warning
iconName: "warning"
delay: false
onClicked: root.openTestnetPopupRequested()
closeBtnVisible: false
}
}
Component {
id: secureYourSeedPhraseComponent
ModuleWarning {
objectName: "secureYourSeedPhraseBanner"
type: ModuleWarning.Type.Danger
text: qsTr("Secure your recovery phrase")
buttonText: qsTr("Back up now")
delay: false
onClicked: root.openBackUpSeedPopupRequested()
onCloseClicked: root.userDeclinedBackupBannerRequested()
}
}
}
+1
View File
@@ -1,4 +1,5 @@
AppMain 1.0 AppMain.qml
GlobalBanner 1.0 GlobalBanner.qml
SplashScreen 1.0 SplashScreen.qml
Popups 1.0 Popups.qml
StatusTrayIcon 1.0 StatusTrayIcon.qml
+1 -12
View File
@@ -14553,17 +14553,6 @@ to load</translation>
<translation>The next screen contains your recovery phrase.&lt;br/&gt;&lt;b&gt;Anyone&lt;/b&gt; who sees it can use it to access to your funds.</translation>
</message>
</context>
<context>
<name>SeedPhraseBackupWarning</name>
<message>
<source>Back up your recovery phrase</source>
<translation>Back up your recovery phrase</translation>
</message>
<message>
<source>Back up</source>
<translation>Back up</translation>
</message>
</context>
<context>
<name>SeedphrasePage</name>
<message>
@@ -18890,4 +18879,4 @@ If a transaction with a lower nonce is pending, higher nonce transactions will r
<translation>This is not a valid account name</translation>
</message>
</context>
</TS>
</TS>
+59 -69
View File
@@ -132,20 +132,21 @@ Item {
Behavior on color {
ColorAnimation {
duration: 150
duration: Theme.AnimationDuration.Fast
}
}
RowLayout {
id: layout
spacing: 12
anchors.centerIn: parent
spacing: Theme.halfPadding
anchors.fill: parent
anchors.leftMargin: Theme.halfPadding
anchors.rightMargin: Theme.halfPadding
StatusRoundIcon {
Layout.preferredHeight: 16
Layout.preferredWidth: 16
Layout.rightMargin: -8
visible: !!root.iconName
asset.name: root.iconName
asset.bgColor: Theme.palette.indirectColor1
@@ -153,27 +154,56 @@ Item {
}
StatusBaseText {
objectName: "bannerText"
Layout.fillWidth: true
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: root.text
font.pixelSize: Theme.additionalTextSize
font.weight: Font.Medium
color: Theme.palette.indirectColor1
linkColor: color
onLinkActivated: root.linkActivated(link)
onLinkActivated: (link) => root.linkActivated(link)
HoverHandler {
id: handler1
cursorShape: hovered && parent.hoveredLink ? Qt.PointingHandCursor : undefined
}
StatusMouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: handler1.hovered && parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
StatusBaseText {
text: qsTr("%1%").arg(progressBar.value)
visible: progressBar.visible
font.pixelSize: Theme.tertiaryTextFontSize
verticalAlignment: Text.AlignVCenter
color: Theme.palette.white
}
ProgressBar {
id: progressBar
from: 0
to: 100
visible: root.progressValue > -1
value: root.progressValue
background: Rectangle {
implicitWidth: 64
implicitHeight: 8
radius: 8
color: "transparent"
border.width: 1
border.color: Theme.palette.white
}
contentItem: Rectangle {
width: progressBar.width*progressBar.position
implicitHeight: 8
radius: 8
color: Theme.palette.white
}
}
Button {
id: button
visible: text != ""
objectName: "actionButton"
visible: !!text
focusPolicy: Qt.NoFocus
padding: 5
onClicked: {
root.clicked()
}
@@ -192,68 +222,28 @@ Item {
border.color: Theme.palette.indirectColor3
color: Theme.palette.getColor("white", button.hovered ? 0.4 : 0.1)
}
StatusMouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
HoverHandler {
cursorShape: Qt.PointingHandCursor
}
}
}
StatusBaseText {
anchors.verticalCenter: parent.verticalCenter
anchors.right: progressBar.left
anchors.rightMargin: Theme.halfPadding
text: qsTr("%1%").arg(progressBar.value)
visible: progressBar.visible
font.pixelSize: Theme.tertiaryTextFontSize
verticalAlignment: Text.AlignVCenter
color: Theme.palette.white
}
StatusIcon {
id: closeImg
objectName: "closeButton"
height: 20
width: 20
icon: "close-circle"
color: Theme.palette.indirectColor1
opacity: closeButtonMouseArea.containsMouse ? 1 : 0.7
ProgressBar {
id: progressBar
anchors.verticalCenter: parent.verticalCenter
anchors.right: closeImg.left
anchors.rightMargin: Theme.bigPadding
from: 0
to: 100
visible: root.progressValue > -1
value: root.progressValue
background: Rectangle {
implicitWidth: 64
implicitHeight: 8
radius: 8
color: "transparent"
border.width: 1
border.color: Theme.palette.white
}
contentItem: Rectangle {
width: progressBar.width*progressBar.position
implicitHeight: 8
radius: 8
color: Theme.palette.white
}
}
StatusIcon {
id: closeImg
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 18
height: 20
width: 20
icon: "close-circle"
color: Theme.palette.indirectColor1
opacity: closeButtonMouseArea.containsMouse ? 1 : 0.7
StatusMouseArea {
id: closeButtonMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.closeClicked()
StatusMouseArea {
id: closeButtonMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.closeClicked()
}
}
}
}