Compare commits

..

40 Commits
1.5.4 ... 1.5.7

Author SHA1 Message Date
79a7c97fe8 update 2023-09-12 22:55:42 +08:00
fd30819393 update 2023-09-12 18:45:15 +08:00
05040ec4a9 update 2023-09-11 18:10:50 +08:00
0297445218 update 2023-09-10 17:05:36 +08:00
3990c95489 update 2023-09-10 16:58:23 +08:00
618b21854f Compatible with static build 2023-09-09 20:09:20 +08:00
ef40e3b109 update 2023-09-09 10:19:47 +08:00
f2b67af58a update 2023-09-08 23:01:31 +08:00
c0f15060af update 2023-09-08 22:43:52 +08:00
24f3cb1027 update 2023-09-08 22:33:23 +08:00
4b01fcf2b4 update 2023-09-08 19:14:45 +08:00
752fe8cfba update 2023-09-08 17:39:10 +08:00
e1292966c1 update 2023-09-08 13:54:40 +08:00
249c294926 update 2023-09-08 01:12:20 +08:00
573898149a update 2023-09-08 00:21:28 +08:00
c92d807ec1 update 2023-09-07 18:07:23 +08:00
531bffdf1a update 2023-09-06 23:17:33 +08:00
db47a75f6b update 2023-09-06 22:52:48 +08:00
ad79480345 update 2023-09-06 18:07:51 +08:00
ed5956d824 update 2023-09-06 14:05:29 +08:00
ddee70cdca add breakPointDownload property 2023-09-06 00:22:37 +08:00
d6bbe3a5ec update 2023-09-05 18:38:16 +08:00
d93d6b7c26 update 2023-09-05 16:48:04 +08:00
54be482833 update 2023-09-04 22:49:50 +08:00
f60eaec07c Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-09-04 20:45:56 +08:00
f7b7d30a6f update 2023-09-04 18:37:55 +08:00
ba32c92133 update 2023-09-04 11:29:15 +08:00
08c4f78454 update 2023-09-01 18:38:21 +08:00
e29150ca52 update THIRD_PARTY_COPYRIGHT 2023-09-01 09:37:07 +08:00
1be9103412 update 2023-08-31 18:06:05 +08:00
8583427a49 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-08-30 18:44:13 +08:00
94a96cf75e update 2023-08-30 18:44:07 +08:00
5b3834ed8f add FluStaggeredView 2023-08-30 17:18:49 +08:00
5fc7ae7e89 add FpsItem 2023-08-28 17:14:21 +08:00
82a3f85f10 fix #266 2023-08-27 18:22:52 +08:00
56a62f0b29 fix #264 2023-08-27 12:40:02 +08:00
e30db258ca fix #265 2023-08-27 11:24:48 +08:00
e2879f564c check update 2023-08-27 09:11:44 +08:00
db74f71e82 update 2023-08-26 17:27:52 +08:00
aedb89b34b update 2023-08-26 17:20:30 +08:00
164 changed files with 6243 additions and 1808 deletions

View File

@ -1,5 +1,6 @@
include(CMakeParseArguments)
find_package(Qt5 REQUIRED COMPONENTS Core)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
function(FindQmlPluginDump)
get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
@ -35,7 +36,6 @@ function(add_qmlplugin TARGET)
${QMLPLUGIN_SOURCES}
)
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
add_custom_target("${TARGET}-qmlfiles" SOURCES ${QMLPLUGIN_QMLFILES})
if(QMLPLUGIN_NO_AUTORCC)
set_target_properties(${TARGET} PROPERTIES AUTOMOC OFF)

View File

@ -1,12 +1,11 @@
// 应用程序版本信息
// 请勿修改此头文件,因为这个文件是自动生成的
#ifndef VERSION_H
#define VERSION_H
#include <QtGlobal>
#define APPLICATION_VERSION "${GIT_SEMVER}.${GIT_COMMIT_COUNT}"
#define APPLICATION_FULL_VERSION "${GIT_SEMVER}.${GIT_COMMIT_COUNT}"
#define VERSION_COUNTER ${GIT_COMMIT_COUNT}
#define COMMIT_HASH "${GIT_DESCRIBE}"
#define APPLICATION_VERSION "${GIT_SEMVER}"
#endif // VERSION_H

View File

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

View File

@ -122,7 +122,7 @@ else()
target_include_directories(example PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_sources(example PRIVATE resource.qrc)
target_sources(example PRIVATE example.qrc)
endif()
#导入component头文件,不然通过QML_NAMED_ELEMENT生成的c++类会找不到头文件报错
@ -130,6 +130,13 @@ target_include_directories(example PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/component
)
#如何是静态库则需要手动注册插件导入FluentUI.h头文件
if(FLUENTUI_BUILD_STATIC_LIB)
target_include_directories(example PRIVATE
${CMAKE_SOURCE_DIR}/src
)
endif()
#设置属性
set_target_properties(example PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
@ -139,27 +146,14 @@ set_target_properties(example PROPERTIES
WIN32_EXECUTABLE TRUE
)
#链接库
if (FLUENTUI_BUILD_STATIC_LIB)
target_link_libraries(example PRIVATE
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Svg
Qt${QT_VERSION_MAJOR}::Network
fluentui
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
else()
target_link_libraries(example PRIVATE
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Svg
Qt${QT_VERSION_MAJOR}::Network
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
endif()
target_link_libraries(example PRIVATE
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Svg
Qt${QT_VERSION_MAJOR}::Network
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
#安装
install(TARGETS example

View File

@ -126,7 +126,6 @@
<file>qml/component/CustomWindow.qml</file>
<file>qml/global/ItemsFooter.qml</file>
<file>qml/global/ItemsOriginal.qml</file>
<file>qml/global/MainEvent.qml</file>
<file>qml/global/qmldir</file>
<file>qml/page/T_Acrylic.qml</file>
<file>qml/page/T_Awesome.qml</file>
@ -184,5 +183,9 @@
<file>qml/window/StandardWindow.qml</file>
<file>res/image/bg_scenic.png</file>
<file>res/image/image_1.jpg</file>
<file>qml/window/PageWindow.qml</file>
<file>qml/page/T_StaggeredView.qml</file>
<file>qml/viewmodel/SettingsViewModel.qml</file>
<file>qml/viewmodel/TextBoxViewModel.qml</file>
</qresource>
</RCC>

View File

@ -35,7 +35,8 @@ Window {
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml"
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.httpInterceptor = interceptor

View File

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

View File

@ -14,7 +14,8 @@ FluObject{
FluPaneItem{
title:lang.about
icon:FluentIcons.Contact
tapFunc:function(){
onDropped: { FluApp.navigate("/about") }
onTapListener:function(){
FluApp.navigate("/about")
}
}
@ -22,8 +23,10 @@ FluObject{
FluPaneItem{
title:lang.settings
icon:FluentIcons.Settings
url:"qrc:/example/qml/page/T_Settings.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
navigationView.push("qrc:/example/qml/page/T_Settings.qml")
navigationView.push(url)
}
}

View File

@ -21,11 +21,13 @@ FluObject{
count: item_home.count
}
icon:FluentIcons.Home
url:"qrc:/example/qml/page/T_Home.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
if(navigationView.getCurrentUrl()){
item_home.count = 0
}
navigationView.push("qrc:/example/qml/page/T_Home.qml")
navigationView.push(url)
}
editDelegate: FluTextBox{
text:item_home.title
@ -69,9 +71,11 @@ FluObject{
image:"qrc:/example/res/image/control/Button.png"
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
url:"qrc:/example/qml/page/T_Buttons.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_buttons.count = 0
navigationView.push("qrc:/example/qml/page/T_Buttons.qml")
navigationView.push(url)
}
}
FluPaneItem{
@ -82,46 +86,48 @@ FluObject{
count: item_text.count
color: Qt.rgba(82/255,196/255,26/255,1)
}
url:"qrc:/example/qml/page/T_Text.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_text.count = 0
navigationView.push("qrc:/example/qml/page/T_Text.qml")
navigationView.push(url)
}
}
FluPaneItem{
title:"Image"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Image.qml")
}
url:"qrc:/example/qml/page/T_Image.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Slider"
image:"qrc:/example/res/image/control/Slider.png"
recentlyUpdated:true
desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."
onTap:{
navigationView.push("qrc:/example/qml/page/T_Slider.qml")
}
url:"qrc:/example/qml/page/T_Slider.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CheckBox"
image:"qrc:/example/res/image/control/Checkbox.png"
recentlyUpdated:true
desc:"A control that a user can select or clear."
onTap:{
navigationView.push("qrc:/example/qml/page/T_CheckBox.qml")
}
url:"qrc:/example/qml/page/T_CheckBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"RadioButton"
onTap:{
navigationView.push("qrc:/example/qml/page/T_RadioButton.qml")
}
url:"qrc:/example/qml/page/T_RadioButton.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"ToggleSwitch"
onTap:{
navigationView.push("qrc:/example/qml/page/T_ToggleSwitch.qml")
}
url:"qrc:/example/qml/page/T_ToggleSwitch.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -130,33 +136,33 @@ FluObject{
icon:FluentIcons.GridView
FluPaneItem{
title:"TextBox"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TextBox.qml")
}
url:"qrc:/example/qml/page/T_TextBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TimePicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TimePicker.qml")
}
url:"qrc:/example/qml/page/T_TimePicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"DatePicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_DatePicker.qml")
}
url:"qrc:/example/qml/page/T_DatePicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CalendarPicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_CalendarPicker.qml")
}
url:"qrc:/example/qml/page/T_CalendarPicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"ColorPicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_ColorPicker.qml")
}
url:"qrc:/example/qml/page/T_ColorPicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -168,57 +174,63 @@ FluObject{
image:"qrc:/example/res/image/control/InfoBar.png"
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
onTap:{
navigationView.push("qrc:/example/qml/page/T_InfoBar.qml")
}
url:"qrc:/example/qml/page/T_InfoBar.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Progress"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Progress.qml")
}
url:"qrc:/example/qml/page/T_Progress.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"RatingControl"
onTap:{
navigationView.push("qrc:/example/qml/page/T_RatingControl.qml")
}
url:"qrc:/example/qml/page/T_RatingControl.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Badge"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Badge.qml")
}
url:"qrc:/example/qml/page/T_Badge.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Rectangle"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Rectangle.qml")
}
url:"qrc:/example/qml/page/T_Rectangle.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"StatusView"
onTap:{
navigationView.push("qrc:/example/qml/page/T_StatusView.qml")
}
url:"qrc:/example/qml/page/T_StatusView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Carousel"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Carousel.qml")
}
url:"qrc:/example/qml/page/T_Carousel.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Expander"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Expander.qml")
}
url:"qrc:/example/qml/page/T_Expander.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"StaggeredView"
url:"qrc:/example/qml/page/T_StaggeredView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Watermark"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Watermark.qml")
}
url:"qrc:/example/qml/page/T_Watermark.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -227,9 +239,9 @@ FluObject{
icon:FluentIcons.ButtonMenu
FluPaneItem{
title:"Dialog"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Dialog.qml")
}
url:"qrc:/example/qml/page/T_Dialog.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
id:item_combobox
@ -239,6 +251,8 @@ FluObject{
count: item_combobox.count
color: Qt.rgba(250/255,173/255,20/255,1)
}
url:"qrc:/example/qml/page/T_ComboBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_combobox.count = 0
navigationView.push("qrc:/example/qml/page/T_ComboBox.qml")
@ -246,15 +260,15 @@ FluObject{
}
FluPaneItem{
title:"Tooltip"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tooltip.qml")
}
url:"qrc:/example/qml/page/T_Tooltip.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Menu"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Menu.qml")
}
url:"qrc:/example/qml/page/T_Menu.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -267,15 +281,15 @@ FluObject{
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
onTap:{
navigationView.push("qrc:/example/qml/page/T_Pivot.qml")
}
url:"qrc:/example/qml/page/T_Pivot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"BreadcrumbBar"
onTap:{
navigationView.push("qrc:/example/qml/page/T_BreadcrumbBar.qml")
}
url:"qrc:/example/qml/page/T_BreadcrumbBar.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TabView"
@ -283,15 +297,15 @@ FluObject{
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
onTap:{
navigationView.push("qrc:/example/qml/page/T_TabView.qml")
}
url:"qrc:/example/qml/page/T_TabView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TreeView"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TreeView.qml")
}
url:"qrc:/example/qml/page/T_TreeView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TableView"
@ -299,21 +313,21 @@ FluObject{
recentlyAdded:true
order:4
desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TableView.qml")
}
url:"qrc:/example/qml/page/T_TableView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Pagination"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Pagination.qml")
}
url:"qrc:/example/qml/page/T_Pagination.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"MultiWindow"
onTap:{
navigationView.push("qrc:/example/qml/page/T_MultiWindow.qml")
}
url:"qrc:/example/qml/page/T_MultiWindow.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"FlipView"
@ -321,9 +335,9 @@ FluObject{
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
onTap:{
navigationView.push("qrc:/example/qml/page/T_FlipView.qml")
}
url:"qrc:/example/qml/page/T_FlipView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -332,27 +346,27 @@ FluObject{
icon:FluentIcons.Brightness
FluPaneItem{
title:"Acrylic"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Acrylic.qml")
}
url:"qrc:/example/qml/page/T_Acrylic.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Theme"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Theme.qml")
}
url:"qrc:/example/qml/page/T_Theme.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Typography"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Typography.qml")
}
url:"qrc:/example/qml/page/T_Typography.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Awesome"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Awesome.qml")
}
url:"qrc:/example/qml/page/T_Awesome.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -366,45 +380,45 @@ FluObject{
icon:FluentIcons.Shop
FluPaneItem{
title:"QRCode"
onTap:{
navigationView.push("qrc:/example/qml/page/T_QRCode.qml")
}
url:"qrc:/example/qml/page/T_QRCode.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Tour"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tour.qml")
}
url:"qrc:/example/qml/page/T_Tour.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Timeline"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Timeline.qml")
}
url:"qrc:/example/qml/page/T_Timeline.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Screenshot"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Screenshot.qml")
}
title:"Screenshot(Todo)"
url:"qrc:/example/qml/page/T_Screenshot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Captcha"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Captcha.qml")
}
url:"qrc:/example/qml/page/T_Captcha.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Chart"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Chart.qml")
}
url:"qrc:/example/qml/page/T_Chart.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Http"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Http.qml")
}
url:"qrc:/example/qml/page/T_Http.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
id:item_other
@ -414,6 +428,8 @@ FluObject{
count: item_other.count
color: Qt.rgba(82/255,196/255,26/255,1)
}
url:"qrc:/example/qml/page/T_RemoteLoader.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_other.count = 0
navigationView.push("qrc:/example/qml/page/T_RemoteLoader.qml")
@ -421,9 +437,10 @@ FluObject{
}
FluPaneItem{
title:"HotLoader"
tapFunc:function(){
onTapListener:function(){
FluApp.navigate("/hotload")
}
onDropped:{ FluApp.navigate("/hotload") }
}
}

View File

@ -1,9 +0,0 @@
pragma Singleton
import QtQuick
import QtQuick.Controls
import FluentUI
QtObject {
property int displayMode : FluNavigationViewType.Auto
}

View File

@ -1,3 +1,2 @@
singleton ItemsOriginal 1.0 ItemsOriginal.qml
singleton ItemsFooter 1.0 ItemsFooter.qml
singleton MainEvent 1.0 MainEvent.qml

View File

@ -50,7 +50,7 @@ FluScrollablePage{
FluRectangle{
width: 1920/4
height: 1200/4
radius:[15,15,15,15]
radius:[8,8,8,8]
Image {
id:image
asynchronous: true

View File

@ -161,6 +161,97 @@ FluScrollablePage{
}'
}
Timer{
id:timer_progress
interval: 200
onTriggered: {
btn_progress.progress = (btn_progress.progress + 0.1).toFixed(1)
if(btn_progress.progress==1){
timer_progress.stop()
}else{
timer_progress.start()
}
}
}
FluArea{
Layout.fillWidth: true
height: 68
Layout.topMargin: 20
paddings: 10
FluProgressButton{
id:btn_progress
disabled:progress_button_switch.checked
text:"Progress Button"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked: {
btn_progress.progress = 0
timer_progress.restart()
}
}
FluToggleSwitch{
id:progress_button_switch
anchors{
right: parent.right
verticalCenter: parent.verticalCenter
}
text:"Disabled"
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluProgressButton{
text:"Progress Button"
onClicked: {
}
}'
}
FluArea{
Layout.fillWidth: true
height: 68
Layout.topMargin: 20
paddings: 10
FluLoadingButton{
id:btn_loading
loading:loading_button_switch.checked
text:"Loading Button"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked: {
}
}
FluToggleSwitch{
id:loading_button_switch
checked: true
anchors{
right: parent.right
verticalCenter: parent.verticalCenter
}
text:"Loading"
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluLoadingButton{
text:"Loading Button"
onClicked: {
}
}'
}
FluArea{
Layout.fillWidth: true

View File

@ -36,20 +36,28 @@ FluScrollablePage{
FluText{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
}
FluCarousel{
radius:[5,5,5,5]
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Item{
width: 400
height: 300
FluShadow{
radius: 8
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
FluCarousel{
anchors.fill: parent
radius:[8,8,8,8]
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
}
}
}
}
@ -66,46 +74,55 @@ FluScrollablePage{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluCarousel{
radius:[15,15,15,15]
loopTime:1500
indicatorGravity: Qt.AlignHCenter | Qt.AlignTop
indicatorMarginTop:15
delegate: Component{
Item{
anchors.fill: parent
Image {
Item{
width: 400
height: 300
FluShadow{
radius: 8
}
FluCarousel{
anchors.fill: parent
radius:[8,8,8,8]
loopTime:1500
indicatorGravity: Qt.AlignHCenter | Qt.AlignTop
indicatorMarginTop:15
delegate: Component{
Item{
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Rectangle{
height: 40
width: parent.width
anchors.bottom: parent.bottom
color: "#33000000"
FluText{
Image {
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
text:model.title
color: FluColors.Grey10
font.pixelSize: 15
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Rectangle{
height: 40
width: parent.width
anchors.bottom: parent.bottom
color: "#33000000"
FluText{
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
text:model.title
color: FluColors.Grey10
font.pixelSize: 15
}
}
}
}
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
var arr = []
arr.push({url:"qrc:/example/res/image/banner_1.jpg",title:"共同应对全球性问题"})
arr.push({url:"qrc:/example/res/image/banner_2.jpg",title:"三小只全程没互动"})
arr.push({url:"qrc:/example/res/image/banner_3.jpg",title:"有效投资扩大 激发增长动能"})
model = arr
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
var arr = []
arr.push({url:"qrc:/example/res/image/banner_1.jpg",title:"共同应对全球性问题"})
arr.push({url:"qrc:/example/res/image/banner_2.jpg",title:"三小只全程没互动"})
arr.push({url:"qrc:/example/res/image/banner_3.jpg",title:"有效投资扩大 激发增长动能"})
model = arr
}
}
}
}
}

View File

@ -28,6 +28,7 @@ FluScrollablePage{
fillMode:Image.PreserveAspectCrop
anchors.fill: parent
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
}
Rectangle{
@ -69,12 +70,12 @@ FluScrollablePage{
width: 220
height: 240
FluShadow{
radius:8
radius:5
anchors.fill: item_content
}
FluItem{
id:item_content
radius: [8,8,8,8]
radius: [5,5,5,5]
width: 200
height: 220
anchors.centerIn: parent
@ -88,7 +89,7 @@ FluScrollablePage{
}
Rectangle{
anchors.fill: parent
radius: 8
radius: 5
color:{
if(FluTheme.dark){
if(item_mouse.containsMouse){

View File

@ -10,14 +10,63 @@ import "qrc:///example/qml/component"
FluContentPage{
title:"Http"
property string cacheDirPath: FluTools.getApplicationDirPath() + "/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: 160
width: 200
clip: true
anchors{
top: parent.top
@ -36,21 +85,8 @@ FluContentPage{
implicitHeight: 36
text: "Get请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://httpbingo.org/get",callable)
var request = http.newRequest("https://httpbingo.org/get")
http.get(request,callable)
}
}
FluButton{
@ -58,25 +94,13 @@ FluContentPage{
implicitHeight: 36
text: "Post表单请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.post("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.post(request,callable)
}
}
FluButton{
@ -84,25 +108,13 @@ FluContentPage{
implicitHeight: 36
text: "Post Json请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.postJson("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.postJson(request,callable)
}
}
FluButton{
@ -110,25 +122,12 @@ FluContentPage{
implicitHeight: 36
text: "Post String请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = "我命由我不由天"
http.postString("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
request.params = "我命由我不由天"
http.postString(request,callable)
}
}
FluButton{
FluProgressButton{
id:btn_download
implicitWidth: parent.width
implicitHeight: 36
@ -137,7 +136,90 @@ FluContentPage{
folder_dialog.open()
}
}
FluButton{
FluProgressButton{
property bool downloading: false
id:btn_breakpoint_download
implicitWidth: parent.width
implicitHeight: 36
text: {
if(downloading){
return "暂停下载"
}
if(progress === 0){
return "断点下载文件"
}else if(progress === 1){
return "打开文件"
}else{
return "继续下载"
}
}
HttpRequest{
id:request_breakpoint_download
url: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
downloadSavePath: FluTools.getApplicationDirPath()+ "/download/big_buck_bunny.mp4"
}
HttpCallable{
id:callable_breakpoint_download
onStart: {
btn_breakpoint_download.downloading = true
}
onFinish: {
btn_breakpoint_download.downloading = false
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
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
@ -146,81 +228,143 @@ FluContentPage{
file_dialog.open()
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "FirstCacheThenRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"FirstCacheThenRequest"}
http_cache_firstcachethenrequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "RequestFailedReadCache缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"RequestFailedReadCache"}
http_cache_requestfailedreadcache.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "IfNoneCacheRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"IfNoneCacheRequest"}
http_cache_ifnonecacherequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "打开缓存路径"
onClicked: {
Qt.openUrlExternally("file:///"+cacheDirPath)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "删除缓存"
onClicked: {
console.debug(FluTools.removeDir(cacheDirPath))
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "清空右边数据"
onClicked: {
text_info.text = ""
}
}
}
}
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 param = {}
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
for(var i=0;i<selectedFiles.length;i++){
var fileUrl = selectedFiles[i]
var fileName = FluTools.getFileNameByUrl(fileUrl)
var filePath = FluTools.toLocalPath(fileUrl)
param[fileName] = filePath
params[fileName] = filePath
}
console.debug(JSON.stringify(param))
var callable = {}
callable.onStart = function(){
btn_upload.disabled = true
}
callable.onFinish = function(){
btn_upload.disabled = false
btn_upload.text = "上传文件"
layout_upload_file_size.visible = false
text_upload_file_size.text = ""
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString,result){
text_info.text = result
console.debug(result)
}
callable.onUploadProgress = function(sent,total){
var locale = Qt.locale()
var precent = (sent/total * 100).toFixed(0) + "%"
btn_upload.text = "上传中..."+precent
text_upload_file_size.text = "%1/%2".arg(locale.formattedDataSize(sent)).arg(locale.formattedDataSize(total))
layout_upload_file_size.visible = true
}
http.upload("https://httpbingo.org/post",callable,param)
request.params = params
http.upload(request,callable_upload)
}
}
HttpCallable{
id:callable_download
onStart: {
btn_download.progress = 0
btn_download.disabled = true
}
onFinish: {
btn_download.disabled = false
}
onError:
(status,errorString,result)=>{
btn_download.progress = 0
showError(errorString)
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_download.progress = recv/total
}
}
FolderDialog {
id: folder_dialog
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
onAccepted: {
var callable = {}
callable.onStart = function(){
btn_download.disabled = true
}
callable.onFinish = function(){
btn_download.disabled = false
btn_download.text = "下载文件"
layout_download_file_size.visible = false
text_download_file_size.text = ""
}
callable.onSuccess = function(result){
showSuccess(result)
}
callable.onError = function(status,errorString){
showError(errorString)
}
callable.onDownloadProgress = function(recv,total){
var locale = Qt.locale()
var precent = (recv/total * 100).toFixed(0) + "%"
btn_download.text = "下载中..."+precent
text_download_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total))
layout_download_file_size.visible = true
}
var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",callable,path)
var request = http.newRequest("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
request.downloadSavePath = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download(request,callable_download)
}
}
FluArea{
anchors{
top: layout_flick.top
@ -246,34 +390,4 @@ FluContentPage{
}
}
}
FluRectangle{
id:layout_download_file_size
radius: [4,4,4,4]
height: 36
width: 160
visible: false
x:layout_flick.width
y: 173 - layout_flick.contentY
FluText{
id:text_download_file_size
anchors.centerIn: parent
}
}
FluRectangle{
id:layout_upload_file_size
radius: [4,4,4,4]
height: 36
width: 160
visible: false
x:layout_flick.width
y: 210 - layout_flick.contentY
FluText{
id:text_upload_file_size
anchors.centerIn: parent
}
}
}

View File

@ -116,7 +116,7 @@ FluScrollablePage{
FluRectangle{
width: 1920/5
height: 1200/5
radius:[15,15,15,15]
radius:[8,8,8,8]
Image {
asynchronous: true
source: "qrc:/example/res/image/banner_1.jpg"

View File

@ -30,9 +30,10 @@ FluScrollablePage{
Layout.topMargin: 10
Layout.leftMargin: 4
Layout.bottomMargin: 4
radius: 4
color: FluTheme.dark ? FluColors.Black : FluColors.White
FluShadow{
radius: 0
radius: 4
color: FluTheme.primaryColor.dark
}
Image{

View File

@ -5,11 +5,58 @@ import QtQuick.Controls
import FluentUI
import "qrc:///example/qml/global"
import "qrc:///example/qml/component"
import "qrc:///example/qml/viewmodel"
FluScrollablePage{
title:"Settings"
SettingsViewModel{
id:viewmodel_settings
}
FluEvent{
id:event_checkupdate_finish
name: "checkUpdateFinish"
onTriggered: {
btn_checkupdate.loading = false
}
}
Component.onCompleted: {
FluEventBus.registerEvent(event_checkupdate_finish)
}
Component.onDestruction: {
FluEventBus.unRegisterEvent(event_checkupdate_finish)
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 60
paddings: 10
Row{
spacing: 20
anchors.verticalCenter: parent.verticalCenter
FluText{
text:"当前版本 v%1".arg(appInfo.version)
font: FluTextStyle.Body
anchors.verticalCenter: parent.verticalCenter
}
FluLoadingButton{
id:btn_checkupdate
text:"检查更新"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
loading = true
FluEventBus.post("checkUpdate")
}
}
}
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
@ -60,10 +107,10 @@ FluScrollablePage{
Repeater{
model: [{title:"Open",mode:FluNavigationViewType.Open},{title:"Compact",mode:FluNavigationViewType.Compact},{title:"Minimal",mode:FluNavigationViewType.Minimal},{title:"Auto",mode:FluNavigationViewType.Auto}]
delegate: FluRadioButton{
checked : MainEvent.displayMode===modelData.mode
checked : viewmodel_settings.displayMode===modelData.mode
text:modelData.title
clickListener:function(){
MainEvent.displayMode = modelData.mode
viewmodel_settings.displayMode = modelData.mode
}
}
}

View File

@ -11,11 +11,18 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
height: 100
paddings: 10
Layout.preferredHeight: 200
Layout.topMargin: 20
FluSlider{
anchors.verticalCenter: parent.verticalCenter
paddings: 10
Row{
spacing: 30
FluSlider{
}
FluSlider{
orientation: Qt.Vertical
anchors.verticalCenter: parent.verticalCenter
}
}
}
CodeExpander{
@ -26,25 +33,27 @@ FluScrollablePage{
}'
}
FluArea{
Layout.fillWidth: true
height: 200
paddings: 10
Layout.preferredHeight: 200
Layout.topMargin: 20
FluSlider{
orientation: Qt.Vertical
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
paddings: 10
Row{
spacing: 30
FluRangeSlider{
}
FluRangeSlider{
orientation: Qt.Vertical
anchors.verticalCenter: parent.verticalCenter
}
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluSlider{
code:'FluRangeSlider{
orientation: Qt.Vertical
value:50
}'
}
}

View File

@ -0,0 +1,59 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import "qrc:///example/qml/component"
import FluentUI 1.0
FluContentPage{
title:"StaggeredView"
property var colors : [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
ListModel{
id:list_model
Component.onCompleted: {
for(var i=0;i<=100;i++){
var item = {}
item.color = colors[rand(0,7)].dark
item.height = rand(100,300)
append(item)
}
}
}
Flickable{
id: scroll
anchors.fill: parent
anchors.topMargin: 20
boundsBehavior:Flickable.StopAtBounds
contentHeight: staggered_view.implicitHeight
clip: true
ScrollBar.vertical: FluScrollBar {}
FluStaggeredView{
id:staggered_view
width: parent.width
itemWidth: 160
model:list_model
delegate: Rectangle{
height: model.height
color:model.color
FluText{
color:"#FFFFFF"
text:model.index
font.bold: true
font.pixelSize: 18
anchors.centerIn: parent
}
}
}
}
function rand(minNum, maxNum){
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
}
}

View File

@ -4,12 +4,19 @@ import QtQuick.Layouts
import QtQuick.Window
import FluentUI
import "qrc:///example/qml/component"
import "qrc:///example/qml/viewmodel"
FluScrollablePage{
launchMode: FluPageType.SingleInstance
title:"TextBox"
TextBoxViewModel{
id:viewModel
}
Component.onDestruction: {
console.debug("T_TextBox页面销毁了")
}
FluArea{
Layout.fillWidth: true
height: 68
@ -20,6 +27,10 @@ FluScrollablePage{
placeholderText: "单行输入框"
disabled:text_box_switch.checked
cleanEnabled: true
text:viewModel.text1
onTextChanged: {
viewModel.text1 = text
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
@ -84,6 +95,10 @@ FluScrollablePage{
FluMultilineTextBox{
id:multiine_textbox
placeholderText: "多行输入框"
text:viewModel.text2
onTextChanged: {
viewModel.text2 = text
}
disabled:text_box_multi_switch.checked
anchors{
verticalCenter: parent.verticalCenter

View File

@ -0,0 +1,13 @@
import QtQuick
import FluentUI
FluViewModel{
objectName: "SettingsViewModel"
property int displayMode
onInitData: {
displayMode = FluNavigationViewType.Auto
}
}

View File

@ -0,0 +1,8 @@
import QtQuick
import FluentUI
FluViewModel {
objectName: "TextBoxView"
property string text1
property string text2
}

View File

@ -7,6 +7,7 @@ import FluentUI
import example
import "qrc:///example/qml/component"
import "qrc:///example/qml/global"
import "qrc:///example/qml/viewmodel"
CustomWindow {
@ -20,14 +21,32 @@ CustomWindow {
appBarVisible: false
launchMode: FluWindowType.SingleTask
SettingsViewModel{
id:viewmodel_settings
}
closeFunc:function(event){
dialog_close.open()
event.accepted = false
}
FluEvent{
id:event_checkupdate
name: "checkUpdate"
onTriggered: {
checkUpdate(false)
}
}
Component.onCompleted: {
FluTools.setQuitOnLastWindowClosed(false)
tour.open()
checkUpdate(true)
FluEventBus.registerEvent(event_checkupdate)
}
Component.onDestruction: {
FluEventBus.unRegisterEvent(event_checkupdate)
}
SystemTrayIcon {
@ -133,13 +152,11 @@ CustomWindow {
}
}
}
FluRemoteLoader{
id:loader
lazy: true
anchors.fill: parent
// source: "http://localhost:9000/RemoteComponent.qml"
source: "https://zhu-zichu.gitee.io/RemoteComponent.qml"
source: "https://zhu-zichu.gitee.io/Qt6_156_LieflatPage.qml"
}
}
front: Item{
@ -165,13 +182,13 @@ CustomWindow {
height: parent.height
z:999
//Stack模式每次切换都会将页面压入栈中随着栈的页面增多消耗的内存也越多内存消耗多就会卡顿这时候就需要按返回将页面pop掉释放内存。该模式可以配合FluPage中的launchMode属性设置页面的启动模式
pageMode: FluNavigationViewType.Stack
// pageMode: FluNavigationViewType.Stack
//NoStack模式每次切换都会销毁之前的页面然后创建一个新的页面只需消耗少量内存推荐
// pageMode: FluNavigationViewType.NoStack
pageMode: FluNavigationViewType.NoStack
items: ItemsOriginal
footerItems:ItemsFooter
topPadding:FluTools.isMacos() ? 20 : 0
displayMode:MainEvent.displayMode
displayMode:viewmodel_settings.displayMode
logo: "qrc:/example/res/image/favicon.ico"
title:"FluentUI"
onLogoClicked:{
@ -277,4 +294,77 @@ CustomWindow {
]
}
FluHttp{
id:http
}
FpsItem{
id:fps_item
}
FluText{
text:"fps %1".arg(fps_item.fps)
opacity: 0.3
anchors{
bottom: parent.bottom
right: parent.right
bottomMargin: 5
rightMargin: 5
}
}
FluContentDialog{
property string newVerson
property string body
id:dialog_update
title:"升级提示"
message:"FluentUI目前最新版本 "+ newVerson +" -- 当前应用版本 "+appInfo.version+" \n现在是否去下载新版本\n\n更新内容\n"+body
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
negativeText: "取消"
positiveText:"确定"
onPositiveClicked:{
Qt.openUrlExternally("https://github.com/zhuzichu520/FluentUI/releases/latest")
}
}
HttpCallable{
id:callable
property bool silent: true
onStart: {
console.debug("satrt check update...")
}
onFinish: {
console.debug("check update finish")
FluEventBus.post("checkUpdateFinish");
}
onSuccess:
(result)=>{
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
}else{
if(!silent){
showInfo("当前版本已经是最新版")
}
}
}
onError:
(status,errorString)=>{
if(!silent){
showError("网络异常!")
}
console.debug(status+";"+errorString)
}
}
function checkUpdate(silent){
callable.silent = silent
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
http.get(request,callable);
}
}

View File

@ -0,0 +1,25 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
import example
import "qrc:///example/qml/component"
CustomWindow {
id:window
width: 800
height: 600
minimumWidth: 520
minimumHeight: 200
launchMode: FluWindowType.SingleInstance
onInitArgument:
(arg)=>{
window.title = arg.title
loader.setSource( arg.url,{animDisabled:true})
}
Loader{
id: loader
anchors.fill: parent
}
}

View File

@ -35,7 +35,8 @@ Window {
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml"
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.httpInterceptor = interceptor

View File

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

View File

@ -14,7 +14,8 @@ FluObject{
FluPaneItem{
title:lang.about
icon:FluentIcons.Contact
tapFunc:function(){
onDropped: { FluApp.navigate("/about") }
onTapListener:function(){
FluApp.navigate("/about")
}
}
@ -22,8 +23,10 @@ FluObject{
FluPaneItem{
title:lang.settings
icon:FluentIcons.Settings
url:"qrc:/example/qml/page/T_Settings.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
navigationView.push("qrc:/example/qml/page/T_Settings.qml")
navigationView.push(url)
}
}

View File

@ -21,11 +21,13 @@ FluObject{
count: item_home.count
}
icon:FluentIcons.Home
url:"qrc:/example/qml/page/T_Home.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
if(navigationView.getCurrentUrl()){
item_home.count = 0
}
navigationView.push("qrc:/example/qml/page/T_Home.qml")
navigationView.push(url)
}
editDelegate: FluTextBox{
text:item_home.title
@ -69,9 +71,11 @@ FluObject{
image:"qrc:/example/res/image/control/Button.png"
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
url:"qrc:/example/qml/page/T_Buttons.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_buttons.count = 0
navigationView.push("qrc:/example/qml/page/T_Buttons.qml")
navigationView.push(url)
}
}
FluPaneItem{
@ -82,46 +86,48 @@ FluObject{
count: item_text.count
color: Qt.rgba(82/255,196/255,26/255,1)
}
url:"qrc:/example/qml/page/T_Text.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_text.count = 0
navigationView.push("qrc:/example/qml/page/T_Text.qml")
navigationView.push(url)
}
}
FluPaneItem{
title:"Image"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Image.qml")
}
url:"qrc:/example/qml/page/T_Image.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Slider"
image:"qrc:/example/res/image/control/Slider.png"
recentlyUpdated:true
desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."
onTap:{
navigationView.push("qrc:/example/qml/page/T_Slider.qml")
}
url:"qrc:/example/qml/page/T_Slider.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CheckBox"
image:"qrc:/example/res/image/control/Checkbox.png"
recentlyUpdated:true
desc:"A control that a user can select or clear."
onTap:{
navigationView.push("qrc:/example/qml/page/T_CheckBox.qml")
}
url:"qrc:/example/qml/page/T_CheckBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"RadioButton"
onTap:{
navigationView.push("qrc:/example/qml/page/T_RadioButton.qml")
}
url:"qrc:/example/qml/page/T_RadioButton.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"ToggleSwitch"
onTap:{
navigationView.push("qrc:/example/qml/page/T_ToggleSwitch.qml")
}
url:"qrc:/example/qml/page/T_ToggleSwitch.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -130,33 +136,33 @@ FluObject{
icon:FluentIcons.GridView
FluPaneItem{
title:"TextBox"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TextBox.qml")
}
url:"qrc:/example/qml/page/T_TextBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TimePicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TimePicker.qml")
}
url:"qrc:/example/qml/page/T_TimePicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"DatePicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_DatePicker.qml")
}
url:"qrc:/example/qml/page/T_DatePicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CalendarPicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_CalendarPicker.qml")
}
url:"qrc:/example/qml/page/T_CalendarPicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"ColorPicker"
onTap:{
navigationView.push("qrc:/example/qml/page/T_ColorPicker.qml")
}
url:"qrc:/example/qml/page/T_ColorPicker.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -168,57 +174,63 @@ FluObject{
image:"qrc:/example/res/image/control/InfoBar.png"
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
onTap:{
navigationView.push("qrc:/example/qml/page/T_InfoBar.qml")
}
url:"qrc:/example/qml/page/T_InfoBar.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Progress"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Progress.qml")
}
url:"qrc:/example/qml/page/T_Progress.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"RatingControl"
onTap:{
navigationView.push("qrc:/example/qml/page/T_RatingControl.qml")
}
url:"qrc:/example/qml/page/T_RatingControl.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Badge"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Badge.qml")
}
url:"qrc:/example/qml/page/T_Badge.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Rectangle"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Rectangle.qml")
}
url:"qrc:/example/qml/page/T_Rectangle.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"StatusView"
onTap:{
navigationView.push("qrc:/example/qml/page/T_StatusView.qml")
}
url:"qrc:/example/qml/page/T_StatusView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Carousel"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Carousel.qml")
}
url:"qrc:/example/qml/page/T_Carousel.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Expander"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Expander.qml")
}
url:"qrc:/example/qml/page/T_Expander.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"StaggeredView"
url:"qrc:/example/qml/page/T_StaggeredView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Watermark"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Watermark.qml")
}
url:"qrc:/example/qml/page/T_Watermark.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -227,9 +239,9 @@ FluObject{
icon:FluentIcons.ButtonMenu
FluPaneItem{
title:"Dialog"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Dialog.qml")
}
url:"qrc:/example/qml/page/T_Dialog.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
id:item_combobox
@ -239,6 +251,8 @@ FluObject{
count: item_combobox.count
color: Qt.rgba(250/255,173/255,20/255,1)
}
url:"qrc:/example/qml/page/T_ComboBox.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_combobox.count = 0
navigationView.push("qrc:/example/qml/page/T_ComboBox.qml")
@ -246,15 +260,15 @@ FluObject{
}
FluPaneItem{
title:"Tooltip"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tooltip.qml")
}
url:"qrc:/example/qml/page/T_Tooltip.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Menu"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Menu.qml")
}
url:"qrc:/example/qml/page/T_Menu.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -267,15 +281,15 @@ FluObject{
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
onTap:{
navigationView.push("qrc:/example/qml/page/T_Pivot.qml")
}
url:"qrc:/example/qml/page/T_Pivot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"BreadcrumbBar"
onTap:{
navigationView.push("qrc:/example/qml/page/T_BreadcrumbBar.qml")
}
url:"qrc:/example/qml/page/T_BreadcrumbBar.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TabView"
@ -283,15 +297,15 @@ FluObject{
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
onTap:{
navigationView.push("qrc:/example/qml/page/T_TabView.qml")
}
url:"qrc:/example/qml/page/T_TabView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TreeView"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TreeView.qml")
}
url:"qrc:/example/qml/page/T_TreeView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"TableView"
@ -299,21 +313,21 @@ FluObject{
recentlyAdded:true
order:4
desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"
onTap:{
navigationView.push("qrc:/example/qml/page/T_TableView.qml")
}
url:"qrc:/example/qml/page/T_TableView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Pagination"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Pagination.qml")
}
url:"qrc:/example/qml/page/T_Pagination.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"MultiWindow"
onTap:{
navigationView.push("qrc:/example/qml/page/T_MultiWindow.qml")
}
url:"qrc:/example/qml/page/T_MultiWindow.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"FlipView"
@ -321,9 +335,9 @@ FluObject{
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
onTap:{
navigationView.push("qrc:/example/qml/page/T_FlipView.qml")
}
url:"qrc:/example/qml/page/T_FlipView.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -332,27 +346,27 @@ FluObject{
icon:FluentIcons.Brightness
FluPaneItem{
title:"Acrylic"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Acrylic.qml")
}
url:"qrc:/example/qml/page/T_Acrylic.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Theme"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Theme.qml")
}
url:"qrc:/example/qml/page/T_Theme.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Typography"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Typography.qml")
}
url:"qrc:/example/qml/page/T_Typography.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Awesome"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Awesome.qml")
}
url:"qrc:/example/qml/page/T_Awesome.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
}
@ -366,45 +380,45 @@ FluObject{
icon:FluentIcons.Shop
FluPaneItem{
title:"QRCode"
onTap:{
navigationView.push("qrc:/example/qml/page/T_QRCode.qml")
}
url:"qrc:/example/qml/page/T_QRCode.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Tour"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tour.qml")
}
url:"qrc:/example/qml/page/T_Tour.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Timeline"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Timeline.qml")
}
url:"qrc:/example/qml/page/T_Timeline.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Screenshot"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Screenshot.qml")
}
title:"Screenshot(Todo)"
url:"qrc:/example/qml/page/T_Screenshot.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Captcha"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Captcha.qml")
}
url:"qrc:/example/qml/page/T_Captcha.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Chart"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Chart.qml")
}
url:"qrc:/example/qml/page/T_Chart.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Http"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Http.qml")
}
url:"qrc:/example/qml/page/T_Http.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{ navigationView.push(url) }
}
FluPaneItem{
id:item_other
@ -414,6 +428,8 @@ FluObject{
count: item_other.count
color: Qt.rgba(82/255,196/255,26/255,1)
}
url:"qrc:/example/qml/page/T_RemoteLoader.qml"
onDropped:{ FluApp.navigate("/pageWindow",{title:title,url:url}) }
onTap:{
item_other.count = 0
navigationView.push("qrc:/example/qml/page/T_RemoteLoader.qml")
@ -421,9 +437,10 @@ FluObject{
}
FluPaneItem{
title:"HotLoader"
tapFunc:function(){
onTapListener:function(){
FluApp.navigate("/hotload")
}
onDropped:{ FluApp.navigate("/hotload") }
}
}

View File

@ -1,9 +0,0 @@
pragma Singleton
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
QtObject {
property int displayMode : FluNavigationViewType.Auto
}

View File

@ -1,3 +1,2 @@
singleton ItemsOriginal 1.0 ItemsOriginal.qml
singleton ItemsFooter 1.0 ItemsFooter.qml
singleton MainEvent 1.0 MainEvent.qml

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -50,7 +51,7 @@ FluScrollablePage{
FluRectangle{
width: 1920/4
height: 1200/4
radius:[15,15,15,15]
radius:[8,8,8,8]
Image {
id:image
asynchronous: true

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -160,6 +161,97 @@ FluScrollablePage{
}'
}
Timer{
id:timer_progress
interval: 200
onTriggered: {
btn_progress.progress = (btn_progress.progress + 0.1).toFixed(1)
if(btn_progress.progress==1){
timer_progress.stop()
}else{
timer_progress.start()
}
}
}
FluArea{
Layout.fillWidth: true
height: 68
Layout.topMargin: 20
paddings: 10
FluProgressButton{
id:btn_progress
disabled:progress_button_switch.checked
text:"Progress Button"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked: {
btn_progress.progress = 0
timer_progress.restart()
}
}
FluToggleSwitch{
id:progress_button_switch
anchors{
right: parent.right
verticalCenter: parent.verticalCenter
}
text:"Disabled"
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluProgressButton{
text:"Progress Button"
onClicked: {
}
}'
}
FluArea{
Layout.fillWidth: true
height: 68
Layout.topMargin: 20
paddings: 10
FluLoadingButton{
id:btn_loading
loading:loading_button_switch.checked
text:"Loading Button"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked: {
}
}
FluToggleSwitch{
id:loading_button_switch
checked: true
anchors{
right: parent.right
verticalCenter: parent.verticalCenter
}
text:"Loading"
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluLoadingButton{
text:"Loading Button"
onClicked: {
}
}'
}
FluArea{
Layout.fillWidth: true

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -36,20 +37,28 @@ FluScrollablePage{
FluText{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
}
FluCarousel{
radius:[5,5,5,5]
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Item{
width: 400
height: 300
FluShadow{
radius: 8
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
FluCarousel{
anchors.fill: parent
radius:[8,8,8,8]
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
}
}
}
}
@ -66,46 +75,55 @@ FluScrollablePage{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluCarousel{
radius:[15,15,15,15]
loopTime:1500
indicatorGravity: Qt.AlignHCenter | Qt.AlignTop
indicatorMarginTop:15
delegate: Component{
Item{
anchors.fill: parent
Image {
Item{
width: 400
height: 300
FluShadow{
radius: 8
}
FluCarousel{
anchors.fill: parent
radius:[8,8,8,8]
loopTime:1500
indicatorGravity: Qt.AlignHCenter | Qt.AlignTop
indicatorMarginTop:15
delegate: Component{
Item{
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Rectangle{
height: 40
width: parent.width
anchors.bottom: parent.bottom
color: "#33000000"
FluText{
Image {
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
text:model.title
color: FluColors.Grey10
font.pixelSize: 15
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Rectangle{
height: 40
width: parent.width
anchors.bottom: parent.bottom
color: "#33000000"
FluText{
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
text:model.title
color: FluColors.Grey10
font.pixelSize: 15
}
}
}
}
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
var arr = []
arr.push({url:"qrc:/example/res/image/banner_1.jpg",title:"共同应对全球性问题"})
arr.push({url:"qrc:/example/res/image/banner_2.jpg",title:"三小只全程没互动"})
arr.push({url:"qrc:/example/res/image/banner_3.jpg",title:"有效投资扩大 激发增长动能"})
model = arr
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
var arr = []
arr.push({url:"qrc:/example/res/image/banner_1.jpg",title:"共同应对全球性问题"})
arr.push({url:"qrc:/example/res/image/banner_2.jpg",title:"三小只全程没互动"})
arr.push({url:"qrc:/example/res/image/banner_3.jpg",title:"有效投资扩大 激发增长动能"})
model = arr
}
}
}
}
}

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -29,6 +29,7 @@ FluScrollablePage{
anchors.fill: parent
asynchronous: true
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
}
Rectangle{
@ -70,12 +71,12 @@ FluScrollablePage{
width: 220
height: 240
FluShadow{
radius:8
radius:5
anchors.fill: item_content
}
FluItem{
id:item_content
radius: [8,8,8,8]
radius: [5,5,5,5]
width: 200
height: 220
anchors.centerIn: parent
@ -89,7 +90,7 @@ FluScrollablePage{
}
Rectangle{
anchors.fill: parent
radius: 8
radius: 5
color:{
if(FluTheme.dark){
if(item_mouse.containsMouse){

View File

@ -6,18 +6,68 @@ 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: FluTools.getApplicationDirPath() + "/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: 160
width: 200
clip: true
anchors{
top: parent.top
@ -36,21 +86,8 @@ FluContentPage{
implicitHeight: 36
text: "Get请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://httpbingo.org/get",callable)
var request = http.newRequest("https://httpbingo.org/get")
http.get(request,callable)
}
}
FluButton{
@ -58,25 +95,13 @@ FluContentPage{
implicitHeight: 36
text: "Post表单请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.post("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.post(request,callable)
}
}
FluButton{
@ -84,25 +109,13 @@ FluContentPage{
implicitHeight: 36
text: "Post Json请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.postJson("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
params.custname = "朱子楚"
params.custtel = "1234567890"
params.custemail = "zhuzichu520@gmail.com"
request.params = params
http.postJson(request,callable)
}
}
FluButton{
@ -110,25 +123,12 @@ FluContentPage{
implicitHeight: 36
text: "Post String请求"
onClicked: {
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = "我命由我不由天"
http.postString("https://httpbingo.org/post",callable,param)
var request = http.newRequest("https://httpbingo.org/post")
request.params = "我命由我不由天"
http.postString(request,callable)
}
}
FluButton{
FluProgressButton{
id:btn_download
implicitWidth: parent.width
implicitHeight: 36
@ -137,7 +137,90 @@ FluContentPage{
folder_dialog.open()
}
}
FluButton{
FluProgressButton{
property bool downloading: false
id:btn_breakpoint_download
implicitWidth: parent.width
implicitHeight: 36
text: {
if(downloading){
return "暂停下载"
}
if(progress === 0){
return "断点下载文件"
}else if(progress === 1){
return "打开文件"
}else{
return "继续下载"
}
}
HttpRequest{
id:request_breakpoint_download
url: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
downloadSavePath: FluTools.getApplicationDirPath()+ "/download/big_buck_bunny.mp4"
}
HttpCallable{
id:callable_breakpoint_download
onStart: {
btn_breakpoint_download.downloading = true
}
onFinish: {
btn_breakpoint_download.downloading = false
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
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
@ -146,81 +229,143 @@ FluContentPage{
file_dialog.open()
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "FirstCacheThenRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"FirstCacheThenRequest"}
http_cache_firstcachethenrequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "RequestFailedReadCache缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"RequestFailedReadCache"}
http_cache_requestfailedreadcache.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "IfNoneCacheRequest缓存"
onClicked: {
var request = http.newRequest("https://httpbingo.org/post")
request.params = {cacheMode:"IfNoneCacheRequest"}
http_cache_ifnonecacherequest.post(request,callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "打开缓存路径"
onClicked: {
Qt.openUrlExternally("file:///"+cacheDirPath)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "删除缓存"
onClicked: {
console.debug(FluTools.removeDir(cacheDirPath))
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "清空右边数据"
onClicked: {
text_info.text = ""
}
}
}
}
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 param = {}
var request = http.newRequest("https://httpbingo.org/post")
var params = {}
for(var i=0;i<selectedFiles.length;i++){
var fileUrl = selectedFiles[i]
var fileName = FluTools.getFileNameByUrl(fileUrl)
var filePath = FluTools.toLocalPath(fileUrl)
param[fileName] = filePath
params[fileName] = filePath
}
console.debug(JSON.stringify(param))
var callable = {}
callable.onStart = function(){
btn_upload.disabled = true
}
callable.onFinish = function(){
btn_upload.disabled = false
btn_upload.text = "上传文件"
layout_upload_file_size.visible = false
text_upload_file_size.text = ""
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString,result){
text_info.text = result
console.debug(result)
}
callable.onUploadProgress = function(sent,total){
var locale = Qt.locale()
var precent = (sent/total * 100).toFixed(0) + "%"
btn_upload.text = "上传中..."+precent
text_upload_file_size.text = "%1/%2".arg(locale.formattedDataSize(sent)).arg(locale.formattedDataSize(total))
layout_upload_file_size.visible = true
}
http.upload("https://httpbingo.org/post",callable,param)
request.params = params
http.upload(request,callable_upload)
}
}
HttpCallable{
id:callable_download
onStart: {
btn_download.progress = 0
btn_download.disabled = true
}
onFinish: {
btn_download.disabled = false
}
onError:
(status,errorString,result)=>{
btn_download.progress = 0
showError(errorString)
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
showSuccess(result)
}
onDownloadProgress:
(recv,total)=>{
btn_download.progress = recv/total
}
}
FolderDialog {
id: folder_dialog
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
onAccepted: {
var callable = {}
callable.onStart = function(){
btn_download.disabled = true
}
callable.onFinish = function(){
btn_download.disabled = false
btn_download.text = "下载文件"
layout_download_file_size.visible = false
text_download_file_size.text = ""
}
callable.onSuccess = function(result){
showSuccess(result)
}
callable.onError = function(status,errorString){
showError(errorString)
}
callable.onDownloadProgress = function(recv,total){
var locale = Qt.locale()
var precent = (recv/total * 100).toFixed(0) + "%"
btn_download.text = "下载中..."+precent
text_download_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total))
layout_download_file_size.visible = true
}
var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",callable,path)
var request = http.newRequest("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
request.downloadSavePath = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http.download(request,callable_download)
}
}
FluArea{
anchors{
top: layout_flick.top
@ -246,34 +391,4 @@ FluContentPage{
}
}
}
FluRectangle{
id:layout_download_file_size
radius: [4,4,4,4]
height: 36
width: 160
visible: false
x:layout_flick.width
y: 173 - layout_flick.contentY
FluText{
id:text_download_file_size
anchors.centerIn: parent
}
}
FluRectangle{
id:layout_upload_file_size
radius: [4,4,4,4]
height: 36
width: 160
visible: false
x:layout_flick.width
y: 210 - layout_flick.contentY
FluText{
id:text_upload_file_size
anchors.centerIn: parent
}
}
}

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import "qrc:///example/qml/component"
import "../component"
import FluentUI 1.0
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -15,9 +16,12 @@ FluScrollablePage{
height: 400
paddings: 10
FluPivot{
anchors.fill: parent
currentIndex: 2
FluPivotItem{
title:"All"
contentItem:FluText{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -5,6 +5,7 @@ import QtQuick.Window 2.15
import FluentUI 1.0
import QtGraphicalEffects 1.15
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage {

View File

@ -4,6 +4,7 @@ import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -116,7 +117,7 @@ FluScrollablePage{
FluRectangle{
width: 1920/5
height: 1200/5
radius:[15,15,15,15]
radius:[8,8,8,8]
Image {
asynchronous: true
source: "qrc:/example/res/image/banner_1.jpg"

View File

@ -4,11 +4,12 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluPage{
launchMode: FluPageType.SingleTop
FluRemoteLoader{
anchors.fill: parent
source: "https://zhu-zichu.gitee.io/T_RemoteLoader.qml"
source: "https://zhu-zichu.gitee.io/Qt5_T_RemoteLoader.qml"
}
}

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{
@ -30,9 +31,10 @@ FluScrollablePage{
Layout.topMargin: 10
Layout.leftMargin: 4
Layout.bottomMargin: 4
radius: 4
color: FluTheme.dark ? FluColors.Black : FluColors.White
FluShadow{
radius: 0
radius: 4
color: FluTheme.primaryColor.dark
}
Image{

View File

@ -5,11 +5,61 @@ import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/global"
import "qrc:///example/qml/component"
import "qrc:///example/qml/viewmodel"
import "../component"
import "../viewmodel"
import "../global"
FluScrollablePage{
title:"Settings"
SettingsViewModel{
id:viewmodel_settings
}
FluEvent{
id:event_checkupdate_finish
name: "checkUpdateFinish"
onTriggered: {
btn_checkupdate.loading = false
}
}
Component.onCompleted: {
FluEventBus.registerEvent(event_checkupdate_finish)
}
Component.onDestruction: {
FluEventBus.unRegisterEvent(event_checkupdate_finish)
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 60
paddings: 10
Row{
spacing: 20
anchors.verticalCenter: parent.verticalCenter
FluText{
text:"当前版本 v%1".arg(appInfo.version)
font: FluTextStyle.Body
anchors.verticalCenter: parent.verticalCenter
}
FluLoadingButton{
id:btn_checkupdate
text:"检查更新"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
loading = true
FluEventBus.post("checkUpdate")
}
}
}
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
@ -60,10 +110,10 @@ FluScrollablePage{
Repeater{
model: [{title:"Open",mode:FluNavigationViewType.Open},{title:"Compact",mode:FluNavigationViewType.Compact},{title:"Minimal",mode:FluNavigationViewType.Minimal},{title:"Auto",mode:FluNavigationViewType.Auto}]
delegate: FluRadioButton{
checked : MainEvent.displayMode===modelData.mode
checked : viewmodel_settings.displayMode===modelData.mode
text:modelData.title
clickListener:function(){
MainEvent.displayMode = modelData.mode
viewmodel_settings.displayMode = modelData.mode
}
}
}

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import "qrc:///example/qml/component"
import "../component"
import FluentUI 1.0
FluScrollablePage{
@ -11,11 +12,18 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
height: 100
paddings: 10
Layout.preferredHeight: 200
Layout.topMargin: 20
FluSlider{
anchors.verticalCenter: parent.verticalCenter
paddings: 10
Row{
spacing: 30
FluSlider{
}
FluSlider{
orientation: Qt.Vertical
anchors.verticalCenter: parent.verticalCenter
}
}
}
CodeExpander{
@ -26,25 +34,28 @@ FluScrollablePage{
}'
}
FluArea{
Layout.fillWidth: true
height: 200
paddings: 10
Layout.preferredHeight: 200
Layout.topMargin: 20
FluSlider{
orientation: Qt.Vertical
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
paddings: 10
Row{
spacing: 30
FluRangeSlider{
}
FluRangeSlider{
orientation: Qt.Vertical
anchors.verticalCenter: parent.verticalCenter
}
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluSlider{
code:'FluRangeSlider{
orientation: Qt.Vertical
value:50
}'
}
}

View File

@ -0,0 +1,61 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import "qrc:///example/qml/component"
import "../component"
import FluentUI 1.0
FluContentPage{
title:"StaggeredView"
property var colors : [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
ListModel{
id:list_model
Component.onCompleted: {
for(var i=0;i<=100;i++){
var item = {}
item.color = colors[rand(0,7)].dark
item.height = rand(100,300)
append(item)
}
}
}
Flickable{
id: scroll
anchors.fill: parent
anchors.topMargin: 20
boundsBehavior:Flickable.StopAtBounds
contentHeight: staggered_view.implicitHeight
clip: true
ScrollBar.vertical: FluScrollBar {}
FluStaggeredView{
id:staggered_view
width: parent.width
itemWidth: 160
model:list_model
delegate: Rectangle{
height: model.height
color:model.color
FluText{
color:"#FFFFFF"
text:model.index
font.bold: true
font.pixelSize: 18
anchors.centerIn: parent
}
}
}
}
function rand(minNum, maxNum){
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
}
}

View File

@ -4,6 +4,7 @@ import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluContentPage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,12 +4,21 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "qrc:///example/qml/viewmodel"
import "../component"
import "../viewmodel"
FluScrollablePage{
launchMode: FluPageType.SingleInstance
title:"TextBox"
TextBoxViewModel{
id:viewModel
}
Component.onDestruction: {
console.debug("T_TextBox页面销毁了")
}
FluArea{
Layout.fillWidth: true
height: 68
@ -20,6 +29,10 @@ FluScrollablePage{
placeholderText: "单行输入框"
disabled:text_box_switch.checked
cleanEnabled: true
text:viewModel.text1
onTextChanged: {
viewModel.text1 = text
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
@ -84,6 +97,10 @@ FluScrollablePage{
FluMultilineTextBox{
id:multiine_textbox
placeholderText: "多行输入框"
text:viewModel.text2
onTextChanged: {
viewModel.text2 = text
}
disabled:text_box_multi_switch.checked
anchors{
verticalCenter: parent.verticalCenter

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage{

View File

@ -4,6 +4,7 @@ import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluScrollablePage {

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluContentPage{

View File

@ -0,0 +1,13 @@
import QtQuick 2.15
import FluentUI 1.0
FluViewModel{
objectName: "SettingsViewModel"
property int displayMode
onInitData: {
displayMode = FluNavigationViewType.Auto
}
}

View File

@ -0,0 +1,8 @@
import QtQuick 2.15
import FluentUI 1.0
FluViewModel {
objectName: "TextBoxView"
property string text1
property string text2
}

View File

@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15
import FluentUI 1.0
import example 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -7,6 +7,10 @@ import FluentUI 1.0
import example 1.0
import "qrc:///example/qml/component"
import "qrc:///example/qml/global"
import "qrc:///example/qml/viewmodel"
import "../component"
import "../viewmodel"
import "../global"
CustomWindow {
@ -20,14 +24,32 @@ CustomWindow {
appBarVisible: false
launchMode: FluWindowType.SingleTask
SettingsViewModel{
id:viewmodel_settings
}
closeFunc:function(event){
dialog_close.open()
event.accepted = false
}
FluEvent{
id:event_checkupdate
name: "checkUpdate"
onTriggered: {
checkUpdate(false)
}
}
Component.onCompleted: {
FluTools.setQuitOnLastWindowClosed(false)
tour.open()
checkUpdate(true)
FluEventBus.registerEvent(event_checkupdate)
}
Component.onDestruction: {
FluEventBus.unRegisterEvent(event_checkupdate)
}
SystemTrayIcon {
@ -133,13 +155,11 @@ CustomWindow {
}
}
}
FluRemoteLoader{
id:loader
lazy: true
anchors.fill: parent
// source: "http://localhost:9000/RemoteComponent.qml"
source: "https://zhu-zichu.gitee.io/RemoteComponent.qml"
source: "https://zhu-zichu.gitee.io/Qt5_156_LieflatPage.qml"
}
}
front: Item{
@ -165,13 +185,13 @@ CustomWindow {
height: parent.height
z:999
//Stack模式每次切换都会将页面压入栈中随着栈的页面增多消耗的内存也越多内存消耗多就会卡顿这时候就需要按返回将页面pop掉释放内存。该模式可以配合FluPage中的launchMode属性设置页面的启动模式
pageMode: FluNavigationViewType.Stack
// pageMode: FluNavigationViewType.Stack
//NoStack模式每次切换都会销毁之前的页面然后创建一个新的页面只需消耗少量内存推荐
// pageMode: FluNavigationViewType.NoStack
pageMode: FluNavigationViewType.NoStack
items: ItemsOriginal
footerItems:ItemsFooter
topPadding:FluTools.isMacos() ? 20 : 0
displayMode:MainEvent.displayMode
displayMode:viewmodel_settings.displayMode
logo: "qrc:/example/res/image/favicon.ico"
title:"FluentUI"
onLogoClicked:{
@ -277,4 +297,77 @@ CustomWindow {
]
}
FluHttp{
id:http
}
FpsItem{
id:fps_item
}
FluText{
text:"fps %1".arg(fps_item.fps)
opacity: 0.3
anchors{
bottom: parent.bottom
right: parent.right
bottomMargin: 5
rightMargin: 5
}
}
FluContentDialog{
property string newVerson
property string body
id:dialog_update
title:"升级提示"
message:"FluentUI目前最新版本 "+ newVerson +" -- 当前应用版本 "+appInfo.version+" \n现在是否去下载新版本\n\n更新内容\n"+body
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
negativeText: "取消"
positiveText:"确定"
onPositiveClicked:{
Qt.openUrlExternally("https://github.com/zhuzichu520/FluentUI/releases/latest")
}
}
HttpCallable{
id:callable
property bool silent: true
onStart: {
console.debug("satrt check update...")
}
onFinish: {
console.debug("check update finish")
FluEventBus.post("checkUpdateFinish");
}
onSuccess:
(result)=>{
var data = JSON.parse(result)
console.debug("current version "+appInfo.version)
console.debug("new version "+data.tag_name)
if(data.tag_name !== appInfo.version){
dialog_update.newVerson = data.tag_name
dialog_update.body = data.body
dialog_update.open()
}else{
if(!silent){
showInfo("当前版本已经是最新版")
}
}
}
onError:
(status,errorString)=>{
if(!silent){
showError("网络异常!")
}
console.debug(status+";"+errorString)
}
}
function checkUpdate(silent){
callable.silent = silent
var request = http.newRequest("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
http.get(request,callable);
}
}

View File

@ -0,0 +1,26 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import example 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {
id:window
width: 800
height: 600
minimumWidth: 520
minimumHeight: 200
launchMode: FluWindowType.SingleInstance
onInitArgument:
(arg)=>{
window.title = arg.title
loader.setSource( arg.url,{animDisabled:true})
}
Loader{
id: loader
anchors.fill: parent
}
}

View File

@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
CustomWindow {

View File

@ -0,0 +1,19 @@
#include "FpsItem.h"
#include <QTimer>
#include <QQuickWindow>
FpsItem::FpsItem()
{
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [this]{
fps(_frameCount);
_frameCount = 0;
});
connect(this, &QQuickItem::windowChanged, this, [this]{
if (window()){
connect(window(), &QQuickWindow::afterRendering, this, [this]{ _frameCount++; }, Qt::DirectConnection);
}
});
timer->start(1000);
}

View File

@ -0,0 +1,19 @@
#ifndef FPSITEM_H
#define FPSITEM_H
#include <QQuickItem>
#include "src/stdafx.h"
class FpsItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY_AUTO(int,fps)
public:
FpsItem();
private:
int _frameCount = 0;
};
#endif // FPSITEM_H

View File

@ -8,13 +8,21 @@
#include <QProcess>
#include <FramelessHelper/Quick/framelessquickmodule.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h>
#include <QtQml/qqmlextensionplugin.h>
#include "AppInfo.h"
#include "src/component/CircularReveal.h"
#include "src/component/FileWatcher.h"
#include "src/component/FpsItem.h"
#ifdef FLUENTUI_BUILD_STATIC_LIB
#if (QT_VERSION > QT_VERSION_CHECK(6, 2, 0))
Q_IMPORT_QML_PLUGIN(FluentUIPlugin)
#endif
#include <FluentUI.h>
#endif
FRAMELESSHELPER_USE_NAMESPACE
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
@ -23,7 +31,6 @@ int main(int argc, char *argv[])
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#endif
//将样式设置为Basic不然会导致组件显示异常
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
FramelessHelper::Quick::initialize();
QGuiApplication::setOrganizationName("ZhuZiChu");
@ -34,7 +41,7 @@ int main(int argc, char *argv[])
FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
#ifdef Q_OS_WIN // 此设置仅在Windows下生效
#ifdef Q_OS_WIN
FramelessConfig::instance()->set(Global::Option::ForceHideWindowFrameBorder);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow,false);
#endif
@ -45,10 +52,12 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes(&engine);
#ifdef FLUENTUI_BUILD_STATIC_LIB
engine.addImportPath("qrc:/"); // 让静态资源可以被QML引擎搜索到
FluentUI::getInstance()->registerTypes(&engine);
#endif
qDebug()<<engine.importPathList();
qmlRegisterType<CircularReveal>("example", 1, 0, "CircularReveal");
qmlRegisterType<FileWatcher>("example", 1, 0, "FileWatcher");
qmlRegisterType<FpsItem>("example", 1, 0, "FpsItem");
appInfo->init(&engine);
const QUrl url(QStringLiteral("qrc:/example/qml/App.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,

View File

@ -1,16 +1,21 @@
cmake_minimum_required(VERSION 3.20)
if (FLUENTUI_BUILD_STATIC_LIB)
if (FLUENTUI_BUILD_STATIC_LIB AND (QT_VERSION VERSION_GREATER_EQUAL "6.2"))
project(fluentui LANGUAGES CXX)
else()
project(fluentuiplugin LANGUAGES CXX)
endif()
#配置通用编译
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
if (FLUENTUI_BUILD_STATIC_LIB)
add_definitions(-DFLUENTUI_BUILD_STATIC_LIB)
endif()
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Quick Qml)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Quick Qml)
@ -32,6 +37,9 @@ endforeach(filepath)
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#删除fluentuiplugin.cpp与fluentuiplugin.h这些只要Qt5使用Qt6不需要
list(REMOVE_ITEM sources_files fluentuiplugin.h fluentuiplugin.cpp)
if (NOT FLUENTUI_BUILD_STATIC_LIB)
list(REMOVE_ITEM sources_files FluentUI.h FluentUI.cpp)
endif()
#遍历所有qml文件
file(GLOB_RECURSE QML_PATHS *.qml)
@ -83,6 +91,9 @@ if(WIN32)
endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
if(FLUENTUI_BUILD_STATIC_LIB)
set(FLUENTUI_QML_PLUGIN_DIRECTORY ${CMAKE_BINARY_DIR}/FluentUI)
endif()
qt_add_library(${PROJECT_NAME} ${LIB_TYPE})
qt_add_qml_module(${PROJECT_NAME}
PLUGIN_TARGET ${PLUGIN_TARGET_NAME}
@ -94,14 +105,14 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
SOURCES ${sources_files} ${FLUENTUI_VERSION_RC_PATH}
QML_FILES ${qml_files}
RESOURCES ${resource_files}
RESOURCE_PREFIX "/"
RESOURCE_PREFIX "/qt/qml"
)
else()
include(QmlPlugin)
add_qmlplugin(${PROJECT_NAME}
URI "FluentUI"
VERSION 1.0
SOURCES ${sources_files} ${FLUENTUI_VERSION_RC_PATH} resource.qrc
SOURCES ${sources_files} ${FLUENTUI_VERSION_RC_PATH} Qt5/imports/fluentui.qrc
QMLFILES ${qml_files}
QMLDIR imports/FluentUI
BINARY_DIR ${FLUENTUI_QML_PLUGIN_DIRECTORY}
@ -109,6 +120,9 @@ else()
)
endif()
#去掉mingw生成的动态库libxxx前缀lib不去掉前缀会导致 module "FluentUI" plugin "fluentuiplugin" not found
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
#链接库
target_link_libraries(${PROJECT_NAME} PUBLIC
Qt${QT_VERSION_MAJOR}::CorePrivate

View File

@ -4,6 +4,27 @@
#include <QObject>
#include <QtQml/qqml.h>
namespace FluViewModelType {
Q_NAMESPACE
enum Scope {
Window = 0x0000,
Application = 0x0001
};
Q_ENUM_NS(Scope)
QML_NAMED_ELEMENT(FluViewModelType)
}
namespace FluHttpType {
Q_NAMESPACE
enum CacheMode {
NoCache = 0x0000,
RequestFailedReadCache = 0x0001,
IfNoneCacheRequest = 0x0002,
FirstCacheThenRequest = 0x0004,
};
Q_ENUM_NS(CacheMode)
QML_NAMED_ELEMENT(FluHttpType)
}
namespace FluScreenshotType {
Q_NAMESPACE

View File

@ -18,28 +18,12 @@
class FluApp : public QObject
{
Q_OBJECT
/**
* @brief initialRoute 初始路由
*/
Q_PROPERTY_AUTO(QString,initialRoute);
/**
* @brief routes 路由表
*/
Q_PROPERTY_AUTO(QJsonObject,routes);
/**
* @brief http拦截器
*/
Q_PROPERTY_AUTO(FluHttpInterceptor*,httpInterceptor);
QML_NAMED_ELEMENT(FluApp)
QML_SINGLETON
private:
/**
* @brief FluApp 将默认构造函数设置为私有则qml创建单例就会走create工厂方法创建单例
* @param parent
*/
explicit FluApp(QObject *parent = nullptr);
public:
~FluApp();
@ -48,50 +32,16 @@ public:
return getInstance();
}
static FluApp *getInstance();
/**
* @brief run
*/
Q_INVOKABLE void run();
/**
* @brief navigate
* @param route
* @param argument
* @param fluRegister
*/
Q_INVOKABLE void navigate(const QString& route,const QJsonObject& argument = {},FluRegister* fluRegister = nullptr);
/**
* @brief init
* @param window
*/
Q_INVOKABLE void init(QQuickWindow *window);
/**
* @brief awesomelist
* @param keyword
* @return
*/
Q_INVOKABLE QJsonArray awesomelist(const QString& keyword = "");
/**
* @brief closeApp
*/
Q_INVOKABLE void closeApp();
Q_INVOKABLE void deleteWindow(QQuickWindow* window);
public:
/**
* @brief wnds
*/
QMap<quint64, QQuickWindow*> wnds;
private:
static FluApp* m_instance;
/**
* @brief appWindow
*/
QWindow *appWindow;
};

View File

@ -8,7 +8,10 @@
FluCaptcha::FluCaptcha(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
font(QFont("楷体",25,QFont::Bold,true));
QFont fontStype;
fontStype.setPixelSize(28);
fontStype.setBold(true);
font(fontStype);
setWidth(180);
setHeight(80);
refresh();

40
src/FluEventBus.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "FluEventBus.h"
FluEventBus* FluEventBus::m_instance = nullptr;
FluEvent::FluEvent(QObject *parent)
: QObject{parent}
{
}
FluEventBus *FluEventBus::getInstance()
{
if(FluEventBus::m_instance == nullptr){
FluEventBus::m_instance = new FluEventBus;
}
return FluEventBus::m_instance;
}
FluEventBus::FluEventBus(QObject *parent)
: QObject{parent}
{
}
void FluEventBus::registerEvent(FluEvent* event){
eventData.append(event);
}
void FluEventBus::unRegisterEvent(FluEvent* event){
eventData.removeOne(event);
}
void FluEventBus::post(const QString& name,const QMap<QString, QVariant>& data){
foreach (auto event, eventData) {
if(event->name()==name){
Q_EMIT event->triggered(data);
}
}
}

38
src/FluEventBus.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef FLUEVENTBUS_H
#define FLUEVENTBUS_H
#include <QObject>
#include <QtQml/qqml.h>
#include "stdafx.h"
class FluEvent : public QObject{
Q_OBJECT
Q_PROPERTY_AUTO(QString,name);
QML_NAMED_ELEMENT(FluEvent)
public:
explicit FluEvent(QObject *parent = nullptr);
Q_SIGNAL void triggered(QMap<QString, QVariant> data);
};
class FluEventBus : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(FluEventBus)
QML_SINGLETON
private:
static FluEventBus* m_instance;
explicit FluEventBus(QObject *parent = nullptr);
public:
static FluEventBus *getInstance();
static FluEventBus *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
{
return getInstance();
}
Q_INVOKABLE void registerEvent(FluEvent* event);
Q_INVOKABLE void unRegisterEvent(FluEvent* event);
Q_INVOKABLE void post(const QString& name,const QMap<QString, QVariant>& params = {});
private:
QList<FluEvent*> eventData;
};
#endif // FLUEVENTBUS_H

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More