mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2024-11-24 03:30:59 +08:00
397 lines
12 KiB
QML
397 lines
12 KiB
QML
import QtQuick
|
||
import QtQuick.Window
|
||
import QtQuick.Controls
|
||
import QtQuick.Layouts
|
||
import Qt.labs.platform
|
||
import FluentUI
|
||
import example
|
||
import "../component"
|
||
import "../global"
|
||
import "../viewmodel"
|
||
|
||
FluWindow {
|
||
|
||
id:window
|
||
title: "FluentUI"
|
||
width: 1000
|
||
height: 680
|
||
minimumWidth: 520
|
||
minimumHeight: 200
|
||
launchMode: FluWindowType.SingleTask
|
||
fitsAppBarWindows: true
|
||
appBar: FluAppBar {
|
||
height: 30
|
||
darkText: qsTr("Dark Mode")
|
||
showDark: true
|
||
darkClickListener:(button)=>handleDarkChanged(button)
|
||
closeClickListener: ()=>{dialog_close.open()}
|
||
z:7
|
||
}
|
||
|
||
SettingsViewModel{
|
||
id:viewmodel_settings
|
||
}
|
||
|
||
FluEvent{
|
||
id:event_checkupdate
|
||
name: "checkUpdate"
|
||
onTriggered: {
|
||
checkUpdate(false)
|
||
}
|
||
}
|
||
|
||
onFirstVisible: {
|
||
timer_tour_delay.restart()
|
||
}
|
||
|
||
Timer{
|
||
id:timer_tour_delay
|
||
interval: 200
|
||
onTriggered: {
|
||
tour.open()
|
||
}
|
||
}
|
||
|
||
Component.onCompleted: {
|
||
checkUpdate(true)
|
||
FluEventBus.registerEvent(event_checkupdate)
|
||
}
|
||
|
||
Component.onDestruction: {
|
||
FluEventBus.unRegisterEvent(event_checkupdate)
|
||
}
|
||
|
||
SystemTrayIcon {
|
||
id:system_tray
|
||
visible: true
|
||
icon.source: "qrc:/example/res/image/favicon.ico"
|
||
tooltip: "FluentUI"
|
||
menu: Menu {
|
||
MenuItem {
|
||
text: "退出"
|
||
onTriggered: {
|
||
FluApp.exit()
|
||
}
|
||
}
|
||
}
|
||
onActivated:
|
||
(reason)=>{
|
||
if(reason === SystemTrayIcon.Trigger){
|
||
window.show()
|
||
window.raise()
|
||
window.requestActivate()
|
||
}
|
||
}
|
||
}
|
||
|
||
Timer{
|
||
id: timer_window_hide_delay
|
||
interval: 150
|
||
onTriggered: {
|
||
window.hide()
|
||
}
|
||
}
|
||
|
||
FluContentDialog{
|
||
id: dialog_close
|
||
title: qsTr("Quit")
|
||
message: qsTr("Are you sure you want to exit the program?")
|
||
negativeText: qsTr("Minimize")
|
||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.NeutralButton | FluContentDialogType.PositiveButton
|
||
onNegativeClicked: {
|
||
system_tray.showMessage(qsTr("Friendly Reminder"),qsTr("FluentUI is hidden from the tray, click on the tray to activate the window again"));
|
||
timer_window_hide_delay.restart()
|
||
}
|
||
positiveText: qsTr("Quit")
|
||
neutralText: qsTr("Cancel")
|
||
onPositiveClicked:{
|
||
FluApp.exit(0)
|
||
}
|
||
}
|
||
|
||
Component{
|
||
id: nav_item_right_menu
|
||
FluMenu{
|
||
width: 186
|
||
FluMenuItem{
|
||
text: qsTr("Open in Separate Window")
|
||
font.pixelSize: 12
|
||
onClicked: {
|
||
FluApp.navigate("/pageWindow",{title:modelData.title,url:modelData.url})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Flipable{
|
||
id:flipable
|
||
anchors.fill: parent
|
||
property bool flipped: false
|
||
property real flipAngle: 0
|
||
transform: Rotation {
|
||
id: rotation
|
||
origin.x: flipable.width/2
|
||
origin.y: flipable.height/2
|
||
axis { x: 0; y: 1; z: 0 }
|
||
angle: flipable.flipAngle
|
||
|
||
}
|
||
states: State {
|
||
PropertyChanges { target: flipable; flipAngle: 180 }
|
||
when: flipable.flipped
|
||
}
|
||
transitions: Transition {
|
||
NumberAnimation { target: flipable; property: "flipAngle"; duration: 1000 ; easing.type: Easing.OutCubic}
|
||
}
|
||
back: Item{
|
||
anchors.fill: flipable
|
||
visible: flipable.flipAngle !== 0
|
||
Row{
|
||
id:layout_back_buttons
|
||
z:8
|
||
anchors{
|
||
top: parent.top
|
||
left: parent.left
|
||
topMargin: FluTools.isMacos() ? 20 : 5
|
||
leftMargin: 5
|
||
}
|
||
FluIconButton{
|
||
iconSource: FluentIcons.ChromeBack
|
||
width: 30
|
||
height: 30
|
||
iconSize: 13
|
||
onClicked: {
|
||
flipable.flipped = false
|
||
}
|
||
}
|
||
FluIconButton{
|
||
iconSource: FluentIcons.Sync
|
||
width: 30
|
||
height: 30
|
||
iconSize: 13
|
||
onClicked: {
|
||
loader.reload()
|
||
}
|
||
}
|
||
Component.onCompleted: {
|
||
appBar.setHitTestVisible(layout_back_buttons)
|
||
}
|
||
}
|
||
FluRemoteLoader{
|
||
id:loader
|
||
lazy: true
|
||
anchors.fill: parent
|
||
source: "https://zhu-zichu.gitee.io/Qt_168_LieflatPage.qml"
|
||
}
|
||
}
|
||
front: Item{
|
||
id:page_front
|
||
visible: flipable.flipAngle !== 180
|
||
anchors.fill: flipable
|
||
FluNavigationView{
|
||
property int clickCount: 0
|
||
id:nav_view
|
||
width: parent.width
|
||
height: parent.height
|
||
z:999
|
||
//Stack模式,每次切换都会将页面压入栈中,随着栈的页面增多,消耗的内存也越多,内存消耗多就会卡顿,这时候就需要按返回将页面pop掉,释放内存。该模式可以配合FluPage中的launchMode属性,设置页面的启动模式
|
||
// pageMode: FluNavigationViewType.Stack
|
||
//NoStack模式,每次切换都会销毁之前的页面然后创建一个新的页面,只需消耗少量内存,可以配合FluViewModel保存页面数据(推荐)
|
||
pageMode: FluNavigationViewType.NoStack
|
||
items: ItemsOriginal
|
||
footerItems:ItemsFooter
|
||
topPadding:{
|
||
if(window.useSystemAppBar){
|
||
return 0
|
||
}
|
||
return FluTools.isMacos() ? 20 : 0
|
||
}
|
||
displayMode:viewmodel_settings.displayMode
|
||
logo: "qrc:/example/res/image/favicon.ico"
|
||
title:"FluentUI"
|
||
onLogoClicked:{
|
||
clickCount += 1
|
||
showSuccess("%1:%2".arg(qsTr("Click Time")).arg(clickCount))
|
||
if(clickCount === 5){
|
||
loader.reload()
|
||
flipable.flipped = true
|
||
clickCount = 0
|
||
}
|
||
}
|
||
autoSuggestBox:FluAutoSuggestBox{
|
||
iconSource: FluentIcons.Search
|
||
items: ItemsOriginal.getSearchData()
|
||
placeholderText: qsTr("Search")
|
||
onItemClicked:
|
||
(data)=>{
|
||
ItemsOriginal.startPageByItem(data)
|
||
}
|
||
}
|
||
Component.onCompleted: {
|
||
ItemsOriginal.navigationView = nav_view
|
||
ItemsOriginal.paneItemMenu = nav_item_right_menu
|
||
ItemsFooter.navigationView = nav_view
|
||
ItemsFooter.paneItemMenu = nav_item_right_menu
|
||
appBar.setHitTestVisible(nav_view.buttonMenu)
|
||
appBar.setHitTestVisible(nav_view.buttonBack)
|
||
appBar.setHitTestVisible(nav_view.imageLogo)
|
||
setCurrentIndex(0)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Component{
|
||
id:com_reveal
|
||
CircularReveal{
|
||
id:reveal
|
||
target:window.contentItem
|
||
anchors.fill: parent
|
||
onAnimationFinished:{
|
||
//动画结束后释放资源
|
||
loader_reveal.sourceComponent = undefined
|
||
}
|
||
onImageChanged: {
|
||
changeDark()
|
||
}
|
||
}
|
||
}
|
||
|
||
FluLoader{
|
||
id:loader_reveal
|
||
anchors.fill: parent
|
||
}
|
||
|
||
function distance(x1,y1,x2,y2){
|
||
return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))
|
||
}
|
||
|
||
function handleDarkChanged(button){
|
||
if(!FluTheme.enableAnimation || window.fitsAppBarWindows === false){
|
||
changeDark()
|
||
}else{
|
||
if(loader_reveal.sourceComponent){
|
||
return
|
||
}
|
||
loader_reveal.sourceComponent = com_reveal
|
||
var target = window.contentItem
|
||
var pos = button.mapToItem(target,0,0)
|
||
var mouseX = pos.x
|
||
var mouseY = pos.y
|
||
var radius = Math.max(distance(mouseX,mouseY,0,0),distance(mouseX,mouseY,target.width,0),distance(mouseX,mouseY,0,target.height),distance(mouseX,mouseY,target.width,target.height))
|
||
var reveal = loader_reveal.item
|
||
reveal.start(reveal.width*Screen.devicePixelRatio,reveal.height*Screen.devicePixelRatio,Qt.point(mouseX,mouseY),radius)
|
||
}
|
||
}
|
||
|
||
function changeDark(){
|
||
if(FluTheme.dark){
|
||
FluTheme.darkMode = FluThemeType.Light
|
||
}else{
|
||
FluTheme.darkMode = FluThemeType.Dark
|
||
}
|
||
}
|
||
|
||
Shortcut {
|
||
sequence: "F5"
|
||
context: Qt.WindowShortcut
|
||
onActivated: {
|
||
if(flipable.flipped){
|
||
loader.reload()
|
||
}
|
||
}
|
||
}
|
||
|
||
Shortcut {
|
||
sequence: "F6"
|
||
context: Qt.WindowShortcut
|
||
onActivated: {
|
||
tour.open()
|
||
}
|
||
}
|
||
|
||
FluTour{
|
||
id: tour
|
||
finishText: qsTr("Finish")
|
||
nextText: qsTr("Next")
|
||
previousText: qsTr("Previous")
|
||
steps:{
|
||
var data = []
|
||
if(!window.useSystemAppBar){
|
||
data.push({title:qsTr("Dark Mode"),description: qsTr("Here you can switch to night mode."),target:()=>appBar.buttonDark})
|
||
}
|
||
data.push({title:qsTr("Hide Easter eggs"),description: qsTr("Try a few more clicks!!"),target:()=>nav_view.imageLogo})
|
||
return data
|
||
}
|
||
}
|
||
|
||
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: qsTr("Upgrade Tips")
|
||
message:qsTr("FluentUI is currently up to date ")+ newVerson +qsTr(" -- The current app version") +AppInfo.version+qsTr(" \nNow go and download the new version?\n\nUpdated content: \n")+body
|
||
buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.PositiveButton
|
||
negativeText: qsTr("Cancel")
|
||
positiveText: qsTr("OK")
|
||
onPositiveClicked:{
|
||
Qt.openUrlExternally("https://github.com/zhuzichu520/FluentUI/releases/latest")
|
||
}
|
||
}
|
||
|
||
FluNetworkCallable{
|
||
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(qsTr("The current version is already the latest"))
|
||
}
|
||
}
|
||
}
|
||
onError:
|
||
(status,errorString)=>{
|
||
if(!silent){
|
||
showError(qsTr("The network is abnormal"))
|
||
}
|
||
console.debug(status+";"+errorString)
|
||
}
|
||
}
|
||
|
||
function checkUpdate(silent){
|
||
callable.silent = silent
|
||
FluNetwork.get("https://api.github.com/repos/zhuzichu520/FluentUI/releases/latest")
|
||
.go(callable)
|
||
}
|
||
}
|