diff --git a/example/qml-Qt6/component/CodeExpander.qml b/example/qml-Qt6/component/CodeExpander.qml index ea9d9781..4c5cd314 100644 --- a/example/qml-Qt6/component/CodeExpander.qml +++ b/example/qml-Qt6/component/CodeExpander.qml @@ -138,7 +138,8 @@ FluExpander{ "FluTimeline", "FluChart", "FluRangeSlider", - "FluStaggeredView" + "FluStaggeredView", + "FluProgressButton" ]; code = code.replace(/\n/g, "
"); code = code.replace(/ /g, " "); diff --git a/example/qml-Qt6/page/T_Buttons.qml b/example/qml-Qt6/page/T_Buttons.qml index 7707333f..7a8e4261 100644 --- a/example/qml-Qt6/page/T_Buttons.qml +++ b/example/qml-Qt6/page/T_Buttons.qml @@ -161,6 +161,58 @@ FluScrollablePage{ }' } + Timer{ + id:timer_progress + interval: 200 + onTriggered: { + btn_progress.progress = (btn_progress.progress + 0.1).toFixed(1) + if(btn_progress.progress==1){ + timer_progress.stop() + }else{ + timer_progress.start() + } + } + } + + FluArea{ + Layout.fillWidth: true + height: 68 + Layout.topMargin: 20 + paddings: 10 + + FluProgressButton{ + id:btn_progress + disabled:progress_button_switch.checked + text:"Progress Button" + anchors{ + verticalCenter: parent.verticalCenter + left: parent.left + } + onClicked: { + btn_progress.progress = 0 + timer_progress.restart() + } + } + FluToggleSwitch{ + id:progress_button_switch + anchors{ + right: parent.right + verticalCenter: parent.verticalCenter + } + text:"Disabled" + } + } + CodeExpander{ + Layout.fillWidth: true + Layout.topMargin: -1 + code:'FluProgressButton{ + text:"Progress Button" + onClicked: { + + } +}' + } + FluArea{ Layout.fillWidth: true diff --git a/example/qml-Qt6/page/T_Http.qml b/example/qml-Qt6/page/T_Http.qml index 483d7aa7..55cf8e59 100644 --- a/example/qml-Qt6/page/T_Http.qml +++ b/example/qml-Qt6/page/T_Http.qml @@ -115,7 +115,7 @@ FluContentPage{ http.postString("https://httpbingo.org/post",callable,param) } } - FluButton{ + FluProgressButton{ id:btn_download implicitWidth: parent.width implicitHeight: 36 @@ -124,7 +124,7 @@ FluContentPage{ folder_dialog.open() } } - FluButton{ + FluProgressButton{ id:btn_upload implicitWidth: parent.width implicitHeight: 36 @@ -198,12 +198,10 @@ FluContentPage{ } onFinish: { btn_upload.disabled = false - btn_upload.text = "上传文件" - layout_upload_file_size.visible = false - text_upload_file_size.text = "" } onError: (status,errorString,result)=>{ + btn_upload.progress = 0 text_info.text = result console.debug(result) } @@ -213,11 +211,7 @@ FluContentPage{ } onUploadProgress: (sent,total)=>{ - var locale = Qt.locale() - var precent = (sent/total * 100).toFixed(0) + "%" - btn_upload.text = "上传中..."+precent - text_upload_file_size.text = "%1/%2".arg(locale.formattedDataSize(sent)).arg(locale.formattedDataSize(total)) - layout_upload_file_size.visible = true + btn_upload.progress = sent/total } } @@ -242,12 +236,10 @@ FluContentPage{ } onFinish: { btn_download.disabled = false - btn_download.text = "下载文件" - layout_download_file_size.visible = false - text_download_file_size.text = "" } onError: (status,errorString,result)=>{ + btn_download.progress = 0 showError(errorString) console.debug(status+";"+errorString+";"+result) } @@ -257,11 +249,7 @@ FluContentPage{ } onDownloadProgress: (recv,total)=>{ - var locale = Qt.locale() - var precent = (recv/total * 100).toFixed(0) + "%" - btn_download.text = "下载中..."+precent - text_download_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total)) - layout_download_file_size.visible = true + btn_download.progress = recv/total } } @@ -300,32 +288,4 @@ FluContentPage{ } } - FluRectangle{ - id:layout_download_file_size - radius: [4,4,4,4] - height: 36 - width: 160 - visible: false - x:layout_flick.width - y: 173 - layout_flick.contentY - FluText{ - id:text_download_file_size - anchors.centerIn: parent - } - } - - FluRectangle{ - id:layout_upload_file_size - radius: [4,4,4,4] - height: 36 - width: 160 - visible: false - x:layout_flick.width - y: 210 - layout_flick.contentY - FluText{ - id:text_upload_file_size - anchors.centerIn: parent - } - } - } diff --git a/example/qml/component/CodeExpander.qml b/example/qml/component/CodeExpander.qml index 0ccc2985..f2731345 100644 --- a/example/qml/component/CodeExpander.qml +++ b/example/qml/component/CodeExpander.qml @@ -138,7 +138,8 @@ FluExpander{ "FluTimeline", "FluChart", "FluRangeSlider", - "FluStaggeredView" + "FluStaggeredView", + "FluProgressButton" ]; code = code.replace(/\n/g, "
"); code = code.replace(/ /g, " "); diff --git a/example/qml/page/T_Buttons.qml b/example/qml/page/T_Buttons.qml index 7749f501..6dd8014c 100644 --- a/example/qml/page/T_Buttons.qml +++ b/example/qml/page/T_Buttons.qml @@ -161,6 +161,58 @@ FluScrollablePage{ }' } + Timer{ + id:timer_progress + interval: 200 + onTriggered: { + btn_progress.progress = (btn_progress.progress + 0.1).toFixed(1) + if(btn_progress.progress==1){ + timer_progress.stop() + }else{ + timer_progress.start() + } + } + } + + FluArea{ + Layout.fillWidth: true + height: 68 + Layout.topMargin: 20 + paddings: 10 + + FluProgressButton{ + id:btn_progress + disabled:progress_button_switch.checked + text:"Progress Button" + anchors{ + verticalCenter: parent.verticalCenter + left: parent.left + } + onClicked: { + btn_progress.progress = 0 + timer_progress.restart() + } + } + FluToggleSwitch{ + id:progress_button_switch + anchors{ + right: parent.right + verticalCenter: parent.verticalCenter + } + text:"Disabled" + } + } + CodeExpander{ + Layout.fillWidth: true + Layout.topMargin: -1 + code:'FluProgressButton{ + text:"Progress Button" + onClicked: { + + } +}' + } + FluArea{ Layout.fillWidth: true diff --git a/example/qml/page/T_Http.qml b/example/qml/page/T_Http.qml index 0722df6c..4bde218a 100644 --- a/example/qml/page/T_Http.qml +++ b/example/qml/page/T_Http.qml @@ -8,6 +8,7 @@ import FluentUI 1.0 import "qrc:///example/qml/component" import "../component" + FluContentPage{ title:"Http" @@ -116,7 +117,7 @@ FluContentPage{ http.postString("https://httpbingo.org/post",callable,param) } } - FluButton{ + FluProgressButton{ id:btn_download implicitWidth: parent.width implicitHeight: 36 @@ -125,7 +126,7 @@ FluContentPage{ folder_dialog.open() } } - FluButton{ + FluProgressButton{ id:btn_upload implicitWidth: parent.width implicitHeight: 36 @@ -199,12 +200,10 @@ FluContentPage{ } onFinish: { btn_upload.disabled = false - btn_upload.text = "上传文件" - layout_upload_file_size.visible = false - text_upload_file_size.text = "" } onError: (status,errorString,result)=>{ + btn_upload.progress = 0 text_info.text = result console.debug(result) } @@ -214,11 +213,7 @@ FluContentPage{ } onUploadProgress: (sent,total)=>{ - var locale = Qt.locale() - var precent = (sent/total * 100).toFixed(0) + "%" - btn_upload.text = "上传中..."+precent - text_upload_file_size.text = "%1/%2".arg(locale.formattedDataSize(sent)).arg(locale.formattedDataSize(total)) - layout_upload_file_size.visible = true + btn_upload.progress = sent/total } } @@ -243,12 +238,10 @@ FluContentPage{ } onFinish: { btn_download.disabled = false - btn_download.text = "下载文件" - layout_download_file_size.visible = false - text_download_file_size.text = "" } onError: (status,errorString,result)=>{ + btn_download.progress = 0 showError(errorString) console.debug(status+";"+errorString+";"+result) } @@ -258,11 +251,7 @@ FluContentPage{ } onDownloadProgress: (recv,total)=>{ - var locale = Qt.locale() - var precent = (recv/total * 100).toFixed(0) + "%" - btn_download.text = "下载中..."+precent - text_download_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total)) - layout_download_file_size.visible = true + btn_download.progress = recv/total } } @@ -301,32 +290,4 @@ FluContentPage{ } } - FluRectangle{ - id:layout_download_file_size - radius: [4,4,4,4] - height: 36 - width: 160 - visible: false - x:layout_flick.width - y: 173 - layout_flick.contentY - FluText{ - id:text_download_file_size - anchors.centerIn: parent - } - } - - FluRectangle{ - id:layout_upload_file_size - radius: [4,4,4,4] - height: 36 - width: 160 - visible: false - x:layout_flick.width - y: 210 - layout_flick.contentY - FluText{ - id:text_upload_file_size - anchors.centerIn: parent - } - } - } diff --git a/src/FluHttp.cpp b/src/FluHttp.cpp index 6a6d72d7..ef84ed40 100644 --- a/src/FluHttp.cpp +++ b/src/FluHttp.cpp @@ -76,7 +76,7 @@ void FluHttp::post(QString url,HttpCallable* callable,QMap pa QEventLoop loop; QNetworkReply* reply = manager.post(request,&multiPart); _cacheReply.append(reply); - connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){ loop.quit(); }); loop.exec(); @@ -128,7 +128,7 @@ void FluHttp::postString(QString url,HttpCallable* callable,QString params,QMap< QEventLoop loop; QNetworkReply* reply = manager.post(request,params.toUtf8()); _cacheReply.append(reply); - connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){ loop.quit(); }); loop.exec(); @@ -180,7 +180,7 @@ void FluHttp::postJson(QString url,HttpCallable* callable,QMap par QEventLoop loop; QNetworkReply* reply = manager.get(request); _cacheReply.append(reply); - connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){ loop.quit(); }); loop.exec(); @@ -278,17 +278,23 @@ void FluHttp::download(QString url,HttpCallable* callable,QString filePath,QMap< return; } QEventLoop loop; - connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){ loop.quit(); }); - QPointer reply = manager.get(request); + QNetworkReply* reply = manager.get(request); _cacheReply.append(reply); - connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){ + connect(reply,&QNetworkReply::readyRead,reply,[reply,file]{ + if (!reply || !file || reply->error() != QNetworkReply::NoError) + { + return; + } + file->write(reply->readAll()); + }); + connect(reply,&QNetworkReply::downloadProgress,reply,[=](qint64 bytesReceived, qint64 bytesTotal){ Q_EMIT callable->downloadProgress(bytesReceived,bytesTotal); }); loop.exec(); if (reply->error() == QNetworkReply::NoError) { - file->write(reply->readAll()); Q_EMIT callable->success(filePath); }else{ Q_EMIT callable->error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString(),""); @@ -328,10 +334,10 @@ void FluHttp::upload(QString url,HttpCallable* callable,QMap QEventLoop loop; QNetworkReply* reply = manager.post(request,&multiPart); _cacheReply.append(reply); - connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){ loop.quit(); }); - connect(reply,&QNetworkReply::uploadProgress,this,[=](qint64 bytesSent, qint64 bytesTotal){ + connect(reply,&QNetworkReply::uploadProgress,reply,[=](qint64 bytesSent, qint64 bytesTotal){ Q_EMIT callable->uploadProgress(bytesSent,bytesTotal); }); loop.exec(); @@ -409,7 +415,7 @@ bool FluHttp::cacheExists(const QMap& request){ } QString FluHttp::getCacheFilePath(const QMap& request){ - auto fileName = FluTools::getInstance()->md5(QJsonDocument::fromVariant(QVariant(request)).toJson()); + auto fileName = FluTools::getInstance()->sha256(QJsonDocument::fromVariant(QVariant(request)).toJson()); QDir dir = _cacheDir; if (!dir.exists(_cacheDir)){ dir.mkpath(_cacheDir); diff --git a/src/FluTools.cpp b/src/FluTools.cpp index 1067a402..1ca3e1ee 100644 --- a/src/FluTools.cpp +++ b/src/FluTools.cpp @@ -150,3 +150,7 @@ bool FluTools::removeDir(QString dirPath){ QDir qDir(dirPath); return qDir.removeRecursively(); } + +QString FluTools::sha256(QString text){ + return QCryptographicHash::hash(text.toUtf8(), QCryptographicHash::Sha256).toHex(); +} diff --git a/src/FluTools.h b/src/FluTools.h index 9df087f4..272eadd5 100644 --- a/src/FluTools.h +++ b/src/FluTools.h @@ -151,6 +151,13 @@ public: */ Q_INVOKABLE QString md5(QString text); + /** + * @brief sha256 + * @param text + * @return + */ + Q_INVOKABLE QString sha256(QString text); + /** * @brief toBase64 * @param text diff --git a/src/Qt5/imports/FluentUI/Controls/FluProgressButton.qml b/src/Qt5/imports/FluentUI/Controls/FluProgressButton.qml new file mode 100644 index 00000000..2ace3bcb --- /dev/null +++ b/src/Qt5/imports/FluentUI/Controls/FluProgressButton.qml @@ -0,0 +1,134 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import FluentUI 1.0 + +Button { + property real progress + property bool disabled: false + property string contentDescription: "" + QtObject{ + id:d + property bool checked: rect_back.height === background.height + } + property color normalColor: { + if(d.checked){ + return FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + }else{ + return FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1) + } + } + property color hoverColor: { + if(d.checked){ + return FluTheme.dark ? Qt.darker(normalColor,1.1) : Qt.lighter(normalColor,1.1) + }else{ + return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) + } + } + property color disableColor: { + if(d.checked){ + return FluTheme.dark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1) + }else{ + return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1) + } + } + property color pressedColor: FluTheme.dark ? Qt.darker(normalColor,1.2) : Qt.lighter(normalColor,1.2) + Accessible.role: Accessible.Button + Accessible.name: control.text + Accessible.description: contentDescription + Accessible.onPressAction: control.clicked() + focusPolicy:Qt.TabFocus + id: control + enabled: !disabled + horizontalPadding:12 + background: FluItem{ + implicitWidth: 28 + implicitHeight: 28 + radius: [4,4,4,4] + Rectangle{ + anchors.fill: parent + border.color: FluTheme.dark ? "#505050" : "#DFDFDF" + border.width: d.checked ? 0 : 1 + radius: 4 + color:{ + if(!enabled){ + return disableColor + } + if(d.checked){ + if(pressed){ + return pressedColor + } + } + return hovered ? hoverColor :normalColor + } + } + Rectangle{ + id:rect_back + width: parent.width * control.progress + height: control.progress === 1 ? background.height : 3 + visible: !d.checked + color: FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + anchors.bottom: parent.bottom + Behavior on height{ + enabled: control.progress !== 1 + SequentialAnimation { + PauseAnimation { + duration: FluTheme.enableAnimation ? 167 : 0 + } + NumberAnimation{ + duration: FluTheme.enableAnimation ? 167 : 0 + from: 3 + to: background.height + } + } + } + Behavior on width{ + NumberAnimation{ + duration: 167 + } + } + } + FluFocusRectangle{ + visible: control.activeFocus + radius:4 + } + } + contentItem: FluText { + text: control.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: { + if(d.checked){ + if(FluTheme.dark){ + if(!enabled){ + return Qt.rgba(173/255,173/255,173/255,1) + } + return Qt.rgba(0,0,0,1) + }else{ + return Qt.rgba(1,1,1,1) + } + }else{ + if(FluTheme.dark){ + if(!enabled){ + return Qt.rgba(131/255,131/255,131/255,1) + } + if(!d.checked){ + if(pressed){ + return Qt.rgba(162/255,162/255,162/255,1) + } + } + return Qt.rgba(1,1,1,1) + }else{ + if(!enabled){ + return Qt.rgba(160/255,160/255,160/255,1) + } + if(!d.checked){ + if(pressed){ + return Qt.rgba(96/255,96/255,96/255,1) + } + } + return Qt.rgba(0,0,0,1) + } + } + } + } +} diff --git a/src/Qt5/imports/FluentUI/Controls/FluToggleButton.qml b/src/Qt5/imports/FluentUI/Controls/FluToggleButton.qml index 6377f493..9e60a194 100644 --- a/src/Qt5/imports/FluentUI/Controls/FluToggleButton.qml +++ b/src/Qt5/imports/FluentUI/Controls/FluToggleButton.qml @@ -52,7 +52,7 @@ Button { border.width: checked ? 0 : 1 FluFocusRectangle{ visible: control.activeFocus - radius:8 + radius:4 } color:{ if(!enabled){ diff --git a/src/Qt5/imports/FluentUI/qmldir b/src/Qt5/imports/FluentUI/qmldir index e05c9be6..f9c12e66 100644 --- a/src/Qt5/imports/FluentUI/qmldir +++ b/src/Qt5/imports/FluentUI/qmldir @@ -94,4 +94,5 @@ FluTreeView 1.0 Controls/FluTreeView.qml FluWindow 1.0 Controls/FluWindow.qml FluRangeSlider 1.0 Controls/FluRangeSlider.qml FluStaggeredView 1.0 Controls/FluStaggeredView.qml +FluProgressButton 1.0 Controls/FluProgressButton.qml plugin fluentuiplugin diff --git a/src/Qt6/imports/FluentUI/Controls/FluProgressButton.qml b/src/Qt6/imports/FluentUI/Controls/FluProgressButton.qml new file mode 100644 index 00000000..ee13ecba --- /dev/null +++ b/src/Qt6/imports/FluentUI/Controls/FluProgressButton.qml @@ -0,0 +1,135 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Basic +import FluentUI + +Button { + property real progress + property bool disabled: false + property string contentDescription: "" + QtObject{ + id:d + property bool checked: rect_back.height === background.height + } + property color normalColor: { + if(d.checked){ + return FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + }else{ + return FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1) + } + } + property color hoverColor: { + if(d.checked){ + return FluTheme.dark ? Qt.darker(normalColor,1.1) : Qt.lighter(normalColor,1.1) + }else{ + return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) + } + } + property color disableColor: { + if(d.checked){ + return FluTheme.dark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1) + }else{ + return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1) + } + } + property color pressedColor: FluTheme.dark ? Qt.darker(normalColor,1.2) : Qt.lighter(normalColor,1.2) + Accessible.role: Accessible.Button + Accessible.name: control.text + Accessible.description: contentDescription + Accessible.onPressAction: control.clicked() + focusPolicy:Qt.TabFocus + id: control + enabled: !disabled + horizontalPadding:12 + background: FluItem{ + implicitWidth: 28 + implicitHeight: 28 + radius: [4,4,4,4] + Rectangle{ + anchors.fill: parent + border.color: FluTheme.dark ? "#505050" : "#DFDFDF" + border.width: d.checked ? 0 : 1 + radius: 4 + color:{ + if(!enabled){ + return disableColor + } + if(d.checked){ + if(pressed){ + return pressedColor + } + } + return hovered ? hoverColor :normalColor + } + } + Rectangle{ + id:rect_back + width: parent.width * control.progress + height: control.progress === 1 ? background.height : 3 + visible: !d.checked + color: FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark + anchors.bottom: parent.bottom + Behavior on height{ + enabled: control.progress === 1 + SequentialAnimation { + PauseAnimation { + duration: FluTheme.enableAnimation ? 167 : 0 + } + NumberAnimation{ + duration: FluTheme.enableAnimation ? 167 : 0 + from: 3 + to: background.height + } + } + } + Behavior on width{ + NumberAnimation{ + duration: 167 + } + } + } + FluFocusRectangle{ + visible: control.activeFocus + radius:4 + } + } + contentItem: FluText { + text: control.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: { + if(d.checked){ + if(FluTheme.dark){ + if(!enabled){ + return Qt.rgba(173/255,173/255,173/255,1) + } + return Qt.rgba(0,0,0,1) + }else{ + return Qt.rgba(1,1,1,1) + } + }else{ + if(FluTheme.dark){ + if(!enabled){ + return Qt.rgba(131/255,131/255,131/255,1) + } + if(!d.checked){ + if(pressed){ + return Qt.rgba(162/255,162/255,162/255,1) + } + } + return Qt.rgba(1,1,1,1) + }else{ + if(!enabled){ + return Qt.rgba(160/255,160/255,160/255,1) + } + if(!d.checked){ + if(pressed){ + return Qt.rgba(96/255,96/255,96/255,1) + } + } + return Qt.rgba(0,0,0,1) + } + } + } + } +} diff --git a/src/Qt6/imports/FluentUI/Controls/FluToggleButton.qml b/src/Qt6/imports/FluentUI/Controls/FluToggleButton.qml index e1fdbe22..9d03b3b4 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluToggleButton.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluToggleButton.qml @@ -48,7 +48,7 @@ Button { border.width: checked ? 0 : 1 FluFocusRectangle{ visible: control.activeFocus - radius:8 + radius:4 } color:{ if(!enabled){ diff --git a/src/resource.qrc b/src/resource.qrc index 7725923b..b00cf1a7 100644 --- a/src/resource.qrc +++ b/src/resource.qrc @@ -94,5 +94,6 @@ Qt5/imports/FluentUI/Controls/ColorPicker/Content/SBPicker.qml Qt5/imports/FluentUI/Controls/FluRangeSlider.qml Qt5/imports/FluentUI/Controls/FluStaggeredView.qml + Qt5/imports/FluentUI/Controls/FluProgressButton.qml