diff --git a/qml/AppUI/FullScreenContent.qml b/qml/AppUI/FullScreenContent.qml index 649b4d8..485f9b1 100644 --- a/qml/AppUI/FullScreenContent.qml +++ b/qml/AppUI/FullScreenContent.qml @@ -53,10 +53,7 @@ RowLayout { }, Transition { to: "contentShow" - SequentialAnimation { PropertyAnimation { properties: "opacity, scale"; duration: animationDuration; easing.type: Easing.InOutCubic } - ScriptAction { script: root.contentShowFinished() } - } } ] @@ -279,13 +276,18 @@ RowLayout { var x = folderIcon.mapToGlobal(0,0).x; var y = folderIcon.mapToGlobal(0,0).y openFolderSignal(id, name, x, y); + // 执行隐藏动画,并且当前图标消失且鼠标区域不可用 root.isContentShow = false; - opacity = 0; + folderIcon.opacity = 0; + enabled = false; + hoverEnabled = false; return; } } function resetOpacity() { - opacity = 1; + folderIcon.opacity = 1; + enabled = true; + hoverEnabled = true; } Component.onCompleted: root.contentShowFinished.connect(resetOpacity) Component.onDestruction: root.contentShowFinished.disconnect(resetOpacity) diff --git a/qml/AppUI/FullScreenFolder.qml b/qml/AppUI/FullScreenFolder.qml index 8329f93..6f793c6 100644 --- a/qml/AppUI/FullScreenFolder.qml +++ b/qml/AppUI/FullScreenFolder.qml @@ -17,149 +17,292 @@ */ 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 -Item { - property alias model: folderGridView.model + +Loader { + id: root + active: false + property var folderModel: modelManager.getFolderModel() property string folderName: "" - property int margins: 20 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() - 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 - alpha: 0.25 + 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; + } - state: isFolderOpened ? "folderOpened" : "folderHidden" - states: [ - State { - name: "folderOpened" - PropertyChanges { - target: folderIconBase - width: 720; height: folderGridView.viewMaxHeight; radius: 36 - x: (parent.width - width) / 2; y: (parent.height - height) / 2 - folderIconSize: 96; iconSpacing: 8 - imageX: 37; imageY: 17 - } - PropertyChanges { target: folderGridView; anchors.margins: margins } - PropertyChanges { target: folderNameText; opacity: 1 } - }, - State { - name: "folderHidden" - PropertyChanges { - target: folderIconBase - width: 86; height: width; radius: 16 - x: parent.parent.mapFromGlobal(folderX, 0).x; y: parent.parent.mapFromGlobal(0, folderY).y - folderIconSize: 16; iconSpacing: 0 - imageX: 0; imageY: 0 - } - PropertyChanges { target: folderGridView; anchors.margins: 8 } - PropertyChanges { target: folderNameText; opacity: 0 } - } - ] - transitions: [ - Transition { - to: "folderHidden" - SequentialAnimation { - ScriptAction { script: folderGridView.positionViewAtBeginning() } - ParallelAnimation { - PropertyAnimation { - duration: animationDuration; easing.type: Easing.InOutCubic - properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, anchors.margins" + 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 } - PropertyAnimation { - duration: animationDuration; easing.type: Easing.OutQuint - properties: "opacity" + 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 + } + } } } - ScriptAction { script: parent.active = false } - } - }, - Transition { - to: "folderOpened" - ParallelAnimation { - PropertyAnimation { - duration: animationDuration; easing.type: Easing.InOutCubic - properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, anchors.margins" - } - PropertyAnimation { - duration: animationDuration; easing.type: Easing.InQuint - properties: "opacity" + ] + + 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 } + } } } - } - ] - GridView { - id: folderGridView - anchors.fill: parent - cellHeight: width / 4; cellWidth: cellHeight - boundsBehavior: Flickable.StopAtBounds - property int viewMaxHeight: Math.ceil(count / 4) * 170 > width ? width + margins*2 : (Math.ceil(count / 4) * 170 + margins*2) - model: modelManager.getFolderModel() - delegate: MouseArea { - hoverEnabled: true - width: GridView.view.cellHeight; height: width - acceptedButtons: Qt.LeftButton | Qt.RightButton - - AppControls2.StyleBackground { + SwipeView { + id: folderSwipeView anchors.fill: parent - useStyleTransparent: false - paletteRole: Palette.Light - radius: 16 - alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00 + property bool needTurnPage: false + property int contentX: contentItem.contentX + property int startContentX: 0 + property int startIndex: 0 - Image { - id: iconImage - source: icon - height: folderIconBase.folderIconSize; width: height - x: folderIconBase.imageX; y: folderIconBase.imageY + 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(); + } } - AppControls2.StyleText { - width: parent.width - horizontalAlignment: Text.AlignHCenter - anchors.top: iconImage.bottom - anchors.topMargin: folderIconBase.iconSpacing - anchors.horizontalCenter: parent.horizontalCenter - text: name - font.pixelSize: 14 - elide: Text.ElideRight - paletteRole: Palette.HighlightedText - } - } - onClicked: { - if (mouse.button === Qt.RightButton) { - menuManager.showMenu(id); - return; - } - if (mouse.button === Qt.LeftButton) { - appManager.launchApp(id); - return; + 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 + font.pixelSize: 14 + elide: Text.ElideRight + paletteRole: Palette.HighlightedText + } + } + onClicked: { + if (mouse.button === Qt.RightButton) { + menuManager.showMenu(id); + 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 + } } } - EditText { - id: folderNameText - anchors.bottom: folderGridView.parent.top - anchors.bottomMargin: 30 - anchors.horizontalCenter: folderGridView.parent.horizontalCenter - height: 47; width: folderGridView.width - textEdited: folderName - textCenterIn: true - isFullScreenFolder: true - } } + diff --git a/qml/AppUI/FullScreenUI.qml b/qml/AppUI/FullScreenUI.qml index 3c7b95f..1a9abf5 100644 --- a/qml/AppUI/FullScreenUI.qml +++ b/qml/AppUI/FullScreenUI.qml @@ -13,7 +13,7 @@ AppControls2.StyleBackground { forceActiveFocus(); mainWindow.hide(); } else { - folderLoader.item.isFolderOpened = false; + folderLoader.isFolderOpened = false; fullScreenContent.visible = true; fullScreenContent.isContentShow = true; } @@ -40,25 +40,15 @@ AppControls2.StyleBackground { FullScreenContent { id: fullScreenContent anchors.fill: parent + Component.onCompleted: folderLoader.turnPageFinished.connect(contentShowFinished) + Component.onDestruction: folderLoader.turnPageFinished.disconnect(contentShowFinished) } - Loader { + FullScreenFolder { id: folderLoader - active: false anchors.fill: parent - sourceComponent: FullScreenFolder {} - - function openFolder(id, name, x, y) { - active = true; - item.model.setFolderId(id); - item.folderName = name; - item.folderX = x; - item.folderY = y; - item.isFolderOpened = true; - } - - Component.onCompleted: fullScreenContent.openFolderSignal.connect(openFolder) - Component.onDestruction: fullScreenContent.openFolderSignal.disconnect(openFolder) + Component.onCompleted: fullScreenContent.openFolderSignal.connect(initFolder) + Component.onDestruction: fullScreenContent.openFolderSignal.disconnect(initFolder) } } diff --git a/src/model/folder-model.cpp b/src/model/folder-model.cpp index c5f6cbb..656d9f8 100644 --- a/src/model/folder-model.cpp +++ b/src/model/folder-model.cpp @@ -62,6 +62,8 @@ void FolderModel::loadFolderData(int id) m_folderId = id; m_apps = folder.getApps(); endResetModel(); + + Q_EMIT countChanged(); } int FolderModel::rowCount(const QModelIndex &parent) const @@ -106,4 +108,9 @@ QHash FolderModel::roleNames() const return DataEntity::AppRoleNames(); } +int FolderModel::count() +{ + return m_apps.count(); +} + } // UkuiMenu diff --git a/src/model/folder-model.h b/src/model/folder-model.h index a6b03fa..1d2ed2c 100644 --- a/src/model/folder-model.h +++ b/src/model/folder-model.h @@ -27,6 +27,7 @@ namespace UkuiMenu { class FolderModel : public QAbstractListModel { Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) public: explicit FolderModel(QObject *parent = nullptr); Q_INVOKABLE void setFolderId(const QString &folderId); @@ -35,6 +36,10 @@ public: int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; + int count(); + +Q_SIGNALS: + void countChanged(); private Q_SLOTS: void loadFolderData(int id);