mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2025-07-01 15:42:20 +08:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
bc0c36772f | |||
46148b3c5c | |||
b4f2f68135 | |||
5d4cfa5286 | |||
ee23554cb4 | |||
a9772a8fb0 | |||
2428a38194 | |||
1a21cd7b31 | |||
bcc47c1496 | |||
95a6be3d28 | |||
9a48880e84 | |||
4f60459166 | |||
29749a5761 | |||
1b3344e9f9 | |||
394d0ab244 | |||
6a925bdad3 | |||
6999067a80 | |||
1047fac4d6 | |||
3b2982a95e | |||
e37d47f629 | |||
d07383ba46 | |||
ce3da2e92f | |||
2e8be5f133 | |||
8662eb97aa | |||
55a77eba4b | |||
5dd3320f66 | |||
3b4c327528 | |||
412842d844 | |||
2242ffc367 | |||
d485ec9e3b | |||
05251e085c | |||
78f5dd0a61 | |||
2f3ed2bd0f | |||
35d85aa801 | |||
542ea0a7b9 | |||
b981ecca7d | |||
a7552e2b5c | |||
637a0f312e | |||
5d11064011 |
@ -58,8 +58,8 @@ if (${QMLPLUGIN_LIBTYPE} MATCHES "SHARED")
|
||||
set(INSTALL_QMLDIR_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/Qt5/${QMLPLUGIN_QMLDIR}/qmldir ${QMLPLUGIN_BINARY_DIR}/qmldir)
|
||||
set(COPY_QMLTYPES_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/Qt5/${QMLPLUGIN_QMLDIR}/plugins.qmltypes $<TARGET_FILE_DIR:${TARGET}>/${QMLPLUGIN_URI}/plugins.qmltypes)
|
||||
set(INSTALL_QMLTYPES_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/Qt5/${QMLPLUGIN_QMLDIR}/plugins.qmltypes ${QMLPLUGIN_BINARY_DIR}/plugins.qmltypes)
|
||||
set(COPY_LIBRARY_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/$<TARGET_FILE_NAME:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${QMLPLUGIN_URI})
|
||||
set(INSTALL_LIBRARY_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/$<TARGET_FILE_NAME:${TARGET}> ${QMLPLUGIN_BINARY_DIR})
|
||||
set(COPY_LIBRARY_COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE_DIR:${TARGET}>/$<TARGET_FILE_NAME:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${QMLPLUGIN_URI})
|
||||
set(INSTALL_LIBRARY_COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE_DIR:${TARGET}>/$<TARGET_FILE_NAME:${TARGET}> ${QMLPLUGIN_BINARY_DIR})
|
||||
if(QMLPLUGIN_QMLDIR)
|
||||
set(COPY_QMLFILES_COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/Qt5/${QMLPLUGIN_QMLDIR} $<TARGET_FILE_DIR:${TARGET}>/${QMLPLUGIN_URI})
|
||||
else()
|
||||
|
@ -18,9 +18,9 @@ endif()
|
||||
|
||||
#设置可执行文件输出目录
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FLUENTUI_DIRECTORY}/bin/debug)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${FLUENTUI_DIRECTORY}/bin/debug>)
|
||||
else()
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FLUENTUI_DIRECTORY}/bin/release)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${FLUENTUI_DIRECTORY}/bin/release>)
|
||||
endif()
|
||||
|
||||
#获取文件路径分隔符(解决执行命令的时候有些平台会报错)
|
||||
|
@ -143,7 +143,6 @@
|
||||
<file>qml/page/T_Expander.qml</file>
|
||||
<file>qml/page/T_FlipView.qml</file>
|
||||
<file>qml/page/T_Home.qml</file>
|
||||
<file>qml/page/T_Http.qml</file>
|
||||
<file>qml/page/T_Image.qml</file>
|
||||
<file>qml/page/T_InfoBar.qml</file>
|
||||
<file>qml/page/T_Menu.qml</file>
|
||||
@ -189,5 +188,7 @@
|
||||
<file>qml/page/T_Clip.qml</file>
|
||||
<file>qml/page/T_3D.qml</file>
|
||||
<file>qml/global/Lang.qml</file>
|
||||
<file>qml/page/T_Network.qml</file>
|
||||
<file>qml/page/T_ShortcutPicker.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -19,26 +19,17 @@ Item {
|
||||
function onVsyncChanged(){
|
||||
SettingsHelper.saveVsync(FluApp.vsync)
|
||||
}
|
||||
}
|
||||
|
||||
FluHttpInterceptor{
|
||||
id:interceptor
|
||||
function onIntercept(request){
|
||||
if(request.method === "get"){
|
||||
request.params["method"] = "get"
|
||||
}
|
||||
if(request.method === "post"){
|
||||
request.params["method"] = "post"
|
||||
}
|
||||
request.headers["token"] ="yyds"
|
||||
request.headers["os"] ="pc"
|
||||
console.debug(JSON.stringify(request))
|
||||
return request
|
||||
function onUseSystemAppBarChanged(){
|
||||
SettingsHelper.saveUseSystemAppBar(FluApp.useSystemAppBar)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
FluNetwork.setInterceptor(function(param){
|
||||
param.addHeader("Token","000000000000000000000")
|
||||
})
|
||||
FluApp.init(app)
|
||||
FluApp.useSystemAppBar = SettingsHelper.getUseSystemAppBar()
|
||||
FluApp.vsync = SettingsHelper.getVsync()
|
||||
FluTheme.darkMode = SettingsHelper.getDarkMode()
|
||||
FluTheme.enableAnimation = true
|
||||
@ -53,7 +44,6 @@ Item {
|
||||
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
|
||||
}
|
||||
FluApp.initialRoute = "/"
|
||||
FluApp.httpInterceptor = interceptor
|
||||
FluApp.run()
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,6 @@ FluExpander{
|
||||
"FluRadioButtons",
|
||||
"FluImage",
|
||||
"FluSpinBox",
|
||||
"FluHttp",
|
||||
"FluWatermark",
|
||||
"FluTour",
|
||||
"FluQRCode",
|
||||
@ -140,7 +139,9 @@ FluExpander{
|
||||
"FluStaggeredView",
|
||||
"FluProgressButton",
|
||||
"FluLoadingButton",
|
||||
"FluClip"
|
||||
"FluClip",
|
||||
"FluNetwork",
|
||||
"FluShortcutPicker"
|
||||
];
|
||||
code = code.replace(/\n/g, "<br>");
|
||||
code = code.replace(/ /g, " ");
|
||||
|
@ -150,6 +150,12 @@ FluObject{
|
||||
url:"qrc:/example/qml/page/T_ColorPicker.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
title:"ShortcutPicker"
|
||||
menuDelegate: paneItemMenu
|
||||
url:"qrc:/example/qml/page/T_ShortcutPicker.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItemExpander{
|
||||
@ -407,9 +413,9 @@ FluObject{
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
title:"Http"
|
||||
title:"Network"
|
||||
menuDelegate: paneItemMenu
|
||||
url:"qrc:/example/qml/page/T_Http.qml"
|
||||
url:"qrc:/example/qml/page/T_Network.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
|
@ -43,6 +43,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
placeholderText: "请输入验证码"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
FluButton{
|
||||
text:"verify"
|
||||
|
@ -115,4 +115,68 @@ FluScrollablePage{
|
||||
showSuccess("点击最小化按钮")
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
height: 68
|
||||
paddings: 10
|
||||
Layout.topMargin: 20
|
||||
FluButton{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Layout.topMargin: 20
|
||||
text:"Custom Content Dialog"
|
||||
onClicked: {
|
||||
custom_btn_dialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
CodeExpander{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -1
|
||||
code:'FluContentDialog{
|
||||
id:dialog
|
||||
title:"友情提示"
|
||||
message:"数据正在加载中,请稍等..."
|
||||
negativeText:"取消加载"
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 80
|
||||
FluProgressRing{
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
onNegativeClicked:{
|
||||
showSuccess("点击取消按钮")
|
||||
}
|
||||
positiveText:"确定"
|
||||
onPositiveClicked:{
|
||||
showSuccess("点击确定按钮")
|
||||
}
|
||||
dialog.open()'
|
||||
}
|
||||
|
||||
FluContentDialog{
|
||||
id:custom_btn_dialog
|
||||
title:"友情提示"
|
||||
message:"数据正在加载中,请稍等..."
|
||||
negativeText:"取消加载"
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 80
|
||||
FluProgressRing{
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
onNegativeClicked:{
|
||||
showSuccess("点击取消按钮")
|
||||
}
|
||||
positiveText:"确定"
|
||||
onPositiveClicked:{
|
||||
showSuccess("点击确定按钮")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,405 +0,0 @@
|
||||
import QtQuick
|
||||
import Qt.labs.platform
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Dialogs
|
||||
import FluentUI
|
||||
import "qrc:///example/qml/component"
|
||||
|
||||
FluContentPage{
|
||||
|
||||
title:"Http"
|
||||
property string cacheDirPath: StandardPaths.writableLocation(StandardPaths.AppLocalDataLocation) + "/cache/http"
|
||||
property bool isDownCompleted: false
|
||||
|
||||
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: 200
|
||||
clip: true
|
||||
anchors{
|
||||
top: parent.top
|
||||
topMargin: 20
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
contentHeight:layout_column.height
|
||||
Column{
|
||||
spacing: 2
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Get请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/get")
|
||||
http.get(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post表单请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/post")
|
||||
var params = {}
|
||||
params.custname = "朱子楚"
|
||||
params.custtel = "1234567890"
|
||||
params.custemail = "zhuzichu520@gmail.com"
|
||||
request.params = params
|
||||
var headers = {}
|
||||
headers.test = "123456789456465321354"
|
||||
request.headers = headers
|
||||
http.post(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Json请求"
|
||||
onClicked: {
|
||||
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{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post String请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/post")
|
||||
request.params = "我命由我不由天"
|
||||
http.postString(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/delete")
|
||||
http.deleteResource(request,callable)
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "下载文件"
|
||||
onClicked: {
|
||||
folder_dialog.open()
|
||||
}
|
||||
}
|
||||
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)=>{
|
||||
if(!isDownCompleted){
|
||||
tour.open()
|
||||
isDownCompleted = true
|
||||
}
|
||||
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
|
||||
text: "文件上传"
|
||||
onClicked: {
|
||||
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(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 = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluTour{
|
||||
id:tour
|
||||
steps:[
|
||||
{title:"友情提示",description: "下载已完成,左击这里可以打开文件所在路径,右击可以弹出菜单删除文件!",target:()=>btn_breakpoint_download}
|
||||
]
|
||||
}
|
||||
|
||||
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 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)
|
||||
params[fileName] = filePath
|
||||
}
|
||||
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 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
|
||||
bottom: layout_flick.bottom
|
||||
left: layout_flick.right
|
||||
right: parent.right
|
||||
leftMargin: 8
|
||||
}
|
||||
Flickable{
|
||||
clip: true
|
||||
id:scrollview
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentWidth: width
|
||||
contentHeight: text_info.height
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
id:text_info
|
||||
width: scrollview.width
|
||||
wrapMode: Text.WrapAnywhere
|
||||
padding: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
531
example/qml-Qt6/page/T_Network.qml
Normal file
531
example/qml-Qt6/page/T_Network.qml
Normal file
@ -0,0 +1,531 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import QtQuick.Controls
|
||||
import FluentUI
|
||||
import Qt.labs.platform
|
||||
import "qrc:///example/qml/component"
|
||||
|
||||
FluContentPage{
|
||||
|
||||
id:root
|
||||
title:"Network"
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable
|
||||
onStart: {
|
||||
showLoading()
|
||||
}
|
||||
onFinish: {
|
||||
hideLoading()
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onCache:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
}
|
||||
|
||||
Flickable{
|
||||
id:layout_flick
|
||||
width: 200
|
||||
clip: true
|
||||
anchors{
|
||||
top: parent.top
|
||||
topMargin: 20
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
contentHeight:layout_column.height
|
||||
Column{
|
||||
spacing: 2
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Get"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.get("https://httpbingo.org/get")
|
||||
.addQuery("name","孙悟空")
|
||||
.addQuery("age",500)
|
||||
.addQuery("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postBody("https://httpbingo.org/post")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postForm("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJsonArray("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putBody("https://httpbingo.org/put")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putForm("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putJson("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putJsonArray("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchBody("https://httpbingo.org/patch")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchForm("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchJson("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchJsonArray("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteBody("https://httpbingo.org/delete")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteForm("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteJson("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteJsonArray("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Custom Header"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.addHeader("os","PC")
|
||||
.addHeader("version","1.0.0")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "RequestFailedReadCache"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.RequestFailedReadCache)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","RequestFailedReadCache")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "IfNoneCacheRequest"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.IfNoneCacheRequest)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","IfNoneCacheRequest")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "FirstCacheThenRequest"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.FirstCacheThenRequest)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","FirstCacheThenRequest")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Timeout And Retry"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setTimeout(5000)
|
||||
.setRetry(3)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("timeout","5000")
|
||||
.add("retry","3")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_upload
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Upload File"
|
||||
onClicked: {
|
||||
file_dialog.open()
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Download File"
|
||||
onClicked: {
|
||||
folder_dialog.showDialog(function(path){
|
||||
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
|
||||
.toDownload(path)
|
||||
.bind(root)
|
||||
.go(callable_download_file)
|
||||
})
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download_breakpoint
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Breakpoint Download File"
|
||||
onClicked: {
|
||||
folder_dialog.showDialog(function(path){
|
||||
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
|
||||
.toDownload(path,true)
|
||||
.bind(root)
|
||||
.go(callable_breakpoint_download_file)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_upload_file
|
||||
onStart: {
|
||||
btn_upload.disabled = true
|
||||
}
|
||||
onFinish: {
|
||||
btn_upload.disabled = false
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
btn_upload.progress = 0
|
||||
text_info.text = result
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
onUploadProgress:
|
||||
(sent,total)=>{
|
||||
btn_upload.progress = sent/total
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_download_file
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_breakpoint_download_file
|
||||
onStart: {
|
||||
btn_download_breakpoint.progress = 0
|
||||
btn_download_breakpoint.disabled = true
|
||||
}
|
||||
onFinish: {
|
||||
btn_download_breakpoint.disabled = false
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
btn_download_breakpoint.progress = 0
|
||||
showError(errorString)
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
showSuccess(result)
|
||||
}
|
||||
onDownloadProgress:
|
||||
(recv,total)=>{
|
||||
btn_download_breakpoint.progress = recv/total
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: file_dialog
|
||||
onAccepted: {
|
||||
FluNetwork.postForm("https://httpbingo.org/post")
|
||||
.setRetry(1)//只请求一次
|
||||
.add("accessToken","12345678")
|
||||
.addFile("file",FluTools.toLocalPath(file_dialog.currentFile))
|
||||
.bind(root)
|
||||
.go(callable_upload_file)
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
property var onSelectListener
|
||||
id: folder_dialog
|
||||
folder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
|
||||
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/big_buck_bunny.mp4"
|
||||
fileMode: FileDialog.SaveFile
|
||||
onAccepted: {
|
||||
folder_dialog.onSelectListener(FluTools.toLocalPath(folder_dialog.currentFile))
|
||||
}
|
||||
function showDialog(listener){
|
||||
folder_dialog.onSelectListener = listener
|
||||
folder_dialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
anchors{
|
||||
top: layout_flick.top
|
||||
bottom: layout_flick.bottom
|
||||
left: layout_flick.right
|
||||
right: parent.right
|
||||
leftMargin: 8
|
||||
}
|
||||
Flickable{
|
||||
clip: true
|
||||
id:scrollview
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentWidth: width
|
||||
contentHeight: text_info.height
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
id:text_info
|
||||
width: scrollview.width
|
||||
wrapMode: Text.WrapAnywhere
|
||||
padding: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"会磨刀的小猪"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,36 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 50
|
||||
paddings: 10
|
||||
FluCheckBox{
|
||||
text:"Use System AppBar"
|
||||
checked: FluApp.useSystemAppBar
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
FluApp.useSystemAppBar = !FluApp.useSystemAppBar
|
||||
dialog_restart.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 50
|
||||
paddings: 10
|
||||
FluCheckBox{
|
||||
text:"fitsAppBarWindows"
|
||||
checked: window.fitsAppBarWindows
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
window.fitsAppBarWindows = !window.fitsAppBarWindows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
@ -199,5 +229,4 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
30
example/qml-Qt6/page/T_ShortcutPicker.qml
Normal file
30
example/qml-Qt6/page/T_ShortcutPicker.qml
Normal file
@ -0,0 +1,30 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import FluentUI
|
||||
import "qrc:///example/qml/component"
|
||||
|
||||
FluScrollablePage{
|
||||
|
||||
title:"ShortcutPicker"
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 100
|
||||
paddings: 10
|
||||
FluShortcutPicker{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
CodeExpander{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -1
|
||||
code:'FluShortcutPicker{
|
||||
|
||||
}'
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"Technical testing 2015-09-01"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
FluFilledButton{
|
||||
text:"Append"
|
||||
|
@ -29,6 +29,7 @@ FluContentPage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"会磨刀的小猪"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,16 @@ FluWindow {
|
||||
minimumWidth: 520
|
||||
minimumHeight: 200
|
||||
launchMode: FluWindowType.SingleTask
|
||||
appBar: undefined
|
||||
fitsAppBarWindows: true
|
||||
appBar: FluAppBar {
|
||||
width: window.width
|
||||
height: 30
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
z:7
|
||||
}
|
||||
|
||||
SettingsViewModel{
|
||||
id:viewmodel_settings
|
||||
@ -32,8 +41,11 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
onFirstVisible: {
|
||||
tour.open()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
checkUpdate(true)
|
||||
FluEventBus.registerEvent(event_checkupdate)
|
||||
}
|
||||
@ -65,15 +77,23 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Timer{
|
||||
id:timer_window_hide_delay
|
||||
interval: 150
|
||||
onTriggered: {
|
||||
window.hide()
|
||||
}
|
||||
}
|
||||
|
||||
FluContentDialog{
|
||||
id:dialog_close
|
||||
title:"退出"
|
||||
message:"确定要退出程序吗?"
|
||||
negativeText:"最小化"
|
||||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.NeutralButton | FluContentDialogType.PositiveButton
|
||||
onNegativeClicked:{
|
||||
window.hide()
|
||||
onNegativeClicked: {
|
||||
system_tray.showMessage("友情提示","FluentUI已隐藏至托盘,点击托盘可再次激活窗口");
|
||||
timer_window_hide_delay.restart()
|
||||
}
|
||||
positiveText:"退出"
|
||||
neutralText:"取消"
|
||||
@ -120,19 +140,8 @@ FluWindow {
|
||||
back: Item{
|
||||
anchors.fill: flipable
|
||||
visible: flipable.flipAngle !== 0
|
||||
FluAppBar {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
z:7
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
}
|
||||
Row{
|
||||
id:layout_back_buttons
|
||||
z:8
|
||||
anchors{
|
||||
top: parent.top
|
||||
@ -163,26 +172,13 @@ FluWindow {
|
||||
id:loader
|
||||
lazy: true
|
||||
anchors.fill: parent
|
||||
source: "https://zhu-zichu.gitee.io/Qt5_156_LieflatPage.qml"
|
||||
source: "https://zhu-zichu.gitee.io/Qt_163_LieflatPage.qml"
|
||||
}
|
||||
}
|
||||
front: Item{
|
||||
id:page_front
|
||||
visible: flipable.flipAngle !== 180
|
||||
anchors.fill: flipable
|
||||
FluAppBar {
|
||||
id:app_bar_front
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
z:7
|
||||
}
|
||||
FluNavigationView{
|
||||
property int clickCount: 0
|
||||
id:nav_view
|
||||
@ -254,7 +250,7 @@ FluWindow {
|
||||
}
|
||||
|
||||
function handleDarkChanged(button){
|
||||
if(!FluTheme.enableAnimation){
|
||||
if(!FluTheme.enableAnimation || window.fitsAppBarWindows === false){
|
||||
changeDark()
|
||||
}else{
|
||||
loader_reveal.sourceComponent = com_reveal
|
||||
@ -296,14 +292,14 @@ FluWindow {
|
||||
|
||||
FluTour{
|
||||
id:tour
|
||||
steps:[
|
||||
{title:"夜间模式",description: "这里可以切换夜间模式.",target:()=>app_bar_front.darkButton()},
|
||||
{title:"隐藏彩蛋",description: "多点几下试试!!",target:()=>nav_view.logoButton()}
|
||||
]
|
||||
}
|
||||
|
||||
FluHttp{
|
||||
id:http
|
||||
steps:{
|
||||
var data = []
|
||||
if(!window.useSystemAppBar){
|
||||
data.push({title:"夜间模式",description: "这里可以切换夜间模式.",target:()=>appBar.darkButton()})
|
||||
}
|
||||
data.push({title:"隐藏彩蛋",description: "多点几下试试!!",target:()=>nav_view.logoButton()})
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
FpsItem{
|
||||
@ -335,7 +331,7 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
HttpCallable{
|
||||
FluNetworkCallable{
|
||||
id:callable
|
||||
property bool silent: true
|
||||
onStart: {
|
||||
@ -371,8 +367,8 @@ FluWindow {
|
||||
|
||||
function checkUpdate(silent){
|
||||
callable.silent = silent
|
||||
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
|
||||
http.get(request,callable);
|
||||
FluNetwork.get("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
|
||||
.go(callable)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,26 +19,17 @@ Item {
|
||||
function onVsyncChanged(){
|
||||
SettingsHelper.saveVsync(FluApp.vsync)
|
||||
}
|
||||
}
|
||||
|
||||
FluHttpInterceptor{
|
||||
id:interceptor
|
||||
function onIntercept(request){
|
||||
if(request.method === "get"){
|
||||
request.params["method"] = "get"
|
||||
}
|
||||
if(request.method === "post"){
|
||||
request.params["method"] = "post"
|
||||
}
|
||||
request.headers["token"] ="yyds"
|
||||
request.headers["os"] ="pc"
|
||||
console.debug(JSON.stringify(request))
|
||||
return request
|
||||
function onUseSystemAppBarChanged(){
|
||||
SettingsHelper.saveUseSystemAppBar(FluApp.useSystemAppBar)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
FluNetwork.setInterceptor(function(param){
|
||||
param.addHeader("Token","000000000000000000000")
|
||||
})
|
||||
FluApp.init(app)
|
||||
FluApp.useSystemAppBar = SettingsHelper.getUseSystemAppBar()
|
||||
FluApp.vsync = SettingsHelper.getVsync()
|
||||
FluTheme.darkMode = SettingsHelper.getDarkMode()
|
||||
FluTheme.enableAnimation = true
|
||||
@ -53,7 +44,6 @@ Item {
|
||||
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
|
||||
}
|
||||
FluApp.initialRoute = "/"
|
||||
FluApp.httpInterceptor = interceptor
|
||||
FluApp.run()
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,6 @@ FluExpander{
|
||||
"FluRadioButtons",
|
||||
"FluImage",
|
||||
"FluSpinBox",
|
||||
"FluHttp",
|
||||
"FluWatermark",
|
||||
"FluTour",
|
||||
"FluQRCode",
|
||||
@ -140,7 +139,9 @@ FluExpander{
|
||||
"FluStaggeredView",
|
||||
"FluProgressButton",
|
||||
"FluLoadingButton",
|
||||
"FluClip"
|
||||
"FluClip",
|
||||
"FluNetwork",
|
||||
"FluShortcutPicker"
|
||||
];
|
||||
code = code.replace(/\n/g, "<br>");
|
||||
code = code.replace(/ /g, " ");
|
||||
|
@ -150,6 +150,12 @@ FluObject{
|
||||
url:"qrc:/example/qml/page/T_ColorPicker.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
title:"ShortcutPicker"
|
||||
menuDelegate: paneItemMenu
|
||||
url:"qrc:/example/qml/page/T_ShortcutPicker.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
}
|
||||
|
||||
FluPaneItemExpander{
|
||||
@ -407,9 +413,9 @@ FluObject{
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
title:"Http"
|
||||
title:"Network"
|
||||
menuDelegate: paneItemMenu
|
||||
url:"qrc:/example/qml/page/T_Http.qml"
|
||||
url:"qrc:/example/qml/page/T_Network.qml"
|
||||
onTap:{ navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
|
@ -44,6 +44,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
placeholderText: "请输入验证码"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
FluButton{
|
||||
text:"verify"
|
||||
|
@ -116,4 +116,68 @@ FluScrollablePage{
|
||||
showSuccess("点击最小化按钮")
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
height: 68
|
||||
paddings: 10
|
||||
Layout.topMargin: 20
|
||||
FluButton{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Layout.topMargin: 20
|
||||
text:"Custom Content Dialog"
|
||||
onClicked: {
|
||||
custom_btn_dialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
CodeExpander{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -1
|
||||
code:'FluContentDialog{
|
||||
id:dialog
|
||||
title:"友情提示"
|
||||
message:"数据正在加载中,请稍等..."
|
||||
negativeText:"取消加载"
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 80
|
||||
FluProgressRing{
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
onNegativeClicked:{
|
||||
showSuccess("点击取消按钮")
|
||||
}
|
||||
positiveText:"确定"
|
||||
onPositiveClicked:{
|
||||
showSuccess("点击确定按钮")
|
||||
}
|
||||
dialog.open()'
|
||||
}
|
||||
|
||||
FluContentDialog{
|
||||
id:custom_btn_dialog
|
||||
title:"友情提示"
|
||||
message:"数据正在加载中,请稍等..."
|
||||
negativeText:"取消加载"
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 80
|
||||
FluProgressRing{
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
onNegativeClicked:{
|
||||
showSuccess("点击取消按钮")
|
||||
}
|
||||
positiveText:"确定"
|
||||
onPositiveClicked:{
|
||||
showSuccess("点击确定按钮")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,406 +0,0 @@
|
||||
import QtQuick 2.15
|
||||
import Qt.labs.platform 1.1
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Dialogs 1.3
|
||||
import FluentUI 1.0
|
||||
import "qrc:///example/qml/component"
|
||||
import "../component"
|
||||
|
||||
FluContentPage{
|
||||
|
||||
title:"Http"
|
||||
property string cacheDirPath: StandardPaths.writableLocation(StandardPaths.AppLocalDataLocation) + "/cache/http"
|
||||
property bool isDownCompleted: false
|
||||
|
||||
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: 200
|
||||
clip: true
|
||||
anchors{
|
||||
top: parent.top
|
||||
topMargin: 20
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
contentHeight:layout_column.height
|
||||
Column{
|
||||
spacing: 2
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Get请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/get")
|
||||
http.get(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post表单请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/post")
|
||||
var params = {}
|
||||
params.custname = "朱子楚"
|
||||
params.custtel = "1234567890"
|
||||
params.custemail = "zhuzichu520@gmail.com"
|
||||
request.params = params
|
||||
var headers = {}
|
||||
headers.test = "123456789456465321354"
|
||||
request.headers = headers
|
||||
http.post(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Json请求"
|
||||
onClicked: {
|
||||
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{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post String请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/post")
|
||||
request.params = "我命由我不由天"
|
||||
http.postString(request,callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete请求"
|
||||
onClicked: {
|
||||
var request = http.newRequest("https://httpbingo.org/delete")
|
||||
http.deleteResource(request,callable)
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "下载文件"
|
||||
onClicked: {
|
||||
folder_dialog.open()
|
||||
}
|
||||
}
|
||||
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)=>{
|
||||
if(!isDownCompleted){
|
||||
tour.open()
|
||||
isDownCompleted = true
|
||||
}
|
||||
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
|
||||
text: "文件上传"
|
||||
onClicked: {
|
||||
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(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 = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluTour{
|
||||
id:tour
|
||||
steps:[
|
||||
{title:"友情提示",description: "下载已完成,左击这里可以打开文件所在路径,右击可以弹出菜单删除文件!",target:()=>btn_breakpoint_download}
|
||||
]
|
||||
}
|
||||
|
||||
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 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)
|
||||
params[fileName] = filePath
|
||||
}
|
||||
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 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
|
||||
bottom: layout_flick.bottom
|
||||
left: layout_flick.right
|
||||
right: parent.right
|
||||
leftMargin: 8
|
||||
}
|
||||
Flickable{
|
||||
clip: true
|
||||
id:scrollview
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentWidth: width
|
||||
contentHeight: text_info.height
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
id:text_info
|
||||
width: scrollview.width
|
||||
wrapMode: Text.WrapAnywhere
|
||||
padding: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
532
example/qml/page/T_Network.qml
Normal file
532
example/qml/page/T_Network.qml
Normal file
@ -0,0 +1,532 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import FluentUI 1.0
|
||||
import Qt.labs.platform 1.0
|
||||
import "qrc:///example/qml/component"
|
||||
import "../component"
|
||||
|
||||
FluContentPage{
|
||||
|
||||
id:root
|
||||
title:"Network"
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable
|
||||
onStart: {
|
||||
showLoading()
|
||||
}
|
||||
onFinish: {
|
||||
hideLoading()
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onCache:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
}
|
||||
|
||||
Flickable{
|
||||
id:layout_flick
|
||||
width: 200
|
||||
clip: true
|
||||
anchors{
|
||||
top: parent.top
|
||||
topMargin: 20
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
contentHeight:layout_column.height
|
||||
Column{
|
||||
spacing: 2
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Get"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.get("https://httpbingo.org/get")
|
||||
.addQuery("name","孙悟空")
|
||||
.addQuery("age",500)
|
||||
.addQuery("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postBody("https://httpbingo.org/post")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postForm("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Post JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJsonArray("https://httpbingo.org/post")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putBody("https://httpbingo.org/put")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putForm("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putJson("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Put JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.putJsonArray("https://httpbingo.org/put")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchBody("https://httpbingo.org/patch")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchForm("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchJson("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Patch JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.patchJsonArray("https://httpbingo.org/patch")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete Body"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteBody("https://httpbingo.org/delete")
|
||||
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete Form"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteForm("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete JSON"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteJson("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Delete JSON Array"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.deleteJsonArray("https://httpbingo.org/delete")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Custom Header"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.addHeader("os","PC")
|
||||
.addHeader("version","1.0.0")
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "RequestFailedReadCache"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.RequestFailedReadCache)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","RequestFailedReadCache")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "IfNoneCacheRequest"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.IfNoneCacheRequest)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","IfNoneCacheRequest")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "FirstCacheThenRequest"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setCacheMode(FluNetworkType.FirstCacheThenRequest)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("cacheMode","FirstCacheThenRequest")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Timeout And Retry"
|
||||
onClicked: {
|
||||
text_info.text = ""
|
||||
FluNetwork.postJson("https://httpbingo.org/post")
|
||||
.setTimeout(5000)
|
||||
.setRetry(3)
|
||||
.add("name","孙悟空")
|
||||
.add("age",500)
|
||||
.add("address","花果山水帘洞")
|
||||
.add("timeout","5000")
|
||||
.add("retry","3")
|
||||
.bind(root)
|
||||
.go(callable)
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_upload
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Upload File"
|
||||
onClicked: {
|
||||
file_dialog.open()
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Download File"
|
||||
onClicked: {
|
||||
folder_dialog.showDialog(function(path){
|
||||
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
|
||||
.toDownload(path)
|
||||
.bind(root)
|
||||
.go(callable_download_file)
|
||||
})
|
||||
}
|
||||
}
|
||||
FluProgressButton{
|
||||
id:btn_download_breakpoint
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 36
|
||||
text: "Breakpoint Download File"
|
||||
onClicked: {
|
||||
folder_dialog.showDialog(function(path){
|
||||
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
|
||||
.toDownload(path,true)
|
||||
.bind(root)
|
||||
.go(callable_breakpoint_download_file)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_upload_file
|
||||
onStart: {
|
||||
btn_upload.disabled = true
|
||||
}
|
||||
onFinish: {
|
||||
btn_upload.disabled = false
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
btn_upload.progress = 0
|
||||
text_info.text = result
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
text_info.text = result
|
||||
}
|
||||
onUploadProgress:
|
||||
(sent,total)=>{
|
||||
btn_upload.progress = sent/total
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_download_file
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
FluNetworkCallable{
|
||||
id:callable_breakpoint_download_file
|
||||
onStart: {
|
||||
btn_download_breakpoint.progress = 0
|
||||
btn_download_breakpoint.disabled = true
|
||||
}
|
||||
onFinish: {
|
||||
btn_download_breakpoint.disabled = false
|
||||
}
|
||||
onError:
|
||||
(status,errorString,result)=>{
|
||||
btn_download_breakpoint.progress = 0
|
||||
showError(errorString)
|
||||
console.debug(status+";"+errorString+";"+result)
|
||||
}
|
||||
onSuccess:
|
||||
(result)=>{
|
||||
showSuccess(result)
|
||||
}
|
||||
onDownloadProgress:
|
||||
(recv,total)=>{
|
||||
btn_download_breakpoint.progress = recv/total
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: file_dialog
|
||||
onAccepted: {
|
||||
FluNetwork.postForm("https://httpbingo.org/post")
|
||||
.setRetry(1)//只请求一次
|
||||
.add("accessToken","12345678")
|
||||
.addFile("file",FluTools.toLocalPath(file_dialog.currentFile))
|
||||
.bind(root)
|
||||
.go(callable_upload_file)
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
property var onSelectListener
|
||||
id: folder_dialog
|
||||
folder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
|
||||
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/big_buck_bunny.mp4"
|
||||
fileMode: FileDialog.SaveFile
|
||||
onAccepted: {
|
||||
folder_dialog.onSelectListener(FluTools.toLocalPath(folder_dialog.currentFile))
|
||||
}
|
||||
function showDialog(listener){
|
||||
folder_dialog.onSelectListener = listener
|
||||
folder_dialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
anchors{
|
||||
top: layout_flick.top
|
||||
bottom: layout_flick.bottom
|
||||
left: layout_flick.right
|
||||
right: parent.right
|
||||
leftMargin: 8
|
||||
}
|
||||
Flickable{
|
||||
clip: true
|
||||
id:scrollview
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentWidth: width
|
||||
contentHeight: text_info.height
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
id:text_info
|
||||
width: scrollview.width
|
||||
wrapMode: Text.WrapAnywhere
|
||||
padding: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"会磨刀的小猪"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,36 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 50
|
||||
paddings: 10
|
||||
FluCheckBox{
|
||||
text:"Use System AppBar"
|
||||
checked: FluApp.useSystemAppBar
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
FluApp.useSystemAppBar = !FluApp.useSystemAppBar
|
||||
dialog_restart.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 50
|
||||
paddings: 10
|
||||
FluCheckBox{
|
||||
text:"fitsAppBarWindows"
|
||||
checked: window.fitsAppBarWindows
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
window.fitsAppBarWindows = !window.fitsAppBarWindows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
@ -202,5 +232,4 @@ FluScrollablePage{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
30
example/qml/page/T_ShortcutPicker.qml
Normal file
30
example/qml/page/T_ShortcutPicker.qml
Normal file
@ -0,0 +1,30 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import FluentUI 1.0
|
||||
import "qrc:///example/qml/component"
|
||||
|
||||
FluScrollablePage{
|
||||
|
||||
title:"ShortcutPicker"
|
||||
|
||||
FluArea{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
height: 100
|
||||
paddings: 10
|
||||
FluShortcutPicker{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
CodeExpander{
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -1
|
||||
code:'FluShortcutPicker{
|
||||
|
||||
}'
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ FluScrollablePage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"Technical testing 2015-09-01"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
FluFilledButton{
|
||||
text:"Append"
|
||||
|
@ -30,6 +30,7 @@ FluContentPage{
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text:"会磨刀的小猪"
|
||||
Layout.preferredWidth: 240
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,16 @@ FluWindow {
|
||||
minimumWidth: 520
|
||||
minimumHeight: 200
|
||||
launchMode: FluWindowType.SingleTask
|
||||
appBar: undefined
|
||||
fitsAppBarWindows: true
|
||||
appBar: FluAppBar {
|
||||
width: window.width
|
||||
height: 30
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
z:7
|
||||
}
|
||||
|
||||
SettingsViewModel{
|
||||
id:viewmodel_settings
|
||||
@ -35,8 +44,11 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
onFirstVisible: {
|
||||
tour.open()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
checkUpdate(true)
|
||||
FluEventBus.registerEvent(event_checkupdate)
|
||||
}
|
||||
@ -68,15 +80,23 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Timer{
|
||||
id:timer_window_hide_delay
|
||||
interval: 150
|
||||
onTriggered: {
|
||||
window.hide()
|
||||
}
|
||||
}
|
||||
|
||||
FluContentDialog{
|
||||
id:dialog_close
|
||||
title:"退出"
|
||||
message:"确定要退出程序吗?"
|
||||
negativeText:"最小化"
|
||||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.NeutralButton | FluContentDialogType.PositiveButton
|
||||
onNegativeClicked:{
|
||||
window.hide()
|
||||
onNegativeClicked: {
|
||||
system_tray.showMessage("友情提示","FluentUI已隐藏至托盘,点击托盘可再次激活窗口");
|
||||
timer_window_hide_delay.restart()
|
||||
}
|
||||
positiveText:"退出"
|
||||
neutralText:"取消"
|
||||
@ -123,19 +143,8 @@ FluWindow {
|
||||
back: Item{
|
||||
anchors.fill: flipable
|
||||
visible: flipable.flipAngle !== 0
|
||||
FluAppBar {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
z:7
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
}
|
||||
Row{
|
||||
id:layout_back_buttons
|
||||
z:8
|
||||
anchors{
|
||||
top: parent.top
|
||||
@ -166,26 +175,13 @@ FluWindow {
|
||||
id:loader
|
||||
lazy: true
|
||||
anchors.fill: parent
|
||||
source: "https://zhu-zichu.gitee.io/Qt5_156_LieflatPage.qml"
|
||||
source: "https://zhu-zichu.gitee.io/Qt_163_LieflatPage.qml"
|
||||
}
|
||||
}
|
||||
front: Item{
|
||||
id:page_front
|
||||
visible: flipable.flipAngle !== 180
|
||||
anchors.fill: flipable
|
||||
FluAppBar {
|
||||
id:app_bar_front
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
darkText: Lang.dark_mode
|
||||
showDark: true
|
||||
darkClickListener:(button)=>handleDarkChanged(button)
|
||||
closeClickListener: ()=>{dialog_close.open()}
|
||||
z:7
|
||||
}
|
||||
FluNavigationView{
|
||||
property int clickCount: 0
|
||||
id:nav_view
|
||||
@ -257,7 +253,7 @@ FluWindow {
|
||||
}
|
||||
|
||||
function handleDarkChanged(button){
|
||||
if(!FluTheme.enableAnimation){
|
||||
if(!FluTheme.enableAnimation || window.fitsAppBarWindows === false){
|
||||
changeDark()
|
||||
}else{
|
||||
loader_reveal.sourceComponent = com_reveal
|
||||
@ -299,14 +295,14 @@ FluWindow {
|
||||
|
||||
FluTour{
|
||||
id:tour
|
||||
steps:[
|
||||
{title:"夜间模式",description: "这里可以切换夜间模式.",target:()=>app_bar_front.darkButton()},
|
||||
{title:"隐藏彩蛋",description: "多点几下试试!!",target:()=>nav_view.logoButton()}
|
||||
]
|
||||
}
|
||||
|
||||
FluHttp{
|
||||
id:http
|
||||
steps:{
|
||||
var data = []
|
||||
if(!window.useSystemAppBar){
|
||||
data.push({title:"夜间模式",description: "这里可以切换夜间模式.",target:()=>appBar.darkButton()})
|
||||
}
|
||||
data.push({title:"隐藏彩蛋",description: "多点几下试试!!",target:()=>nav_view.logoButton()})
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
FpsItem{
|
||||
@ -338,7 +334,7 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
HttpCallable{
|
||||
FluNetworkCallable{
|
||||
id:callable
|
||||
property bool silent: true
|
||||
onStart: {
|
||||
@ -374,8 +370,8 @@ FluWindow {
|
||||
|
||||
function checkUpdate(silent){
|
||||
callable.silent = silent
|
||||
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
|
||||
http.get(request,callable);
|
||||
FluNetwork.get("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
|
||||
.go(callable)
|
||||
}
|
||||
|
||||
}
|
||||
|
69
example/src/helper/Log.cpp
Normal file
69
example/src/helper/Log.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "Log.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qfile.h>
|
||||
#include <QtCore/qtextstream.h>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef QT_ENDL
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
# define QT_ENDL Qt::endl
|
||||
# else
|
||||
# define QT_ENDL endl
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static QString g_app = {};
|
||||
static bool g_logError = false;
|
||||
|
||||
static std::unique_ptr<QFile> g_logFile = nullptr;
|
||||
static std::unique_ptr<QTextStream> g_logStream = nullptr;
|
||||
|
||||
static inline void myMessageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
if (message.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const QString finalMessage = qFormatLogMessage(type, context, message).trimmed();
|
||||
if ((type == QtInfoMsg) || (type == QtDebugMsg)) {
|
||||
std::cout << qUtf8Printable(finalMessage) << std::endl;
|
||||
} else {
|
||||
std::cerr << qUtf8Printable(finalMessage) << std::endl;
|
||||
}
|
||||
if (g_logError) {
|
||||
return;
|
||||
}
|
||||
if (!g_logFile) {
|
||||
g_logFile = std::make_unique<QFile>();
|
||||
g_logFile->setFileName(QString("debug-%1.log").arg(g_app));
|
||||
if (!g_logFile->open(QFile::WriteOnly | QFile::Text | QFile::Append)) {
|
||||
std::cerr << "Can't open file to write: " << qUtf8Printable(g_logFile->errorString()) << std::endl;
|
||||
g_logFile.reset();
|
||||
g_logError = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!g_logStream) {
|
||||
g_logStream = std::make_unique<QTextStream>();
|
||||
g_logStream->setDevice(g_logFile.get());
|
||||
}
|
||||
(*g_logStream) << finalMessage << QT_ENDL;
|
||||
}
|
||||
|
||||
void Log::setup(const QString &app)
|
||||
{
|
||||
Q_ASSERT(!app.isEmpty());
|
||||
if (app.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
static bool once = false;
|
||||
if (once) {
|
||||
return;
|
||||
}
|
||||
once = true;
|
||||
g_app = app;
|
||||
qSetMessagePattern(QString(
|
||||
"[%{time yyyy/MM/dd hh:mm:ss.zzz}] <%{if-info}INFO%{endif}%{if-debug}DEBUG"
|
||||
"%{endif}%{if-warning}WARNING%{endif}%{if-critical}CRITICAL%{endif}%{if-fatal}"
|
||||
"FATAL%{endif}> %{if-category}%{category}: %{endif}%{message}"));
|
||||
qInstallMessageHandler(myMessageHandler);
|
||||
}
|
10
example/src/helper/Log.h
Normal file
10
example/src/helper/Log.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
namespace Log
|
||||
{
|
||||
void setup(const QString &app);
|
||||
}
|
||||
|
||||
#endif // LOG_H
|
@ -25,6 +25,8 @@ public:
|
||||
Q_INVOKABLE QVariant getDarkMode(){return get("darkMode",QVariant(0));}
|
||||
Q_INVOKABLE void saveVsync(bool vsync){save("vsync",vsync);}
|
||||
Q_INVOKABLE QVariant getVsync(){return get("vsync",QVariant(true));}
|
||||
Q_INVOKABLE void saveUseSystemAppBar(bool useSystemAppBar){save("useSystemAppBar",useSystemAppBar);}
|
||||
Q_INVOKABLE QVariant getUseSystemAppBar(){return get("useSystemAppBar",QVariant(false));}
|
||||
private:
|
||||
void save(const QString& key,QVariant val);
|
||||
QVariant get(const QString& key,QVariant def={});
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <QtQml/qqmlextensionplugin.h>
|
||||
#include <QLoggingCategory>
|
||||
#include "AppInfo.h"
|
||||
#include "helper/Log.h"
|
||||
#include "src/component/CircularReveal.h"
|
||||
#include "src/component/FileWatcher.h"
|
||||
#include "src/component/FpsItem.h"
|
||||
@ -23,6 +24,7 @@ Q_IMPORT_QML_PLUGIN(FluentUIPlugin)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup("example");
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
Submodule framelesshelper updated: e01c6518db...27fcd913b4
@ -14,7 +14,7 @@ Q_ENUM_NS(Scope)
|
||||
QML_NAMED_ELEMENT(FluViewModelType)
|
||||
}
|
||||
|
||||
namespace FluHttpType {
|
||||
namespace FluNetworkType {
|
||||
Q_NAMESPACE
|
||||
enum CacheMode {
|
||||
NoCache = 0x0000,
|
||||
@ -23,7 +23,7 @@ enum CacheMode {
|
||||
FirstCacheThenRequest = 0x0004,
|
||||
};
|
||||
Q_ENUM_NS(CacheMode)
|
||||
QML_NAMED_ELEMENT(FluHttpType)
|
||||
QML_NAMED_ELEMENT(FluNetworkType)
|
||||
}
|
||||
|
||||
namespace FluScreenshotType {
|
||||
|
@ -14,8 +14,9 @@
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
FluApp::FluApp(QObject *parent):QObject{parent}{
|
||||
connect(this,&FluApp::useSystemAppBarChanged,this,[=]{FramelessConfig::instance()->set(Global::Option::UseSystemAppBar,_useSystemAppBar);});
|
||||
vsync(true);
|
||||
httpInterceptor(nullptr);
|
||||
useSystemAppBar(false);
|
||||
}
|
||||
|
||||
FluApp::~FluApp(){
|
||||
@ -23,7 +24,7 @@ FluApp::~FluApp(){
|
||||
|
||||
void FluApp::init(QObject *application){
|
||||
this->_application = application;
|
||||
FramelessHelper::Quick::initialize();
|
||||
FramelessHelperQuickInitialize();
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
|
||||
QQmlEngine *engine = qmlEngine(_application);
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <QJsonObject>
|
||||
#include <QQmlEngine>
|
||||
#include "FluRegister.h"
|
||||
#include "FluHttpInterceptor.h"
|
||||
#include "stdafx.h"
|
||||
#include "singleton.h"
|
||||
|
||||
@ -22,7 +21,7 @@ class FluApp : public QObject
|
||||
Q_PROPERTY_AUTO(bool,vsync)
|
||||
Q_PROPERTY_AUTO(QString,initialRoute);
|
||||
Q_PROPERTY_AUTO(QJsonObject,routes);
|
||||
Q_PROPERTY_AUTO(FluHttpInterceptor*,httpInterceptor);
|
||||
Q_PROPERTY_AUTO(bool,useSystemAppBar);
|
||||
QML_NAMED_ELEMENT(FluApp)
|
||||
QML_SINGLETON
|
||||
private:
|
||||
|
681
src/FluHttp.cpp
681
src/FluHttp.cpp
@ -1,681 +0,0 @@
|
||||
#include "FluHttp.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrlQuery>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QGuiApplication>
|
||||
#include <QJsonDocument>
|
||||
#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{
|
||||
_headers = headers();
|
||||
}
|
||||
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(){
|
||||
cancel();
|
||||
}
|
||||
|
||||
void FluHttp::cancel(){
|
||||
foreach (QPointer<QNetworkReply> item, _cacheReply) {
|
||||
if(item){
|
||||
item->abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::post(HttpRequest* r,HttpCallable* c){
|
||||
auto request = QPointer(r);
|
||||
auto callable = QPointer(c);
|
||||
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) {
|
||||
QUrl url(request->url());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
|
||||
for (const auto& each : data["params"].toMap().toStdMap())
|
||||
{
|
||||
const QString& key = each.first;
|
||||
const QString& value = each.second.toString();
|
||||
QString dispositionHeader = QString("form-data; name=\"%1\"").arg(key);
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader);
|
||||
part.setBody(value.toUtf8());
|
||||
multiPart.append(part);
|
||||
}
|
||||
QNetworkReply* reply = manager.post(req,&multiPart);
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
loop.exec();
|
||||
QString result = QString::fromUtf8(reply->readAll());
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString errorString = reply->errorString();
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
bool isSuccess = error == QNetworkReply::NoError;
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(error == QNetworkReply::OperationCanceledError){
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
void FluHttp::postString(HttpRequest* r,HttpCallable* c){
|
||||
auto request = QPointer(r);
|
||||
auto callable = QPointer(c);
|
||||
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) {
|
||||
QUrl url(request->url());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QString contentType = QString("text/plain;charset=utf-8");
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
|
||||
QNetworkReply* reply = manager.post(req,params.toUtf8());
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
loop.exec();
|
||||
QString result = QString::fromUtf8(reply->readAll());
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString errorString = reply->errorString();
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
bool isSuccess = error == QNetworkReply::NoError;
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(error == QNetworkReply::OperationCanceledError){
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
void FluHttp::postJson(HttpRequest* r,HttpCallable* c){
|
||||
auto request = QPointer(r);
|
||||
auto callable = QPointer(c);
|
||||
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) {
|
||||
QUrl url(request->url());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QString contentType = QString("application/json;charset=utf-8");
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
|
||||
QNetworkReply* reply = manager.post(req,QJsonDocument::fromVariant(data["params"]).toJson());
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
loop.exec();
|
||||
QString result = QString::fromUtf8(reply->readAll());
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString errorString = reply->errorString();
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
bool isSuccess = error == QNetworkReply::NoError;
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(error == QNetworkReply::OperationCanceledError){
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
void FluHttp::get(HttpRequest* r,HttpCallable* c){
|
||||
auto request = QPointer(r);
|
||||
auto callable = QPointer(c);
|
||||
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) {
|
||||
QUrl url(request->url());
|
||||
addQueryParam(&url,data["params"].toMap());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QNetworkReply* reply = manager.get(req);
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
loop.exec();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString errorString = reply->errorString();
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
bool isSuccess = error == QNetworkReply::NoError;
|
||||
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;
|
||||
if(error == QNetworkReply::OperationCanceledError){
|
||||
break;
|
||||
}
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
void FluHttp::download(HttpRequest* r,HttpCallable* c){
|
||||
auto request = QPointer(r);
|
||||
auto callable = QPointer(c);
|
||||
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(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());
|
||||
}
|
||||
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);
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
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) {
|
||||
onSuccess(callable,savePath);
|
||||
}else{
|
||||
onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString(),"");
|
||||
}
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
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(request->url());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
|
||||
for (const auto& each : data["params"].toMap().toStdMap())
|
||||
{
|
||||
const QString& key = each.first;
|
||||
const QString& filePath = each.second.toString();
|
||||
QFile *file = new QFile(filePath);
|
||||
file->open(QIODevice::ReadOnly);
|
||||
file->setParent(&multiPart);
|
||||
QString dispositionHeader = QString("form-data; name=\"%1\"; filename=\"%2\"").arg(key,filePath);
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader);
|
||||
part.setBodyDevice(file);
|
||||
multiPart.append(part);
|
||||
}
|
||||
QNetworkReply* reply = manager.post(req,&multiPart);
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
_cacheReply.append(reply);
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
connect(reply,&QNetworkReply::uploadProgress,reply,[=](qint64 bytesSent, qint64 bytesTotal){
|
||||
onUploadProgress(callable,bytesSent,bytesTotal);
|
||||
});
|
||||
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;
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
if (isSuccess) {
|
||||
onSuccess(callable,result);
|
||||
}else{
|
||||
onError(callable,status,errorString,result);
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
void FluHttp::deleteResource(HttpRequest* request,HttpCallable* callable)
|
||||
{
|
||||
request->method("deleteResource");
|
||||
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) {
|
||||
QUrl url(request->url());
|
||||
addQueryParam(&url,data["params"].toMap());
|
||||
QNetworkRequest req(url);
|
||||
addHeaders(&req,data["headers"].toMap());
|
||||
QEventLoop loop;
|
||||
QNetworkReply* reply = manager.deleteResource(req);
|
||||
_cacheReply.append(reply);
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop](){loop.quit();});
|
||||
loop.exec();
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString errorString = reply->errorString();
|
||||
bool isSuccess = reply->error() == QNetworkReply::NoError;
|
||||
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);
|
||||
}
|
||||
}
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
if(error == QNetworkReply::OperationCanceledError){
|
||||
break;
|
||||
}
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
}
|
||||
onFinish(callable,request);
|
||||
});
|
||||
}
|
||||
|
||||
QVariant FluHttp::invokeIntercept(QMap<QString, QVariant> request){
|
||||
if(!FluApp::getInstance()->httpInterceptor()){
|
||||
return request;
|
||||
}
|
||||
QVariant target;
|
||||
QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, request));
|
||||
return target;
|
||||
}
|
||||
|
||||
void FluHttp::addQueryParam(QUrl* url,const QMap<QString, QVariant>& params){
|
||||
QMapIterator<QString, QVariant> iter(params);
|
||||
QUrlQuery urlQuery(*url);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
urlQuery.addQueryItem(iter.key(), iter.value().toString());
|
||||
}
|
||||
url->setQuery(urlQuery);
|
||||
}
|
||||
|
||||
void FluHttp::addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& headers){
|
||||
QMapIterator<QString, QVariant> iter(headers);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool FluHttp::cacheExists(const QString& httpId){
|
||||
return QFile(getCacheFilePath(httpId)).exists();
|
||||
}
|
||||
|
||||
QString FluHttp::getCacheFilePath(const QString& httpId){
|
||||
QString path = FluTools::getInstance()->toLocalPath(QUrl(_cacheDir));
|
||||
QDir dir = path;
|
||||
if (!dir.exists(path)){
|
||||
dir.mkpath(path);
|
||||
}
|
||||
auto filePath = path+"/"+httpId;
|
||||
return filePath;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
HttpRequest* FluHttp::newRequest(QString url){
|
||||
HttpRequest* request = new HttpRequest(this);
|
||||
request->url(url);
|
||||
return request;
|
||||
}
|
||||
|
||||
void FluHttp::onStart(QPointer<HttpCallable> callable){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->start();
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onFinish(QPointer<HttpCallable> callable,QPointer<HttpRequest> request){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->finish();
|
||||
}
|
||||
if(request&&request->parent()->inherits("FluHttp")){
|
||||
request->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onError(QPointer<HttpCallable> callable,int status,QString errorString,QString result){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->error(status,errorString,result);
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onSuccess(QPointer<HttpCallable> callable,QString result){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->success(result);
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onCache(QPointer<HttpCallable> callable,QString result){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->cache(result);
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onDownloadProgress(QPointer<HttpCallable> callable,qint64 recv,qint64 total){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->downloadProgress(recv,total);
|
||||
}
|
||||
}
|
||||
|
||||
void FluHttp::onUploadProgress(QPointer<HttpCallable> callable,qint64 sent,qint64 total){
|
||||
if (!callable.isNull()) {
|
||||
Q_EMIT callable->uploadProgress(sent,total);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
#ifndef FLUHTTP_H
|
||||
#define FLUHTTP_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QFile>
|
||||
#include <QJsonValue>
|
||||
#include <QNetworkAccessManager>
|
||||
#include "stdafx.h"
|
||||
|
||||
class HttpRequest : public QObject{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(QString,url);
|
||||
# if (QT_VERSION == QT_VERSION_CHECK(6, 4, 3))
|
||||
Q_PROPERTY_AUTO(QJsonValue,params);
|
||||
Q_PROPERTY_AUTO(QJsonValue,headers);
|
||||
# else
|
||||
Q_PROPERTY_AUTO(QVariant,params);
|
||||
Q_PROPERTY_AUTO(QVariant,headers);
|
||||
# endif
|
||||
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(QMap<QString, QVariant> request);
|
||||
void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params);
|
||||
void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& params);
|
||||
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,QPointer<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();
|
||||
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 void deleteResource(HttpRequest* request,HttpCallable* callable);
|
||||
Q_INVOKABLE qreal getBreakPointProgress(HttpRequest* request);
|
||||
Q_INVOKABLE void cancel();
|
||||
private:
|
||||
QList<QPointer<QNetworkReply>> _cacheReply;
|
||||
};
|
||||
|
||||
#endif // FLUHTTP_H
|
@ -1,4 +0,0 @@
|
||||
#include "FluHttpInterceptor.h"
|
||||
|
||||
FluHttpInterceptor::FluHttpInterceptor(QObject *parent):QObject{parent}{
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#ifndef FLUHTTPINTERCEPTOR_H
|
||||
#define FLUHTTPINTERCEPTOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
class FluHttpInterceptor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(FluHttpInterceptor)
|
||||
public:
|
||||
explicit FluHttpInterceptor(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif // FLUHTTPINTERCEPTOR_H
|
574
src/FluNetwork.cpp
Normal file
574
src/FluNetwork.cpp
Normal file
@ -0,0 +1,574 @@
|
||||
#include "FluNetwork.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <QBuffer>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QJSEngine>
|
||||
#include <QJsonArray>
|
||||
#include <QStandardPaths>
|
||||
#include <QThreadPool>
|
||||
#include <QDir>
|
||||
#include <QEventLoop>
|
||||
#include <QGuiApplication>
|
||||
|
||||
NetworkCallable::NetworkCallable(QObject *parent):QObject{parent}{
|
||||
|
||||
}
|
||||
|
||||
QString NetworkParams::method2String(){
|
||||
switch (_method) {
|
||||
case METHOD_GET:
|
||||
return "GET";
|
||||
case METHOD_HEAD:
|
||||
return "HEAD";
|
||||
case METHOD_POST:
|
||||
return "POST";
|
||||
case METHOD_PUT:
|
||||
return "PUT";
|
||||
case METHOD_PATCH:
|
||||
return "PATCH";
|
||||
case METHOD_DELETE:
|
||||
return "DELETE";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int NetworkParams::getTimeout(){
|
||||
if(_timeout != -1){
|
||||
return _timeout;
|
||||
}
|
||||
return FluNetwork::getInstance()->timeout();
|
||||
}
|
||||
|
||||
int NetworkParams::getRetry(){
|
||||
if(_retry != -1){
|
||||
return _retry;
|
||||
}
|
||||
return FluNetwork::getInstance()->retry();
|
||||
}
|
||||
|
||||
DownloadParam::DownloadParam(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
}
|
||||
|
||||
DownloadParam::DownloadParam(QString destPath,bool append,QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
this->_destPath = destPath;
|
||||
this->_append = append;
|
||||
}
|
||||
|
||||
NetworkParams::NetworkParams(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
}
|
||||
|
||||
NetworkParams::NetworkParams(QString url,Type type,Method method,QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
this->_method = method;
|
||||
this->_url = url;
|
||||
this->_type = type;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::add(QString key,QVariant val){
|
||||
_paramMap.insert(key,val);
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::addFile(QString key,QVariant val){
|
||||
_fileMap.insert(key,val);
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::addHeader(QString key,QVariant val){
|
||||
_headerMap.insert(key,val);
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::addQuery(QString key,QVariant val){
|
||||
_queryMap.insert(key,val);
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::setBody(QString val){
|
||||
_body = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::setTimeout(int val){
|
||||
_timeout = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::setRetry(int val){
|
||||
_retry = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::setCacheMode(int val){
|
||||
_cacheMode = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::toDownload(QString destPath,bool append){
|
||||
_downloadParam = new DownloadParam(destPath,append,this);
|
||||
return this;
|
||||
}
|
||||
|
||||
NetworkParams* NetworkParams::bind(QObject* target){
|
||||
_target = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
QString NetworkParams::buildCacheKey(){
|
||||
QJsonObject obj;
|
||||
obj.insert("url",_url);
|
||||
obj.insert("method",method2String());
|
||||
obj.insert("body",_body);
|
||||
obj.insert("query",QJsonDocument::fromVariant(_queryMap).object());
|
||||
obj.insert("param",QJsonDocument::fromVariant(_paramMap).object());
|
||||
obj.insert("header",QJsonDocument::fromVariant(_headerMap).object());
|
||||
obj.insert("file",QJsonDocument::fromVariant(_fileMap).object());
|
||||
if(_downloadParam){
|
||||
QJsonObject downObj;
|
||||
downObj.insert("destPath",_downloadParam->_destPath);
|
||||
downObj.insert("append",_downloadParam->_append);
|
||||
obj.insert("download",downObj);
|
||||
}
|
||||
QByteArray data = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
return QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex();
|
||||
}
|
||||
|
||||
void NetworkParams::go(NetworkCallable* callable){
|
||||
QJSValueList data;
|
||||
data<<qjsEngine(FluNetwork::getInstance())->newQObject(this);
|
||||
FluNetwork::getInstance()->_interceptor.call(data);
|
||||
if(_downloadParam){
|
||||
FluNetwork::getInstance()->handleDownload(this,callable);
|
||||
}else{
|
||||
FluNetwork::getInstance()->handle(this,callable);
|
||||
}
|
||||
}
|
||||
|
||||
void FluNetwork::handle(NetworkParams* params,NetworkCallable* c){
|
||||
QPointer<NetworkCallable> callable(c);
|
||||
QThreadPool::globalInstance()->start([=](){
|
||||
if(!callable.isNull()){
|
||||
callable->start();
|
||||
}
|
||||
QString cacheKey = params->buildCacheKey();
|
||||
if(params->_cacheMode == FluNetworkType::CacheMode::FirstCacheThenRequest && cacheExists(cacheKey)){
|
||||
if(!callable.isNull()){
|
||||
callable->cache(readCache(cacheKey));
|
||||
}
|
||||
}
|
||||
if(params->_cacheMode == FluNetworkType::CacheMode::IfNoneCacheRequest && cacheExists(cacheKey)){
|
||||
if(!callable.isNull()){
|
||||
callable->cache(readCache(cacheKey));
|
||||
callable->finish();
|
||||
params->deleteLater();
|
||||
}
|
||||
return;
|
||||
}
|
||||
QNetworkAccessManager manager;
|
||||
manager.setTransferTimeout(params->getTimeout());
|
||||
QEventLoop loop;
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
for (int i = 0; i < params->getRetry(); ++i) {
|
||||
QUrl url(params->_url);
|
||||
addQueryParam(&url,params->_queryMap);
|
||||
QNetworkRequest request(url);
|
||||
addHeaders(&request,params->_headerMap);
|
||||
QNetworkReply* reply;
|
||||
sendRequest(&manager,request,params,reply,callable);
|
||||
if(!QPointer(qApp)){
|
||||
reply->deleteLater();
|
||||
reply = nullptr;
|
||||
return;
|
||||
}
|
||||
auto abortCallable = [&loop,reply,&i,params]{
|
||||
if(reply){
|
||||
i = params->getRetry();
|
||||
reply->abort();
|
||||
}
|
||||
};
|
||||
QMetaObject::Connection conn_destoryed = {};
|
||||
QMetaObject::Connection conn_quit = {};
|
||||
if(params->_target){
|
||||
conn_destoryed = connect(params->_target,&QObject::destroyed,&manager,abortCallable);
|
||||
}
|
||||
conn_quit = connect(qApp,&QGuiApplication::aboutToQuit,&manager, abortCallable);
|
||||
loop.exec();
|
||||
if(conn_destoryed){
|
||||
disconnect(conn_destoryed);
|
||||
}
|
||||
if(conn_quit){
|
||||
disconnect(conn_quit);
|
||||
}
|
||||
QString response;
|
||||
if(reply->isOpen()){
|
||||
response = QString::fromUtf8(reply->readAll());
|
||||
}
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
if(error == QNetworkReply::NoError){
|
||||
if(!callable.isNull()){
|
||||
if(params->_cacheMode != FluNetworkType::CacheMode::NoCache){
|
||||
saveResponse(cacheKey,response);
|
||||
}
|
||||
callable->success(response);
|
||||
}
|
||||
break;
|
||||
}else{
|
||||
if(i == params->getRetry()-1){
|
||||
if(!callable.isNull()){
|
||||
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if(params->_cacheMode == FluNetworkType::CacheMode::RequestFailedReadCache && cacheExists(cacheKey)){
|
||||
if(!callable.isNull()){
|
||||
callable->cache(readCache(cacheKey));
|
||||
}
|
||||
}
|
||||
callable->error(httpStatus,reply->errorString(),response);
|
||||
}
|
||||
}
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
params->deleteLater();
|
||||
if(!callable.isNull()){
|
||||
callable->finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FluNetwork::handleDownload(NetworkParams* params,NetworkCallable* c){
|
||||
QPointer<NetworkCallable> callable(c);
|
||||
QThreadPool::globalInstance()->start([=](){
|
||||
if(!callable.isNull()){
|
||||
callable->start();
|
||||
}
|
||||
QString cacheKey = params->buildCacheKey();
|
||||
QUrl url(params->_url);
|
||||
QNetworkAccessManager manager;
|
||||
manager.setTransferTimeout(params->getTimeout());
|
||||
addQueryParam(&url,params->_queryMap);
|
||||
QNetworkRequest request(url);
|
||||
addHeaders(&request,params->_headerMap);
|
||||
QString cachePath = getCacheFilePath(cacheKey);
|
||||
QString destPath = params->_downloadParam->_destPath;
|
||||
QFile* destFile = new QFile(destPath);
|
||||
QFile* cacheFile = new QFile(cachePath);
|
||||
bool isOpen = false;
|
||||
qint64 seek = 0;
|
||||
if(cacheFile->exists() && destFile->exists() && params->_downloadParam->_append){
|
||||
QJsonObject cacheInfo = QJsonDocument::fromJson(readCache(cacheKey).toUtf8()).object();
|
||||
qint64 fileSize = cacheInfo.value("fileSize").toDouble();
|
||||
qint64 contentLength = cacheInfo.value("contentLength").toDouble();
|
||||
if(fileSize == contentLength && destFile->size() == contentLength){
|
||||
if(!callable.isNull()){
|
||||
callable->downloadProgress(fileSize,contentLength);
|
||||
callable->success(destPath);
|
||||
callable->finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(fileSize==destFile->size()){
|
||||
request.setRawHeader("Range", QString("bytes=%1-").arg(fileSize).toUtf8());
|
||||
seek = fileSize;
|
||||
isOpen = destFile->open(QIODevice::WriteOnly|QIODevice::Append);
|
||||
}else{
|
||||
isOpen = destFile->open(QIODevice::WriteOnly|QIODevice::Truncate);
|
||||
}
|
||||
}else{
|
||||
isOpen = destFile->open(QIODevice::WriteOnly|QIODevice::Truncate);
|
||||
}
|
||||
if(!isOpen){
|
||||
if(!callable.isNull()){
|
||||
callable->error(-1,"device not open","");
|
||||
callable->finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(params->_downloadParam->_append){
|
||||
if (!cacheFile->open(QIODevice::WriteOnly|QIODevice::Truncate))
|
||||
{
|
||||
if(!callable.isNull()){
|
||||
callable->error(-1,"cache file device not open","");
|
||||
callable->finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
QEventLoop loop;
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
destFile->setParent(reply);
|
||||
cacheFile->setParent(reply);
|
||||
auto abortCallable = [&loop,reply,params]{
|
||||
if(reply){
|
||||
reply->abort();
|
||||
}
|
||||
};
|
||||
connect(&manager,&QNetworkAccessManager::finished,&manager,[&loop](QNetworkReply *reply){loop.quit();});
|
||||
connect(qApp,&QGuiApplication::aboutToQuit,&manager, [&loop,reply](){reply->abort(),loop.quit();});
|
||||
QMetaObject::Connection conn_destoryed = {};
|
||||
QMetaObject::Connection conn_quit = {};
|
||||
if(params->_target){
|
||||
conn_destoryed = connect(params->_target,&QObject::destroyed,&manager,abortCallable);
|
||||
}
|
||||
conn_quit = connect(qApp,&QGuiApplication::aboutToQuit,&manager, abortCallable);
|
||||
connect(reply,&QNetworkReply::readyRead,reply,[reply,seek,destFile,cacheFile,callable]{
|
||||
if (!reply || !destFile || reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QMap<QString, QVariant> downInfo;
|
||||
qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong()+seek;
|
||||
downInfo.insert("contentLength",contentLength);
|
||||
QString eTag = reply->header(QNetworkRequest::ETagHeader).toString();
|
||||
downInfo.insert("eTag",eTag);
|
||||
destFile->write(reply->readAll());
|
||||
destFile->flush();
|
||||
downInfo.insert("fileSize",destFile->size());
|
||||
if(cacheFile->isOpen()){
|
||||
cacheFile->resize(0);
|
||||
cacheFile->write(QJsonDocument::fromVariant(QVariant(downInfo)).toJson().toBase64());
|
||||
cacheFile->flush();
|
||||
}
|
||||
if(!callable.isNull()){
|
||||
callable->downloadProgress(destFile->size(),contentLength);
|
||||
}
|
||||
});
|
||||
loop.exec();
|
||||
if(conn_destoryed){
|
||||
disconnect(conn_destoryed);
|
||||
}
|
||||
if(conn_quit){
|
||||
disconnect(conn_quit);
|
||||
}
|
||||
params->deleteLater();
|
||||
reply->deleteLater();
|
||||
if(!callable.isNull()){
|
||||
callable->finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString FluNetwork::readCache(const QString& key){
|
||||
auto filePath = getCacheFilePath(key);
|
||||
QString result;
|
||||
QFile file(filePath);
|
||||
if(!file.exists()){
|
||||
return result;
|
||||
}
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QTextStream stream(&file);
|
||||
result = QString(QByteArray::fromBase64(stream.readAll().toUtf8()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FluNetwork::cacheExists(const QString& key){
|
||||
return QFile(getCacheFilePath(key)).exists();
|
||||
}
|
||||
|
||||
QString FluNetwork::getCacheFilePath(const QString& key){
|
||||
QDir cacheDir(_cacheDir);
|
||||
if(!cacheDir.exists()){
|
||||
cacheDir.mkpath(_cacheDir);
|
||||
}
|
||||
return cacheDir.absoluteFilePath(key);
|
||||
}
|
||||
|
||||
void FluNetwork::sendRequest(QNetworkAccessManager* manager,QNetworkRequest request,NetworkParams* params,QNetworkReply*& reply,QPointer<NetworkCallable> callable){
|
||||
QByteArray verb = params->method2String().toUtf8();
|
||||
switch (params->_type) {
|
||||
case NetworkParams::TYPE_FORM:{
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart();
|
||||
multiPart->setContentType(QHttpMultiPart::FormDataType);
|
||||
for (const auto& each : params->_paramMap.toStdMap())
|
||||
{
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(each.first));
|
||||
part.setBody(each.second.toByteArray());
|
||||
multiPart->append(part);
|
||||
}
|
||||
for (const auto& each : params->_fileMap.toStdMap())
|
||||
{
|
||||
QString filePath = each.second.toString();
|
||||
QString name = each.first;
|
||||
QFile *file = new QFile(filePath);
|
||||
QString fileName = QFileInfo(filePath).fileName();
|
||||
file->open(QIODevice::ReadOnly);
|
||||
file->setParent(multiPart);
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"; filename=\"%2\"").arg(name,fileName));
|
||||
part.setBodyDevice(file);
|
||||
multiPart->append(part);
|
||||
}
|
||||
reply = manager->sendCustomRequest(request,verb,multiPart);
|
||||
multiPart->setParent(reply);
|
||||
if(!params->_fileMap.isEmpty()){
|
||||
connect(reply,&QNetworkReply::uploadProgress,reply,[callable](qint64 bytesSent, qint64 bytesTotal){
|
||||
if(!callable.isNull() && bytesSent!=0 && bytesTotal!=0){
|
||||
callable->uploadProgress(bytesSent,bytesTotal);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetworkParams::TYPE_JSON:{
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json;charset=utf-8"));
|
||||
QJsonObject json;
|
||||
for (const auto& each : params->_paramMap.toStdMap())
|
||||
{
|
||||
json.insert(each.first,each.second.toJsonValue());
|
||||
}
|
||||
QByteArray data = QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
reply = manager->sendCustomRequest(request,verb,data);
|
||||
break;
|
||||
}
|
||||
case NetworkParams::TYPE_JSONARRAY:{
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json;charset=utf-8"));
|
||||
QJsonArray jsonArray;
|
||||
for (const auto& each : params->_paramMap.toStdMap())
|
||||
{
|
||||
QJsonObject json;
|
||||
json.insert(each.first,each.second.toJsonValue());
|
||||
jsonArray.append(json);
|
||||
}
|
||||
QByteArray data = QJsonDocument(jsonArray).toJson(QJsonDocument::Compact);
|
||||
reply = manager->sendCustomRequest(request,params->method2String().toUtf8(),data);
|
||||
break;
|
||||
}
|
||||
case NetworkParams::TYPE_BODY:{
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("text/plain;charset=utf-8"));
|
||||
QByteArray data = params->_body.toUtf8();
|
||||
reply = manager->sendCustomRequest(request,verb,data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
reply = manager->sendCustomRequest(request,verb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FluNetwork::saveResponse(QString key,QString response){
|
||||
QSharedPointer<QFile> file(new QFile(getCacheFilePath(key)));
|
||||
QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate;
|
||||
if (!file->open(mode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
file->write(response.toUtf8().toBase64());
|
||||
}
|
||||
|
||||
void FluNetwork::addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& headers){
|
||||
QMapIterator<QString, QVariant> iter(headers);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
void FluNetwork::addQueryParam(QUrl* url,const QMap<QString, QVariant>& params){
|
||||
QMapIterator<QString, QVariant> iter(params);
|
||||
QUrlQuery urlQuery(*url);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
iter.next();
|
||||
urlQuery.addQueryItem(iter.key(), iter.value().toString());
|
||||
}
|
||||
url->setQuery(urlQuery);
|
||||
}
|
||||
|
||||
FluNetwork::FluNetwork(QObject *parent): QObject{parent}
|
||||
{
|
||||
timeout(5000);
|
||||
retry(3);
|
||||
cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation).append(QDir::separator()).append("network"));
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::get(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_NONE,NetworkParams::METHOD_GET,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::head(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_NONE,NetworkParams::METHOD_HEAD,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::postBody(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_POST,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::putBody(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_PUT,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::patchBody(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_PATCH,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::deleteBody(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_DELETE,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::postForm(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_POST,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::putForm(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_PUT,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::patchForm(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_PATCH,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::deleteForm(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_DELETE,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::postJson(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_POST,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::putJson(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_PUT,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::patchJson(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_PATCH,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::deleteJson(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_DELETE,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::postJsonArray(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_POST,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::putJsonArray(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_PUT,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::patchJsonArray(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_PATCH,this);
|
||||
}
|
||||
|
||||
NetworkParams* FluNetwork::deleteJsonArray(const QString& url){
|
||||
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_DELETE,this);
|
||||
}
|
||||
|
||||
void FluNetwork::setInterceptor(QJSValue interceptor){
|
||||
this->_interceptor = interceptor;
|
||||
}
|
137
src/FluNetwork.h
Normal file
137
src/FluNetwork.h
Normal file
@ -0,0 +1,137 @@
|
||||
#ifndef FLUNETWORK_H
|
||||
#define FLUNETWORK_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QFile>
|
||||
#include <QJsonValue>
|
||||
#include <QJSValue>
|
||||
#include <QNetworkAccessManager>
|
||||
#include "Def.h"
|
||||
#include "stdafx.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class NetworkCallable : public QObject{
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(FluNetworkCallable)
|
||||
public:
|
||||
explicit NetworkCallable(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 uploadProgress(qint64 sent, qint64 total);
|
||||
Q_SIGNAL void downloadProgress(qint64 recv, qint64 total);
|
||||
};
|
||||
|
||||
class DownloadParam : public QObject{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DownloadParam(QObject *parent = nullptr);
|
||||
DownloadParam(QString destPath,bool append,QObject *parent = nullptr);
|
||||
public:
|
||||
QString _destPath;
|
||||
bool _append;
|
||||
};
|
||||
|
||||
class NetworkParams : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(FluNetworkParams)
|
||||
public:
|
||||
enum Method{
|
||||
METHOD_GET,
|
||||
METHOD_HEAD,
|
||||
METHOD_POST,
|
||||
METHOD_PUT,
|
||||
METHOD_PATCH,
|
||||
METHOD_DELETE
|
||||
};
|
||||
enum Type{
|
||||
TYPE_NONE,
|
||||
TYPE_FORM,
|
||||
TYPE_JSON,
|
||||
TYPE_JSONARRAY,
|
||||
TYPE_BODY
|
||||
};
|
||||
explicit NetworkParams(QObject *parent = nullptr);
|
||||
NetworkParams(QString url,Type type,Method method,QObject *parent = nullptr);
|
||||
Q_INVOKABLE NetworkParams* addQuery(QString key,QVariant val);
|
||||
Q_INVOKABLE NetworkParams* addHeader(QString key,QVariant val);
|
||||
Q_INVOKABLE NetworkParams* add(QString key,QVariant val);
|
||||
Q_INVOKABLE NetworkParams* addFile(QString key,QVariant val);
|
||||
Q_INVOKABLE NetworkParams* setBody(QString val);
|
||||
Q_INVOKABLE NetworkParams* setTimeout(int val);
|
||||
Q_INVOKABLE NetworkParams* setRetry(int val);
|
||||
Q_INVOKABLE NetworkParams* setCacheMode(int val);
|
||||
Q_INVOKABLE NetworkParams* toDownload(QString destPath,bool append = false);
|
||||
Q_INVOKABLE NetworkParams* bind(QObject* target);
|
||||
Q_INVOKABLE void go(NetworkCallable* result);
|
||||
QString buildCacheKey();
|
||||
QString method2String();
|
||||
int getTimeout();
|
||||
int getRetry();
|
||||
public:
|
||||
DownloadParam* _downloadParam = nullptr;
|
||||
QObject* _target = nullptr;
|
||||
Method _method;
|
||||
Type _type;
|
||||
QString _url;
|
||||
QString _body;
|
||||
QMap<QString, QVariant> _queryMap;
|
||||
QMap<QString, QVariant> _headerMap;
|
||||
QMap<QString, QVariant> _paramMap;
|
||||
QMap<QString, QVariant> _fileMap;
|
||||
int _timeout = -1;
|
||||
int _retry = -1;
|
||||
int _cacheMode = FluNetworkType::CacheMode::NoCache;
|
||||
};
|
||||
|
||||
class FluNetwork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(int,timeout)
|
||||
Q_PROPERTY_AUTO(int,retry)
|
||||
Q_PROPERTY_AUTO(QString,cacheDir)
|
||||
QML_NAMED_ELEMENT(FluNetwork)
|
||||
QML_SINGLETON
|
||||
private:
|
||||
explicit FluNetwork(QObject *parent = nullptr);
|
||||
public:
|
||||
SINGLETONG(FluNetwork)
|
||||
static FluNetwork *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
|
||||
Q_INVOKABLE NetworkParams* get(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* head(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* postBody(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* putBody(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* patchBody(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* deleteBody(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* postForm(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* putForm(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* patchForm(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* deleteForm(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* postJson(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* putJson(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* patchJson(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* deleteJson(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* postJsonArray(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* putJsonArray(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* patchJsonArray(const QString& url);
|
||||
Q_INVOKABLE NetworkParams* deleteJsonArray(const QString& url);
|
||||
Q_INVOKABLE void setInterceptor(QJSValue interceptor);
|
||||
void handle(NetworkParams* params,NetworkCallable* result);
|
||||
void handleDownload(NetworkParams* params,NetworkCallable* result);
|
||||
private:
|
||||
void sendRequest(QNetworkAccessManager* manager,QNetworkRequest request,NetworkParams* params,QNetworkReply*& reply,QPointer<NetworkCallable> callable);
|
||||
void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params);
|
||||
void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& headers);
|
||||
void saveResponse(QString key,QString response);
|
||||
QString readCache(const QString& key);
|
||||
bool cacheExists(const QString& key);
|
||||
QString getCacheFilePath(const QString& key);
|
||||
public:
|
||||
QJSValue _interceptor;
|
||||
};
|
||||
|
||||
#endif // FLUNETWORK_H
|
@ -11,26 +11,26 @@ FluTextStyle::FluTextStyle(QObject *parent):QObject{parent}{
|
||||
|
||||
QFont bodyStrong;
|
||||
bodyStrong.setPixelSize(13);
|
||||
bodyStrong.setBold(true);
|
||||
bodyStrong.setWeight(QFont::DemiBold);
|
||||
BodyStrong(bodyStrong);
|
||||
|
||||
QFont subtitle;
|
||||
subtitle.setPixelSize(20);
|
||||
subtitle.setBold(true);
|
||||
subtitle.setWeight(QFont::DemiBold);
|
||||
Subtitle(subtitle);
|
||||
|
||||
QFont title;
|
||||
title.setPixelSize(28);
|
||||
title.setBold(true);
|
||||
title.setWeight(QFont::DemiBold);
|
||||
Title(title);
|
||||
|
||||
QFont titleLarge;
|
||||
titleLarge.setPixelSize(40);
|
||||
titleLarge.setBold(true);
|
||||
titleLarge.setWeight(QFont::DemiBold);
|
||||
TitleLarge(titleLarge);
|
||||
|
||||
QFont display;
|
||||
display.setPixelSize(68);
|
||||
display.setBold(true);
|
||||
display.setWeight(QFont::DemiBold);
|
||||
Display(display);
|
||||
}
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "FluTheme.h"
|
||||
#include "FluTools.h"
|
||||
#include "FluTextStyle.h"
|
||||
#include "FluHttp.h"
|
||||
#include "FluHttpInterceptor.h"
|
||||
#include "FluWatermark.h"
|
||||
#include "FluCaptcha.h"
|
||||
#include "FluEventBus.h"
|
||||
@ -17,22 +15,9 @@
|
||||
#include "FluViewModel.h"
|
||||
#include "Screenshot.h"
|
||||
#include "FluRectangle.h"
|
||||
#include "FluNetwork.h"
|
||||
#include "QRCode.h"
|
||||
|
||||
int major = 1;
|
||||
int minor = 0;
|
||||
auto uri = "FluentUI";
|
||||
|
||||
FluentUI* FluentUI::m_instance = nullptr;
|
||||
|
||||
FluentUI *FluentUI::getInstance()
|
||||
{
|
||||
if(FluentUI::m_instance == nullptr){
|
||||
FluentUI::m_instance = new FluentUI;
|
||||
}
|
||||
return FluentUI::m_instance;
|
||||
}
|
||||
|
||||
void FluentUI::registerTypes(QQmlEngine *engine){
|
||||
initializeEngine(engine,uri);
|
||||
registerTypes(uri);
|
||||
@ -49,14 +34,12 @@ void FluentUI::registerTypes(const char *uri){
|
||||
qmlRegisterType<ScreenshotBackground>(uri,major,minor,"ScreenshotBackground");
|
||||
qmlRegisterType<Screenshot>(uri,major,minor,"Screenshot");
|
||||
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");
|
||||
qmlRegisterType<FluEvent>(uri,major,minor,"FluEvent");
|
||||
qmlRegisterType<FluViewModel>(uri,major,minor,"FluViewModel");
|
||||
qmlRegisterType<FluTreeModel>(uri,major,minor,"FluTreeModel");
|
||||
qmlRegisterType<FluRectangle>(uri,major,minor,"FluRectangle");
|
||||
qmlRegisterType<NetworkCallable>(uri,major,minor,"FluNetworkCallable");
|
||||
qmlRegisterType<NetworkParams>(uri,major,minor,"FluNetworkParams");
|
||||
|
||||
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/ColorPicker.qml"),uri,major,minor,"ColorPicker");
|
||||
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/Content/Checkerboard.qml"),uri,major,minor,"Checkerboard");
|
||||
@ -155,7 +138,6 @@ void FluentUI::registerTypes(const char *uri){
|
||||
|
||||
|
||||
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");
|
||||
@ -169,6 +151,7 @@ void FluentUI::registerTypes(const char *uri){
|
||||
qmlRegisterUncreatableMetaObject(FluTimelineType::staticMetaObject, uri,major,minor,"FluTimelineType", "Access to enums & flags only");
|
||||
qmlRegisterUncreatableMetaObject(FluScreenshotType::staticMetaObject, uri,major,minor,"FluScreenshotType", "Access to enums & flags only");
|
||||
qmlRegisterUncreatableMetaObject(FluViewModelType::staticMetaObject, uri,major,minor,"FluViewModelType", "Access to enums & flags only");
|
||||
qmlRegisterUncreatableMetaObject(FluNetworkType::staticMetaObject, uri,major,minor,"FluNetworkType", "Access to enums & flags only");
|
||||
|
||||
qmlRegisterModule(uri,major,minor);
|
||||
}
|
||||
@ -176,7 +159,7 @@ void FluentUI::registerTypes(const char *uri){
|
||||
void FluentUI::initializeEngine(QQmlEngine *engine, const char *uri){
|
||||
#ifdef Q_OS_WIN
|
||||
QFont font;
|
||||
font.setFamily("Microsoft YaHei");
|
||||
font.setFamily("Microsoft YaHei UI");
|
||||
QGuiApplication::setFont(font);
|
||||
#endif
|
||||
FluApp* app = FluApp::getInstance();
|
||||
@ -191,5 +174,7 @@ void FluentUI::initializeEngine(QQmlEngine *engine, const char *uri){
|
||||
engine->rootContext()->setContextProperty("FluTextStyle",textStyle);
|
||||
FluEventBus* eventBus = FluEventBus::getInstance();
|
||||
engine->rootContext()->setContextProperty("FluEventBus",eventBus);
|
||||
FluNetwork* network = FluNetwork::getInstance();
|
||||
engine->rootContext()->setContextProperty("FluNetwork",network);
|
||||
engine->addImportPath("qrc:/qt/qml");
|
||||
}
|
||||
|
@ -3,17 +3,20 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include "singleton.h"
|
||||
|
||||
class FluentUI : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static FluentUI *getInstance();
|
||||
SINGLETONG(FluentUI)
|
||||
Q_DECL_EXPORT void registerTypes(QQmlEngine *engine);
|
||||
void registerTypes(const char *uri);
|
||||
void initializeEngine(QQmlEngine *engine, const char *uri);
|
||||
private:
|
||||
static FluentUI* m_instance;
|
||||
const int major = 1;
|
||||
const int minor = 0;
|
||||
const char *uri = "FluentUI";
|
||||
};
|
||||
|
||||
#endif // FLUENTUI_H
|
||||
|
@ -4,13 +4,14 @@ import FluentUI 1.0
|
||||
|
||||
Item {
|
||||
id: control
|
||||
property color tintColor: Qt.rgba(1,1,1,1)
|
||||
property color tintColor: Qt.rgba(1, 1, 1, 1)
|
||||
property real tintOpacity: 0.65
|
||||
property real luminosity: 0.01
|
||||
property real noiseOpacity : 0.066
|
||||
property alias target : effect_source.sourceItem
|
||||
property real noiseOpacity: 0.02
|
||||
property alias target: effect_source.sourceItem
|
||||
property int blurRadius: 32
|
||||
property rect targetRect : Qt.rect(control.x, control.y, control.width, control.height)
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,
|
||||
control.height)
|
||||
ShaderEffectSource {
|
||||
id: effect_source
|
||||
anchors.fill: parent
|
||||
@ -18,20 +19,20 @@ Item {
|
||||
sourceRect: control.targetRect
|
||||
}
|
||||
FastBlur {
|
||||
id:fast_blur
|
||||
id: fast_blur
|
||||
anchors.fill: parent
|
||||
source: effect_source
|
||||
radius: control.blurRadius
|
||||
}
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(1, 1, 1, luminosity)
|
||||
}
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(tintColor.r, tintColor.g, tintColor.b, tintOpacity)
|
||||
}
|
||||
Image{
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "../Image/noise.png"
|
||||
fillMode: Image.Tile
|
||||
|
@ -72,10 +72,10 @@ Rectangle{
|
||||
return false
|
||||
}
|
||||
property bool isRestore: win && Window.Maximized === win.visibility
|
||||
property bool resizable: win && !(win.minimumHeight === win.maximumHeight && win.maximumWidth === win.minimumWidth)
|
||||
property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth)
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: if (tapCount === 2) btn_maximize.clicked()
|
||||
onTapped: if (tapCount === 2 && d.resizable) btn_maximize.clicked()
|
||||
gesturePolicy: TapHandler.DragThreshold
|
||||
}
|
||||
DragHandler {
|
||||
|
@ -6,8 +6,8 @@ Button {
|
||||
property bool disabled: false
|
||||
property string contentDescription: ""
|
||||
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
property color textColor: {
|
||||
if(FluTheme.dark){
|
||||
if(!enabled){
|
||||
@ -33,6 +33,7 @@ Button {
|
||||
Accessible.onPressAction: control.clicked()
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
font:FluTextStyle.Body
|
||||
focusPolicy:Qt.TabFocus
|
||||
|
@ -5,51 +5,37 @@ import QtQuick.Window 2.15
|
||||
import FluentUI 1.0
|
||||
|
||||
FluPopup {
|
||||
id: popup
|
||||
property string title: "Title"
|
||||
property string message: "Message"
|
||||
id: control
|
||||
property string title: ""
|
||||
property string message: ""
|
||||
property string neutralText: "Neutral"
|
||||
property string negativeText: "Negative"
|
||||
property string positiveText: "Positive"
|
||||
property alias messageTextFormart: text_message.textFormat
|
||||
property int messageTextFormart: Text.AutoText
|
||||
property int delayTime: 100
|
||||
property int buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
|
||||
property var contentDelegate: Component{
|
||||
Item{
|
||||
}
|
||||
}
|
||||
property var onNeutralClickListener
|
||||
property var onNegativeClickListener
|
||||
property var onPositiveClickListener
|
||||
signal neutralClicked
|
||||
signal negativeClicked
|
||||
signal positiveClicked
|
||||
property int buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
|
||||
focus: true
|
||||
implicitWidth: 400
|
||||
implicitHeight: text_title.height + sroll_message.height + layout_actions.height
|
||||
Rectangle {
|
||||
id:layout_content
|
||||
anchors.fill: parent
|
||||
color: 'transparent'
|
||||
radius:5
|
||||
FluText{
|
||||
id:text_title
|
||||
font: FluTextStyle.TitleLarge
|
||||
text:title
|
||||
topPadding: 20
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
wrapMode: Text.WrapAnywhere
|
||||
anchors{
|
||||
top:parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
implicitHeight: layout_content.height
|
||||
focus: true
|
||||
Component{
|
||||
id:com_message
|
||||
Flickable{
|
||||
id:sroll_message
|
||||
contentHeight: text_message.height
|
||||
contentWidth: width
|
||||
clip: true
|
||||
anchors{
|
||||
top:text_title.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
contentHeight: text_message.height
|
||||
width: parent.width
|
||||
height: Math.min(text_message.height,300)
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
@ -58,82 +44,113 @@ FluPopup {
|
||||
wrapMode: Text.WrapAnywhere
|
||||
text:message
|
||||
width: parent.width
|
||||
topPadding: 14
|
||||
topPadding: 4
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
bottomPadding: 14
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
id:layout_actions
|
||||
height: 68
|
||||
radius: 5
|
||||
color: FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
|
||||
anchors{
|
||||
top:sroll_message.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
RowLayout{
|
||||
anchors
|
||||
{
|
||||
centerIn: parent
|
||||
margins: spacing
|
||||
fill: parent
|
||||
}
|
||||
spacing: 15
|
||||
FluButton{
|
||||
id:neutral_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.NeutralButton
|
||||
text: neutralText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.NeutralButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
id:negative_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.NegativeButton
|
||||
text: negativeText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.NegativeButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
FluFilledButton{
|
||||
id:positive_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.PositiveButton
|
||||
text: positiveText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.PositiveButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
bottomPadding: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer{
|
||||
property int targetFlags
|
||||
id:timer_delay
|
||||
interval: popup.delayTime
|
||||
onTriggered: {
|
||||
if(targetFlags === FluContentDialogType.NegativeButton){
|
||||
negativeClicked()
|
||||
Rectangle {
|
||||
id:layout_content
|
||||
width: parent.width
|
||||
height: layout_column.childrenRect.height
|
||||
color: 'transparent'
|
||||
radius:5
|
||||
ColumnLayout{
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluText{
|
||||
id:text_title
|
||||
font: FluTextStyle.Title
|
||||
text:title
|
||||
topPadding: 20
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
if(targetFlags === FluContentDialogType.NeutralButton){
|
||||
neutralClicked()
|
||||
FluLoader{
|
||||
sourceComponent: com_message
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: status===Loader.Ready ? item.height : 0
|
||||
}
|
||||
if(targetFlags === FluContentDialogType.PositiveButton){
|
||||
positiveClicked()
|
||||
FluLoader{
|
||||
sourceComponent: control.contentDelegate
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: status===Loader.Ready ? item.height : 0
|
||||
}
|
||||
Rectangle{
|
||||
id:layout_actions
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 60
|
||||
radius: 5
|
||||
color: FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
|
||||
RowLayout{
|
||||
anchors
|
||||
{
|
||||
centerIn: parent
|
||||
margins: spacing
|
||||
fill: parent
|
||||
}
|
||||
spacing: 10
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.NeutralButton
|
||||
FluButton{
|
||||
id:neutral_btn
|
||||
text: neutralText
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
onClicked: {
|
||||
if(control.onNeutralClickListener){
|
||||
control.onNeutralClickListener()
|
||||
}else{
|
||||
neutralClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.NegativeButton
|
||||
FluButton{
|
||||
id:negative_btn
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
text: negativeText
|
||||
onClicked: {
|
||||
if(control.onNegativeClickListener){
|
||||
control.onNegativeClickListener()
|
||||
}else{
|
||||
negativeClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.PositiveButton
|
||||
FluFilledButton{
|
||||
id:positive_btn
|
||||
text: positiveText
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
onClicked: {
|
||||
if(control.onPositiveClickListener){
|
||||
control.onPositiveClickListener()
|
||||
}else{
|
||||
positiveClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ Button {
|
||||
property bool disabled: false
|
||||
property string contentDescription: ""
|
||||
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
property color textColor: {
|
||||
if(FluTheme.dark){
|
||||
if(!enabled){
|
||||
@ -38,6 +38,7 @@ Button {
|
||||
rightPadding:35
|
||||
enabled: !disabled
|
||||
focusPolicy:Qt.TabFocus
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: Rectangle{
|
||||
implicitWidth: 28
|
||||
|
@ -27,6 +27,7 @@ Button {
|
||||
enabled: !disabled
|
||||
focusPolicy:Qt.TabFocus
|
||||
font:FluTextStyle.Body
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: Rectangle{
|
||||
implicitWidth: 28
|
||||
|
@ -976,7 +976,6 @@ Item {
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
ListView{
|
||||
id:nav_list
|
||||
clip: true
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
|
@ -21,14 +21,14 @@ Button {
|
||||
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)
|
||||
return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/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)
|
||||
return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
}
|
||||
}
|
||||
property color pressedColor: FluTheme.dark ? Qt.darker(normalColor,1.2) : Qt.lighter(normalColor,1.2)
|
||||
@ -39,6 +39,7 @@ Button {
|
||||
focusPolicy:Qt.TabFocus
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: FluClip{
|
||||
implicitWidth: 28
|
||||
@ -69,7 +70,7 @@ Button {
|
||||
color: FluTheme.primaryColor
|
||||
anchors.bottom: parent.bottom
|
||||
Behavior on height{
|
||||
enabled: control.progress !== 1
|
||||
enabled: control.progress === 1
|
||||
SequentialAnimation {
|
||||
PauseAnimation {
|
||||
duration: FluTheme.enableAnimation ? 167 : 0
|
||||
|
231
src/Qt5/imports/FluentUI/Controls/FluShortcutPicker.qml
Normal file
231
src/Qt5/imports/FluentUI/Controls/FluShortcutPicker.qml
Normal file
@ -0,0 +1,231 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import FluentUI 1.0
|
||||
|
||||
FluIconButton {
|
||||
id:control
|
||||
property var current : ["Ctrl","Shift","A"]
|
||||
property string title: "激活快捷键"
|
||||
property string message: "按下组合键以更改此快捷键"
|
||||
property string positiveText: "保存"
|
||||
property string neutralText: "取消"
|
||||
property string negativeText: "重置"
|
||||
signal accepted()
|
||||
QtObject{
|
||||
id: d
|
||||
function keyToString(key_code,shift = true)
|
||||
{
|
||||
switch(key_code)
|
||||
{
|
||||
case Qt.Key_Period: return ".";
|
||||
case Qt.Key_Greater: return shift ? ">" : ".";
|
||||
case Qt.Key_Comma: return ",";
|
||||
case Qt.Key_Less: return shift ? "<" : ",";
|
||||
case Qt.Key_Slash: return "/";
|
||||
case Qt.Key_Question: return shift ? "?" : "/";
|
||||
case Qt.Key_Semicolon: return ";";
|
||||
case Qt.Key_Colon: return shift ? ":" : ";";
|
||||
case Qt.Key_Apostrophe: return "'";
|
||||
case Qt.Key_QuoteDbl: return shift ? "'" : "\"";
|
||||
case Qt.Key_QuoteLeft: return "`";
|
||||
case Qt.Key_AsciiTilde: return shift ? "~" : "`";
|
||||
case Qt.Key_Minus: return "-";
|
||||
case Qt.Key_Underscore: return shift ? "_" : "-";
|
||||
case Qt.Key_Equal: return "=";
|
||||
case Qt.Key_Plus: return shift ? "+" : "=";
|
||||
case Qt.Key_BracketLeft: return "[";
|
||||
case Qt.Key_BraceLeft: return shift ? "{" : "[";
|
||||
case Qt.Key_BracketRight: return "]";
|
||||
case Qt.Key_BraceRight: return shift ? "}" : "]";
|
||||
case Qt.Key_Backslash: return "\\";
|
||||
case Qt.Key_Bar: return shift ? "|" : "\\";
|
||||
case Qt.Key_Up: return "Up";
|
||||
case Qt.Key_Down: return "Down";
|
||||
case Qt.Key_Right: return "Right";
|
||||
case Qt.Key_Left: return "Left";
|
||||
case Qt.Key_Space: return "Space";
|
||||
case Qt.Key_PageDown: return "PgDown";
|
||||
case Qt.Key_PageUp: return "PgUp";
|
||||
case Qt.Key_0: return "0";
|
||||
case Qt.Key_1: return "1";
|
||||
case Qt.Key_2: return "2";
|
||||
case Qt.Key_3: return "3";
|
||||
case Qt.Key_4: return "4";
|
||||
case Qt.Key_5: return "5";
|
||||
case Qt.Key_6: return "6";
|
||||
case Qt.Key_7: return "7";
|
||||
case Qt.Key_8: return "8";
|
||||
case Qt.Key_9: return "9";
|
||||
case Qt.Key_Exclam: return shift ? "!" : "1";
|
||||
case Qt.Key_At: return shift ? "@" : "2";
|
||||
case Qt.Key_NumberSign: return shift ? "#" : "3";
|
||||
case Qt.Key_Dollar: return shift ? "$" : "4";
|
||||
case Qt.Key_Percent: return shift ? "%" : "5";
|
||||
case Qt.Key_AsciiCircum: return shift ? "^" : "6";
|
||||
case Qt.Key_Ampersand: return shift ? "&" : "7";
|
||||
case Qt.Key_Asterisk: return shift ? "*" : "8";
|
||||
case Qt.Key_ParenLeft: return shift ? "(" : "9";
|
||||
case Qt.Key_ParenRight: return shift ? ")" : "0";
|
||||
case Qt.Key_A: return "A";
|
||||
case Qt.Key_B: return "B";
|
||||
case Qt.Key_C: return "C";
|
||||
case Qt.Key_D: return "D";
|
||||
case Qt.Key_E: return "E";
|
||||
case Qt.Key_F: return "F";
|
||||
case Qt.Key_G: return "G";
|
||||
case Qt.Key_H: return "H";
|
||||
case Qt.Key_I: return "I";
|
||||
case Qt.Key_J: return "J";
|
||||
case Qt.Key_K: return "K";
|
||||
case Qt.Key_L: return "L";
|
||||
case Qt.Key_M: return "M";
|
||||
case Qt.Key_N: return "N";
|
||||
case Qt.Key_O: return "O";
|
||||
case Qt.Key_P: return "P";
|
||||
case Qt.Key_Q: return "Q";
|
||||
case Qt.Key_R: return "R";
|
||||
case Qt.Key_S: return "S";
|
||||
case Qt.Key_T: return "T";
|
||||
case Qt.Key_U: return "U";
|
||||
case Qt.Key_V: return "V";
|
||||
case Qt.Key_W: return "W";
|
||||
case Qt.Key_X: return "X";
|
||||
case Qt.Key_Y: return "Y";
|
||||
case Qt.Key_Z: return "Z";
|
||||
case Qt.Key_F1: return "F1";
|
||||
case Qt.Key_F2: return "F2";
|
||||
case Qt.Key_F3: return "F3";
|
||||
case Qt.Key_F4: return "F4";
|
||||
case Qt.Key_F5: return "F5";
|
||||
case Qt.Key_F6: return "F6";
|
||||
case Qt.Key_F7: return "F7";
|
||||
case Qt.Key_F8: return "F8";
|
||||
case Qt.Key_F9: return "F9";
|
||||
case Qt.Key_F10: return "F10";
|
||||
case Qt.Key_F11: return "F11";
|
||||
case Qt.Key_F12: return "F12";
|
||||
case Qt.Key_Home: return "Home";
|
||||
case Qt.Key_End: return "End";
|
||||
case Qt.Key_Insert: return "Insert";
|
||||
case Qt.Key_Delete: return "Delete";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
background: Rectangle{
|
||||
border.color: FluTheme.dark ? "#505050" : "#DFDFDF"
|
||||
border.width: 1
|
||||
implicitHeight: 42
|
||||
implicitWidth: layout_row.width+28
|
||||
radius: control.radius
|
||||
color:control.color
|
||||
FluFocusRectangle{
|
||||
visible: control.activeFocus
|
||||
}
|
||||
}
|
||||
component ItemKey:Rectangle{
|
||||
id:item_key_control
|
||||
property string text : ""
|
||||
color:FluTheme.primaryColor
|
||||
width: Math.max(item_text.implicitWidth+12,28)
|
||||
height: Math.max(item_text.implicitHeight,28)
|
||||
radius: 4
|
||||
Text{
|
||||
id:item_text
|
||||
color: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
|
||||
font.pixelSize: 13
|
||||
text: item_key_control.text
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
Row{
|
||||
id:layout_row
|
||||
spacing: 5
|
||||
anchors.centerIn: parent
|
||||
Repeater{
|
||||
model: control.current
|
||||
delegate: ItemKey{
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
Item{
|
||||
width: 3
|
||||
height: 1
|
||||
}
|
||||
FluIcon{
|
||||
iconSource: FluentIcons.EditMirrored
|
||||
iconSize: 13
|
||||
anchors{
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
FluContentDialog{
|
||||
id:content_dialog
|
||||
property var keysModel: []
|
||||
title: control.title
|
||||
message: control.message
|
||||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton | FluContentDialogType.NeutralButton
|
||||
positiveText: control.positiveText
|
||||
neutralText: control.neutralText
|
||||
negativeText: control.negativeText
|
||||
onVisibleChanged: {
|
||||
if(visible){
|
||||
content_dialog.keysModel = control.current
|
||||
}
|
||||
}
|
||||
onPositiveClicked: {
|
||||
control.current = content_dialog.keysModel
|
||||
control.accepted()
|
||||
}
|
||||
onNegativeClickListener: function(){
|
||||
content_dialog.keysModel = control.current
|
||||
}
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 100
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
}
|
||||
Keys.enabled: true
|
||||
Keys.onPressed:
|
||||
(event)=>{
|
||||
var keyNames = []
|
||||
if (event.modifiers & Qt.AltModifier) {
|
||||
keyNames.push("Alt")
|
||||
}
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyNames.push("Ctrl")
|
||||
}
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
keyNames.push("Shift")
|
||||
}
|
||||
var keyName = d.keyToString(event.key,false)
|
||||
if(keyName!==""){
|
||||
keyNames.push(keyName)
|
||||
content_dialog.keysModel = keyNames
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
Keys.onTabPressed:
|
||||
(event)=>{
|
||||
event.accepted = true
|
||||
}
|
||||
Row{
|
||||
spacing: 5
|
||||
anchors.centerIn: parent
|
||||
Repeater{
|
||||
model: content_dialog.keysModel
|
||||
delegate: ItemKey{
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
content_dialog.open()
|
||||
}
|
||||
}
|
@ -71,7 +71,7 @@ T.SpinBox {
|
||||
}
|
||||
}
|
||||
|
||||
up.indicator: FluRectangle {
|
||||
up.indicator: FluClip {
|
||||
x: control.mirrored ? 0 : control.width - width
|
||||
height: control.height
|
||||
implicitWidth: 32
|
||||
@ -106,7 +106,7 @@ T.SpinBox {
|
||||
}
|
||||
|
||||
|
||||
down.indicator: FluRectangle {
|
||||
down.indicator: FluClip {
|
||||
x: control.mirrored ? parent.width - width : 0
|
||||
height: control.height
|
||||
implicitWidth: 32
|
||||
|
@ -16,14 +16,14 @@ Button {
|
||||
if(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)
|
||||
return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
}
|
||||
}
|
||||
property color disableColor: {
|
||||
if(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)
|
||||
return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
}
|
||||
}
|
||||
property var clickListener : function(){
|
||||
@ -37,6 +37,7 @@ Button {
|
||||
focusPolicy:Qt.TabFocus
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
onClicked: clickListener()
|
||||
onCheckableChanged: {
|
||||
|
@ -120,8 +120,18 @@ Popup{
|
||||
width: 500
|
||||
height: 88 + text_desc.height
|
||||
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
|
||||
property int dir : {
|
||||
if(y<d.pos.y)
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
x: Math.min(Math.max(0,d.pos.x+d.target.width/2-width/2),d.windowWidth-width)
|
||||
y: d.pos.y+d.target.height+control.targetMargins + 15
|
||||
y:{
|
||||
var ty=d.pos.y+d.target.height+control.targetMargins + 15
|
||||
if((ty+height)>d.windowHeight)
|
||||
return d.pos.y-height-control.targetMargins - 15
|
||||
return ty
|
||||
}
|
||||
border.width: 0
|
||||
FluShadow{
|
||||
radius: 5
|
||||
@ -194,9 +204,9 @@ Popup{
|
||||
}
|
||||
}
|
||||
FluIcon{
|
||||
iconSource: FluentIcons.FlickDown
|
||||
iconSource: layout_panne.dir?FluentIcons.FlickUp:FluentIcons.FlickDown
|
||||
color: layout_panne.color
|
||||
x: d.pos.x+d.target.width/2-10
|
||||
y: d.pos.y+d.target.height
|
||||
y: d.pos.y+(layout_panne.dir?-height:d.target.height)
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,17 @@ Window {
|
||||
property var background : com_background
|
||||
property bool fixSize: false
|
||||
property Component loadingItem: com_loading
|
||||
property var appBar: com_app_bar
|
||||
property bool fitsAppBarWindows: false
|
||||
property Item appBar: FluAppBar {
|
||||
title: window.title
|
||||
width: window.width
|
||||
height: 30
|
||||
showDark: window.showDark
|
||||
showClose: window.showClose
|
||||
showMinimize: window.showMinimize
|
||||
showMaximize: window.showMaximize
|
||||
showStayTop: window.showStayTop
|
||||
}
|
||||
property color backgroundColor: {
|
||||
if(active){
|
||||
return FluTheme.windowActiveBackgroundColor
|
||||
@ -28,6 +38,8 @@ Window {
|
||||
property bool showMinimize: true
|
||||
property bool showMaximize: true
|
||||
property bool showStayTop: true
|
||||
property bool useSystemAppBar
|
||||
property bool autoMaximize: false
|
||||
property var closeListener: function(event){
|
||||
if(closeDestory){
|
||||
destoryOnClose()
|
||||
@ -37,24 +49,43 @@ Window {
|
||||
}
|
||||
}
|
||||
signal initArgument(var argument)
|
||||
signal firstVisible()
|
||||
id:window
|
||||
maximumWidth: useSystemAppBar&&fixSize ? width : 16777215
|
||||
maximumHeight: useSystemAppBar&&fixSize ? height : 16777215
|
||||
minimumWidth: useSystemAppBar&&fixSize ? width : 0
|
||||
minimumHeight: useSystemAppBar&&fixSize ? height : 0
|
||||
color:"transparent"
|
||||
onStayTopChanged: {
|
||||
d.changedStayTop()
|
||||
}
|
||||
Component.onCompleted: {
|
||||
useSystemAppBar = FluApp.useSystemAppBar
|
||||
lifecycle.onCompleted(window)
|
||||
initArgument(argument)
|
||||
d.changedStayTop()
|
||||
if(useSystemAppBar){
|
||||
window.moveWindowToDesktopCenter()
|
||||
if(window.autoMaximize){
|
||||
window.showMaximized()
|
||||
}else{
|
||||
window.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
lifecycle.onDestruction()
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if(visible && d.isFirstVisible){
|
||||
window.firstVisible()
|
||||
d.isFirstVisible = false
|
||||
}
|
||||
lifecycle.onVisible(visible)
|
||||
}
|
||||
QtObject{
|
||||
id:d
|
||||
property bool isFirstVisible: true
|
||||
function changedStayTop(){
|
||||
function toggleStayTop(){
|
||||
if(window.stayTop){
|
||||
@ -82,34 +113,35 @@ Window {
|
||||
color: window.backgroundColor
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_app_bar
|
||||
FluAppBar {
|
||||
title: window.title
|
||||
showDark: window.showDark
|
||||
showClose: window.showClose
|
||||
showMinimize: window.showMinimize
|
||||
showMaximize: window.showMaximize
|
||||
showStayTop: window.showStayTop
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
anchors.fill: parent
|
||||
sourceComponent: background
|
||||
}
|
||||
FluLoader{
|
||||
id: loader_title_bar
|
||||
id:loader_app_bar
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
sourceComponent: window.appBar
|
||||
sourceComponent: window.useSystemAppBar ? undefined : com_app_bar
|
||||
}
|
||||
Component{
|
||||
id:com_app_bar
|
||||
Item{
|
||||
data: window.appBar
|
||||
height: {
|
||||
if(FluApp.useSystemAppBar){
|
||||
return 0
|
||||
}
|
||||
return window.fitsAppBarWindows ? 0 : childrenRect.height
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
id:container
|
||||
anchors{
|
||||
top: loader_title_bar.bottom
|
||||
top: loader_app_bar.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
@ -202,38 +234,47 @@ Window {
|
||||
onReady: {
|
||||
flags = flags | Qt.Window | Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
|
||||
if(appBar){
|
||||
var title_bar = loader_title_bar.item
|
||||
setTitleBarItem(title_bar)
|
||||
moveWindowToDesktopCenter()
|
||||
setHitTestVisible(title_bar.minimizeButton())
|
||||
setHitTestVisible(title_bar.maximizeButton())
|
||||
setHitTestVisible(title_bar.closeButton())
|
||||
setHitTestVisible(title_bar.stayTopButton())
|
||||
var appbar = window.appBar
|
||||
window.moveWindowToDesktopCenter()
|
||||
setWindowFixedSize(fixSize)
|
||||
title_bar.maximizeButton.visible = !fixSize
|
||||
if (blurBehindWindowEnabled)
|
||||
window.background = undefined
|
||||
}
|
||||
window.show()
|
||||
if(window.autoMaximize){
|
||||
window.showMaximized()
|
||||
}else{
|
||||
window.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
WindowLifecycle{
|
||||
id:lifecycle
|
||||
}
|
||||
WindowBorder{
|
||||
z:999
|
||||
visible: !FluTools.isLinux()
|
||||
}
|
||||
Rectangle{
|
||||
FluLoader{
|
||||
id:loader_window_border
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
border.width: 1
|
||||
visible: FluTools.isLinux()
|
||||
border.color: {
|
||||
if(window.active){
|
||||
return "#333333"
|
||||
z:999
|
||||
sourceComponent: FluApp.useSystemAppBar ? undefined : com_window_border
|
||||
}
|
||||
Component{
|
||||
id:com_window_border
|
||||
Item{
|
||||
WindowBorder{
|
||||
anchors.fill: parent
|
||||
visible: !FluTools.isLinux()
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0,0,0,0)
|
||||
border.width: 1
|
||||
visible: FluTools.isLinux()
|
||||
border.color: {
|
||||
if(window.active){
|
||||
return Qt.rgba(51/255,51/255,51/255,1)
|
||||
}
|
||||
return Qt.rgba(153/255,153/255,153/255,1)
|
||||
}
|
||||
}
|
||||
return "#999999"
|
||||
}
|
||||
}
|
||||
function destoryOnClose(){
|
||||
@ -262,9 +303,15 @@ Window {
|
||||
function registerForWindowResult(path){
|
||||
return lifecycle.createRegister(window,path)
|
||||
}
|
||||
function moveWindowToDesktopCenter(){
|
||||
return framless_helper.moveWindowToDesktopCenter()
|
||||
}
|
||||
function onResult(data){
|
||||
if(_pageRegister){
|
||||
_pageRegister.onResult(data)
|
||||
}
|
||||
}
|
||||
function containerItem(){
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
@ -75,80 +75,6 @@ Module {
|
||||
Parameter { name: "data"; type: "QVariantMap" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluHttp"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluHttp 1.0"]
|
||||
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: "newRequest"
|
||||
type: "HttpRequest*"
|
||||
Parameter { name: "url"; type: "string" }
|
||||
}
|
||||
Method { name: "newRequest"; type: "HttpRequest*" }
|
||||
Method {
|
||||
name: "get"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "post"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "postString"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "postJson"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "download"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "upload"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
Parameter { name: "callable"; type: "HttpCallable"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "getBreakPointProgress"
|
||||
type: "double"
|
||||
Parameter { name: "request"; type: "HttpRequest"; isPointer: true }
|
||||
}
|
||||
Method { name: "cancel" }
|
||||
}
|
||||
Component {
|
||||
name: "FluHttpInterceptor"
|
||||
prototype: "QObject"
|
||||
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"]
|
||||
@ -171,6 +97,21 @@ Module {
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluNetworkType"
|
||||
exports: ["FluentUI/FluNetworkType 1.0"]
|
||||
isCreatable: false
|
||||
exportMetaObjectRevisions: [0]
|
||||
Enum {
|
||||
name: "CacheMode"
|
||||
values: {
|
||||
"NoCache": 0,
|
||||
"RequestFailedReadCache": 1,
|
||||
"IfNoneCacheRequest": 2,
|
||||
"FirstCacheThenRequest": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluPageType"
|
||||
exports: ["FluentUI/FluPageType 1.0"]
|
||||
@ -372,7 +313,6 @@ Module {
|
||||
exports: ["FluentUI/FluViewModel 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "scope"; type: "int" }
|
||||
Property { name: "target"; type: "QObject"; isPointer: true }
|
||||
Signal { name: "initData" }
|
||||
}
|
||||
Component {
|
||||
@ -1830,9 +1770,9 @@ Module {
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "HttpCallable"
|
||||
name: "NetworkCallable"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/HttpCallable 1.0"]
|
||||
exports: ["FluentUI/FluNetworkCallable 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Signal { name: "start" }
|
||||
Signal { name: "finish" }
|
||||
@ -1850,28 +1790,86 @@ Module {
|
||||
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" }
|
||||
}
|
||||
Signal {
|
||||
name: "downloadProgress"
|
||||
Parameter { name: "recv"; type: "qlonglong" }
|
||||
Parameter { name: "total"; type: "qlonglong" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "HttpRequest"
|
||||
name: "NetworkParams"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/HttpRequest 1.0"]
|
||||
exports: ["FluentUI/FluNetworkParams 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" }
|
||||
Method {
|
||||
name: "addQuery"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "key"; type: "string" }
|
||||
Parameter { name: "val"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "addHeader"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "key"; type: "string" }
|
||||
Parameter { name: "val"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "add"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "key"; type: "string" }
|
||||
Parameter { name: "val"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "addFile"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "key"; type: "string" }
|
||||
Parameter { name: "val"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "setBody"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "val"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "setTimeout"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "val"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "setRetry"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "val"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "setCacheMode"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "val"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "toDownload"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "destPath"; type: "string" }
|
||||
Parameter { name: "append"; type: "bool" }
|
||||
}
|
||||
Method {
|
||||
name: "toDownload"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "destPath"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "bind"
|
||||
type: "NetworkParams*"
|
||||
Parameter { name: "target"; type: "QObject"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "go"
|
||||
Parameter { name: "result"; type: "NetworkCallable"; isPointer: true }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "QAbstractItemModel"
|
||||
@ -2244,12 +2242,6 @@ Module {
|
||||
Parameter { name: "b"; type: "QVariant" }
|
||||
Parameter { name: "a"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "_rgb"
|
||||
type: "QVariant"
|
||||
Parameter { name: "rgb"; type: "QVariant" }
|
||||
Parameter { name: "a"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "_fullColorString"
|
||||
type: "QVariant"
|
||||
@ -2311,6 +2303,8 @@ Module {
|
||||
Property { name: "restoreText"; type: "string" }
|
||||
Property { name: "maximizeText"; type: "string" }
|
||||
Property { name: "closeText"; type: "string" }
|
||||
Property { name: "stayTopText"; type: "string" }
|
||||
Property { name: "stayTopCancelText"; type: "string" }
|
||||
Property { name: "textColor"; type: "QColor" }
|
||||
Property { name: "minimizeNormalColor"; type: "QColor" }
|
||||
Property { name: "minimizeHoverColor"; type: "QColor" }
|
||||
@ -2325,6 +2319,7 @@ Module {
|
||||
Property { name: "showClose"; type: "bool" }
|
||||
Property { name: "showMinimize"; type: "bool" }
|
||||
Property { name: "showMaximize"; type: "bool" }
|
||||
Property { name: "showStayTop"; type: "bool" }
|
||||
Property { name: "titleVisible"; type: "bool" }
|
||||
Property { name: "icon"; type: "QUrl" }
|
||||
Property { name: "iconSize"; type: "int" }
|
||||
@ -2333,7 +2328,9 @@ Module {
|
||||
Property { name: "maxClickListener"; type: "QVariant" }
|
||||
Property { name: "minClickListener"; type: "QVariant" }
|
||||
Property { name: "closeClickListener"; type: "QVariant" }
|
||||
Property { name: "stayTopClickListener"; type: "QVariant" }
|
||||
Property { name: "darkClickListener"; type: "QVariant" }
|
||||
Method { name: "stayTopButton"; type: "QVariant" }
|
||||
Method { name: "minimizeButton"; type: "QVariant" }
|
||||
Method { name: "maximizeButton"; type: "QVariant" }
|
||||
Method { name: "closeButton"; type: "QVariant" }
|
||||
@ -2386,7 +2383,6 @@ Module {
|
||||
Property { name: "placeholderNormalColor"; type: "QColor" }
|
||||
Property { name: "placeholderFocusColor"; type: "QColor" }
|
||||
Property { name: "placeholderDisableColor"; type: "QColor" }
|
||||
Property { name: "iconRightMargin"; type: "int" }
|
||||
Property { name: "cleanEnabled"; type: "bool" }
|
||||
Signal {
|
||||
name: "commit"
|
||||
@ -2542,6 +2538,7 @@ Module {
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
Property { name: "window"; type: "QVariant" }
|
||||
Property { name: "jsChart"; type: "QVariant" }
|
||||
Property { name: "chartType"; type: "string" }
|
||||
Property { name: "chartData"; type: "QVariant" }
|
||||
@ -2582,6 +2579,7 @@ Module {
|
||||
Property { name: "textSpacing"; type: "double" }
|
||||
Property { name: "enableAnimation"; type: "bool" }
|
||||
Property { name: "clickListener"; type: "QVariant" }
|
||||
Property { name: "indeterminate"; type: "bool" }
|
||||
Property { name: "textColor"; type: "QColor" }
|
||||
}
|
||||
Component {
|
||||
@ -2600,6 +2598,7 @@ Module {
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
Property { name: "colorValue"; type: "QColor" }
|
||||
Property { name: "enableAlphaChannel"; type: "bool" }
|
||||
Method {
|
||||
name: "setColor"
|
||||
type: "QVariant"
|
||||
@ -2615,6 +2614,7 @@ Module {
|
||||
defaultProperty: "data"
|
||||
Property { name: "radius"; type: "int" }
|
||||
Property { name: "colorValue"; type: "QColor" }
|
||||
Property { name: "enableAlphaChannel"; type: "bool" }
|
||||
Method {
|
||||
name: "setColor"
|
||||
type: "QVariant"
|
||||
@ -2651,6 +2651,7 @@ Module {
|
||||
Property { name: "positiveText"; type: "string" }
|
||||
Property { name: "delayTime"; type: "int" }
|
||||
Property { name: "buttonFlags"; type: "int" }
|
||||
Property { name: "messageTextFormart"; type: "int" }
|
||||
Signal { name: "neutralClicked" }
|
||||
Signal { name: "negativeClicked" }
|
||||
Signal { name: "positiveClicked" }
|
||||
@ -2733,14 +2734,15 @@ Module {
|
||||
}
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickRectangle"
|
||||
prototype: "QQuickItem"
|
||||
name: "FluentUI/FluDivider 1.0"
|
||||
exports: ["FluentUI/FluDivider 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
Property { name: "spacing"; type: "double" }
|
||||
Property { name: "separatorHeight"; type: "double" }
|
||||
Property { name: "orientation"; type: "int" }
|
||||
Property { name: "spacing"; type: "int" }
|
||||
Property { name: "size"; type: "int" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickButton"
|
||||
@ -2835,6 +2837,7 @@ Module {
|
||||
Property { name: "iconDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "color"; type: "QColor" }
|
||||
Property { name: "iconColor"; type: "QColor" }
|
||||
Property { name: "textColor"; type: "QColor" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickImage"
|
||||
@ -2901,6 +2904,14 @@ Module {
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickLoader"
|
||||
name: "FluentUI/FluLoader 1.0"
|
||||
exports: ["FluentUI/FluLoader 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickButton"
|
||||
name: "FluentUI/FluLoadingButton 1.0"
|
||||
@ -2977,6 +2988,7 @@ Module {
|
||||
Property { name: "placeholderNormalColor"; type: "QColor" }
|
||||
Property { name: "placeholderFocusColor"; type: "QColor" }
|
||||
Property { name: "placeholderDisableColor"; type: "QColor" }
|
||||
Property { name: "isCtrlEnterForNewline"; type: "bool" }
|
||||
Signal {
|
||||
name: "commit"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
@ -2991,17 +3003,20 @@ Module {
|
||||
defaultProperty: "data"
|
||||
Property { name: "logo"; type: "QUrl" }
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "items"; type: "FluObject_QMLTYPE_140"; isPointer: true }
|
||||
Property { name: "footerItems"; type: "FluObject_QMLTYPE_140"; isPointer: true }
|
||||
Property { name: "items"; type: "FluObject_QMLTYPE_124"; isPointer: true }
|
||||
Property { name: "footerItems"; type: "FluObject_QMLTYPE_124"; isPointer: true }
|
||||
Property { name: "displayMode"; type: "int" }
|
||||
Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "topPadding"; type: "int" }
|
||||
Property { name: "pageMode"; type: "int" }
|
||||
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_52"; isPointer: true }
|
||||
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_52"; isPointer: true }
|
||||
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_39"; isPointer: true }
|
||||
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_39"; isPointer: true }
|
||||
Property { name: "navCompactWidth"; type: "int" }
|
||||
Property { name: "navTopMargin"; type: "int" }
|
||||
Property { name: "cellHeight"; type: "int" }
|
||||
Property { name: "cellWidth"; type: "int" }
|
||||
Property { name: "hideNavAppBar"; type: "bool" }
|
||||
Signal { name: "logoClicked" }
|
||||
Method { name: "collapseAll"; type: "QVariant" }
|
||||
Method {
|
||||
@ -3082,28 +3097,25 @@ Module {
|
||||
Property { name: "key"; type: "string"; isReadonly: true }
|
||||
Property { name: "_idx"; type: "int" }
|
||||
Property { name: "_ext"; type: "QVariant" }
|
||||
Property { name: "_parent"; type: "QVariant" }
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "order"; type: "int" }
|
||||
Property { name: "icon"; type: "int" }
|
||||
Property { name: "url"; type: "QVariant" }
|
||||
Property { name: "disabled"; type: "bool" }
|
||||
Property { name: "cusIcon"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "icon"; type: "int" }
|
||||
Property { name: "iconVisible"; type: "bool" }
|
||||
Property { name: "infoBadge"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "recentlyAdded"; type: "bool" }
|
||||
Property { name: "recentlyUpdated"; type: "bool" }
|
||||
Property { name: "desc"; type: "string" }
|
||||
Property { name: "image"; type: "QVariant" }
|
||||
Property { name: "parent"; type: "QVariant" }
|
||||
Property { name: "count"; type: "int" }
|
||||
Property { name: "onTapListener"; type: "QVariant" }
|
||||
Property { name: "iconDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "menuDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "editDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "showEdit"; type: "bool" }
|
||||
Signal { name: "tap" }
|
||||
Signal {
|
||||
name: "dropped"
|
||||
Parameter { name: "drag"; type: "QVariant" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
prototype: "QObject"
|
||||
@ -3114,7 +3126,7 @@ Module {
|
||||
Property { name: "key"; type: "string"; isReadonly: true }
|
||||
Property { name: "_idx"; type: "int" }
|
||||
Property { name: "_ext"; type: "QVariant" }
|
||||
Property { name: "parent"; type: "QVariant" }
|
||||
Property { name: "_parent"; type: "QVariant" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QObject"
|
||||
@ -3128,12 +3140,12 @@ Module {
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "icon"; type: "QVariant" }
|
||||
Property { name: "disabled"; type: "bool" }
|
||||
Property { name: "cusIcon"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "iconVisible"; type: "bool" }
|
||||
Property { name: "isExpand"; type: "bool" }
|
||||
Property { name: "parent"; type: "QVariant" }
|
||||
Property { name: "showEdit"; type: "bool" }
|
||||
Property { name: "iconDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "menuDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "editDelegate"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "showEdit"; type: "bool" }
|
||||
Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
|
||||
}
|
||||
Component {
|
||||
@ -3528,11 +3540,27 @@ Module {
|
||||
defaultProperty: "data"
|
||||
Property { name: "columnSource"; type: "QVariant" }
|
||||
Property { name: "dataSource"; type: "QVariant" }
|
||||
Property { name: "selectionColor"; type: "QColor" }
|
||||
Property { name: "hoverButtonColor"; type: "QColor" }
|
||||
Property { name: "pressedButtonColor"; type: "QColor" }
|
||||
Property { name: "borderColor"; type: "QColor" }
|
||||
Property { name: "tableModel"; type: "QQmlTableModel"; isReadonly: true; isPointer: true }
|
||||
Method { name: "closeEditor"; type: "QVariant" }
|
||||
Method { name: "resetPosition"; type: "QVariant" }
|
||||
Method {
|
||||
name: "customItem"
|
||||
type: "QVariant"
|
||||
Parameter { name: "comId"; type: "QVariant" }
|
||||
Parameter { name: "options"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "updateRow"
|
||||
type: "QVariant"
|
||||
Parameter { name: "row"; type: "QVariant" }
|
||||
Parameter { name: "obj"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "sort"
|
||||
type: "QVariant"
|
||||
Parameter { name: "order"; type: "QVariant" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickText"
|
||||
@ -3557,7 +3585,6 @@ Module {
|
||||
Property { name: "placeholderNormalColor"; type: "QColor" }
|
||||
Property { name: "placeholderFocusColor"; type: "QColor" }
|
||||
Property { name: "placeholderDisableColor"; type: "QColor" }
|
||||
Property { name: "iconRightMargin"; type: "int" }
|
||||
Property { name: "cleanEnabled"; type: "bool" }
|
||||
Signal {
|
||||
name: "commit"
|
||||
@ -3731,74 +3758,6 @@ Module {
|
||||
Method { name: "allExpand"; type: "QVariant" }
|
||||
Method { name: "allCollapse"; type: "QVariant" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickWindowQmlImpl"
|
||||
name: "FluentUI/FluWindow 1.0"
|
||||
exports: ["FluentUI/FluWindow 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "content"
|
||||
Property { name: "closeDestory"; type: "bool" }
|
||||
Property { name: "launchMode"; type: "int" }
|
||||
Property { name: "argument"; type: "QVariant" }
|
||||
Property { name: "background"; type: "QVariant" }
|
||||
Property { name: "loadingItem"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "backgroundColor"; type: "QColor" }
|
||||
Property { name: "_pageRegister"; type: "QVariant" }
|
||||
Property { name: "_route"; type: "string" }
|
||||
Property { name: "closeListener"; type: "QVariant" }
|
||||
Property { name: "content"; type: "QObject"; isList: true; isReadonly: true }
|
||||
Signal {
|
||||
name: "initArgument"
|
||||
Parameter { name: "argument"; type: "QVariant" }
|
||||
}
|
||||
Method { name: "destoryOnClose"; type: "QVariant" }
|
||||
Method {
|
||||
name: "showLoading"
|
||||
type: "QVariant"
|
||||
Parameter { name: "text"; type: "QVariant" }
|
||||
Parameter { name: "cancel"; type: "QVariant" }
|
||||
}
|
||||
Method { name: "hideLoading"; type: "QVariant" }
|
||||
Method {
|
||||
name: "showSuccess"
|
||||
type: "QVariant"
|
||||
Parameter { name: "text"; type: "QVariant" }
|
||||
Parameter { name: "duration"; type: "QVariant" }
|
||||
Parameter { name: "moremsg"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "showInfo"
|
||||
type: "QVariant"
|
||||
Parameter { name: "text"; type: "QVariant" }
|
||||
Parameter { name: "duration"; type: "QVariant" }
|
||||
Parameter { name: "moremsg"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "showWarning"
|
||||
type: "QVariant"
|
||||
Parameter { name: "text"; type: "QVariant" }
|
||||
Parameter { name: "duration"; type: "QVariant" }
|
||||
Parameter { name: "moremsg"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "showError"
|
||||
type: "QVariant"
|
||||
Parameter { name: "text"; type: "QVariant" }
|
||||
Parameter { name: "duration"; type: "QVariant" }
|
||||
Parameter { name: "moremsg"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "registerForWindowResult"
|
||||
type: "QVariant"
|
||||
Parameter { name: "path"; type: "QVariant" }
|
||||
}
|
||||
Method {
|
||||
name: "onResult"
|
||||
type: "QVariant"
|
||||
Parameter { name: "data"; type: "QVariant" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickRow"
|
||||
name: "FluentUI/NumberBox 1.0"
|
||||
|
@ -96,4 +96,5 @@ FluProgressButton 1.0 Controls/FluProgressButton.qml
|
||||
FluLoadingButton 1.0 Controls/FluLoadingButton.qml
|
||||
FluClip 1.0 Controls/FluClip.qml
|
||||
FluLoader 1.0 Controls/FluLoader.qml
|
||||
FluShortcutPicker 1.0 Controls/FluShortcutPicker.qml
|
||||
plugin fluentuiplugin
|
||||
|
@ -96,5 +96,6 @@
|
||||
<file>FluentUI/Controls/FluLoadingButton.qml</file>
|
||||
<file>FluentUI/Controls/FluClip.qml</file>
|
||||
<file>FluentUI/Controls/FluLoader.qml</file>
|
||||
<file>FluentUI/Controls/FluShortcutPicker.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -4,13 +4,14 @@ import FluentUI
|
||||
|
||||
Item {
|
||||
id: control
|
||||
property color tintColor: Qt.rgba(1,1,1,1)
|
||||
property color tintColor: Qt.rgba(1, 1, 1, 1)
|
||||
property real tintOpacity: 0.65
|
||||
property real luminosity: 0.01
|
||||
property real noiseOpacity : 0.066
|
||||
property alias target : effect_source.sourceItem
|
||||
property real noiseOpacity: 0.02
|
||||
property alias target: effect_source.sourceItem
|
||||
property int blurRadius: 32
|
||||
property rect targetRect : Qt.rect(control.x, control.y, control.width, control.height)
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,
|
||||
control.height)
|
||||
ShaderEffectSource {
|
||||
id: effect_source
|
||||
anchors.fill: parent
|
||||
@ -18,20 +19,20 @@ Item {
|
||||
sourceRect: control.targetRect
|
||||
}
|
||||
FastBlur {
|
||||
id:fast_blur
|
||||
id: fast_blur
|
||||
anchors.fill: parent
|
||||
source: effect_source
|
||||
radius: control.blurRadius
|
||||
}
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(1, 1, 1, luminosity)
|
||||
}
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(tintColor.r, tintColor.g, tintColor.b, tintOpacity)
|
||||
}
|
||||
Image{
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "../Image/noise.png"
|
||||
fillMode: Image.Tile
|
||||
|
@ -72,10 +72,10 @@ Rectangle{
|
||||
return false
|
||||
}
|
||||
property bool isRestore: win && Window.Maximized === win.visibility
|
||||
property bool resizable: win && !(win.minimumHeight === win.maximumHeight && win.maximumWidth === win.minimumWidth)
|
||||
property bool resizable: win && !(win.height === win.maximumHeight && win.height === win.minimumHeight && win.width === win.maximumWidth && win.width === win.minimumWidth)
|
||||
}
|
||||
TapHandler {
|
||||
onTapped: if (tapCount === 2) btn_maximize.clicked()
|
||||
onTapped: if (tapCount === 2 && d.resizable) btn_maximize.clicked()
|
||||
gesturePolicy: TapHandler.DragThreshold
|
||||
}
|
||||
DragHandler {
|
||||
|
@ -7,8 +7,8 @@ Button {
|
||||
property bool disabled: false
|
||||
property string contentDescription: ""
|
||||
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
property color textColor: {
|
||||
if(FluTheme.dark){
|
||||
if(!enabled){
|
||||
@ -34,6 +34,7 @@ Button {
|
||||
Accessible.onPressAction: control.clicked()
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
font:FluTextStyle.Body
|
||||
focusPolicy:Qt.TabFocus
|
||||
|
@ -5,51 +5,37 @@ import QtQuick.Window
|
||||
import FluentUI
|
||||
|
||||
FluPopup {
|
||||
id: popup
|
||||
property string title: "Title"
|
||||
property string message: "Message"
|
||||
id: control
|
||||
property string title: ""
|
||||
property string message: ""
|
||||
property string neutralText: "Neutral"
|
||||
property string negativeText: "Negative"
|
||||
property string positiveText: "Positive"
|
||||
property alias messageTextFormart: text_message.textFormat
|
||||
property int messageTextFormart: Text.AutoText
|
||||
property int delayTime: 100
|
||||
property int buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
|
||||
property var contentDelegate: Component{
|
||||
Item{
|
||||
}
|
||||
}
|
||||
property var onNeutralClickListener
|
||||
property var onNegativeClickListener
|
||||
property var onPositiveClickListener
|
||||
signal neutralClicked
|
||||
signal negativeClicked
|
||||
signal positiveClicked
|
||||
property int buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
|
||||
focus: true
|
||||
implicitWidth: 400
|
||||
implicitHeight: text_title.height + sroll_message.height + layout_actions.height
|
||||
Rectangle {
|
||||
id:layout_content
|
||||
anchors.fill: parent
|
||||
color: 'transparent'
|
||||
radius:5
|
||||
FluText{
|
||||
id:text_title
|
||||
font: FluTextStyle.TitleLarge
|
||||
text:title
|
||||
topPadding: 20
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
wrapMode: Text.WrapAnywhere
|
||||
anchors{
|
||||
top:parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
implicitHeight: layout_content.height
|
||||
focus: true
|
||||
Component{
|
||||
id:com_message
|
||||
Flickable{
|
||||
id:sroll_message
|
||||
contentHeight: text_message.height
|
||||
contentWidth: width
|
||||
clip: true
|
||||
anchors{
|
||||
top:text_title.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
boundsBehavior:Flickable.StopAtBounds
|
||||
contentHeight: text_message.height
|
||||
width: parent.width
|
||||
height: Math.min(text_message.height,300)
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
FluText{
|
||||
@ -58,82 +44,113 @@ FluPopup {
|
||||
wrapMode: Text.WrapAnywhere
|
||||
text:message
|
||||
width: parent.width
|
||||
topPadding: 14
|
||||
topPadding: 4
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
bottomPadding: 14
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
id:layout_actions
|
||||
height: 68
|
||||
radius: 5
|
||||
color: FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
|
||||
anchors{
|
||||
top:sroll_message.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
RowLayout{
|
||||
anchors
|
||||
{
|
||||
centerIn: parent
|
||||
margins: spacing
|
||||
fill: parent
|
||||
}
|
||||
spacing: 15
|
||||
FluButton{
|
||||
id:neutral_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.NeutralButton
|
||||
text: neutralText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.NeutralButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
id:negative_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.NegativeButton
|
||||
text: negativeText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.NegativeButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
FluFilledButton{
|
||||
id:positive_btn
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: popup.buttonFlags&FluContentDialogType.PositiveButton
|
||||
text: positiveText
|
||||
onClicked: {
|
||||
popup.close()
|
||||
timer_delay.targetFlags = FluContentDialogType.PositiveButton
|
||||
timer_delay.restart()
|
||||
}
|
||||
}
|
||||
bottomPadding: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer{
|
||||
property int targetFlags
|
||||
id:timer_delay
|
||||
interval: popup.delayTime
|
||||
onTriggered: {
|
||||
if(targetFlags === FluContentDialogType.NegativeButton){
|
||||
negativeClicked()
|
||||
Rectangle {
|
||||
id:layout_content
|
||||
width: parent.width
|
||||
height: layout_column.childrenRect.height
|
||||
color: 'transparent'
|
||||
radius:5
|
||||
ColumnLayout{
|
||||
id:layout_column
|
||||
width: parent.width
|
||||
FluText{
|
||||
id:text_title
|
||||
font: FluTextStyle.Title
|
||||
text:title
|
||||
topPadding: 20
|
||||
leftPadding: 20
|
||||
rightPadding: 20
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
if(targetFlags === FluContentDialogType.NeutralButton){
|
||||
neutralClicked()
|
||||
FluLoader{
|
||||
sourceComponent: com_message
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: status===Loader.Ready ? item.height : 0
|
||||
}
|
||||
if(targetFlags === FluContentDialogType.PositiveButton){
|
||||
positiveClicked()
|
||||
FluLoader{
|
||||
sourceComponent: control.contentDelegate
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: status===Loader.Ready ? item.height : 0
|
||||
}
|
||||
Rectangle{
|
||||
id:layout_actions
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 60
|
||||
radius: 5
|
||||
color: FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
|
||||
RowLayout{
|
||||
anchors
|
||||
{
|
||||
centerIn: parent
|
||||
margins: spacing
|
||||
fill: parent
|
||||
}
|
||||
spacing: 10
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.NeutralButton
|
||||
FluButton{
|
||||
id:neutral_btn
|
||||
text: neutralText
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
onClicked: {
|
||||
if(control.onNeutralClickListener){
|
||||
control.onNeutralClickListener()
|
||||
}else{
|
||||
neutralClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.NegativeButton
|
||||
FluButton{
|
||||
id:negative_btn
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
text: negativeText
|
||||
onClicked: {
|
||||
if(control.onNegativeClickListener){
|
||||
control.onNegativeClickListener()
|
||||
}else{
|
||||
negativeClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: control.buttonFlags&FluContentDialogType.PositiveButton
|
||||
FluFilledButton{
|
||||
id:positive_btn
|
||||
text: positiveText
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
onClicked: {
|
||||
if(control.onPositiveClickListener){
|
||||
control.onPositiveClickListener()
|
||||
}else{
|
||||
positiveClicked()
|
||||
control.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ Button {
|
||||
property bool disabled: false
|
||||
property string contentDescription: ""
|
||||
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
|
||||
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
property color textColor: {
|
||||
if(FluTheme.dark){
|
||||
if(!enabled){
|
||||
@ -39,6 +39,7 @@ Button {
|
||||
rightPadding:35
|
||||
enabled: !disabled
|
||||
focusPolicy:Qt.TabFocus
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: Rectangle{
|
||||
implicitWidth: 28
|
||||
|
@ -28,6 +28,7 @@ Button {
|
||||
enabled: !disabled
|
||||
focusPolicy:Qt.TabFocus
|
||||
font:FluTextStyle.Body
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: Rectangle{
|
||||
implicitWidth: 28
|
||||
|
@ -977,7 +977,6 @@ Item {
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
ListView{
|
||||
id:nav_list
|
||||
clip: true
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
|
@ -22,14 +22,14 @@ Button {
|
||||
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)
|
||||
return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/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)
|
||||
return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
}
|
||||
}
|
||||
property color pressedColor: FluTheme.dark ? Qt.darker(normalColor,1.2) : Qt.lighter(normalColor,1.2)
|
||||
@ -40,6 +40,7 @@ Button {
|
||||
focusPolicy:Qt.TabFocus
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
background: FluClip{
|
||||
implicitWidth: 28
|
||||
|
231
src/Qt6/imports/FluentUI/Controls/FluShortcutPicker.qml
Normal file
231
src/Qt6/imports/FluentUI/Controls/FluShortcutPicker.qml
Normal file
@ -0,0 +1,231 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import FluentUI
|
||||
|
||||
FluIconButton {
|
||||
id:control
|
||||
property var current : ["Ctrl","Shift","A"]
|
||||
property string title: "激活快捷键"
|
||||
property string message: "按下组合键以更改此快捷键"
|
||||
property string positiveText: "保存"
|
||||
property string neutralText: "取消"
|
||||
property string negativeText: "重置"
|
||||
signal accepted()
|
||||
QtObject{
|
||||
id: d
|
||||
function keyToString(key_code,shift = true)
|
||||
{
|
||||
switch(key_code)
|
||||
{
|
||||
case Qt.Key_Period: return ".";
|
||||
case Qt.Key_Greater: return shift ? ">" : ".";
|
||||
case Qt.Key_Comma: return ",";
|
||||
case Qt.Key_Less: return shift ? "<" : ",";
|
||||
case Qt.Key_Slash: return "/";
|
||||
case Qt.Key_Question: return shift ? "?" : "/";
|
||||
case Qt.Key_Semicolon: return ";";
|
||||
case Qt.Key_Colon: return shift ? ":" : ";";
|
||||
case Qt.Key_Apostrophe: return "'";
|
||||
case Qt.Key_QuoteDbl: return shift ? "'" : "\"";
|
||||
case Qt.Key_QuoteLeft: return "`";
|
||||
case Qt.Key_AsciiTilde: return shift ? "~" : "`";
|
||||
case Qt.Key_Minus: return "-";
|
||||
case Qt.Key_Underscore: return shift ? "_" : "-";
|
||||
case Qt.Key_Equal: return "=";
|
||||
case Qt.Key_Plus: return shift ? "+" : "=";
|
||||
case Qt.Key_BracketLeft: return "[";
|
||||
case Qt.Key_BraceLeft: return shift ? "{" : "[";
|
||||
case Qt.Key_BracketRight: return "]";
|
||||
case Qt.Key_BraceRight: return shift ? "}" : "]";
|
||||
case Qt.Key_Backslash: return "\\";
|
||||
case Qt.Key_Bar: return shift ? "|" : "\\";
|
||||
case Qt.Key_Up: return "Up";
|
||||
case Qt.Key_Down: return "Down";
|
||||
case Qt.Key_Right: return "Right";
|
||||
case Qt.Key_Left: return "Left";
|
||||
case Qt.Key_Space: return "Space";
|
||||
case Qt.Key_PageDown: return "PgDown";
|
||||
case Qt.Key_PageUp: return "PgUp";
|
||||
case Qt.Key_0: return "0";
|
||||
case Qt.Key_1: return "1";
|
||||
case Qt.Key_2: return "2";
|
||||
case Qt.Key_3: return "3";
|
||||
case Qt.Key_4: return "4";
|
||||
case Qt.Key_5: return "5";
|
||||
case Qt.Key_6: return "6";
|
||||
case Qt.Key_7: return "7";
|
||||
case Qt.Key_8: return "8";
|
||||
case Qt.Key_9: return "9";
|
||||
case Qt.Key_Exclam: return shift ? "!" : "1";
|
||||
case Qt.Key_At: return shift ? "@" : "2";
|
||||
case Qt.Key_NumberSign: return shift ? "#" : "3";
|
||||
case Qt.Key_Dollar: return shift ? "$" : "4";
|
||||
case Qt.Key_Percent: return shift ? "%" : "5";
|
||||
case Qt.Key_AsciiCircum: return shift ? "^" : "6";
|
||||
case Qt.Key_Ampersand: return shift ? "&" : "7";
|
||||
case Qt.Key_Asterisk: return shift ? "*" : "8";
|
||||
case Qt.Key_ParenLeft: return shift ? "(" : "9";
|
||||
case Qt.Key_ParenRight: return shift ? ")" : "0";
|
||||
case Qt.Key_A: return "A";
|
||||
case Qt.Key_B: return "B";
|
||||
case Qt.Key_C: return "C";
|
||||
case Qt.Key_D: return "D";
|
||||
case Qt.Key_E: return "E";
|
||||
case Qt.Key_F: return "F";
|
||||
case Qt.Key_G: return "G";
|
||||
case Qt.Key_H: return "H";
|
||||
case Qt.Key_I: return "I";
|
||||
case Qt.Key_J: return "J";
|
||||
case Qt.Key_K: return "K";
|
||||
case Qt.Key_L: return "L";
|
||||
case Qt.Key_M: return "M";
|
||||
case Qt.Key_N: return "N";
|
||||
case Qt.Key_O: return "O";
|
||||
case Qt.Key_P: return "P";
|
||||
case Qt.Key_Q: return "Q";
|
||||
case Qt.Key_R: return "R";
|
||||
case Qt.Key_S: return "S";
|
||||
case Qt.Key_T: return "T";
|
||||
case Qt.Key_U: return "U";
|
||||
case Qt.Key_V: return "V";
|
||||
case Qt.Key_W: return "W";
|
||||
case Qt.Key_X: return "X";
|
||||
case Qt.Key_Y: return "Y";
|
||||
case Qt.Key_Z: return "Z";
|
||||
case Qt.Key_F1: return "F1";
|
||||
case Qt.Key_F2: return "F2";
|
||||
case Qt.Key_F3: return "F3";
|
||||
case Qt.Key_F4: return "F4";
|
||||
case Qt.Key_F5: return "F5";
|
||||
case Qt.Key_F6: return "F6";
|
||||
case Qt.Key_F7: return "F7";
|
||||
case Qt.Key_F8: return "F8";
|
||||
case Qt.Key_F9: return "F9";
|
||||
case Qt.Key_F10: return "F10";
|
||||
case Qt.Key_F11: return "F11";
|
||||
case Qt.Key_F12: return "F12";
|
||||
case Qt.Key_Home: return "Home";
|
||||
case Qt.Key_End: return "End";
|
||||
case Qt.Key_Insert: return "Insert";
|
||||
case Qt.Key_Delete: return "Delete";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
background: Rectangle{
|
||||
border.color: FluTheme.dark ? "#505050" : "#DFDFDF"
|
||||
border.width: 1
|
||||
implicitHeight: 42
|
||||
implicitWidth: layout_row.width+28
|
||||
radius: control.radius
|
||||
color:control.color
|
||||
FluFocusRectangle{
|
||||
visible: control.activeFocus
|
||||
}
|
||||
}
|
||||
component ItemKey:Rectangle{
|
||||
id:item_key_control
|
||||
property string text : ""
|
||||
color:FluTheme.primaryColor
|
||||
width: Math.max(item_text.implicitWidth+12,28)
|
||||
height: Math.max(item_text.implicitHeight,28)
|
||||
radius: 4
|
||||
Text{
|
||||
id:item_text
|
||||
color: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
|
||||
font.pixelSize: 13
|
||||
text: item_key_control.text
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
Row{
|
||||
id:layout_row
|
||||
spacing: 5
|
||||
anchors.centerIn: parent
|
||||
Repeater{
|
||||
model: control.current
|
||||
delegate: ItemKey{
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
Item{
|
||||
width: 3
|
||||
height: 1
|
||||
}
|
||||
FluIcon{
|
||||
iconSource: FluentIcons.EditMirrored
|
||||
iconSize: 13
|
||||
anchors{
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
FluContentDialog{
|
||||
id:content_dialog
|
||||
property var keysModel: []
|
||||
title: control.title
|
||||
message: control.message
|
||||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton | FluContentDialogType.NeutralButton
|
||||
positiveText: control.positiveText
|
||||
neutralText: control.neutralText
|
||||
negativeText: control.negativeText
|
||||
onVisibleChanged: {
|
||||
if(visible){
|
||||
content_dialog.keysModel = control.current
|
||||
}
|
||||
}
|
||||
onPositiveClicked: {
|
||||
control.current = content_dialog.keysModel
|
||||
control.accepted()
|
||||
}
|
||||
onNegativeClickListener: function(){
|
||||
content_dialog.keysModel = control.current
|
||||
}
|
||||
contentDelegate: Component{
|
||||
Item{
|
||||
width: parent.width
|
||||
height: 100
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
}
|
||||
Keys.enabled: true
|
||||
Keys.onPressed:
|
||||
(event)=>{
|
||||
var keyNames = []
|
||||
if (event.modifiers & Qt.AltModifier) {
|
||||
keyNames.push("Alt")
|
||||
}
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyNames.push("Ctrl")
|
||||
}
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
keyNames.push("Shift")
|
||||
}
|
||||
var keyName = d.keyToString(event.key,false)
|
||||
if(keyName!==""){
|
||||
keyNames.push(keyName)
|
||||
content_dialog.keysModel = keyNames
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
Keys.onTabPressed:
|
||||
(event)=>{
|
||||
event.accepted = true
|
||||
}
|
||||
Row{
|
||||
spacing: 5
|
||||
anchors.centerIn: parent
|
||||
Repeater{
|
||||
model: content_dialog.keysModel
|
||||
delegate: ItemKey{
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
content_dialog.open()
|
||||
}
|
||||
}
|
@ -72,7 +72,7 @@ T.SpinBox {
|
||||
}
|
||||
}
|
||||
|
||||
up.indicator: FluRectangle {
|
||||
up.indicator: FluClip {
|
||||
x: control.mirrored ? 0 : control.width - width
|
||||
height: control.height
|
||||
implicitWidth: 32
|
||||
@ -107,7 +107,7 @@ T.SpinBox {
|
||||
}
|
||||
|
||||
|
||||
down.indicator: FluRectangle {
|
||||
down.indicator: FluClip {
|
||||
x: control.mirrored ? parent.width - width : 0
|
||||
height: control.height
|
||||
implicitWidth: 32
|
||||
|
@ -17,14 +17,14 @@ Button {
|
||||
if(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)
|
||||
return FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(246/255,246/255,246/255,1)
|
||||
}
|
||||
}
|
||||
property color disableColor: {
|
||||
if(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)
|
||||
return FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(244/255,244/255,244/255,1)
|
||||
}
|
||||
}
|
||||
property var clickListener : function(){
|
||||
@ -38,6 +38,7 @@ Button {
|
||||
focusPolicy:Qt.TabFocus
|
||||
id: control
|
||||
enabled: !disabled
|
||||
verticalPadding: 0
|
||||
horizontalPadding:12
|
||||
onClicked: clickListener()
|
||||
background: Rectangle{
|
||||
|
@ -109,8 +109,12 @@ Popup{
|
||||
width: 500
|
||||
height: 88 + text_desc.height
|
||||
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
|
||||
property int dir : (y<d.pos.y)?1:0
|
||||
x: Math.min(Math.max(0,d.pos.x+d.target.width/2-width/2),d.window?.width-width)
|
||||
y: d.pos.y+d.target.height+control.targetMargins + 15
|
||||
y: {
|
||||
var ty=d.pos.y+d.target.height+control.targetMargins + 15
|
||||
return ((ty+height)>d.window?.height)?(d.pos.y-height-control.targetMargins - 15):ty
|
||||
}
|
||||
border.width: 0
|
||||
FluShadow{
|
||||
radius: 5
|
||||
@ -183,9 +187,9 @@ Popup{
|
||||
}
|
||||
}
|
||||
FluIcon{
|
||||
iconSource: FluentIcons.FlickDown
|
||||
iconSource: layout_panne.dir?FluentIcons.FlickUp:FluentIcons.FlickDown
|
||||
color: layout_panne.color
|
||||
x: d.pos.x+d.target.width/2-10
|
||||
y: d.pos.y+d.target.height
|
||||
y: d.pos.y+(layout_panne.dir?-height:d.target.height)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,17 @@ Window {
|
||||
property var background : com_background
|
||||
property bool fixSize: false
|
||||
property Component loadingItem: com_loading
|
||||
property var appBar: com_app_bar
|
||||
property bool fitsAppBarWindows: false
|
||||
property Item appBar: FluAppBar {
|
||||
title: window.title
|
||||
width: window.width
|
||||
height: 30
|
||||
showDark: window.showDark
|
||||
showClose: window.showClose
|
||||
showMinimize: window.showMinimize
|
||||
showMaximize: window.showMaximize
|
||||
showStayTop: window.showStayTop
|
||||
}
|
||||
property color backgroundColor: {
|
||||
if(active){
|
||||
return FluTheme.windowActiveBackgroundColor
|
||||
@ -27,6 +37,8 @@ Window {
|
||||
property bool showMinimize: true
|
||||
property bool showMaximize: true
|
||||
property bool showStayTop: true
|
||||
property bool useSystemAppBar
|
||||
property bool autoMaximize: false
|
||||
property var closeListener: function(event){
|
||||
if(closeDestory){
|
||||
destoryOnClose()
|
||||
@ -36,24 +48,43 @@ Window {
|
||||
}
|
||||
}
|
||||
signal initArgument(var argument)
|
||||
signal firstVisible()
|
||||
id:window
|
||||
maximumWidth: useSystemAppBar&&fixSize ? width : 16777215
|
||||
maximumHeight: useSystemAppBar&&fixSize ? height : 16777215
|
||||
minimumWidth: useSystemAppBar&&fixSize ? width : 0
|
||||
minimumHeight: useSystemAppBar&&fixSize ? height : 0
|
||||
color:"transparent"
|
||||
onStayTopChanged: {
|
||||
d.changedStayTop()
|
||||
}
|
||||
Component.onCompleted: {
|
||||
useSystemAppBar = FluApp.useSystemAppBar
|
||||
lifecycle.onCompleted(window)
|
||||
initArgument(argument)
|
||||
d.changedStayTop()
|
||||
if(useSystemAppBar){
|
||||
window.moveWindowToDesktopCenter()
|
||||
if(window.autoMaximize){
|
||||
window.showMaximized()
|
||||
}else{
|
||||
window.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
lifecycle.onDestruction()
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if(visible && d.isFirstVisible){
|
||||
window.firstVisible()
|
||||
d.isFirstVisible = false
|
||||
}
|
||||
lifecycle.onVisible(visible)
|
||||
}
|
||||
QtObject{
|
||||
id:d
|
||||
property bool isFirstVisible: true
|
||||
function changedStayTop(){
|
||||
function toggleStayTop(){
|
||||
if(window.stayTop){
|
||||
@ -81,34 +112,35 @@ Window {
|
||||
color: window.backgroundColor
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_app_bar
|
||||
FluAppBar {
|
||||
title: window.title
|
||||
showDark: window.showDark
|
||||
showClose: window.showClose
|
||||
showMinimize: window.showMinimize
|
||||
showMaximize: window.showMaximize
|
||||
showStayTop: window.showStayTop
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
anchors.fill: parent
|
||||
sourceComponent: background
|
||||
}
|
||||
FluLoader{
|
||||
id: loader_title_bar
|
||||
id:loader_app_bar
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
sourceComponent: window.appBar
|
||||
sourceComponent: window.useSystemAppBar ? undefined : com_app_bar
|
||||
}
|
||||
Component{
|
||||
id:com_app_bar
|
||||
Item{
|
||||
data: window.appBar
|
||||
height: {
|
||||
if(FluApp.useSystemAppBar){
|
||||
return 0
|
||||
}
|
||||
return window.fitsAppBarWindows ? 0 : childrenRect.height
|
||||
}
|
||||
}
|
||||
}
|
||||
Item{
|
||||
id:container
|
||||
anchors{
|
||||
top: loader_title_bar.bottom
|
||||
top: loader_app_bar.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
@ -201,38 +233,47 @@ Window {
|
||||
onReady: {
|
||||
flags = flags | Qt.Window | Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
|
||||
if(appBar){
|
||||
var title_bar = loader_title_bar.item
|
||||
setTitleBarItem(title_bar)
|
||||
moveWindowToDesktopCenter()
|
||||
setHitTestVisible(title_bar.minimizeButton())
|
||||
setHitTestVisible(title_bar.maximizeButton())
|
||||
setHitTestVisible(title_bar.closeButton())
|
||||
setHitTestVisible(title_bar.stayTopButton())
|
||||
var appbar = window.appBar
|
||||
window.moveWindowToDesktopCenter()
|
||||
setWindowFixedSize(fixSize)
|
||||
title_bar.maximizeButton.visible = !fixSize
|
||||
if (blurBehindWindowEnabled)
|
||||
window.background = undefined
|
||||
}
|
||||
window.show()
|
||||
if(window.autoMaximize){
|
||||
window.showMaximized()
|
||||
}else{
|
||||
window.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
WindowLifecycle{
|
||||
id:lifecycle
|
||||
}
|
||||
WindowBorder{
|
||||
z:999
|
||||
visible: !FluTools.isLinux()
|
||||
}
|
||||
Rectangle{
|
||||
FluLoader{
|
||||
id:loader_window_border
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
border.width: 1
|
||||
visible: FluTools.isLinux()
|
||||
border.color: {
|
||||
if(window.active){
|
||||
return "#333333"
|
||||
z:999
|
||||
sourceComponent: FluApp.useSystemAppBar ? undefined : com_window_border
|
||||
}
|
||||
Component{
|
||||
id:com_window_border
|
||||
Item{
|
||||
WindowBorder{
|
||||
anchors.fill: parent
|
||||
visible: !FluTools.isLinux()
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0,0,0,0)
|
||||
border.width: 1
|
||||
visible: FluTools.isLinux()
|
||||
border.color: {
|
||||
if(window.active){
|
||||
return Qt.rgba(51/255,51/255,51/255,1)
|
||||
}
|
||||
return Qt.rgba(153/255,153/255,153/255,1)
|
||||
}
|
||||
}
|
||||
return "#999999"
|
||||
}
|
||||
}
|
||||
function destoryOnClose(){
|
||||
@ -261,9 +302,15 @@ Window {
|
||||
function registerForWindowResult(path){
|
||||
return lifecycle.createRegister(window,path)
|
||||
}
|
||||
function moveWindowToDesktopCenter(){
|
||||
return framless_helper.moveWindowToDesktopCenter()
|
||||
}
|
||||
function onResult(data){
|
||||
if(_pageRegister){
|
||||
_pageRegister.onResult(data)
|
||||
}
|
||||
}
|
||||
function containerItem(){
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user