/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.0 import QtQml.Models 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 import org.ukui.menu.core 1.0 import AppControls2 1.0 as AppControls2 Loader { id: root active: false property var folderModel: modelManager.getFolderModel() property string folderName: "" property int folderX: 0 property int folderY: 0 property int viewMaxRow: 0 property bool isFolderOpened: false property int margins: 20 property int animationDuration: 300 property bool mouseEnable: false signal turnPageFinished() function initFolder(id, name, x, y) { folderModel.setFolderId(id); folderName = name; folderX = x; folderY = y; viewMaxRow = Math.ceil(folderModel.count / 4) > 4 ? 4 : Math.ceil(folderModel.count / 4); active = true; isFolderOpened = true; } sourceComponent: folderComponent Component { id: folderComponent Item { AppControls2.StyleBackground { id: folderIconBase paletteRole: Palette.Text useStyleTransparent: false property int folderIconSize: 0 property int iconSpacing: 0 property int imageX: 0 property int imageY: 0 property int gridViewMargin: 8 alpha: 0.25 state: isFolderOpened ? "folderOpened" : "folderHidden" states: [ State { name: "folderOpened" PropertyChanges { target: folderIconBase width: 720 height: viewMaxRow * 170 + margins * 2 radius: 36 gridViewMargin: margins x: (parent.width - width) / 2 y: (parent.height - height) / 2 // 内部图标尺寸和布局 folderIconSize: 96 iconSpacing: 8 imageX: 37 imageY: 17 } PropertyChanges { target: folderNameText; opacity: 1 } }, State { name: "folderHidden" PropertyChanges { target: folderIconBase width: 86 height: 86 radius: 16 gridViewMargin: 8 x: root.mapFromGlobal(folderX, 0).x y: root.mapFromGlobal(0, folderY).y // 内部图标尺寸和布局 folderIconSize: 16 iconSpacing: 0 imageX: 0 imageY: 0 } PropertyChanges { target: folderNameText; opacity: 0 } } ] transitions: [ Transition { to: "folderHidden" SequentialAnimation { ScriptAction { script: mouseEnable = false } ParallelAnimation { PropertyAnimation { duration: animationDuration; easing.type: Easing.InOutCubic properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, gridViewMargin" } PropertyAnimation { duration: animationDuration; easing.type: Easing.OutQuint properties: "opacity" } } ScriptAction { script: folderSwipeView.hideFolder() } } }, Transition { to: "folderOpened" SequentialAnimation { ParallelAnimation { PropertyAnimation { duration: animationDuration; easing.type: Easing.InOutCubic properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, gridViewMargin" } PropertyAnimation { duration: animationDuration; easing.type: Easing.InQuint properties: "opacity" } } ScriptAction { script: { folderSwipeView.contentItem.highlightMoveDuration = 0; mouseEnable = true } } } } ] PageIndicator { id: pageIndicator interactive: true count: folderSwipeView.count visible: count > 1 currentIndex: folderSwipeView.currentIndex anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter delegate: Rectangle { color: "grey" width: (index === folderSwipeView.currentIndex )? 20 : 6; height: 6; radius: width / 2 opacity: (index === folderSwipeView.currentIndex )? 1 : 0.6 Behavior on width { NumberAnimation { duration: animationDuration; easing.type: Easing.InOutCubic } } } } SwipeView { id: folderSwipeView anchors.fill: parent property bool needTurnPage: false property int contentX: contentItem.contentX property int startContentX: 0 property int startIndex: 0 function hideFolder() { // 在非第一页时,执行翻页动画 if (currentIndex > 0) { interactive = false; needTurnPage = true; pageIndicator.visible = false; contentItem.highlightFollowsCurrentItem = true; contentItem.highlightMoveDuration = 300; contentItem.highlightMoveVelocity = -1; startContentX = contentX; startIndex = currentIndex; currentIndex = 0; // 在第一页或单页时,全屏文件夹直接隐藏 } else { reset(); } } function reset() { interactive = true; root.active = false; pageIndicator.visible = false; turnPageFinished(); } // 判断执行翻页结束后,全屏文件夹隐藏 onContentXChanged: { // 对比翻页过程的位移 if (needTurnPage && startContentX - contentX === startIndex * 86) { needTurnPage = false; reset(); } } Repeater { model: Math.ceil(folderModel.count / 16) Item { id: base property int currentPage: SwipeView.index GridView { id: folderGridView cellHeight: width / 4; cellWidth: cellHeight anchors.fill: parent anchors.margins: folderIconBase.gridViewMargin boundsBehavior: Flickable.StopAtBounds model: DelegateModel { property int maxItemNumPerPage: 16 filterOnGroup: "folderContent" groups: DelegateModelGroup { name: "folderContent" } items.onChanged: { var groupIndex = groups.length - 1; if (groups[groupIndex].count !== 0) { groups[groupIndex].remove(0, groups[groupIndex].count); } for (var i = base.currentPage * maxItemNumPerPage; i < Math.min((base.currentPage + 1) * maxItemNumPerPage, items.count); i ++) { items.addGroups(i, 1, "folderContent"); } } model: folderModel delegate: MouseArea { hoverEnabled: true enabled: mouseEnable width: GridView.view.cellWidth; height: GridView.view.cellHeight acceptedButtons: Qt.LeftButton | Qt.RightButton AppControls2.StyleBackground { anchors.fill: parent useStyleTransparent: false paletteRole: Palette.Light radius: 16 alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00 Image { id: iconImage source: icon height: folderIconBase.folderIconSize; width: height x: folderIconBase.imageX; y: folderIconBase.imageY } AppControls2.StyleText { width: parent.width horizontalAlignment: Text.AlignHCenter anchors.top: iconImage.bottom anchors.topMargin: folderIconBase.iconSpacing anchors.horizontalCenter: parent.horizontalCenter text: name elide: Text.ElideRight paletteRole: Palette.HighlightedText } } onClicked: { if (mouse.button === Qt.RightButton) { menuManager.showMenu(id, MenuInfo.FullScreenFolder); return; } if (mouse.button === Qt.LeftButton) { appManager.launchApp(id); return; } } } } } } } } } EditText { id: folderNameText anchors.bottom: folderIconBase.top anchors.bottomMargin: 30 anchors.horizontalCenter: folderIconBase.horizontalCenter height: 47; width: folderIconBase.width textEdited: folderName textCenterIn: true isFullScreenFolder: true } } } }