Compare commits

..

20 Commits
1.5.5 ... 1.5.6

Author SHA1 Message Date
e1292966c1 update 2023-09-08 13:54:40 +08:00
249c294926 update 2023-09-08 01:12:20 +08:00
573898149a update 2023-09-08 00:21:28 +08:00
c92d807ec1 update 2023-09-07 18:07:23 +08:00
531bffdf1a update 2023-09-06 23:17:33 +08:00
db47a75f6b update 2023-09-06 22:52:48 +08:00
ad79480345 update 2023-09-06 18:07:51 +08:00
ed5956d824 update 2023-09-06 14:05:29 +08:00
ddee70cdca add breakPointDownload property 2023-09-06 00:22:37 +08:00
d6bbe3a5ec update 2023-09-05 18:38:16 +08:00
d93d6b7c26 update 2023-09-05 16:48:04 +08:00
54be482833 update 2023-09-04 22:49:50 +08:00
f60eaec07c Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-09-04 20:45:56 +08:00
f7b7d30a6f update 2023-09-04 18:37:55 +08:00
ba32c92133 update 2023-09-04 11:29:15 +08:00
08c4f78454 update 2023-09-01 18:38:21 +08:00
e29150ca52 update THIRD_PARTY_COPYRIGHT 2023-09-01 09:37:07 +08:00
1be9103412 update 2023-08-31 18:06:05 +08:00
8583427a49 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-08-30 18:44:13 +08:00
94a96cf75e update 2023-08-30 18:44:07 +08:00
37 changed files with 1713 additions and 684 deletions

View File

@ -262,4 +262,29 @@ zxing-cpp
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
************************************************************************************
ChartJs2QML
MIT License
Copyright (c) 2020 ChartJs2QML contributors (starting with Elypson, Michael A. Voelkel, https://github.com/Elypson)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -138,7 +138,8 @@ FluExpander{
"FluTimeline",
"FluChart",
"FluRangeSlider",
"FluStaggeredView"
"FluStaggeredView",
"FluProgressButton"
];
code = code.replace(/\n/g, "<br>");
code = code.replace(/ /g, "&nbsp;");

View File

@ -88,7 +88,10 @@ FluObject{
}
url:"qrc:/example/qml/page/T_Text.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
onTap:{
item_text.count = 0
navigationView.push(url)
}
}
FluPaneItem{
title:"Image"
@ -394,7 +397,7 @@ FluObject{
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Screenshot"
title:"Screenshot(Todo)"
url:"qrc:/example/qml/page/T_Screenshot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }

View File

@ -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

View File

@ -28,6 +28,7 @@ FluScrollablePage{
fillMode:Image.PreserveAspectCrop
anchors.fill: parent
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
}
Rectangle{

View File

@ -10,14 +10,62 @@ import "qrc:///example/qml/component"
FluContentPage{
title:"Http"
property string cacheDirPath: FluTools.getApplicationDirPath() + "/cache/http"
FluHttp{
id:http
cacheDir:cacheDirPath
}
FluHttp{
id:http_breakpoint_download
cacheDir:cacheDirPath
breakPointDownload: true
}
FluHttp{
id:http_cache_ifnonecacherequest
cacheMode:FluHttpType.IfNoneCacheRequest
cacheDir:cacheDirPath
}
FluHttp{
id:http_cache_requestfailedreadcache
cacheMode:FluHttpType.RequestFailedReadCache
cacheDir:cacheDirPath
}
FluHttp{
id:http_cache_firstcachethenrequest
cacheMode:FluHttpType.FirstCacheThenRequest
cacheDir:cacheDirPath
}
HttpCallable{
id:callable
onStart: {
showLoading()
}
onFinish: {
hideLoading()
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
text_info.text = result
}
onCache:
(result)=>{
text_info.text = result
}
}
Flickable{
id:layout_flick
width: 160
width: 200
clip: true
anchors{
top: parent.top
@ -36,21 +84,8 @@ FluContentPage{
implicitHeight: 36
text: "Get请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://httpbingo.org/get",callable)
var request = http.newRequest("https://httpbingo.org/get")
http.get(request,callable)
}
}
FluButton{
@ -58,25 +93,13 @@ FluContentPage{
implicitHeight: 36
text: "Post表单请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.post("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.post(request,callable)
}
}
FluButton{
@ -84,25 +107,13 @@ FluContentPage{
implicitHeight: 36
text: "Post Json请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.postJson("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.postJson(request,callable)
}
}
FluButton{
@ -110,25 +121,12 @@ FluContentPage{
implicitHeight: 36
text: "Post String请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = "我命由我不由天"
http.postString("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
request.params = "我命由我不由天"
http.postString(request,callable)
}
}
FluButton{
FluProgressButton{
id:btn_download
implicitWidth: parent.width
implicitHeight: 36
@ -137,7 +135,86 @@ FluContentPage{
folder_dialog.open()
}
}
FluButton{
FluProgressButton{
property bool downloading: false
id:btn_breakpoint_download
implicitWidth: parent.width
implicitHeight: 36
text: {
if(downloading){
return "暂停下载"
}
if(progress === 0){
return "断点下载文件"
}else if(progress === 1){
return "打开文件"
}else{
return "继续下载"
}
}
HttpRequest{
id:request_breakpoint_download
url: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
downloadSavePath: FluTools.getApplicationDirPath()+ "/download/big_buck_bunny.mp4"
}
HttpCallable{
id:callable_breakpoint_download
onStart: {
btn_breakpoint_download.downloading = true
}
onFinish: {
btn_breakpoint_download.downloading = false
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_breakpoint_download.progress = recv/total
}
}
Component.onCompleted: {
progress = http_breakpoint_download.getBreakPointProgress(request_breakpoint_download)
}
onClicked: {
if(downloading){
http_breakpoint_download.cancel()
return
}
if(progress === 1){
FluTools.showFileInFolder(request_breakpoint_download.downloadSavePath)
}else{
http_breakpoint_download.download(request_breakpoint_download,callable_breakpoint_download)
}
}
FluMenu{
id:menu_breakpoint_download
width: 120
FluMenuItem{
text: "删除文件"
onClicked: {
if(FluTools.removeFile(request_breakpoint_download.downloadSavePath)){
btn_breakpoint_download.progress = 0
}
}
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if(btn_breakpoint_download.progress === 1){
menu_breakpoint_download.popup()
}
}
}
}
FluProgressButton{
id:btn_upload
implicitWidth: parent.width
implicitHeight: 36
@ -146,81 +223,136 @@ FluContentPage{
file_dialog.open()
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "FirstCacheThenRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"FirstCacheThenRequest"}
http_cache_firstcachethenrequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "RequestFailedReadCache缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"RequestFailedReadCache"}
http_cache_requestfailedreadcache.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "IfNoneCacheRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"IfNoneCacheRequest"}
http_cache_ifnonecacherequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "打开缓存路径"
onClicked: {
Qt.openUrlExternally("file:///"+cacheDirPath)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "删除缓存"
onClicked: {
console.debug(FluTools.removeDir(cacheDirPath))
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "清空右边数据"
onClicked: {
text_info.text = ""
}
}
}
}
HttpCallable{
id:callable_upload
onStart: {
btn_upload.disabled = true
}
onFinish: {
btn_upload.disabled = false
}
onError:
(status,errorString,result)=>{
btn_upload.progress = 0
text_info.text = result
console.debug(result)
}
onSuccess:
(result)=>{
text_info.text = result
}
onUploadProgress:
(sent,total)=>{
btn_upload.progress = sent/total
}
}
FileDialog {
id: file_dialog
onAccepted: {
var param = {}
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
for(var i=0;i<selectedFiles.length;i++){
var fileUrl = selectedFiles[i]
var fileName = FluTools.getFileNameByUrl(fileUrl)
var filePath = FluTools.toLocalPath(fileUrl)
param[fileName] = filePath
params[fileName] = filePath
}
console.debug(JSON.stringify(param))
var callable = {}
callable.onStart = function(){
btn_upload.disabled = true
}
callable.onFinish = function(){
btn_upload.disabled = false
btn_upload.text = "上传文件"
layout_upload_file_size.visible = false
text_upload_file_size.text = ""
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString,result){
text_info.text = result
console.debug(result)
}
callable.onUploadProgress = function(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
}
http.upload("https://httpbingo.org/post",callable,param)
request.params = params
http.upload(request,callable_upload)
}
}
HttpCallable{
id:callable_download
onStart: {
btn_download.progress = 0
btn_download.disabled = true
}
onFinish: {
btn_download.disabled = false
}
onError:
(status,errorString,result)=>{
btn_download.progress = 0
showError(errorString)
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_download.progress = recv/total
}
}
FolderDialog {
id: folder_dialog
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
onAccepted: {
var callable = {}
callable.onStart = function(){
btn_download.disabled = true
}
callable.onFinish = function(){
btn_download.disabled = false
btn_download.text = "下载文件"
layout_download_file_size.visible = false
text_download_file_size.text = ""
}
callable.onSuccess = function(result){
showSuccess(result)
}
callable.onError = function(status,errorString){
showError(errorString)
}
callable.onDownloadProgress = function(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
}
var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",callable,path)
var request = http.newRequest("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
request.downloadSavePath = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download(request,callable_download)
}
}
FluArea{
anchors{
top: layout_flick.top
@ -246,34 +378,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
}
}
}

View File

@ -138,7 +138,7 @@ CustomWindow {
id:loader
lazy: true
anchors.fill: parent
source: "https://zhu-zichu.gitee.io/Qt6_155_LieflatPage.qml"
source: "https://zhu-zichu.gitee.io/Qt6_156_LieflatPage.qml"
}
}
front: Item{
@ -309,28 +309,34 @@ CustomWindow {
}
}
function checkUpdate(){
var callable = {}
callable.onStart = function(){
HttpCallable{
id:callable
onStart: {
console.debug("satrt check update...")
}
callable.onFinish = function(){
onFinish: {
console.debug("check update finish")
}
callable.onSuccess = function(result){
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
onSuccess:
(result)=>{
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
}
}
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest",callable)
onError:
(status,errorString)=>{
console.debug(status+";"+errorString)
}
}
function checkUpdate(){
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
http.get(request,callable);
}
}

View File

@ -138,7 +138,8 @@ FluExpander{
"FluTimeline",
"FluChart",
"FluRangeSlider",
"FluStaggeredView"
"FluStaggeredView",
"FluProgressButton"
];
code = code.replace(/\n/g, "<br>");
code = code.replace(/ /g, "&nbsp;");

View File

@ -88,7 +88,10 @@ FluObject{
}
url:"qrc:/example/qml/page/T_Text.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
onTap:{
item_text.count = 0
navigationView.push(url)
}
}
FluPaneItem{
title:"Image"
@ -394,7 +397,7 @@ FluObject{
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Screenshot"
title:"Screenshot(Todo)"
url:"qrc:/example/qml/page/T_Screenshot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }

View File

@ -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

View File

@ -29,6 +29,7 @@ FluScrollablePage{
anchors.fill: parent
asynchronous: true
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
}
Rectangle{

View File

@ -11,14 +11,62 @@ import "../component"
FluContentPage{
title:"Http"
property string cacheDirPath: FluTools.getApplicationDirPath() + "/cache/http"
FluHttp{
id:http
cacheDir:cacheDirPath
}
FluHttp{
id:http_breakpoint_download
cacheDir:cacheDirPath
breakPointDownload: true
}
FluHttp{
id:http_cache_ifnonecacherequest
cacheMode:FluHttpType.IfNoneCacheRequest
cacheDir:cacheDirPath
}
FluHttp{
id:http_cache_requestfailedreadcache
cacheMode:FluHttpType.RequestFailedReadCache
cacheDir:cacheDirPath
}
FluHttp{
id:http_cache_firstcachethenrequest
cacheMode:FluHttpType.FirstCacheThenRequest
cacheDir:cacheDirPath
}
HttpCallable{
id:callable
onStart: {
showLoading()
}
onFinish: {
hideLoading()
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
text_info.text = result
}
onCache:
(result)=>{
text_info.text = result
}
}
Flickable{
id:layout_flick
width: 160
width: 200
clip: true
anchors{
top: parent.top
@ -37,21 +85,8 @@ FluContentPage{
implicitHeight: 36
text: "Get请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://httpbingo.org/get",callable)
var request = http.newRequest("https://httpbingo.org/get")
http.get(request,callable)
}
}
FluButton{
@ -59,25 +94,13 @@ FluContentPage{
implicitHeight: 36
text: "Post表单请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.post("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.post(request,callable)
}
}
FluButton{
@ -85,25 +108,13 @@ FluContentPage{
implicitHeight: 36
text: "Post Json请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.postJson("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.postJson(request,callable)
}
}
FluButton{
@ -111,25 +122,12 @@ FluContentPage{
implicitHeight: 36
text: "Post String请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = "我命由我不由天"
http.postString("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
request.params = "我命由我不由天"
http.postString(request,callable)
}
}
FluButton{
FluProgressButton{
id:btn_download
implicitWidth: parent.width
implicitHeight: 36
@ -138,7 +136,86 @@ FluContentPage{
folder_dialog.open()
}
}
FluButton{
FluProgressButton{
property bool downloading: false
id:btn_breakpoint_download
implicitWidth: parent.width
implicitHeight: 36
text: {
if(downloading){
return "暂停下载"
}
if(progress === 0){
return "断点下载文件"
}else if(progress === 1){
return "打开文件"
}else{
return "继续下载"
}
}
HttpRequest{
id:request_breakpoint_download
url: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
downloadSavePath: FluTools.getApplicationDirPath()+ "/download/big_buck_bunny.mp4"
}
HttpCallable{
id:callable_breakpoint_download
onStart: {
btn_breakpoint_download.downloading = true
}
onFinish: {
btn_breakpoint_download.downloading = false
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_breakpoint_download.progress = recv/total
}
}
Component.onCompleted: {
progress = http_breakpoint_download.getBreakPointProgress(request_breakpoint_download)
}
onClicked: {
if(downloading){
http_breakpoint_download.cancel()
return
}
if(progress === 1){
FluTools.showFileInFolder(request_breakpoint_download.downloadSavePath)
}else{
http_breakpoint_download.download(request_breakpoint_download,callable_breakpoint_download)
}
}
FluMenu{
id:menu_breakpoint_download
width: 120
FluMenuItem{
text: "删除文件"
onClicked: {
if(FluTools.removeFile(request_breakpoint_download.downloadSavePath)){
btn_breakpoint_download.progress = 0
}
}
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if(btn_breakpoint_download.progress === 1){
menu_breakpoint_download.popup()
}
}
}
}
FluProgressButton{
id:btn_upload
implicitWidth: parent.width
implicitHeight: 36
@ -147,81 +224,136 @@ FluContentPage{
file_dialog.open()
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "FirstCacheThenRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"FirstCacheThenRequest"}
http_cache_firstcachethenrequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "RequestFailedReadCache缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"RequestFailedReadCache"}
http_cache_requestfailedreadcache.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "IfNoneCacheRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"IfNoneCacheRequest"}
http_cache_ifnonecacherequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "打开缓存路径"
onClicked: {
Qt.openUrlExternally("file:///"+cacheDirPath)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "删除缓存"
onClicked: {
console.debug(FluTools.removeDir(cacheDirPath))
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "清空右边数据"
onClicked: {
text_info.text = ""
}
}
}
}
HttpCallable{
id:callable_upload
onStart: {
btn_upload.disabled = true
}
onFinish: {
btn_upload.disabled = false
}
onError:
(status,errorString,result)=>{
btn_upload.progress = 0
text_info.text = result
console.debug(result)
}
onSuccess:
(result)=>{
text_info.text = result
}
onUploadProgress:
(sent,total)=>{
btn_upload.progress = sent/total
}
}
FileDialog {
id: file_dialog
onAccepted: {
var param = {}
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
for(var i=0;i<selectedFiles.length;i++){
var fileUrl = selectedFiles[i]
var fileName = FluTools.getFileNameByUrl(fileUrl)
var filePath = FluTools.toLocalPath(fileUrl)
param[fileName] = filePath
params[fileName] = filePath
}
console.debug(JSON.stringify(param))
var callable = {}
callable.onStart = function(){
btn_upload.disabled = true
}
callable.onFinish = function(){
btn_upload.disabled = false
btn_upload.text = "上传文件"
layout_upload_file_size.visible = false
text_upload_file_size.text = ""
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString,result){
text_info.text = result
console.debug(result)
}
callable.onUploadProgress = function(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
}
http.upload("https://httpbingo.org/post",callable,param)
request.params = params
http.upload(request,callable_upload)
}
}
HttpCallable{
id:callable_download
onStart: {
btn_download.progress = 0
btn_download.disabled = true
}
onFinish: {
btn_download.disabled = false
}
onError:
(status,errorString,result)=>{
btn_download.progress = 0
showError(errorString)
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_download.progress = recv/total
}
}
FolderDialog {
id: folder_dialog
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
onAccepted: {
var callable = {}
callable.onStart = function(){
btn_download.disabled = true
}
callable.onFinish = function(){
btn_download.disabled = false
btn_download.text = "下载文件"
layout_download_file_size.visible = false
text_download_file_size.text = ""
}
callable.onSuccess = function(result){
showSuccess(result)
}
callable.onError = function(status,errorString){
showError(errorString)
}
callable.onDownloadProgress = function(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
}
var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",callable,path)
var request = http.newRequest("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
request.downloadSavePath = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download(request,callable_download)
}
}
FluArea{
anchors{
top: layout_flick.top
@ -247,34 +379,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
}
}
}

View File

@ -139,7 +139,7 @@ CustomWindow {
id:loader
lazy: true
anchors.fill: parent
source: "https://zhu-zichu.gitee.io/Qt5_155_LieflatPage.qml"
source: "https://zhu-zichu.gitee.io/Qt6_156_LieflatPage.qml"
}
}
front: Item{
@ -310,28 +310,34 @@ CustomWindow {
}
}
function checkUpdate(){
var callable = {}
callable.onStart = function(){
HttpCallable{
id:callable
onStart: {
console.debug("satrt check update...")
}
callable.onFinish = function(){
onFinish: {
console.debug("check update finish")
}
callable.onSuccess = function(result){
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
onSuccess:
(result)=>{
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
}
}
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest",callable)
onError:
(status,errorString)=>{
console.debug(status+";"+errorString)
}
}
function checkUpdate(){
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
http.get(request,callable);
}
}

View File

@ -4,6 +4,24 @@
#include <QObject>
#include <QtQml/qqml.h>
namespace FluHttpType {
Q_NAMESPACE
enum CacheMode {
/** 不使用缓存 */
NoCache = 0x0000,
/** 请求网络失败后,读取缓存 */
RequestFailedReadCache = 0x0001,
/** 如果缓存不存在才请求网络,否则使用缓存 */
IfNoneCacheRequest = 0x0002,
/** 先使用缓存,不管是否存在,仍然请求网络 */
FirstCacheThenRequest = 0x0004,
};
Q_ENUM_NS(CacheMode)
QML_NAMED_ELEMENT(FluHttpType)
}
namespace FluScreenshotType {
Q_NAMESPACE

View File

@ -5,15 +5,69 @@
#include <QNetworkReply>
#include <QUrlQuery>
#include <QHttpMultiPart>
#include <QGuiApplication>
#include <QJsonDocument>
#include "MainThread.h"
#include <QStandardPaths>
#include <QTextStream>
#include <QDir>
#include "Def.h"
#include "FluApp.h"
#include "FluTools.h"
HttpRequest::HttpRequest(QObject *parent)
: QObject{parent}
{
}
QMap<QString, QVariant> HttpRequest::toMap(){
QVariant _params;
bool isPostString = method() == "postString";
if(params().isNull()){
if(isPostString){
_params = "";
}else{
_params = QMap<QString,QVariant>();
}
}else{
_params = params();
}
QVariant _headers;
if(headers().isNull()){
_headers = QMap<QString,QVariant>();
}else{
_params = params();
}
QMap<QString, QVariant> request = {
{"url",url()},
{"headers",_headers.toMap()},
{"method",method()},
{"downloadSavePath",downloadSavePath()}
};
if(isPostString){
request.insert("params",_params.toString());
}else{
request.insert("params",_params.toMap());
}
return request;
}
QString HttpRequest::httpId(){
return FluTools::getInstance()->sha256(QJsonDocument::fromVariant(QVariant(toMap())).toJson(QJsonDocument::Compact));
}
HttpCallable::HttpCallable(QObject *parent)
: QObject{parent}
{
}
FluHttp::FluHttp(QObject *parent)
: QObject{parent}
{
retry(3);
timeout(15000);
cacheMode(FluHttpType::CacheMode::NoCache);
cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+"/httpcache");
breakPointDownload(false);
}
FluHttp::~FluHttp(){
@ -21,27 +75,34 @@ FluHttp::~FluHttp(){
}
void FluHttp::cancel(){
foreach (QPointer<QNetworkReply> item, _cache) {
foreach (QPointer<QNetworkReply> item, _cacheReply) {
if(item){
item->abort();
}
}
}
void FluHttp::handleReply(QNetworkReply* reply){
_cache.append(reply);
}
void FluHttp::post(QString url,QJSValue callable,QMap<QString, QVariant> params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"post").toMap();
void FluHttp::post(HttpRequest* request,HttpCallable* callable){
request->method("post");
auto requestMap = request->toMap();
auto httpId = request->httpId();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
if(_cacheMode == FluHttpType::CacheMode::IfNoneCacheRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
onFinish(callable,request);
return;
}
if(_cacheMode == FluHttpType::CacheMode::FirstCacheThenRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
QUrl _url(url);
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QUrl url(request->url());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
for (const auto& each : data["params"].toMap().toStdMap())
{
@ -54,198 +115,283 @@ void FluHttp::post(QString url,QJSValue callable,QMap<QString, QVariant> params,
multiPart.append(part);
}
QEventLoop loop;
QNetworkReply* reply = manager.post(request,&multiPart);
_cache.append(reply);
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
QNetworkReply* reply = manager.post(req,&multiPart);
_cacheReply.append(reply);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
loop.exec();
QString result = QString::fromUtf8(reply->readAll());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString errorString = reply->errorString();
bool isSuccess = reply->error() == QNetworkReply::NoError;
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
if (isSuccess) {
handleCache(httpId,result);
onSuccess(callable,result);
break;
}else{
if(i == retry()-1){
if(_cacheMode == FluHttpType::CacheMode::RequestFailedReadCache && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
onError(callable,status,errorString,result);
}
}
}
onFinish(callable);
onFinish(callable,request);
});
}
void FluHttp::postString(QString url,QJSValue callable,QString params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"postString").toMap();
void FluHttp::postString(HttpRequest* request,HttpCallable* callable){
request->method("postString");
auto requestMap = request->toMap();
auto httpId = request->httpId();
QString params = request->params().toString();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
if(_cacheMode == FluHttpType::CacheMode::IfNoneCacheRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
onFinish(callable,request);
return;
}
if(_cacheMode == FluHttpType::CacheMode::FirstCacheThenRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
QUrl _url(url);
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QUrl url(request->url());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QString contentType = QString("text/plain;charset=utf-8");
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
req.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
QEventLoop loop;
QNetworkReply* reply = manager.post(request,params.toUtf8());
_cache.append(reply);
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
QNetworkReply* reply = manager.post(req,params.toUtf8());
_cacheReply.append(reply);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
loop.exec();
QString result = QString::fromUtf8(reply->readAll());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString errorString = reply->errorString();
bool isSuccess = reply->error() == QNetworkReply::NoError;
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
if (isSuccess) {
handleCache(httpId,result);
onSuccess(callable,result);
break;
}else{
if(i == retry()-1){
if(_cacheMode == FluHttpType::CacheMode::RequestFailedReadCache && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
onError(callable,status,errorString,result);
}
}
}
onFinish(callable);
onFinish(callable,request);
});
}
void FluHttp::postJson(QString url,QJSValue callable,QMap<QString, QVariant> params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"postJson").toMap();
void FluHttp::postJson(HttpRequest* request,HttpCallable* callable){
request->method("postJson");
auto requestMap = request->toMap();
auto httpId = request->httpId();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
if(_cacheMode == FluHttpType::CacheMode::IfNoneCacheRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
onFinish(callable,request);
return;
}
if(_cacheMode == FluHttpType::CacheMode::FirstCacheThenRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
QUrl _url(url);
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QUrl url(request->url());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QString contentType = QString("application/json;charset=utf-8");
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
req.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
QEventLoop loop;
QNetworkReply* reply = manager.post(request,QJsonDocument::fromVariant(data["params"]).toJson());
_cache.append(reply);
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
QNetworkReply* reply = manager.post(req,QJsonDocument::fromVariant(data["params"]).toJson());
_cacheReply.append(reply);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
loop.exec();
QString result = QString::fromUtf8(reply->readAll());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString errorString = reply->errorString();
bool isSuccess = reply->error() == QNetworkReply::NoError;
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
if (isSuccess) {
handleCache(httpId,result);
onSuccess(callable,result);
break;
}else{
if(i == retry()-1){
if(_cacheMode == FluHttpType::CacheMode::RequestFailedReadCache && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
onError(callable,status,errorString,result);
}
}
}
onFinish(callable);
onFinish(callable,request);
});
}
void FluHttp::get(QString url,QJSValue callable,QMap<QString, QVariant> params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"get").toMap();
void FluHttp::get(HttpRequest* request,HttpCallable* callable){
request->method("get");
auto requestMap = request->toMap();
auto httpId = request->httpId();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
if(_cacheMode == FluHttpType::CacheMode::FirstCacheThenRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
if(_cacheMode == FluHttpType::CacheMode::IfNoneCacheRequest && cacheExists(httpId)){
onCache(callable,readCache(httpId));
onFinish(callable,request);
return;
}
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
for (int i = 0; i < retry(); ++i) {
onStart(callable);
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
QUrl _url(url);
addQueryParam(&_url,data["params"].toMap());
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QUrl url(request->url());
addQueryParam(&url,data["params"].toMap());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QEventLoop loop;
QNetworkReply* reply = manager.get(request);
_cache.append(reply);
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
QNetworkReply* reply = manager.get(req);
_cacheReply.append(reply);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
loop.exec();
QString result = QString::fromUtf8(reply->readAll());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString errorString = reply->errorString();
bool isSuccess = reply->error() == QNetworkReply::NoError;
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
QString result = QString::fromUtf8(reply->readAll());
if (isSuccess) {
handleCache(httpId,result);
onSuccess(callable,result);
break;
}else{
if(i == retry()-1){
if(_cacheMode == FluHttpType::CacheMode::RequestFailedReadCache && cacheExists(httpId)){
onCache(callable,readCache(httpId));
}
onError(callable,status,errorString,result);
}
}
reply->deleteLater();
reply = nullptr;
}
onFinish(callable);
onFinish(callable,request);
});
}
void FluHttp::download(QString url,QJSValue callable,QString filePath,QMap<QString, QVariant> params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"download").toMap();
void FluHttp::download(HttpRequest* request,HttpCallable* callable){
request->method("download");
auto requestMap = request->toMap();
auto httpId = request->httpId();
auto savePath = request->downloadSavePath();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
QNetworkAccessManager manager;
QUrl _url(url);
addQueryParam(&_url,data["params"].toMap());
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QSharedPointer<QFile> file(new QFile(filePath));
QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate;
if (!file->open(mode))
{
onError(callable,-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName()),"");
onFinish(callable);
return;
QUrl url(request->url());
addQueryParam(&url,data["params"].toMap());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QSharedPointer<QFile> file(new QFile(savePath));
QDir dir = QFileInfo(savePath).path();
if (!dir.exists(dir.path())){
dir.mkpath(dir.path());
}
QEventLoop loop;
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
QPointer<QNetworkReply> reply = manager.get(request);
_cache.append(reply);
connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){
onDownloadProgress(callable,bytesReceived,bytesTotal);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
qint64 seek = 0;
auto filePath = getCacheFilePath(httpId);
QSharedPointer<QFile> fileCache(new QFile(filePath));
if(fileCache->exists() && file->exists() && _breakPointDownload){
QJsonObject cacheInfo = QJsonDocument::fromJson(readCache(httpId).toUtf8()).object();
qint64 fileSize = cacheInfo.value("fileSize").toDouble();
qint64 contentLength = cacheInfo.value("contentLength").toDouble();
if(fileSize == contentLength && file->size() == contentLength){
onDownloadProgress(callable,fileSize,contentLength);
onSuccess(callable,savePath);
onFinish(callable,request);
return;
}
if(fileSize==file->size()){
req.setRawHeader("Range", QString("bytes=%1-").arg(fileSize).toUtf8());
seek = fileSize;
file->open(QIODevice::WriteOnly|QIODevice::Append);
}else{
file->open(QIODevice::WriteOnly|QIODevice::Truncate);
}
}else{
file->open(QIODevice::WriteOnly|QIODevice::Truncate);
}
QNetworkReply* reply = manager.get(req);
_cacheReply.append(reply);
if (!fileCache->open(QIODevice::WriteOnly|QIODevice::Truncate))
{
qDebug()<<"FileCache Error";
}
connect(reply,&QNetworkReply::readyRead,reply,[reply,file,fileCache,requestMap,callable,seek,this]{
if (!reply || !file || reply->error() != QNetworkReply::NoError)
{
return;
}
QMap<QString, QVariant> downMap = requestMap;
qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong()+seek;
downMap.insert("contentLength",contentLength);
QString eTag = reply->header(QNetworkRequest::ETagHeader).toString();
downMap.insert("eTag",eTag);
file->write(reply->readAll());
file->flush();
downMap.insert("fileSize",file->size());
fileCache->resize(0);
fileCache->write(FluTools::getInstance()->toBase64(QJsonDocument::fromVariant(QVariant(downMap)).toJson()).toUtf8());
fileCache->flush();
onDownloadProgress(callable,file->size(),contentLength);
});
loop.exec();
if (reply->error() == QNetworkReply::NoError) {
file->write(reply->readAll());
onSuccess(callable,filePath);
onSuccess(callable,savePath);
}else{
onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString(),"");
}
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
onFinish(callable);
onFinish(callable,request);
});
}
void FluHttp::upload(QString url,QJSValue callable,QMap<QString, QVariant> params,QMap<QString, QVariant> headers){
QMap<QString, QVariant> data = invokeIntercept(params,headers,"upload").toMap();
void FluHttp::upload(HttpRequest* request,HttpCallable* callable){
request->method("upload");
auto requestMap = request->toMap();
QMap<QString, QVariant> data = invokeIntercept(requestMap).toMap();
QThreadPool::globalInstance()->start([=](){
onStart(callable);
QNetworkAccessManager manager;
manager.setTransferTimeout(timeout());
QUrl _url(url);
QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap());
QUrl url(request->url());
QNetworkRequest req(url);
addHeaders(&req,data["headers"].toMap());
QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
qDebug()<<data["params"].toMap();
for (const auto& each : data["params"].toMap().toStdMap())
{
const QString& key = each.first;
@ -261,12 +407,11 @@ void FluHttp::upload(QString url,QJSValue callable,QMap<QString, QVariant> param
multiPart.append(part);
}
QEventLoop loop;
QNetworkReply* reply = manager.post(request,&multiPart);
_cache.append(reply);
connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){
loop.quit();
});
connect(reply,&QNetworkReply::uploadProgress,this,[=](qint64 bytesSent, qint64 bytesTotal){
QNetworkReply* reply = manager.post(req,&multiPart);
_cacheReply.append(reply);
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
connect(reply,&QNetworkReply::uploadProgress,reply,[=](qint64 bytesSent, qint64 bytesTotal){
onUploadProgress(callable,bytesSent,bytesTotal);
});
loop.exec();
@ -274,7 +419,6 @@ void FluHttp::upload(QString url,QJSValue callable,QMap<QString, QVariant> param
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString errorString = reply->errorString();
bool isSuccess = reply->error() == QNetworkReply::NoError;
_cache.removeOne(reply);
reply->deleteLater();
reply = nullptr;
if (isSuccess) {
@ -282,21 +426,16 @@ void FluHttp::upload(QString url,QJSValue callable,QMap<QString, QVariant> param
}else{
onError(callable,status,errorString,result);
}
onFinish(callable);
onFinish(callable,request);
});
}
QVariant FluHttp::invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method){
QMap<QString, QVariant> requet = {
{"params",params},
{"headers",headers},
{"method",method}
};
QVariant FluHttp::invokeIntercept(QMap<QString, QVariant> request){
if(!FluApp::getInstance()->httpInterceptor()){
return requet;
return request;
}
QVariant target;
QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, requet));
QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, request));
return target;
}
@ -320,54 +459,117 @@ void FluHttp::addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>&
}
}
void FluHttp::onStart(const QJSValue& callable){
MainThread::post([=](){
QJSValue onStart = callable.property("onStart");
onStart.call();
});
QString FluHttp::readCache(const QString& httpId){
auto filePath = getCacheFilePath(httpId);
QString result;
QFile file(filePath);
if(!file.exists()){
return result;
}
if (file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
result = FluTools::getInstance()->fromBase64(stream.readAll().toUtf8());
}
return result;
}
void FluHttp::onFinish(const QJSValue& callable){
MainThread::post([=](){
QJSValue onFinish = callable.property("onFinish");
onFinish.call();
});
bool FluHttp::cacheExists(const QString& httpId){
return QFile(getCacheFilePath(httpId)).exists();
}
void FluHttp::onError(const QJSValue& callable,int status,QString errorString,QString result){
MainThread::post([=](){
QJSValue onError = callable.property("onError");
QJSValueList args;
args<<status<<errorString<<result;
onError.call(args);
});
QString FluHttp::getCacheFilePath(const QString& httpId){
QDir dir = _cacheDir;
if (!dir.exists(_cacheDir)){
dir.mkpath(_cacheDir);
}
auto filePath = _cacheDir+"/"+httpId;
return filePath;
}
void FluHttp::onSuccess(const QJSValue& callable,QString result){
MainThread::post([=](){
QJSValueList args;
args<<result;
QJSValue onSuccess = callable.property("onSuccess");
onSuccess.call(args);
});
void FluHttp::handleCache(const QString& httpId,const QString& result){
if(_cacheMode==FluHttpType::CacheMode::NoCache){
return;
}
auto filePath = getCacheFilePath(httpId);
QSharedPointer<QFile> file(new QFile(filePath));
QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate;
if (!file->open(mode))
{
return;
}
file->write(FluTools::getInstance()->toBase64(result).toUtf8());
}
void FluHttp::onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total){
MainThread::post([=](){
QJSValueList args;
args<<static_cast<double>(recv);
args<<static_cast<double>(total);
QJSValue onDownloadProgress = callable.property("onDownloadProgress");
onDownloadProgress.call(args);
});
qreal FluHttp::getBreakPointProgress(HttpRequest* request){
request->method("download");
auto httpId = request->httpId();
QSharedPointer<QFile> file(new QFile(request->downloadSavePath()));
auto filePath = getCacheFilePath(httpId);
QSharedPointer<QFile> fileCache(new QFile(filePath));
if(fileCache->exists() && file->exists() && _breakPointDownload){
QJsonObject cacheInfo = QJsonDocument::fromJson(readCache(httpId).toUtf8()).object();
double fileSize = cacheInfo.value("fileSize").toDouble();
double contentLength = cacheInfo.value("contentLength").toDouble();
if(fileSize == contentLength && file->size() == contentLength){
return 1;
}
if(fileSize==file->size()){
return fileSize/contentLength;
}else{
return 0;
}
}else{
return 0;
}
}
void FluHttp::onUploadProgress(const QJSValue& callable,qint64 sent, qint64 total){
MainThread::post([=](){
QJSValueList args;
args<<static_cast<double>(sent);
args<<static_cast<double>(total);
QJSValue onUploadProgress = callable.property("onUploadProgress");
onUploadProgress.call(args);
});
HttpRequest* FluHttp::newRequest(QString url){
HttpRequest* request = new HttpRequest(this);
request->url(url);
return request;
}
void FluHttp::onStart(QPointer<HttpCallable> callable){
if(callable){
Q_EMIT callable->start();
}
}
void FluHttp::onFinish(QPointer<HttpCallable> callable,HttpRequest* request){
if(callable){
Q_EMIT callable->finish();
}
if(request->parent()->inherits("FluHttp")){
request->deleteLater();
}
}
void FluHttp::onError(QPointer<HttpCallable> callable,int status,QString errorString,QString result){
if(callable){
Q_EMIT callable->error(status,errorString,result);
}
}
void FluHttp::onSuccess(QPointer<HttpCallable> callable,QString result){
if(callable){
Q_EMIT callable->success(result);
}
}
void FluHttp::onCache(QPointer<HttpCallable> callable,QString result){
if(callable){
Q_EMIT callable->cache(result);
}
}
void FluHttp::onDownloadProgress(QPointer<HttpCallable> callable,qint64 recv,qint64 total){
if(callable){
Q_EMIT callable->downloadProgress(recv,total);
}
}
void FluHttp::onUploadProgress(QPointer<HttpCallable> callable,qint64 sent,qint64 total){
if(callable){
Q_EMIT callable->uploadProgress(sent,total);
}
}

View File

@ -7,36 +7,72 @@
#include <QNetworkAccessManager>
#include "stdafx.h"
class HttpRequest : public QObject{
Q_OBJECT
Q_PROPERTY_AUTO(QString,url);
Q_PROPERTY_AUTO(QVariant,params);
Q_PROPERTY_AUTO(QVariant,headers);
Q_PROPERTY_AUTO(QString,method);
Q_PROPERTY_AUTO(QString,downloadSavePath);
QML_NAMED_ELEMENT(HttpRequest)
public:
explicit HttpRequest(QObject *parent = nullptr);
QMap<QString, QVariant> toMap();
Q_INVOKABLE QString httpId();
};
class HttpCallable : public QObject{
Q_OBJECT
QML_NAMED_ELEMENT(HttpCallable)
public:
explicit HttpCallable(QObject *parent = nullptr);
Q_SIGNAL void start();
Q_SIGNAL void finish();
Q_SIGNAL void error(int status,QString errorString,QString result);
Q_SIGNAL void success(QString result);
Q_SIGNAL void cache(QString result);
Q_SIGNAL void downloadProgress(qint64 recv, qint64 total);
Q_SIGNAL void uploadProgress(qint64 sent, qint64 total);
};
class FluHttp : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(int,retry);
Q_PROPERTY_AUTO(int,timeout)
Q_PROPERTY_AUTO(int,cacheMode);
Q_PROPERTY_AUTO(QString,cacheDir);
Q_PROPERTY_AUTO(bool,breakPointDownload);
QML_NAMED_ELEMENT(FluHttp)
private:
QVariant invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method);
void handleReply(QNetworkReply* reply);
QVariant invokeIntercept(QMap<QString, QVariant> request);
void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params);
void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& params);
void onStart(const QJSValue& callable);
void onFinish(const QJSValue& callable);
void onError(const QJSValue& callable,int status,QString errorString,QString result);
void onSuccess(const QJSValue& callable,QString result);
void onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total);
void onUploadProgress(const QJSValue& callable,qint64 recv, qint64 total);
void handleCache(const QString& httpId, const QString& result);
QString readCache(const QString& httpId);
bool cacheExists(const QString& httpId);
QString getCacheFilePath(const QString& httpId);
void onStart(QPointer<HttpCallable> callable);
void onFinish(QPointer<HttpCallable> callable,HttpRequest* request);
void onError(QPointer<HttpCallable> callable,int status,QString errorString,QString result);
void onSuccess(QPointer<HttpCallable> callable,QString result);
void onCache(QPointer<HttpCallable> callable,QString result);
void onDownloadProgress(QPointer<HttpCallable> callable,qint64 recv,qint64 total);
void onUploadProgress(QPointer<HttpCallable> callable,qint64 sent,qint64 total);
public:
explicit FluHttp(QObject *parent = nullptr);
~FluHttp();
//神坑!!! 如果参数使用QVariantMap会有问题在6.4.3版本中QML一调用就会编译失败。所以改用QMap<QString, QVariant>
Q_INVOKABLE void get(QString url,QJSValue callable,QMap<QString, QVariant> params= {},QMap<QString, QVariant> headers = {});
Q_INVOKABLE void post(QString url,QJSValue callable,QMap<QString, QVariant> params= {},QMap<QString, QVariant> headers = {});
Q_INVOKABLE void postString(QString url,QJSValue callable,QString params = "",QMap<QString, QVariant> headers = {});
Q_INVOKABLE void postJson(QString url,QJSValue callable,QMap<QString, QVariant> params = {},QMap<QString, QVariant> headers = {});
Q_INVOKABLE void download(QString url,QJSValue callable,QString filePath,QMap<QString, QVariant> params = {},QMap<QString, QVariant> headers = {});
Q_INVOKABLE void upload(QString url,QJSValue callable,QMap<QString, QVariant> params = {},QMap<QString, QVariant> headers = {});
Q_INVOKABLE HttpRequest* newRequest(QString url = "");
Q_INVOKABLE void get(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE void post(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE void postString(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE void postJson(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE void download(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE void upload(HttpRequest* request,HttpCallable* callable);
Q_INVOKABLE qreal getBreakPointProgress(HttpRequest* request);
Q_INVOKABLE void cancel();
private:
QList<QPointer<QNetworkReply>> _cache;
QList<QPointer<QNetworkReply>> _cacheReply;
};
#endif // FLUHTTP_H

View File

@ -31,7 +31,7 @@ FluTheme::FluTheme(QObject *parent)
});
primaryColor(FluColors::getInstance()->Blue());
nativeText(false);
enableAnimation(false);
enableAnimation(true);
darkMode(FluThemeType::DarkMode::Light);
_systemDark = systemDark();
qApp->installEventFilter(this);

View File

@ -6,6 +6,9 @@
#include <QScreen>
#include <QColor>
#include <QFileInfo>
#include <QProcess>
#include <QDir>
#include <QCryptographicHash>
#include <QTextDocument>
FluTools* FluTools::m_instance = nullptr;
@ -128,3 +131,48 @@ QUrl FluTools::getUrlByFilePath(const QString& path){
QColor FluTools::colorAlpha(const QColor& color,qreal alpha){
return QColor(color.red(),color.green(),color.blue(),255*alpha);
}
QString FluTools::md5(QString text)
{
return QCryptographicHash::hash(text.toUtf8(), QCryptographicHash::Md5).toHex();
}
QString FluTools::toBase64(QString text)
{
return text.toUtf8().toBase64();
}
QString FluTools::fromBase64(QString text)
{
return QByteArray::fromBase64(text.toUtf8());
}
bool FluTools::removeDir(QString dirPath){
QDir qDir(dirPath);
return qDir.removeRecursively();
}
bool FluTools::removeFile(QString filePath){
QFile file(filePath);
return file.remove();
}
QString FluTools::sha256(QString text){
return QCryptographicHash::hash(text.toUtf8(), QCryptographicHash::Sha256).toHex();
}
void FluTools::showFileInFolder(QString path){
#if defined(Q_OS_WIN)
QProcess::startDetached("explorer.exe", {"/select,", QDir::toNativeSeparators(path)});
#endif
#if defined(Q_OS_LINUX)
QFileInfo fileInfo(path);
auto process = "xdg-open";
auto arguments = { fileInfo.absoluteDir().absolutePath() };
QProcess::startDetached(process, arguments);
#endif
#if defined(Q_OS_MACOS)
QProcess::execute("/usr/bin/osascript", {"-e", "tell application \"Finder\" to reveal POSIX file \"" + path + "\""});
QProcess::execute("/usr/bin/osascript", {"-e", "tell application \"Finder\" to activate"});
#endif
}

View File

@ -144,6 +144,55 @@ public:
*/
Q_INVOKABLE QColor colorAlpha(const QColor&,qreal alpha);
/**
* @brief md5
* @param text
* @return
*/
Q_INVOKABLE QString md5(QString text);
/**
* @brief sha256
* @param text
* @return
*/
Q_INVOKABLE QString sha256(QString text);
/**
* @brief toBase64
* @param text
* @return
*/
Q_INVOKABLE QString toBase64(QString text);
/**
* @brief fromBase64
* @param text
* @return
*/
Q_INVOKABLE QString fromBase64(QString text);
/**
* @brief removeDir
* @param dirPath
* @return
*/
Q_INVOKABLE bool removeDir(QString dirPath);
/**
* @brief removeFile
* @param filePath
* @return
*/
Q_INVOKABLE bool removeFile(QString filePath);
/**
* @brief showFileInFolder
* @param path
*/
Q_INVOKABLE void showFileInFolder(QString path);
};
#endif // FLUTOOLS_H

View File

@ -752,7 +752,12 @@ Item {
id:nav_stack2
anchors.fill: nav_stack
clip: true
visible: FluPageType.SingleInstance === nav_stack.currentItem.launchMode
visible: {
if(!nav_stack.currentItem){
return false
}
return FluPageType.SingleInstance === nav_stack.currentItem.launchMode
}
}
function navStack(){
return nav_stack

View File

@ -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)
}
}
}
}
}

View File

@ -26,7 +26,7 @@ Item{
Component{
id:com_screen
Window{
property bool isZeroPos: screenshot.start == Qt.point(0,0) && screenshot.end == Qt.point(0,0)
property bool isZeroPos: screenshot.start.x === 0 && screenshot.start.y === 0 && screenshot.end.x === 0 && screenshot.end.y === 0
id:window_screen
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
x:-1
@ -41,7 +41,7 @@ Item{
}
}
Component.onCompleted: {
setGeometry(0,0,screenshot_background.width,screenshot_background.height)
setGeometry(0,0,screenshot_background.width,screenshot_background.height+1)
}
ScreenshotBackground{
id:screenshot_background
@ -123,7 +123,7 @@ Item{
MouseArea{
property point clickPos: Qt.point(0,0)
anchors.fill: parent
cursorShape: Qt.SizeAllCursor
cursorShape: d.isEdit ? Qt.ArrowCursor : Qt.SizeAllCursor
onPressed:
(mouse)=>{
clickPos = Qt.point(mouse.x, mouse.y)
@ -134,7 +134,7 @@ Item{
var w = Math.abs(screenshot.end.x - screenshot.start.x)
var h = Math.abs(screenshot.end.y - screenshot.start.y)
var x = Math.min(Math.max(rect_capture.x + delta.x,0),window_screen.width-w)
var y =Math.min(Math.max(rect_capture.y + delta.y,0),window_screen.height-h)
var y = Math.min(Math.max(rect_capture.y + delta.y,0),window_screen.height-h)
screenshot.start = Qt.point(x,y)
screenshot.end = Qt.point(x+w,y+h)
}
@ -477,7 +477,7 @@ Item{
width: 100
height: 40
visible: {
if(screenshot.start === Qt.point(0,0) && screenshot.end === Qt.point(0,0)){
if(isZeroPos){
return false
}
if(d.enablePosition){

View File

@ -52,7 +52,7 @@ Button {
border.width: checked ? 0 : 1
FluFocusRectangle{
visible: control.activeFocus
radius:8
radius:4
}
color:{
if(!enabled){

View File

@ -96,24 +96,22 @@ Popup{
ctx.globalCompositeOperation = 'destination-out'
ctx.fillStyle = 'black'
var rect = Qt.rect(d.pos.x-control.targetMargins,d.pos.y-control.targetMargins, d.target.width+control.targetMargins*2, d.target.height+control.targetMargins*2)
ctx.fillRect(rect.x,rect.y,rect.width,rect.height)
drawRoundedRect(rect,2,ctx)
ctx.restore()
}
//Todo
function drawRoundedRect(rect, r, ctx) {
var ptA = Qt.point(rect.x + r, rect.y)
var ptB = Qt.point(rect.x + rect.width, rect.y)
var ptC = Qt.point(rect.x + rect.width, rect.y + rect.height)
var ptD = Qt.point(rect.x, rect.y + rect.height)
var ptE = Qt.point(rect.x, rect.y)
ctx.beginPath()
ctx.moveTo(ptA.x, ptA.y)
ctx.arcTo(ptB.x, ptB.y, ptC.x, ptC.y, r)
ctx.arcTo(ptC.x, ptC.y, ptD.x, ptD.y, r)
ctx.arcTo(ptD.x, ptD.y, ptE.x, ptE.y, r)
ctx.arcTo(ptE.x, ptE.y, ptA.x, ptA.y, r)
ctx.beginPath();
ctx.moveTo(rect.x + r, rect.y);
ctx.lineTo(rect.x + rect.width - r, rect.y);
ctx.arcTo(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + r, r);
ctx.lineTo(rect.x + rect.width, rect.y + rect.height - r);
ctx.arcTo(rect.x + rect.width, rect.y + rect.height, rect.x + rect.width - r, rect.y + rect.height, r);
ctx.lineTo(rect.x + r, rect.y + rect.height);
ctx.arcTo(rect.x, rect.y + rect.height, rect.x, rect.y + rect.height - r, r);
ctx.lineTo(rect.x, rect.y + r);
ctx.arcTo(rect.x, rect.y, rect.x + r, rect.y, r);
ctx.closePath();
ctx.fill()
ctx.closePath()
}
}
FluArea{

View File

@ -69,6 +69,8 @@ Window {
id:popup_loading
modal:true
focus: true
width: window.width
height: window.height
anchors.centerIn: Overlay.overlay
closePolicy: {
if(cancel){
@ -76,17 +78,38 @@ Window {
}
return Popup.NoAutoClose
}
Overlay.modal: Rectangle {
color: "#44000000"
}
Overlay.modal: Item {}
onVisibleChanged: {
if(!visible){
loader_loading.sourceComponent = undefined
}
}
visible: true
background: Item{}
padding: 0
opacity: 0
visible:true
Behavior on opacity {
SequentialAnimation {
PauseAnimation {
duration: 88
}
NumberAnimation{
duration: 167
}
}
}
Component.onCompleted: {
opacity = 1
}
background: Rectangle{
color:"#44000000"
}
contentItem: Item{
MouseArea{
anchors.fill: parent
onClicked: {
popup_loading.visible = false
}
}
ColumnLayout{
spacing: 8
anchors.centerIn: parent

View File

@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
// 'qmlplugindump -nonrelocatable FluentUI 1.0 D:/QtProjects/build-FluentUI-Desktop_Qt_5_15_2_MSVC2019_64bit-Release/src'
// 'qmlplugindump -nonrelocatable FluentUI 1.0 D:\QtProjects\build-FluentUI-Desktop_Qt_5_15_2_MSVC2019_64bit-Release\src'
Module {
dependencies: ["QtQuick 2.0"]
@ -70,116 +70,49 @@ Module {
exportMetaObjectRevisions: [0]
Property { name: "retry"; type: "int" }
Property { name: "timeout"; type: "int" }
Property { name: "cacheMode"; type: "int" }
Property { name: "cacheDir"; type: "string" }
Property { name: "breakPointDownload"; type: "bool" }
Method {
name: "get"
name: "newRequest"
type: "HttpRequest*"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
Parameter { name: "headers"; type: "QVariantMap" }
}
Method { name: "newRequest"; type: "HttpRequest*" }
Method {
name: "get"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
}
Method {
name: "get"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "post"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
Parameter { name: "headers"; type: "QVariantMap" }
}
Method {
name: "post"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
}
Method {
name: "post"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "postString"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "string" }
Parameter { name: "headers"; type: "QVariantMap" }
}
Method {
name: "postString"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "string" }
}
Method {
name: "postString"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "postJson"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
Parameter { name: "headers"; type: "QVariantMap" }
}
Method {
name: "postJson"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
}
Method {
name: "postJson"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "download"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "filePath"; type: "string" }
Parameter { name: "params"; type: "QVariantMap" }
Parameter { name: "headers"; type: "QVariantMap" }
}
Method {
name: "download"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "filePath"; type: "string" }
Parameter { name: "params"; type: "QVariantMap" }
}
Method {
name: "download"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "filePath"; type: "string" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "upload"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
Parameter { name: "headers"; type: "QVariantMap" }
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
}
Method {
name: "upload"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
Parameter { name: "params"; type: "QVariantMap" }
}
Method {
name: "upload"
Parameter { name: "url"; type: "string" }
Parameter { name: "callable"; type: "QJSValue" }
name: "getBreakPointProgress"
type: "double"
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
}
Method { name: "cancel" }
}
@ -189,6 +122,21 @@ Module {
exports: ["FluentUI/FluHttpInterceptor 1.0"]
exportMetaObjectRevisions: [0]
}
Component {
name: "FluHttpType"
exports: ["FluentUI/FluHttpType 1.0"]
isCreatable: false
exportMetaObjectRevisions: [0]
Enum {
name: "CacheMode"
values: {
"NoCache": 0,
"RequestFailedReadCache": 1,
"IfNoneCacheRequest": 2,
"FirstCacheThenRequest": 4
}
}
}
Component {
name: "FluNavigationViewType"
exports: ["FluentUI/FluNavigationViewType 1.0"]
@ -226,7 +174,7 @@ Module {
}
}
}
Component {
Component {
name: "FluScreenshotType"
exports: ["FluentUI/FluScreenshotType 1.0"]
isCreatable: false
@ -238,20 +186,6 @@ Module {
"File": 1
}
}
}
Component {
name: "FluTimelineType"
exports: ["FluentUI/FluTimelineType 1.0"]
isCreatable: false
exportMetaObjectRevisions: [0]
Enum {
name: "Mode"
values: {
"Left": 0,
"Right": 1,
"Alternate": 2
}
}
}
Component {
name: "FluStatusViewType"
@ -317,6 +251,20 @@ Module {
}
}
}
Component {
name: "FluTimelineType"
exports: ["FluentUI/FluTimelineType 1.0"]
isCreatable: false
exportMetaObjectRevisions: [0]
Enum {
name: "Mode"
values: {
"Left": 0,
"Right": 1,
"Alternate": 2
}
}
}
Component {
name: "FluTreeViewType"
exports: ["FluentUI/FluTreeViewType 1.0"]
@ -1772,6 +1720,50 @@ Module {
}
}
}
Component {
name: "HttpCallable"
prototype: "QObject"
exports: ["FluentUI/HttpCallable 1.0"]
exportMetaObjectRevisions: [0]
Signal { name: "start" }
Signal { name: "finish" }
Signal {
name: "error"
Parameter { name: "status"; type: "int" }
Parameter { name: "errorString"; type: "string" }
Parameter { name: "result"; type: "string" }
}
Signal {
name: "success"
Parameter { name: "result"; type: "string" }
}
Signal {
name: "cache"
Parameter { name: "result"; type: "string" }
}
Signal {
name: "downloadProgress"
Parameter { name: "recv"; type: "qlonglong" }
Parameter { name: "total"; type: "qlonglong" }
}
Signal {
name: "uploadProgress"
Parameter { name: "sent"; type: "qlonglong" }
Parameter { name: "total"; type: "qlonglong" }
}
}
Component {
name: "HttpRequest"
prototype: "QObject"
exports: ["FluentUI/HttpRequest 1.0"]
exportMetaObjectRevisions: [0]
Property { name: "url"; type: "string" }
Property { name: "params"; type: "QVariant" }
Property { name: "headers"; type: "QVariant" }
Property { name: "method"; type: "string" }
Property { name: "downloadSavePath"; type: "string" }
Method { name: "httpId"; type: "string" }
}
Component {
name: "QRCode"
defaultProperty: "data"

View File

@ -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

View File

@ -753,7 +753,12 @@ Item {
id:nav_stack2
anchors.fill: nav_stack
clip: true
visible: FluPageType.SingleInstance === nav_stack.currentItem.launchMode
visible: {
if(!nav_stack.currentItem){
return false
}
return FluPageType.SingleInstance === nav_stack.currentItem.launchMode
}
}
function navStack(){
return nav_stack

View File

@ -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)
}
}
}
}
}

View File

@ -26,7 +26,7 @@ Item{
Component{
id:com_screen
Window{
property bool isZeroPos: screenshot.start === Qt.point(0,0) && screenshot.end === Qt.point(0,0)
property bool isZeroPos: screenshot.start.x === 0 && screenshot.start.y === 0 && screenshot.end.x === 0 && screenshot.end.y === 0
id:window_screen
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
x:-1
@ -41,7 +41,7 @@ Item{
}
}
Component.onCompleted: {
setGeometry(0,0,screenshot_background.width,screenshot_background.height)
setGeometry(0,0,screenshot_background.width,screenshot_background.height+1)
}
ScreenshotBackground{
id:screenshot_background
@ -123,7 +123,7 @@ Item{
MouseArea{
property point clickPos: Qt.point(0,0)
anchors.fill: parent
cursorShape: Qt.SizeAllCursor
cursorShape: d.isEdit ? Qt.ArrowCursor : Qt.SizeAllCursor
onPressed:
(mouse)=>{
clickPos = Qt.point(mouse.x, mouse.y)
@ -134,7 +134,7 @@ Item{
var w = Math.abs(screenshot.end.x - screenshot.start.x)
var h = Math.abs(screenshot.end.y - screenshot.start.y)
var x = Math.min(Math.max(rect_capture.x + delta.x,0),window_screen.width-w)
var y =Math.min(Math.max(rect_capture.y + delta.y,0),window_screen.height-h)
var y = Math.min(Math.max(rect_capture.y + delta.y,0),window_screen.height-h)
screenshot.start = Qt.point(x,y)
screenshot.end = Qt.point(x+w,y+h)
}
@ -477,7 +477,7 @@ Item{
width: 100
height: 40
visible: {
if(screenshot.start === Qt.point(0,0) && screenshot.end === Qt.point(0,0)){
if(isZeroPos){
return false
}
if(d.enablePosition){

View File

@ -48,7 +48,7 @@ Button {
border.width: checked ? 0 : 1
FluFocusRectangle{
visible: control.activeFocus
radius:8
radius:4
}
color:{
if(!enabled){

View File

@ -89,19 +89,18 @@ Popup{
ctx.restore()
}
function drawRoundedRect(rect, r, ctx) {
var ptA = Qt.point(rect.x + r, rect.y)
var ptB = Qt.point(rect.x + rect.width, rect.y)
var ptC = Qt.point(rect.x + rect.width, rect.y + rect.height)
var ptD = Qt.point(rect.x, rect.y + rect.height)
var ptE = Qt.point(rect.x, rect.y)
ctx.beginPath()
ctx.moveTo(ptA.x, ptA.y)
ctx.arcTo(ptB.x, ptB.y, ptC.x, ptC.y, r)
ctx.arcTo(ptC.x, ptC.y, ptD.x, ptD.y, r)
ctx.arcTo(ptD.x, ptD.y, ptE.x, ptE.y, r)
ctx.arcTo(ptE.x, ptE.y, ptA.x, ptA.y, r)
ctx.beginPath();
ctx.moveTo(rect.x + r, rect.y);
ctx.lineTo(rect.x + rect.width - r, rect.y);
ctx.arcTo(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + r, r);
ctx.lineTo(rect.x + rect.width, rect.y + rect.height - r);
ctx.arcTo(rect.x + rect.width, rect.y + rect.height, rect.x + rect.width - r, rect.y + rect.height, r);
ctx.lineTo(rect.x + r, rect.y + rect.height);
ctx.arcTo(rect.x, rect.y + rect.height, rect.x, rect.y + rect.height - r, r);
ctx.lineTo(rect.x, rect.y + r);
ctx.arcTo(rect.x, rect.y, rect.x + r, rect.y, r);
ctx.closePath();
ctx.fill()
ctx.closePath()
}
}
FluArea{

View File

@ -68,6 +68,8 @@ Window {
id:popup_loading
modal:true
focus: true
width: window.width
height: window.height
anchors.centerIn: Overlay.overlay
closePolicy: {
if(cancel){
@ -75,17 +77,38 @@ Window {
}
return Popup.NoAutoClose
}
Overlay.modal: Rectangle {
color: "#44000000"
}
Overlay.modal: Item {}
onVisibleChanged: {
if(!visible){
loader_loading.sourceComponent = undefined
}
}
visible: true
background: Item{}
padding: 0
opacity: 0
visible:true
Behavior on opacity {
SequentialAnimation {
PauseAnimation {
duration: 88
}
NumberAnimation{
duration: 167
}
}
}
Component.onCompleted: {
opacity = 1
}
background: Rectangle{
color:"#44000000"
}
contentItem: Item{
MouseArea{
anchors.fill: parent
onClicked: {
popup_loading.visible = false
}
}
ColumnLayout{
spacing: 8
anchors.centerIn: parent

View File

@ -9,10 +9,11 @@
#include "Def.h"
Screenshot::Screenshot(QQuickItem* parent) : QQuickPaintedItem(parent)
{
_desktopGeometry = qApp->primaryScreen()->virtualGeometry();
maskColor(QColor(0,0,0,80));
maskColor(QColor(0,0,0,150));
start(QPoint(0,0));
end(QPoint(0,0));
connect(this,&Screenshot::startChanged,this,[=]{update();});
@ -53,6 +54,7 @@ void ScreenshotBackground::paint(QPainter* painter)
}
void ScreenshotBackground::capture(const QPoint& start,const QPoint& end){
update();
auto pixelRatio = qApp->primaryScreen()->devicePixelRatio();
auto x = qMin(start.x(),end.x()) * pixelRatio;
auto y = qMin(start.y(),end.y()) * pixelRatio;
@ -72,4 +74,3 @@ void ScreenshotBackground::capture(const QPoint& start,const QPoint& end){
Q_EMIT captrueToFileCompleted(QUrl::fromLocalFile(filePath));
}
}

View File

@ -6,6 +6,7 @@
#include <QPainter>
#include <QQuickItemGrabResult>
#include "stdafx.h"
#include <qmath.h>
class ScreenshotBackground : public QQuickPaintedItem
{

View File

@ -38,7 +38,10 @@ void FluentUIPlugin::registerTypes(const char *uri)
qmlRegisterType<FluColorSet>(uri,major,minor,"FluColorSet");
qmlRegisterType<FluHttpInterceptor>(uri,major,minor,"FluHttpInterceptor");
qmlRegisterType<FluHttp>(uri,major,minor,"FluHttp");
qmlRegisterType<HttpCallable>(uri,major,minor,"HttpCallable");
qmlRegisterType<HttpRequest>(uri,major,minor,"HttpRequest");
qmlRegisterUncreatableMetaObject(Fluent_Awesome::staticMetaObject, uri,major,minor,"FluentIcons", "Access to enums & flags only");
qmlRegisterUncreatableMetaObject(FluHttpType::staticMetaObject, uri,major,minor,"FluHttpType", "Access to enums & flags only");
qmlRegisterUncreatableMetaObject(FluThemeType::staticMetaObject, uri,major,minor,"FluThemeType", "Access to enums & flags only");
qmlRegisterUncreatableMetaObject(FluPageType::staticMetaObject, uri,major,minor,"FluPageType", "Access to enums & flags only");
qmlRegisterUncreatableMetaObject(FluWindowType::staticMetaObject, uri,major,minor,"FluWindowType", "Access to enums & flags only");

View File

@ -94,5 +94,6 @@
<file>Qt5/imports/FluentUI/Controls/ColorPicker/Content/SBPicker.qml</file>
<file>Qt5/imports/FluentUI/Controls/FluRangeSlider.qml</file>
<file>Qt5/imports/FluentUI/Controls/FluStaggeredView.qml</file>
<file>Qt5/imports/FluentUI/Controls/FluProgressButton.qml</file>
</qresource>
</RCC>