feat(qml):调整全屏下收藏区域和应用组显示和三态

This commit is contained in:
qiqi49 2024-02-01 18:55:21 +08:00 committed by hewenfei
parent 55b4901ded
commit fd55d6d765
15 changed files with 473 additions and 392 deletions

View File

@ -28,9 +28,7 @@ Item {
property bool textCenterIn: false property bool textCenterIn: false
property bool editStatus: false property bool editStatus: false
property string textEdited: title property string textEdited: title
property bool isFullScreen: false property real textSize
property bool isFolder: false
property real textInputSize: 14
signal textEditingFinished(string text) signal textEditingFinished(string text)
Component { Component {
@ -41,21 +39,14 @@ Item {
horizontalAlignment: contain.textCenterIn ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: contain.textCenterIn ? Text.AlignHCenter : Text.AlignLeft
elide: Text.ElideRight elide: Text.ElideRight
text: contain.textEdited text: contain.textEdited
paletteRole: isFullScreen ? Platform.Theme.HighlightedText : Platform.Theme.Text paletteRole: Platform.Theme.Text
font.bold: isFolder font.bold: true
// AppControls2 StyleText font.pointSize: textSize
property real textUltra: 2*systemFontSize
property real systemFontSize: 16
font.pointSize:(isFolder && isFullScreen) ? textUltra : systemFontSize
MouseArea { MouseArea {
id: textArea id: textArea
anchors.fill: parent anchors.fill: parent
onDoubleClicked: { onDoubleClicked: contain.editStatus = true;
contain.editStatus = true;
contain.textInputSize = textShow.font.pointSize;
}
} }
} }
} }
@ -84,8 +75,7 @@ Item {
text: contain.textEdited text: contain.textEdited
selectByMouse: true selectByMouse: true
maximumLength: 14 maximumLength: 14
font.bold: !isFolder font.pointSize: textSize
font.pointSize: contain.textInputSize
onEditingFinished: { onEditingFinished: {
// modelManager.getFolderModel().renameFolder(text); // modelManager.getFolderModel().renameFolder(text);
@ -95,7 +85,7 @@ Item {
} }
function updateTextInputColor() { function updateTextInputColor() {
color = isFullScreen ? Platform.Theme.highlightedText() : Platform.Theme.text(); color = Platform.Theme.text();
selectionColor = Platform.Theme.highlight(); selectionColor = Platform.Theme.highlight();
} }

View File

@ -43,29 +43,25 @@ MouseArea {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 16 anchors.topMargin: 16
spacing: 0 anchors.bottomMargin: 16
spacing: 8
UkuiItems.Icon { UkuiItems.Icon {
id: appIcon id: appIcon
Layout.minimumWidth: 32 Layout.preferredWidth: styleBackground.width * 0.6
Layout.minimumHeight: 32 Layout.preferredHeight: width
Layout.maximumWidth: 96 Layout.alignment: Qt.AlignHCenter
Layout.maximumHeight: 96
Layout.preferredWidth: 96
Layout.preferredHeight: 96
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
} }
UkuiItems.StyleText { UkuiItems.StyleText {
id: appName id: appName
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.preferredHeight: contentHeight
Layout.maximumHeight: contentHeight
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
paletteRole: Platform.Theme.Text paletteRole: Platform.Theme.Text
horizontalAlignment: Text.AlignHCenter
} }
} }
} }

View File

@ -24,6 +24,7 @@ import QtQuick.Layouts 1.12
import org.ukui.menu.core 1.0 import org.ukui.menu.core 1.0
import org.ukui.menu.extension 1.0 import org.ukui.menu.extension 1.0
import "../extensions" as Extension
import AppControls2 1.0 as AppControls2 import AppControls2 1.0 as AppControls2
import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.items 1.0 as UkuiItems
@ -31,8 +32,14 @@ import org.ukui.quick.platform 1.0 as Platform
ListView { ListView {
id: root id: root
signal openFolderSignal(string folderId, string folderName, int x, int y)
signal contentShowFinished()
property bool isContentShow
property int itemHeight: 40 property int itemHeight: 40
property alias sourceModel: appGroupModel.sourceModel property alias sourceModel: appGroupModel.sourceModel
// TODO:
property int column: 10
spacing: 5 spacing: 5
clip: true clip: true
@ -61,8 +68,7 @@ ListView {
GridView { GridView {
width: parent.width width: parent.width
height: childrenRect.height height: childrenRect.height
// TODO: cellWidth: width / root.column
cellWidth: width / 8
cellHeight: cellWidth cellHeight: cellWidth
interactive: false interactive: false
@ -98,67 +104,68 @@ ListView {
} }
header: Item { header: Item {
width: ListView.view.width width: root.width
height: childrenRect.height + ListView.view.spacing height: childrenRect.height
property alias widgets: widgetView.widgets property var widgets: []
property alias widgetCount: widgetView.count property var widgetInfos: []
property alias widgetInfos: widgetView.widgetInfos property int widgetCount: 1
ListView { Component.onCompleted: {
id: widgetView widgetInfos.push({label: "favorite", display: "non-starred-symbolic", type: WidgetMetadata.Widget});
widgets.push("favorite");
}
property var widgets: [] Column {
property var widgetInfos: []
anchors.top: parent.top
width: parent.width width: parent.width
height: childrenRect.height height: childrenRect.height + spacing
interactive: false spacing: root.spacing
spacing: parent.ListView.view.spacing
onCountChanged: { AppControls2.LabelItem {
widgets = []; width: parent.width
widgetInfos = []; height: root.itemHeight
for (let i = 0; i < count; ++i) { displayName: qsTr("Favorite")
let item = itemAtIndex(i);
widgetInfos.push({label: item.widgetId, display: item.icon, type: LabelItem.Icon});
widgets.push(item.widgetId);
}
} }
model: WidgetModel { GridView {
flags: WidgetMetadata.OnlyFullScreen id: favoriteView
} width: parent.width
delegate: Column { height: contentHeight
property string icon: model.icon property string mergeToAppId: ""
property string widgetId: model.id property bool isMergeToFolder: false
property bool dragTypeIsMerge: false
property int exchangedStartIndex: 0
property alias viewModel: visualModel
width: ListView.view.width cellWidth: width / root.column
height: childrenRect.height cellHeight: cellWidth
spacing: ListView.view.spacing model: DelegateModel {
id: visualModel
model: favoriteModel
delegate: Item {
id: container
width: favoriteView.cellWidth
height: favoriteView.cellHeight
Extension.FavoriteDelegate {
anchors.fill: parent
anchors.margins: 12
AppControls2.LabelItem { visualIndex: container.DelegateModel.itemsIndex
width: parent.width delegateLayout.anchors.topMargin: 16
height: root.itemHeight delegateLayout.anchors.bottomMargin: 16
displayName: model.name delegateLayout.spacing: 8
} mergePrompt.anchors.topMargin: 10
mergePrompt.width: width*0.67
mergePrompt.radius: 32
Loader { Component.onCompleted: contentShowFinished.connect(resetOpacity)
width: parent.width Component.onDestruction: contentShowFinished.disconnect(resetOpacity)
// height: item === null ? 0 : item.height
height: item === null ? 0 : 200
property var extensionData: model.data
onExtensionDataChanged: {
if (item !== null) {
item.extensionData = extensionData;
} }
} }
}
Component.onCompleted: { displaced: Transition {
setSource(model.main, {extensionData: extensionData}); NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad; duration: 200 }
}
} }
} }
} }

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.12
import QtQml.Models 2.12 import QtQml.Models 2.12
import org.ukui.menu.core 1.0 import org.ukui.menu.core 1.0
import "../extensions" as Extension
import AppControls2 1.0 as AppControls2 import AppControls2 1.0 as AppControls2
import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.items 1.0 as UkuiItems
@ -19,16 +20,54 @@ UkuiItems.StyleBackground {
forceActiveFocus(); forceActiveFocus();
mainWindow.hide(); mainWindow.hide();
} else { } else {
mainContainer.visible = true; folderLoader.isFolderOpened = false;
} }
} }
} }
Extension.FullScreenFolder {
id: folderLoader
anchors.fill: parent
folderModel: FolderModel
Component.onCompleted: fullScreenAppList.openFolderSignal.connect(initFolder)
Component.onDestruction: fullScreenAppList.openFolderSignal.disconnect(initFolder)
}
Item { Item {
id: mainContainer id: mainContainer
anchors.fill: parent anchors.fill: parent
z: 10 z: 10
state: !fullScreenAppList.isContentShow ? "contentShow" : "contentHidden"
states: [
State {
name: "contentHidden"
PropertyChanges { target: mainContainer; opacity: 0; scale: 0.95 }
},
State {
name: "contentShow"
PropertyChanges { target: mainContainer; opacity: 1; scale: 1 }
}
]
transitions: [
Transition {
to:"contentHidden"
SequentialAnimation {
PropertyAnimation { properties: "opacity, scale"; duration: 300; easing.type: Easing.InOutCubic }
ScriptAction { script: mainContainer.visible = false }
}
},
Transition {
to: "contentShow"
SequentialAnimation {
ScriptAction { script: mainContainer.visible = true }
PropertyAnimation { properties: "opacity, scale"; duration: 300; easing.type: Easing.InOutCubic }
}
}
]
// //
GridLayout { GridLayout {
anchors.fill: parent anchors.fill: parent
@ -168,6 +207,7 @@ UkuiItems.StyleBackground {
Layout.fillHeight: true Layout.fillHeight: true
sourceModel: AppPageBackend.appModel sourceModel: AppPageBackend.appModel
isContentShow: folderLoader.isFolderOpened
function positionLabel(label) { function positionLabel(label) {
// Widget // Widget
@ -195,7 +235,9 @@ UkuiItems.StyleBackground {
Component.onCompleted: { Component.onCompleted: {
positionViewAtBeginning(); positionViewAtBeginning();
folderLoader.turnPageFinished.connect(contentShowFinished)
} }
Component.onDestruction: folderLoader.turnPageFinished.disconnect(contentShowFinished)
} }
} }
} }

View File

@ -10,33 +10,100 @@ import AppControls2 1.0 as AppControls2
UkuiItems.StyleBackground { UkuiItems.StyleBackground {
id: iconItem id: iconItem
property bool hold: false property bool hold: false
property alias draggedIcon: itemLoader property alias delegateLayout: itemLayout
property alias mergePrompt: mergePrompt
radius: 8 radius: 8
useStyleTransparency: false useStyleTransparency: false
paletteRole: Platform.Theme.Text paletteRole: Platform.Theme.Text
alpha: hold ? 0 : control.containsPress ? 0.15 : control.containsMouse ? 0.08 : 0 alpha: hold ? 0 : control.containsPress ? 0.15 : control.containsMouse ? 0.08 : 0
// 52*52 property int visualIndex
Binding { target: itemLoader; property: "visualIndex"; value: visualIndex }
// 52*52
UkuiItems.StyleBackground { UkuiItems.StyleBackground {
width: 52 id: mergePrompt
height: width height: width
radius: 14
anchors.top: parent.top anchors.top: parent.top
anchors.margins: 6
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
paletteRole: Platform.Theme.Text paletteRole: Platform.Theme.Text
useStyleTransparency: false useStyleTransparency: false
alpha: (delegateDropArea.enterSourceId !== model.id) alpha: (delegateDropArea.enterSourceId !== model.id)
&& delegateDropArea.containsDrag && dragTypeIsMerge ? 0.15 : 0 && delegateDropArea.containsDrag && favoriteView.dragTypeIsMerge ? 0.15 : 0
z: -1 z: -1
} }
DropArea {
id: delegateDropArea
anchors.fill: parent
anchors.margins: 10
property string enterSourceId: ""
// drag.source [itemLoader]
onEntered: {
if (drag.source.isFolder) {
return;
}
enterSourceId = drag.source.sourceId;
delegateDropTimer.running = true;
}
onExited: {
if (delegateDropTimer.timeOutCount < 1) {
favoriteView.dragTypeIsMerge = false;
favoriteView.viewModel.items.move(drag.source.visualIndex, iconItem.visualIndex);
}
delegateDropTimer.running = false;
enterSourceId = "";
}
}
Timer {
id: delegateDropTimer
property int timeOutCount: 0
interval: 300
repeat: true
onTriggered: {
++timeOutCount;
if (timeOutCount == 1) {
favoriteView.mergeToAppId = model.id;
favoriteView.isMergeToFolder = (model.type === DataType.Folder);
favoriteView.dragTypeIsMerge = true;
}
}
onRunningChanged: timeOutCount = 0
}
MouseArea {
id: control
anchors.fill: parent
hoverEnabled: true
pressAndHoldInterval: 300
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
itemLoader.item.itemClicked(mouse.button);
}
onPressAndHold: {
if (mouse.button === Qt.LeftButton) {
drag.target = itemLoader;
iconItem.hold = true;
favoriteView.exchangedStartIndex = itemLoader.visualIndex;
itemLoader.sourceId = model.id;
}
}
onReleased: {
drag.target = null;
}
}
ColumnLayout { ColumnLayout {
id: itemLayout id: itemLayout
width: parent.width anchors.fill: parent
anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
anchors.horizontalCenter: parent.horizontalCenter anchors.bottomMargin: 14
spacing: 6 spacing: 6
ToolTip.visible: iconText.truncated && control.containsMouse ToolTip.visible: iconText.truncated && control.containsMouse
@ -45,8 +112,8 @@ UkuiItems.StyleBackground {
Item { Item {
id: loaderBase id: loaderBase
Layout.preferredHeight: 48 Layout.preferredWidth: iconItem.width * 0.6
Layout.preferredWidth: 48 Layout.preferredHeight: width
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Loader { Loader {
@ -63,7 +130,9 @@ UkuiItems.StyleBackground {
if (Drag.active) { if (Drag.active) {
itemLoader.parent = favoriteView; itemLoader.parent = favoriteView;
} else { } else {
if (dragTypeIsMerge && (model.id !== mergeToAppId) && (model.type === DataType.Normal)) { if (favoriteView.dragTypeIsMerge
&& (model.id !== favoriteView.mergeToAppId)
&& (model.type === DataType.Normal)) {
iconItem.hold = false; iconItem.hold = false;
} else { } else {
@ -116,6 +185,8 @@ UkuiItems.StyleBackground {
UkuiItems.StyleText { UkuiItems.StyleText {
id: iconText id: iconText
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: contentHeight
Layout.maximumHeight: contentHeight
text: name text: name
elide: Text.ElideRight elide: Text.ElideRight
@ -140,7 +211,7 @@ UkuiItems.StyleBackground {
function itemClicked(mouseButton) { function itemClicked(mouseButton) {
if (mouseButton === Qt.RightButton) { if (mouseButton === Qt.RightButton) {
visualModel.model.openMenu(index) favoriteModel.openMenu(index)
} else { } else {
var data = {"id": model.id}; var data = {"id": model.id};
send(data); send(data);
@ -154,24 +225,26 @@ UkuiItems.StyleBackground {
Item { Item {
AppControls2.FolderIcon { AppControls2.FolderIcon {
id: folderIcon id: folderIcon
width: 40 height: width
height: 40
anchors.centerIn: parent anchors.centerIn: parent
alpha: 0.10
rows: 2; columns: 2
spacing: 2; padding: 2
icons: icon icons: icon
radius: 4; alpha: 0.10 columns: rows
width: mainWindow.isFullScreen ? 84: 40
rows: mainWindow.isFullScreen ? 4 : 2
spacing: mainWindow.isFullScreen ? 4 : 2
padding: mainWindow.isFullScreen ? 8 : 2
radius: mainWindow.isFullScreen ? 16 :4
} }
function itemClicked(mouseButton) { function itemClicked(mouseButton) {
if (mouseButton === Qt.RightButton) { if (mouseButton === Qt.RightButton) {
visualModel.model.openMenu(index); favoriteModel.openMenu(index);
} else { } else {
var x = mapToGlobal(folderIcon.x, folderIcon.y).x; var x = mapToGlobal(folderIcon.x, folderIcon.y).x;
var y = mapToGlobal(folderIcon.x, folderIcon.y).y var y = mapToGlobal(folderIcon.x, folderIcon.y).y
openFolderSignal(id, name, x, y); openFolderSignal(id, name, x, y);
// //
favoriteView.isContentShow = false;
opacity = 0; opacity = 0;
control.enabled = false; control.enabled = false;
control.hoverEnabled = false; control.hoverEnabled = false;
@ -180,52 +253,27 @@ UkuiItems.StyleBackground {
} }
} }
MouseArea {
id: control
anchors.fill: parent
hoverEnabled: true
pressAndHoldInterval: 300
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
itemLoader.item.itemClicked(mouse.button);
}
onPressAndHold: {
if (mouse.button === Qt.LeftButton) {
drag.target = itemLoader;
iconItem.hold = true;
exchangedStartIndex = itemLoader.visualIndex;
itemLoader.sourceId = model.id;
}
}
onReleased: {
drag.target = null;
}
}
// folderFunction // folderFunction
function resetOpacity() { function resetOpacity() {
itemLoader.item.opacity = 1; itemLoader.item.opacity = 1;
control.enabled = true; control.enabled = true;
control.hoverEnabled = true; control.hoverEnabled = true;
} }
Component.onCompleted: favoriteView.contentShowFinished.connect(resetOpacity)
Component.onDestruction: favoriteView.contentShowFinished.disconnect(resetOpacity)
onHoldChanged: { onHoldChanged: {
if (hold) { if (hold) {
favoriteView.interactive = false; favoriteView.interactive = false;
} else { } else {
favoriteView.interactive = contentHeight > favoriteView.parent.height; favoriteView.interactive = contentHeight > favoriteView.parent.height;
if (dragTypeIsMerge && (model.id !== mergeToAppId) && (model.type === DataType.Normal)) { if (favoriteView.dragTypeIsMerge && (model.id !== favoriteView.mergeToAppId) && (model.type === DataType.Normal)) {
if (isMergeToFolder) { if (favoriteView.isMergeToFolder) {
visualModel.model.addAppToFolder(model.id, mergeToAppId); favoriteModel.addAppToFolder(model.id, favoriteView.mergeToAppId);
} else { } else {
visualModel.model.addAppsToNewFolder(model.id, mergeToAppId); favoriteModel.addAppsToNewFolder(model.id, favoriteView.mergeToAppId);
} }
} else if (exchangedStartIndex !== itemLoader.visualIndex) { } else if (favoriteView.exchangedStartIndex !== itemLoader.visualIndex) {
visualModel.model.exchangedAppsOrder(exchangedStartIndex, itemLoader.visualIndex); favoriteModel.exchangedAppsOrder(favoriteView.exchangedStartIndex, itemLoader.visualIndex);
} }
} }
} }

View File

@ -42,11 +42,9 @@ UkuiMenuExtension {
} }
folderLoader.isFolderOpened = false; folderLoader.isFolderOpened = false;
favoriteView.visible = true;
favoriteView.isContentShow = true;
} }
} }
UkuiItems.Menu { UkuiItems.Menu {
id: menu id: menu
content: [ content: [
@ -105,6 +103,7 @@ UkuiMenuExtension {
width: parent.width width: parent.width
height: (contentHeight > parent.height) ? parent.height : contentHeight height: (contentHeight > parent.height) ? parent.height : contentHeight
interactive: contentHeight > parent.height interactive: contentHeight > parent.height
isContentShow: !folderLoader.isFolderOpened
Component.onCompleted: { Component.onCompleted: {
favoriteView.viewModel.model = extensionData.favoriteAppsModel favoriteView.viewModel.model = extensionData.favoriteAppsModel

View File

@ -32,10 +32,9 @@ GridView {
cellHeight: cellWidth + 12 cellHeight: cellWidth + 12
signal openFolderSignal(string folderId, string folderName, int x, int y) signal openFolderSignal(string folderId, string folderName, int x, int y)
signal contentShowFinished() signal contentShowFinished()
property bool isContentShow: true property bool isContentShow
property int spacing: 4 property int spacing: 4
property int itemHeight: 84
property int column: 5 property int column: 5
property alias viewModel: visualModel property alias viewModel: visualModel
@ -66,7 +65,10 @@ GridView {
}, },
Transition { Transition {
to: "contentShow" to: "contentShow"
PropertyAnimation { properties: "opacity, scale"; duration: 300; easing.type: Easing.InOutCubic } SequentialAnimation {
ScriptAction { script: favoriteView.visible = true }
PropertyAnimation { properties: "opacity, scale"; duration: 300; easing.type: Easing.InOutCubic }
}
} }
] ]
// //
@ -100,12 +102,6 @@ GridView {
currentIndex = currentIndex - column; currentIndex = currentIndex - column;
} }
ScrollBar.vertical: AppControls2.ScrollBar {
id: scrollBar
visible: viewMouseArea.containsMouse
width: 14; height: favoriteView.height
}
displaced: Transition { displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad; duration: 200 } NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad; duration: 200 }
} }
@ -117,8 +113,7 @@ GridView {
focus: true focus: true
width: favoriteView.cellWidth width: favoriteView.cellWidth
height: favoriteView.cellHeight height: favoriteView.cellHeight
property int visualIndex: DelegateModel.itemsIndex
Binding { target: iconItem.draggedIcon; property: "visualIndex"; value: visualIndex }
states: State { states: State {
when: activeFocus when: activeFocus
PropertyChanges { PropertyChanges {
@ -131,87 +126,48 @@ GridView {
send(data); send(data);
} }
DropArea { FavoriteDelegate {
id: delegateDropArea id: iconItem
anchors.fill: parent
anchors.margins: 14
property string enterSourceId: ""
// drag.source [iconItem.draggedIcon]
onEntered: {
if (drag.source.isFolder) {
return;
}
enterSourceId = drag.source.sourceId;
delegateDropTimer.running = true;
}
onExited: {
if (delegateDropTimer.timeOutCount < 1) {
dragTypeIsMerge = false;
visualModel.items.move(drag.source.visualIndex, iconItem.visualIndex);
}
delegateDropTimer.running = false;
enterSourceId = "";
}
}
Item {
anchors.fill: parent anchors.fill: parent
anchors.margins: 2 anchors.margins: 2
Timer { visualIndex: container.DelegateModel.itemsIndex
id: delegateDropTimer mergePrompt.anchors.topMargin: 6
property int timeOutCount: 0 mergePrompt.width: 52
interval: 300 mergePrompt.radius: 14
repeat: true
onTriggered: { Component.onCompleted: favoriteView.contentShowFinished.connect(resetOpacity)
++timeOutCount; Component.onDestruction: favoriteView.contentShowFinished.disconnect(resetOpacity)
if (timeOutCount == 1) { }
mergeToAppId = model.id;
isMergeToFolder = (model.type === DataType.Folder);
dragTypeIsMerge = true; //
Loader {
id: tag
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: 10
Component {
id: editImage
UkuiItems.Button {
width: 28
height: 28
icon.width: 16
icon.height: 16
background.paletteRole: Platform.Theme.Light
background.alpha: 1
activeFocusOnTab: false
onClicked: {
visualModel.model.removeAppFromFavorites(id);
} }
background.radius: width / 2
icon.source: "ukui-cancel-star-symbolic"
} }
onRunningChanged: timeOutCount = 0
} }
FavoriteDelegate { sourceComponent: mainWindow.editMode && (type === DataType.Normal) ? editImage : null
id: iconItem
anchors.fill: parent
property int visualIndex: container.DelegateModel.itemsIndex
}
//
Loader {
id: tag
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: 10
Component {
id: editImage
UkuiItems.Button {
width: 28
height: 28
icon.width: 16
icon.height: 16
background.paletteRole: Platform.Theme.Light
background.alpha: 1
activeFocusOnTab: false
onClicked: {
visualModel.model.removeAppFromFavorites(id);
}
background.radius: width / 2
icon.source: "ukui-cancel-star-symbolic"
}
}
sourceComponent: mainWindow.editMode && (type === DataType.Normal) ? editImage : null
}
} }
} }
} }

View File

@ -23,164 +23,152 @@ import QtQuick.Controls 2.5
import org.ukui.menu.core 1.0 import org.ukui.menu.core 1.0
import org.ukui.quick.platform 1.0 as Platform import org.ukui.quick.platform 1.0 as Platform
import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.items 1.0 as UkuiItems
Item {
SwipeView {
id: folderSwipeView
anchors.margins: contentMargins
property bool needTurnPage: false
property int contentX: contentItem.contentX
property int startContentX: 0
property int startIndex: 0
property var folderContentModel property var folderContentModel
property alias folderSwipeView: folderSwipeView property alias folderSwipeView: folderSwipeView
property bool mouseEnable: false property bool mouseEnable: false
property int contentMargins property int contentMargins
property int labelMagrins property int labelMagrins
property int labelSpacing
property bool isFullScreen: false property bool isFullScreen: false
PageIndicator { function hideFolder() {
id: pageIndicator //
interactive: true if (currentIndex > 0) {
count: folderSwipeView.count interactive = false;
visible: count > 1 needTurnPage = true;
currentIndex: folderSwipeView.currentIndex pageIndicator.visible = false;
anchors.bottom: parent.bottom contentItem.highlightFollowsCurrentItem = true;
anchors.horizontalCenter: parent.horizontalCenter contentItem.highlightMoveDuration = 300;
contentItem.highlightMoveVelocity = -1;
delegate: Rectangle { startContentX = contentX;
color: "grey" startIndex = currentIndex;
width: (index === folderSwipeView.currentIndex )? 20 : 6; height: 6; currentIndex = 0;
radius: width / 2 //
opacity: (index === folderSwipeView.currentIndex )? 1 : 0.6 } else {
Behavior on width { reset();
NumberAnimation { duration: 300; easing.type: Easing.InOutCubic }
}
} }
} }
SwipeView { function reset() {
id: folderSwipeView interactive = true;
anchors.fill: parent root.active = false;
anchors.margins: contentMargins pageIndicator.visible = false;
property bool needTurnPage: false turnPageFinished();
property int contentX: contentItem.contentX }
property int startContentX: 0
property int startIndex: 0
function hideFolder() { //
// onContentXChanged: {
if (currentIndex > 0) { //
interactive = false; if (needTurnPage && startContentX - contentX === startIndex * width) {
needTurnPage = true; needTurnPage = false;
pageIndicator.visible = false; reset();
contentItem.highlightFollowsCurrentItem = true;
contentItem.highlightMoveDuration = 300;
contentItem.highlightMoveVelocity = -1;
startContentX = contentX;
startIndex = currentIndex;
currentIndex = 0;
//
} else {
reset();
}
} }
}
function reset() { Repeater {
interactive = true; model: Math.ceil(folderModel.count / 16)
root.active = false;
pageIndicator.visible = false;
turnPageFinished();
}
// Item {
onContentXChanged: { id: base
// property int currentPage: SwipeView.index
if (needTurnPage && startContentX - contentX === startIndex * 86) {
needTurnPage = false;
reset();
}
}
Repeater { GridView {
model: Math.ceil(folderModel.count / 16) id: folderGridView
cellHeight: isFullScreen ? cellWidth : (cellWidth + 12)
cellWidth: width / 4
anchors.fill: parent
interactive: false
Item { model: DelegateModel {
id: base property int maxItemNumPerPage: 16
property int currentPage: SwipeView.index filterOnGroup: "folderContent"
groups: DelegateModelGroup {
name: "folderContent"
}
GridView { items.onChanged: {
id: folderGridView var groupIndex = groups.length - 1;
cellHeight: isFullScreen ? cellWidth : (cellWidth + 12) if (groups[groupIndex].count !== 0) {
cellWidth: width / 4 groups[groupIndex].remove(0, groups[groupIndex].count);
anchors.fill: parent
interactive: false
model: DelegateModel {
property int maxItemNumPerPage: 16
filterOnGroup: "folderContent"
groups: DelegateModelGroup {
name: "folderContent"
} }
items.onChanged: { for (var i = base.currentPage * maxItemNumPerPage;
var groupIndex = groups.length - 1; i < Math.min((base.currentPage + 1) * maxItemNumPerPage, items.count); i ++) {
if (groups[groupIndex].count !== 0) { items.addGroups(i, 1, "folderContent");
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");
}
} }
}
onCountChanged: {
if (count === 0) {
reset();
folderLoader.isFolderOpened = false;
}
}
model: folderContentModel model: folderContentModel
delegate: Item { delegate: Item {
width: folderGridView.cellWidth width: folderGridView.cellWidth
height: folderGridView.cellHeight height: folderGridView.cellHeight
MouseArea { MouseArea {
hoverEnabled: true hoverEnabled: true
enabled: mouseEnable enabled: mouseEnable
anchors.fill: parent
anchors.margins: labelMagrins
acceptedButtons: Qt.LeftButton | Qt.RightButton
UkuiItems.StyleBackground {
anchors.fill: parent anchors.fill: parent
anchors.margins: 2 useStyleTransparency: false
acceptedButtons: Qt.LeftButton | Qt.RightButton paletteRole: Platform.Theme.Text
radius: Platform.Theme.maxRadius
alpha: parent.containsPress ? 0.15 : parent.containsMouse ? 0.08 : 0.00
clip: false
UkuiItems.StyleBackground { ColumnLayout {
anchors.fill: parent anchors.fill: parent
useStyleTransparency: false anchors.margins: labelSpacing
paletteRole: isFullScreen ? Platform.Theme.Light : Platform.Theme.Text spacing: (parent.width > 40) ? 4 : 0
radius: Platform.Theme.maxRadius Image {
alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00 id: iconImage
clip: false source: icon
Layout.minimumHeight: 16
Layout.minimumWidth: 16
Layout.maximumWidth: 96
Layout.maximumHeight: 96
ColumnLayout { Layout.fillHeight: true
anchors.fill: parent Layout.preferredWidth: height
anchors.margins: labelMagrins Layout.alignment: Qt.AlignHCenter
spacing: (parent.width > 40) ? 4 : 0 }
Image {
id: iconImage
source: icon
Layout.minimumHeight: 16
Layout.minimumWidth: 16
Layout.fillHeight: true
Layout.preferredWidth: height
Layout.alignment: Qt.AlignHCenter
}
UkuiItems.StyleText { UkuiItems.StyleText {
text: name text: name
elide: Text.ElideRight elide: Text.ElideRight
paletteRole: isFullScreen ? Platform.Theme.HighlightedText : Platform.Theme.Text paletteRole: Platform.Theme.Text
Layout.preferredHeight: contentHeight Layout.preferredHeight: contentHeight
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
}
} }
} }
onClicked: { }
if (mouse.button === Qt.RightButton) { onClicked: {
menuManager.showMenu(id, MenuInfo.Folder); if (mouse.button === Qt.RightButton) {
return; menuManager.showMenu(id, MenuInfo.Folder);
} return;
if (mouse.button === Qt.LeftButton) { }
appManager.launchApp(id); if (mouse.button === Qt.LeftButton) {
return; appManager.launchApp(id);
} return;
} }
} }
} }
@ -190,4 +178,3 @@ Item {
} }
} }
} }

View File

@ -55,7 +55,7 @@ Loader {
Component { Component {
id: folderComponent id: folderComponent
Item { Item {
UkuiItems.StyleBackground { UkuiItems.StyleBackground {
id: folderIconBase id: folderIconBase
paletteRole: Platform.Theme.Text paletteRole: Platform.Theme.Text
useStyleTransparency: false useStyleTransparency: false
@ -72,7 +72,7 @@ Loader {
PropertyChanges { PropertyChanges {
target: folderIconBase target: folderIconBase
width: 348 width: 348
height: viewMaxRow * 100 height: viewMaxRow * 100 // itemHeight:96 + spacing:4
radius: Platform.Theme.maxRadius radius: Platform.Theme.maxRadius
x: (parent.width - width) / 2 x: (parent.width - width) / 2
y: 82 y: 82
@ -81,7 +81,8 @@ Loader {
PropertyChanges { PropertyChanges {
target: content target: content
contentMargins: 0 contentMargins: 0
labelMagrins: 8 labelSpacing: 8
labelMagrins: 2
} }
PropertyChanges { target: folderNameText; opacity: 1 } PropertyChanges { target: folderNameText; opacity: 1 }
}, },
@ -99,6 +100,7 @@ Loader {
PropertyChanges { PropertyChanges {
target: content target: content
contentMargins: 3 contentMargins: 3
labelSpacing: 0
labelMagrins: 0 labelMagrins: 0
} }
PropertyChanges { target: folderNameText; opacity: 0 } PropertyChanges { target: folderNameText; opacity: 0 }
@ -120,7 +122,7 @@ Loader {
} }
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.OutQuint duration: animationDuration; easing.type: Easing.OutQuint
properties: "contentMargins, labelMagrins" properties: "contentMargins, labelMagrins, labelSpacing"
} }
} }
ScriptAction { script: content.folderSwipeView.hideFolder() } ScriptAction { script: content.folderSwipeView.hideFolder() }
@ -140,7 +142,7 @@ Loader {
} }
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.OutQuint duration: animationDuration; easing.type: Easing.OutQuint
properties: "contentMargins, labelMagrins" properties: "contentMargins, labelMagrins, labelSpacing"
} }
} }
ScriptAction { ScriptAction {
@ -160,6 +162,23 @@ Loader {
} }
} }
PageIndicator {
id: pageIndicator
interactive: true
count: content.count
visible: count > 1
currentIndex: content.currentIndex
anchors.top: folderIconBase.bottom
anchors.horizontalCenter: folderIconBase.horizontalCenter
delegate: Rectangle {
color: "black"
width: 6; height: width;
radius: width / 2
opacity: (index === content.currentIndex )? 0.9 : 0.3
}
}
AppUI.EditText { AppUI.EditText {
id: folderNameText id: folderNameText
anchors.bottom: folderIconBase.top anchors.bottom: folderIconBase.top
@ -169,9 +188,7 @@ Loader {
height: 47; width: folderIconBase.width height: 47; width: folderIconBase.width
textEdited: folderName textEdited: folderName
textCenterIn: true textCenterIn: true
isFolder: true textSize: 16
isFullScreen: isFullScreen
textInputSize: 16
onTextEditingFinished: text=> { onTextEditingFinished: text=> {
folderModel.renameFolder(text); folderModel.renameFolder(text);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023, KylinSoft Co., Ltd. * Copyright (C) 2024, KylinSoft Co., Ltd.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@ import QtQuick.Controls 2.5
import org.ukui.menu.core 1.0 import org.ukui.menu.core 1.0
import org.ukui.quick.platform 1.0 as Platform import org.ukui.quick.platform 1.0 as Platform
import org.ukui.quick.items 1.0 as UkuiItems import org.ukui.quick.items 1.0 as UkuiItems
import AppUI 1.0 as AppUI
Loader { Loader {
id: root id: root
@ -34,13 +35,12 @@ Loader {
property int viewMaxRow: 0 property int viewMaxRow: 0
property bool isFolderOpened: false property bool isFolderOpened: false
property bool isFullScreen: true property int margins: 20
property int margins: isFullScreen? 20 : 0
property int animationDuration: 300 property int animationDuration: 300
signal turnPageFinished() signal turnPageFinished()
function initFolder(id, name, x, y) { function initFolder(id, name, x, y) {
extensionData.folderModel.setFolderId(id); FolderModel.setFolderId(id);
folderName = name; folderName = name;
folderX = x; folderX = x;
folderY = y; folderY = y;
@ -58,12 +58,13 @@ Loader {
id: folderIconBase id: folderIconBase
paletteRole: Platform.Theme.Text paletteRole: Platform.Theme.Text
useStyleTransparency: false useStyleTransparency: false
alpha: 0.1
property int folderIconSize: 0 property int folderIconSize: 0
property int iconSpacing: 0 property int iconSpacing: 0
property int imageX: 0 property int imageX: 0
property int imageY: 0 property int imageY: 0
property int gridViewMargin: 8 property int gridViewMargin: 8
alpha: 0.25
state: isFolderOpened ? "folderOpened" : "folderHidden" state: isFolderOpened ? "folderOpened" : "folderHidden"
states: [ states: [
@ -71,17 +72,17 @@ Loader {
name: "folderOpened" name: "folderOpened"
PropertyChanges { PropertyChanges {
target: folderIconBase target: folderIconBase
width: isFullScreen ? 720 : 348 width: 720 // margins: 16
height: isFullScreen ? (viewMaxRow * 170 + margins * 2) : (viewMaxRow * 85 + margins * 2) height: viewMaxRow*176 + content.contentMargins*2 // itemHeight: 160 + spacing: 16 + margins: 24
radius: Platform.Theme.maxRadius radius: Platform.Theme.maxRadius //? 32
gridViewMargin: margins x: (parent.width - width) / 2
x: isFullScreen ? (parent.width - width) / 2 : 56 y: (parent.height - height) / 2
y: isFullScreen ? (parent.height - height) / 2 : 104 }
// PropertyChanges {
folderIconSize:isFullScreen ? 96 : 48 target: content
iconSpacing: 8 contentMargins: 8
imageX: isFullScreen ? 37 : 13 labelSpacing: 8
imageY: isFullScreen ? 17 : 8 labelMagrins: 8
} }
PropertyChanges { target: folderNameText; opacity: 1 } PropertyChanges { target: folderNameText; opacity: 1 }
}, },
@ -89,17 +90,17 @@ Loader {
name: "folderHidden" name: "folderHidden"
PropertyChanges { PropertyChanges {
target: folderIconBase target: folderIconBase
width: 86 width: 84
height: 86 height: 84
radius: Platform.Theme.maxRadius radius: Platform.Theme.maxRadius
gridViewMargin: 8
x: root.mapFromGlobal(folderX, 0).x x: root.mapFromGlobal(folderX, 0).x
y: root.mapFromGlobal(0, folderY).y y: root.mapFromGlobal(0, folderY).y
// }
folderIconSize: 16 PropertyChanges {
iconSpacing: 0 target: content
imageX: 0 contentMargins: 0
imageY: 0 labelSpacing: 0
labelMagrins: 0
} }
PropertyChanges { target: folderNameText; opacity: 0 } PropertyChanges { target: folderNameText; opacity: 0 }
} }
@ -112,12 +113,16 @@ Loader {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.InOutCubic duration: animationDuration; easing.type: Easing.InOutCubic
properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, gridViewMargin" properties: "x, y, width, height, radius, alpha"
} }
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.OutQuint duration: animationDuration; easing.type: Easing.OutQuint
properties: "opacity" properties: "opacity"
} }
PropertyAnimation {
duration: animationDuration; easing.type: Easing.OutQuint
properties: "contentMargins, labelMagrins, labelSpacing"
}
} }
ScriptAction { script: content.folderSwipeView.hideFolder() } ScriptAction { script: content.folderSwipeView.hideFolder() }
} }
@ -128,12 +133,16 @@ Loader {
ParallelAnimation { ParallelAnimation {
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.InOutCubic duration: animationDuration; easing.type: Easing.InOutCubic
properties: "x, y, width, height, folderIconSize, iconSpacing, radius, imageX, imageY, gridViewMargin" properties: "x, y, width, height, radius, alpha"
} }
PropertyAnimation { PropertyAnimation {
duration: animationDuration; easing.type: Easing.InQuint duration: animationDuration; easing.type: Easing.InQuint
properties: "opacity" properties: "opacity"
} }
PropertyAnimation {
duration: animationDuration; easing.type: Easing.OutQuint
properties: "contentMargins, labelMagrins, labelSpacing"
}
} }
ScriptAction { ScriptAction {
script: { script: {
@ -148,23 +157,42 @@ Loader {
id: content id: content
anchors.fill: parent anchors.fill: parent
folderContentModel: folderModel folderContentModel: folderModel
contentMargins: folderIconBase.gridViewMargin isFullScreen: true
labelMagrins: isFullScreen ? 16 : 8
} }
} }
EditText { PageIndicator {
id: pageIndicator
interactive: true
count: content.count
visible: count > 1
currentIndex: content.currentIndex
anchors.bottom: folderIconBase.bottom
anchors.horizontalCenter: folderIconBase.horizontalCenter
delegate: Rectangle {
color: "black"
width: 6; height: width;
radius: width / 2
opacity: (index === content.currentIndex )? 0.9 : 0.3
}
}
AppUI.EditText {
id: folderNameText id: folderNameText
anchors.bottom: folderIconBase.top anchors.bottom: folderIconBase.top
anchors.bottomMargin: 30 anchors.bottomMargin: 30
anchors.horizontalCenter: folderIconBase.horizontalCenter anchors.horizontalCenter: folderIconBase.horizontalCenter
height: 47; width: folderIconBase.width height: 47; width: folderIconBase.width
textEdited: folderName textEdited: folderName
textCenterIn: true textCenterIn: true
isFolder: true textSize: 32
isFullScreen: isFullScreen
onTextEditingFinished: text=> {
folderModel.renameFolder(text);
}
} }
} }
} }
} }

View File

@ -36,9 +36,8 @@ FavoriteWidget::FavoriteWidget(QObject *parent) : WidgetExtension(parent)
FavoritesModel::instance().setSourceModel(&AppFavoritesModel::instance()); FavoritesModel::instance().setSourceModel(&AppFavoritesModel::instance());
FavoritesModel::instance().sort(0); FavoritesModel::instance().sort(0);
m_folderModel = new FolderModel;
m_data.insert("favoriteAppsModel", QVariant::fromValue(&FavoritesModel::instance())); m_data.insert("favoriteAppsModel", QVariant::fromValue(&FavoritesModel::instance()));
m_data.insert("folderModel", QVariant::fromValue(m_folderModel)); m_data.insert("folderModel", QVariant::fromValue(&FolderModel::instance()));
} }
int FavoriteWidget::index() const int FavoriteWidget::index() const

View File

@ -38,7 +38,6 @@ public:
private: private:
MetadataMap m_metadata; MetadataMap m_metadata;
QVariantMap m_data; QVariantMap m_data;
FolderModel *m_folderModel;
}; };
} // UkuiMenu } // UkuiMenu

View File

@ -117,4 +117,10 @@ int FolderModel::count()
return m_apps.count(); return m_apps.count();
} }
FolderModel &FolderModel::instance()
{
static FolderModel folderModel;
return folderModel;
}
} // UkuiMenu } // UkuiMenu

View File

@ -29,7 +29,8 @@ class FolderModel : public QAbstractListModel
Q_OBJECT Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(int count READ count NOTIFY countChanged)
public: public:
explicit FolderModel(QObject *parent = nullptr); static FolderModel &instance();
Q_INVOKABLE void setFolderId(const QString &folderId); Q_INVOKABLE void setFolderId(const QString &folderId);
Q_INVOKABLE void renameFolder(const QString &folderName); Q_INVOKABLE void renameFolder(const QString &folderName);
@ -45,6 +46,8 @@ private Q_SLOTS:
void loadFolderData(int id); void loadFolderData(int id);
private: private:
explicit FolderModel(QObject *parent = nullptr);
int m_folderId; int m_folderId;
QStringList m_apps; QStringList m_apps;
}; };

View File

@ -29,6 +29,8 @@
#include "widget-model.h" #include "widget-model.h"
#include "app-page-backend.h" #include "app-page-backend.h"
#include "app-group-model.h" #include "app-group-model.h"
#include "favorite/favorites-model.h"
#include "favorite/folder-model.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
@ -91,6 +93,8 @@ void UkuiMenuApplication::initQmlEngine()
context->setContextProperty("menuManager", ContextMenuManager::instance()); context->setContextProperty("menuManager", ContextMenuManager::instance());
context->setContextProperty("appManager", AppManager::instance()); context->setContextProperty("appManager", AppManager::instance());
context->setContextProperty("favoriteModel", &FavoritesModel::instance());
context->setContextProperty("FolderModel", &FolderModel::instance());
// MenuMainWindow // MenuMainWindow
// const QUrl url(QStringLiteral("qrc:/qml/MenuMainWindow.qml")); // const QUrl url(QStringLiteral("qrc:/qml/MenuMainWindow.qml"));
// QQmlApplicationEngine *m_applicationEngine{nullptr}; // QQmlApplicationEngine *m_applicationEngine{nullptr};