ukui-menu/qml/AppUI/FullScreenContent.qml

486 lines
20 KiB
QML
Raw Normal View History

/*
* 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 <https://www.gnu.org/licenses/>.
*
*/
2023-03-17 17:25:50 +08:00
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQml.Models 2.12
import QtQuick.Controls 2.5
2023-03-17 17:25:50 +08:00
import org.ukui.menu.core 1.0
import AppControls2 1.0 as AppControls2
RowLayout {
id: root
2023-03-17 17:25:50 +08:00
clip: true
signal openFolderSignal(string folderId, string folderName, int x, int y)
signal contentShowFinished()
property bool isContentShow: true
property int animationDuration: 300
state: isContentShow ? "contentShow" : "contentHidden"
states: [
State {
name: "contentHidden"
PropertyChanges { target: root; opacity: 0; scale: 0.95 }
},
State {
name: "contentShow"
PropertyChanges { target: root; opacity: 1; scale: 1 }
}
]
transitions: [
Transition {
to:"contentHidden"
SequentialAnimation {
PropertyAnimation { properties: "opacity, scale"; duration: animationDuration; easing.type: Easing.InOutCubic }
ScriptAction { script: root.visible = false }
}
},
Transition {
to: "contentShow"
PropertyAnimation { properties: "opacity, scale"; duration: animationDuration; easing.type: Easing.InOutCubic }
}
]
2023-03-17 17:25:50 +08:00
Item {
Layout.preferredWidth: 145
2023-03-17 17:25:50 +08:00
Layout.fillHeight: true
Layout.leftMargin: 15
2023-03-17 17:25:50 +08:00
ListView {
id: labelListView
signal labelClicked(string labelId)
property int maxLabelWidth: count < 20 ? width : 30
2023-03-17 17:25:50 +08:00
anchors.centerIn: parent
width: parent.width
height: contentHeight > parent.height ? parent.height : contentHeight
interactive: contentHeight > parent.height
highlightMoveDuration: animationDuration
highlight: AppControls2.StyleBackground {
width: labelListView.maxLabelWidth; height: 30
radius: 4
useStyleTransparent: false
paletteRole: Palette.Light
border.width: 1
alpha: 0.18; borderAlpha: 0.7
borderColor: Palette.HighlightedText
}
onCountChanged: currentIndex = 0
2023-03-17 17:25:50 +08:00
model: DelegateModel {
groups: DelegateModelGroup {
name: "disabledItem"
includeByDefault: false
}
items.onChanged: {
for (let i = 0; i < items.count;) {
let item = items.get(i);
if (item.model.isDisable) {
items.setGroups(i, 1, "disabledItem");
continue;
}
++i;
}
}
model: modelManager.getLabelModel()
delegate: MouseArea {
width: labelListView.maxLabelWidth
2023-03-17 17:25:50 +08:00
height: 30
hoverEnabled: true
AppControls2.StyleText {
2023-03-17 17:25:50 +08:00
anchors.fill: parent
paletteRole: Palette.HighlightedText
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: model.displayName
2023-03-17 17:25:50 +08:00
}
onClicked: {
labelListView.currentIndex = DelegateModel.itemsIndex;
2023-03-17 17:25:50 +08:00
labelListView.labelClicked(model.id)
}
}
}
}
}
Item {
id: contentViewBase
Layout.fillWidth: true
Layout.fillHeight: true
property int maxColumns: 8
property int columns: {
let c = Math.floor(width / cellWidth);
return c > maxColumns ? maxColumns : c;
}
property int cellWidth: 220
// property int cellWidth: Math.min(Math.floor(width / columns), 220)
property int cellHeight: cellWidth
property int headerHeight: 30
Component.onCompleted: {
changeView(modelManager.getLabelGroupModel().containLabel);
modelManager.getLabelGroupModel().containLabelChanged.connect(changeView);
}
Component.onDestruction: {
modelManager.getLabelGroupModel().containLabelChanged.disconnect(changeView);
contentViewLoader.sourceComponent = undefined;
}
function changeView(toLabelView) {
contentViewLoader.sourceComponent = toLabelView ? labelViewComponent : appViewComponent;
}
Loader {
id: contentViewLoader
height: parent.height
width: contentViewBase.cellWidth * contentViewBase.columns + 2
anchors.horizontalCenter: parent.horizontalCenter
}
// view id: 1
Component {
id: appViewComponent
GridView {
ScrollBar.vertical: fullScreenScrollBar
cellWidth: contentViewBase.cellWidth
cellHeight: contentViewBase.cellHeight
boundsBehavior: Flickable.StopAtBounds
2023-03-17 17:25:50 +08:00
model: modelManager.getAppModel()
2023-03-17 17:25:50 +08:00
delegate: Loader {
width: GridView.view.cellWidth
height: width
property int index: model.index
property int type: model.type
property string id: model.id
2023-03-17 17:25:50 +08:00
property string name: model.name
property string icon: model.icon
sourceComponent: {
if (type === DataType.Normal) {
return appComponent;
}
if (type === DataType.Folder) {
return normalFolderComponent;
2023-03-17 17:25:50 +08:00
}
}
}
Component {
id: appComponent
Item {
MouseArea {
anchors.centerIn: parent
hoverEnabled: true
width: 170; height: width
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
AppControls2.IconLabel {
anchors.fill: parent
iconWidth: 96; iconHeight: 96
appName: name; appIcon: icon
spacing: 8
textHighLight: true
}
}
onClicked: {
if (mouse.button === Qt.RightButton) {
2023-05-06 09:20:34 +08:00
modelManager.getAppModel().openMenu(index, MenuInfo.FullScreen);
return;
}
if (mouse.button === Qt.LeftButton) {
parent.parent.GridView.view.model.appClicked(index);
return;
}
}
2023-03-17 17:25:50 +08:00
}
}
2023-03-17 17:25:50 +08:00
}
Component {
id: normalFolderComponent
2023-03-17 17:25:50 +08:00
Item {
MouseArea {
anchors.centerIn: parent
hoverEnabled: true
width: 170; height: width
acceptedButtons: Qt.LeftButton | Qt.RightButton
AppControls2.StyleBackground {
2023-03-17 17:25:50 +08:00
anchors.fill: parent
useStyleTransparent: false
paletteRole: Palette.Light
radius: 16
alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00
ColumnLayout {
height: 128; width: parent.width
anchors.centerIn: parent
spacing: 8
AppControls2.FolderIcon {
id: folderIcon
Layout.margins: 5
rows: 4; columns: 4
spacing: 2; padding: 8
icons: icon
radius: 16; alpha: 0.25
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 86; Layout.preferredHeight: 86
}
AppControls2.StyleText {
Layout.fillWidth: true; Layout.fillHeight: true
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
text: name
font.pixelSize: 14
paletteRole: Palette.HighlightedText
}
}
}
onClicked: {
if (mouse.button === Qt.RightButton) {
2023-05-06 09:20:34 +08:00
modelManager.getAppModel().openMenu(index, MenuInfo.FullScreen);
return;
}
if (mouse.button === Qt.LeftButton) {
var x = folderIcon.mapToGlobal(0,0).x;
var y = folderIcon.mapToGlobal(0,0).y
openFolderSignal(id, name, x, y);
2023-04-18 10:43:21 +08:00
// 执行隐藏动画,并且当前图标消失且鼠标区域不可用
root.isContentShow = false;
2023-04-18 10:43:21 +08:00
folderIcon.opacity = 0;
enabled = false;
hoverEnabled = false;
return;
}
}
function resetOpacity() {
2023-04-18 10:43:21 +08:00
folderIcon.opacity = 1;
enabled = true;
hoverEnabled = true;
2023-03-17 17:25:50 +08:00
}
Component.onCompleted: root.contentShowFinished.connect(resetOpacity)
Component.onDestruction: root.contentShowFinished.disconnect(resetOpacity)
2023-03-17 17:25:50 +08:00
}
}
}
}
}
// view id: 2
Component {
id: labelViewComponent
Flickable {
id: labelViewFlickable
ScrollBar.vertical: fullScreenScrollBar
contentHeight: labelColumn.height
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
2023-03-17 17:25:50 +08:00
interactive: !contentYAnimation.running
Column {
id: labelColumn
width: parent.width
height: childrenRect.height
Repeater {
id: labelRepeater
model: modelManager.getLabelGroupModel()
delegate: GridView {
id: labelAppsGridView
width: parent.width
height: contentHeight
property int labelIndex: index
interactive: false
cacheBuffer: 50
cellWidth: contentViewBase.cellWidth
cellHeight: contentViewBase.cellHeight
header: Item {
2023-03-17 17:25:50 +08:00
width: labelAppsGridView.width
height: contentViewBase.headerHeight
Row {
anchors.fill: parent
anchors.leftMargin: 67
spacing: 15
AppControls2.StyleText {
id: labelName
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
width: contentWidth
text: name
paletteRole: Palette.HighlightedText
}
2023-03-17 17:25:50 +08:00
AppControls2.StyleBackground {
anchors.verticalCenter: parent.verticalCenter
useStyleTransparent: false
alpha: 0.14
paletteRole: Palette.Light
height: 1
width: parent.width - labelName.width - parent.spacing
}
2023-03-17 17:25:50 +08:00
}
}
model: extraData
delegate: Item {
width: GridView.view.cellWidth
height: GridView.view.cellHeight
MouseArea {
anchors.centerIn: parent
hoverEnabled: true
width: 170; height: width
2023-05-06 09:20:34 +08:00
acceptedButtons: Qt.LeftButton | Qt.RightButton
AppControls2.StyleBackground {
2023-03-17 17:25:50 +08:00
anchors.fill: parent
useStyleTransparent: false
paletteRole: Palette.Light
radius: 16
alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00
AppControls2.IconLabel {
anchors.fill: parent
iconWidth: 96; iconHeight: 96
appName: modelData.name
appIcon: modelData.icon
spacing: 8
textHighLight: true
}
2023-03-17 17:25:50 +08:00
}
2023-05-06 09:20:34 +08:00
onClicked: function (mouse) {
if (mouse.button === Qt.RightButton) {
labelRepeater.model.openMenu(labelAppsGridView.labelIndex, model.index);
return;
}
if (mouse.button === Qt.LeftButton) {
labelRepeater.model.openApp(labelAppsGridView.labelIndex, model.index);
return;
}
2023-03-17 17:25:50 +08:00
}
}
}
}
}
}
2023-04-10 14:52:37 +08:00
onContentYChanged: {
if (contentYAnimation.running) {
return
}
if ((contentY + height) === contentHeight) {
labelListView.currentIndex = labelRepeater.count - 1
return
}
labelListView.currentIndex = labelColumn.childAt(contentX,contentY).labelIndex
}
2023-03-17 17:25:50 +08:00
NumberAnimation {
id: contentYAnimation
target: labelViewFlickable
property: "contentY"
duration: animationDuration
2023-03-17 17:25:50 +08:00
onFinished: {
labelViewFlickable.returnToBounds();
}
}
function scrollerView(labelId) {
let labelindex = labelRepeater.model.getLabelIndex(labelId);
if (labelindex < 0 || labelindex >= labelRepeater.count) {
return;
}
let nextY = labelRepeater.itemAt(labelindex).y;
let sh = labelColumn.height - nextY;
if (sh < height) {
nextY -= (height - sh);
}
contentYAnimation.running = false;
if (nextY === contentY) {
return;
}
contentYAnimation.from = contentY;
contentYAnimation.to = nextY;
contentYAnimation.running = true;
}
Component.onCompleted: {
labelListView.labelClicked.connect(scrollerView);
}
Component.onDestruction: {
labelListView.labelClicked.disconnect(scrollerView);
}
}
}
}
Item {
Layout.preferredWidth: 160
2023-03-17 17:25:50 +08:00
Layout.fillHeight: true
ScrollBar {
2023-03-17 17:25:50 +08:00
id: fullScreenScrollBar
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.right
anchors.horizontalCenterOffset: -24
height: 200
width: (hovered || pressed) ? 8 : 4
padding: 0
opacity: fullScreenScrollBar.size < 1.0 ? 1.0 : 0.0
Behavior on width {
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
}
background: AppControls2.StyleBackground {
useStyleTransparent: false
paletteRole: Palette.Dark
alpha: 0.25
radius: width / 2
}
contentItem: AppControls2.StyleBackground {
radius: width / 2
useStyleTransparent: false
paletteRole: Palette.Light
alpha: fullScreenScrollBar.pressed ? 0.90 : fullScreenScrollBar.hovered ? 0.78 : 0.60
}
2023-03-17 17:25:50 +08:00
}
}
}