diff --git a/qml/extensions/FavoriteDelegate.qml b/qml/extensions/FavoriteDelegate.qml
new file mode 100644
index 0000000..120c2b0
--- /dev/null
+++ b/qml/extensions/FavoriteDelegate.qml
@@ -0,0 +1,234 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.5
+import QtQuick.Layouts 1.15
+import org.ukui.menu.core 1.0
+import org.ukui.menu.extension 1.0
+import org.ukui.quick.platform 1.0 as Platform
+import org.ukui.quick.items 1.0 as UkuiItems
+import AppControls2 1.0 as AppControls2
+
+UkuiItems.StyleBackground {
+ id: iconItem
+ property bool hold: false
+ property alias draggedIcon: itemLoader
+ radius: 8
+ useStyleTransparency: false
+ paletteRole: Platform.Theme.Text
+ alpha: hold ? 0 : control.containsPress ? 0.15 : control.containsMouse ? 0.08 : 0
+
+ // 合并提升框 52*52
+ UkuiItems.StyleBackground {
+ width: 52
+ height: width
+ radius: 14
+ anchors.top: parent.top
+ anchors.margins: 6
+ anchors.horizontalCenter: parent.horizontalCenter
+ paletteRole: Platform.Theme.Text
+ useStyleTransparency: false
+ alpha: (delegateDropArea.enterSourceId !== model.id)
+ && delegateDropArea.containsDrag && dragTypeIsMerge ? 0.15 : 0
+ z: -1
+ }
+
+ ColumnLayout {
+ id: itemLayout
+ width: parent.width
+ anchors.top: parent.top
+ anchors.topMargin: 8
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 6
+
+ ToolTip.visible: iconText.truncated && control.containsMouse
+ ToolTip.text: model.name
+ ToolTip.delay: 500
+
+ Item {
+ id: loaderBase
+ Layout.preferredHeight: 48
+ Layout.preferredWidth: 48
+ Layout.alignment: Qt.AlignHCenter
+
+ Loader {
+ id: itemLoader
+ width: loaderBase.width
+ height: loaderBase.height
+ x: 0; y: 0
+ Drag.active: control.drag.active
+ Drag.source: itemLoader
+ Drag.hotSpot.x: width / 2
+ Drag.hotSpot.y: height / 2
+
+ Drag.onActiveChanged: {
+ if (Drag.active) {
+ itemLoader.parent = favoriteView;
+ } else {
+ if (dragTypeIsMerge && (model.id !== mergeToAppId) && (model.type === DataType.Normal)) {
+ iconItem.hold = false;
+
+ } else {
+ iconResetAnimation.start();
+ }
+ }
+ }
+
+ ParallelAnimation {
+ id: iconResetAnimation
+ NumberAnimation {
+ target: itemLoader
+ property: "x"
+ to: container.x + loaderBase.x
+ easing.type: Easing.OutQuad
+ duration: 300
+ }
+ NumberAnimation {
+ target: itemLoader
+ property: "y"
+ to: (container.y + 8) - favoriteView.contentY
+ easing.type: Easing.OutQuad
+ duration: 300
+ }
+
+ onFinished: {
+ iconItem.hold = false;
+ itemLoader.parent = loaderBase;
+ itemLoader.x = 0; itemLoader.y = 0;
+ }
+ }
+
+ property int visualIndex: 0
+ property string sourceId: ""
+ property bool isFolder: model.type === DataType.Folder
+ property string icon: model.icon
+ property bool isFavorite: true
+ sourceComponent: {
+ if (type === DataType.Normal) {
+ return appIconComponent;
+ }
+ if (type === DataType.Folder) {
+ return folderIconComponent;
+ }
+ }
+ }
+ }
+
+
+ UkuiItems.StyleText {
+ id: iconText
+ Layout.fillWidth: true
+
+ text: name
+ elide: Text.ElideRight
+ paletteRole: Platform.Theme.Text
+ horizontalAlignment: Text.AlignHCenter
+ opacity: !itemLoader.Drag.active
+
+ Behavior on opacity {
+ NumberAnimation { duration: 150}
+ }
+ }
+ }
+
+ Component {
+ id: appIconComponent
+ Image {
+ id: iconImage
+ sourceSize.height: height
+ sourceSize.width: width
+ source: icon
+ cache: false
+
+ function itemClicked(mouseButton) {
+ if (mouseButton === Qt.RightButton) {
+ visualModel.model.openMenu(index)
+ } else {
+ var data = {"id": model.id};
+ send(data);
+ }
+ }
+ }
+ }
+
+ Component {
+ id: folderIconComponent
+ Item {
+ AppControls2.FolderIcon {
+ id: folderIcon
+ width: 40
+ height: 40
+ anchors.centerIn: parent
+
+ rows: 2; columns: 2
+ spacing: 2; padding: 2
+ icons: icon
+ radius: 4; alpha: 0.25
+ }
+
+ function itemClicked(mouseButton) {
+ if (mouseButton === Qt.RightButton) {
+ visualModel.model.openMenu(index);
+ } else {
+ var x = mapToGlobal(0,0).x;
+ var y = mapToGlobal(0,0).y
+ openFolderSignal(id, name, x, y);
+ // 执行隐藏动画,并且当前图标消失且鼠标区域不可用
+ favoriteView.isContentShow = false;
+ opacity = 0;
+ control.enabled = false;
+ control.hoverEnabled = false;
+ }
+ }
+ }
+ }
+
+ 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
+ function resetOpacity() {
+ itemLoader.item.opacity = 1;
+ control.enabled = true;
+ control.hoverEnabled = true;
+ }
+ Component.onCompleted: favoriteView.contentShowFinished.connect(resetOpacity)
+ Component.onDestruction: favoriteView.contentShowFinished.disconnect(resetOpacity)
+
+ onHoldChanged: {
+ if (hold) {
+ favoriteView.interactive = false;
+ } else {
+ favoriteView.interactive = contentHeight > favoriteView.parent.height;
+ if (dragTypeIsMerge && (model.id !== mergeToAppId) && (model.type === DataType.Normal)) {
+ if (isMergeToFolder) {
+ visualModel.model.addAppToFolder(model.id, mergeToAppId);
+ } else {
+ visualModel.model.addAppsToNewFolder(model.id, mergeToAppId);
+ }
+
+ } else if (exchangedStartIndex !== itemLoader.visualIndex) {
+ visualModel.model.exchangedAppsOrder(exchangedStartIndex, itemLoader.visualIndex);
+ }
+ }
+ }
+}
+
diff --git a/qml/extensions/FavoriteExtension.qml b/qml/extensions/FavoriteExtension.qml
index c0acd96..fc6937a 100644
--- a/qml/extensions/FavoriteExtension.qml
+++ b/qml/extensions/FavoriteExtension.qml
@@ -31,13 +31,35 @@ UkuiMenuExtension {
id: viewMouseArea
anchors.fill: parent
hoverEnabled: true
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
- folderLoader.isFolderOpened = false;
- favoriteView.visible = true;
- favoriteView.isContentShow = true;
- }
+ if (mouse.button === Qt.RightButton) {
+ menu.open();
+ } else {
+ if (mainWindow.editMode) {
+ mainWindow.editMode = false;
+ }
+ folderLoader.isFolderOpened = false;
+ favoriteView.visible = true;
+ favoriteView.isContentShow = true;
+ }
+
+ }
+ UkuiItems.Menu {
+ id: menu
+ content: [
+ UkuiItems.MenuItem {
+ text: qsTr("Enable editing mode")
+ onClicked: mainWindow.editMode = true;
+ },
+ UkuiItems.MenuItem {
+ text: qsTr("Remove all favorite apps")
+ onClicked: extensionData.favoriteAppsModel.clearFavorites();
+ }
+ ]
+ }
UkuiItems.StyleBackground {
anchors.top: parent.top
width: parent.width; height: 1
@@ -58,17 +80,38 @@ UkuiMenuExtension {
Component.onDestruction: favoriteView.openFolderSignal.disconnect(initFolder)
}
- FavoriteGridView {
- id: favoriteView
+ Item {
anchors.fill: parent
+ anchors.bottomMargin: 8
anchors.leftMargin: 16
- anchors.topMargin: 12
- anchors.bottomMargin: 6
- Component.onCompleted: {
- favoriteView.viewModel.model = extensionData.favoriteAppsModel
- folderLoader.turnPageFinished.connect(contentShowFinished)
+ anchors.rightMargin: 16
+ anchors.topMargin: 8
+
+ // 拖动到文件到空白区域 添加到收藏
+ DropArea {
+ anchors.fill: parent
+ onEntered: {
+ if (drag.source.isFavorite) {
+ favoriteView.dragTypeIsMerge = false;
+ } else {
+ var id = drag.source.id;
+ extensionData.favoriteAppsModel.addAppToFavorites(id);
+ }
+ }
}
- Component.onDestruction: folderLoader.turnPageFinished.disconnect(contentShowFinished)
- }
+
+ FavoriteGridView {
+ id: favoriteView
+ width: parent.width
+ height: (contentHeight > parent.height) ? parent.height : contentHeight
+ interactive: contentHeight > parent.height
+
+ Component.onCompleted: {
+ favoriteView.viewModel.model = extensionData.favoriteAppsModel
+ folderLoader.turnPageFinished.connect(contentShowFinished)
+ }
+ Component.onDestruction: folderLoader.turnPageFinished.disconnect(contentShowFinished)
+ }
+ }
}
}
diff --git a/qml/extensions/FavoriteGridView.qml b/qml/extensions/FavoriteGridView.qml
index 3bb85f6..c73cf11 100644
--- a/qml/extensions/FavoriteGridView.qml
+++ b/qml/extensions/FavoriteGridView.qml
@@ -28,19 +28,21 @@ import AppControls2 1.0 as AppControls2
GridView {
id: favoriteView
- cellWidth: itemHeight + spacing; cellHeight: cellWidth
+ cellWidth: width / column
+ cellHeight: cellWidth + 8
signal openFolderSignal(string folderId, string folderName, int x, int y)
signal contentShowFinished()
property bool isContentShow: true
- property int exchangedStartIndex: 0
property int spacing: 4
property int itemHeight: 84
- property int column: Math.floor(width / cellWidth)
+ property int column: 5
property alias viewModel: visualModel
+
property string mergeToAppId: ""
property bool isMergeToFolder: false
property bool dragTypeIsMerge: false
+ property int exchangedStartIndex: 0
state: isContentShow ? "contentShow" : "contentHidden"
states: [
@@ -116,7 +118,7 @@ GridView {
width: favoriteView.cellWidth
height: favoriteView.cellHeight
property int visualIndex: DelegateModel.itemsIndex
- Binding { target: iconItem; property: "visualIndex"; value: visualIndex }
+ Binding { target: iconItem.draggedIcon; property: "visualIndex"; value: visualIndex }
states: State {
when: activeFocus
PropertyChanges {
@@ -129,31 +131,13 @@ GridView {
send(data);
}
- Timer {
- id: delegateDropTimer
- property int timeOutCount: 0
- interval: 300
- repeat: true
-
- onTriggered: {
- ++timeOutCount;
- if (timeOutCount == 1) {
- mergeToAppId = model.id;
- isMergeToFolder = (model.type === DataType.Folder);
- dragTypeIsMerge = true;
- }
- }
- onRunningChanged:timeOutCount = 0
- }
-
DropArea {
id: delegateDropArea
- width: 48; height: 48
- anchors.top: parent.top
- anchors.topMargin: 8
- anchors.horizontalCenter: parent.horizontalCenter
+ anchors.fill: parent
+ anchors.margins: 14
property string enterSourceId: ""
+ // drag.source [iconItem.draggedIcon]
onEntered: {
if (drag.source.isFolder) {
return;
@@ -173,277 +157,60 @@ GridView {
}
}
- UkuiItems.StyleBackground {
- id: iconItem
- height: favoriteView.itemHeight; width: height
- property bool hold: false
- property int visualIndex: 0
- property string sourceId: ""
- property bool isFolder: model.type === DataType.Folder
- x: 0; y: 0
- radius: 8
- useStyleTransparency: false
- paletteRole: Platform.Theme.Text
- alpha: hold ? 0 : control.containsPress ? 0.15 : control.containsMouse ? 0.08 : 0
+ Item {
+ anchors.fill: parent
+ anchors.margins: 2
- Behavior on scale {
- NumberAnimation { duration: 300; easing.type: Easing.InOutCubic }
- }
+ Timer {
+ id: delegateDropTimer
+ property int timeOutCount: 0
+ interval: 300
+ repeat: true
- UkuiItems.StyleBackground {
- width: 52
- height: width
- radius: 14
- anchors.top: parent.top
- anchors.margins: 6
- anchors.horizontalCenter: parent.horizontalCenter
- paletteRole: Platform.Theme.Text
- useStyleTransparency: false
- alpha: (delegateDropArea.enterSourceId !== model.id)
- && delegateDropArea.containsDrag && dragTypeIsMerge ? 0.15 : 0
- z: -1
- }
-
- Loader {
- id: itemLoader
- anchors.centerIn: parent
- property int index: model.index
- property int type: model.type
- property string id: model.id
- property string name: model.name
- property string icon: model.icon
- sourceComponent: {
- if (type === DataType.Normal) {
- return appItemComponent;
- }
- if (type === DataType.Folder) {
- return folderItemComponent;
- }
- }
- }
- Component {
- id: appItemComponent
- Item {
- height: iconItem.height
- width: iconItem.width
- ToolTip.visible: iconText.truncated && control.containsMouse
- ToolTip.text: model.name
- ToolTip.delay: 500
-
- function itemClicked(mouseButton) {
- if (mouseButton === Qt.RightButton) {
- visualModel.model.openMenu(index)
- } else {
- var data = {"id": model.id};
- send(data);
- }
- }
- ColumnLayout {
- width: parent.width
- anchors.top: parent.top
- anchors.topMargin: 8
- anchors.horizontalCenter: parent.horizontalCenter
- spacing: 6
- Image {
- id: iconImage
- Layout.preferredHeight: 48
- Layout.preferredWidth: 48
- sourceSize.height: height
- sourceSize.width: width
- source: icon
- cache: false
- Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
- }
-
- UkuiItems.StyleText {
- id: iconText
- Layout.fillWidth: true
- text: name
- elide: Text.ElideRight
- paletteRole: Platform.Theme.Text
- horizontalAlignment: Text.AlignHCenter
- }
-
- }
- Loader {
- id: tag
- visible: mainWindow.editMode
- 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 ? editImage : null
- }
- }
- }
- Component {
- id: folderItemComponent
- UkuiItems.StyleBackground {
- height: iconItem.height
- width: iconItem.width - 14
- useStyleTransparency: false
- paletteRole: Platform.Theme.Light
- radius: 6
- alpha: parent.containsPress ? 0.25 : parent.containsMouse ? 0.15 : 0.00
-
- function itemClicked(mouseButton) {
- if (mouseButton === Qt.RightButton) {
- visualModel.model.openMenu(index);
- } else {
- var x = mapToGlobal(0,0).x;
- var y = mapToGlobal(0,0).y
- openFolderSignal(id, name, x, y);
- // 执行隐藏动画,并且当前图标消失且鼠标区域不可用
- favoriteView.isContentShow = false;
- opacity = 0;
- control.enabled = false;
- control.hoverEnabled = false;
- }
- }
-
- Item {
- id: folderItem
- property bool isSelect: false
- anchors.horizontalCenter: parent.horizontalCenter
- height: 40; width: 40
- anchors.top: parent.top
- anchors.topMargin: 12
-
- UkuiItems.StyleBackground {
- anchors.fill: parent
- paletteRole: Palette.Text
- useStyleTransparency: false
- alpha: 0.25
- radius: 24
- visible: folderItem.isSelect
- }
-
- AppControls2.FolderIcon {
- id: folderIcon
- anchors.fill: parent
- rows: 2; columns: 2
- spacing: 2; padding: 2
- icons: icon
- radius: 4; alpha: folderItem.isSelect ? 0 : 0.25
- anchors.centerIn: parent
- }
- }
-
- UkuiItems.StyleText {
- id: folderText
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 14
- width: parent.width
- horizontalAlignment: Text.AlignHCenter
- anchors.horizontalCenter: parent.horizontalCenter
- elide: Text.ElideRight
- text: name
+ onTriggered: {
+ ++timeOutCount;
+ if (timeOutCount == 1) {
+ mergeToAppId = model.id;
+ isMergeToFolder = (model.type === DataType.Folder);
+ dragTypeIsMerge = true;
}
}
+ onRunningChanged: timeOutCount = 0
}
- MouseArea {
- id: control
+ FavoriteDelegate {
+ id: iconItem
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 = iconItem;
- iconItem.hold = true;
- exchangedStartIndex = iconItem.visualIndex;
- iconItem.sourceId = model.id;
- }
- }
- onReleased: {
- iconItem.hold = false;
- drag.target = null;
- }
-
+ property int visualIndex: container.DelegateModel.itemsIndex
}
- // folderFunction
- function resetOpacity() {
- itemLoader.item.opacity = 1;
- control.enabled = true;
- control.hoverEnabled = true;
- }
- Component.onCompleted: favoriteView.contentShowFinished.connect(resetOpacity)
- Component.onDestruction: favoriteView.contentShowFinished.disconnect(resetOpacity)
- onHoldChanged: {
- if (hold) {
- favoriteView.interactive = false;
- } else {
- favoriteView.interactive = true;
- if (dragTypeIsMerge && (model.id !== mergeToAppId) && (model.type === DataType.Normal)) {
- if (isMergeToFolder) {
- visualModel.model.addAppToFolder(model.id, mergeToAppId);
- } else {
- visualModel.model.addAppsToNewFolder(model.id, mergeToAppId);
+ //编辑模式标志
+ 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);
}
- } else if (exchangedStartIndex != iconItem.visualIndex) {
- visualModel.model.exchangedAppsOrder(exchangedStartIndex, iconItem.visualIndex);
+ background.radius: width / 2
+ icon.source: "ukui-cancel-star-symbolic"
}
}
- }
- Drag.active: control.drag.active
- Drag.source: iconItem
- Drag.hotSpot.x: iconItem.width / 2
- Drag.hotSpot.y: iconItem.height / 2
-
- Drag.onActiveChanged: {
- if (Drag.active) {
- iconItem.parent = favoriteView;
- } else {
- iconResetAnimation.start();
- }
- }
- ParallelAnimation {
- id: iconResetAnimation
- NumberAnimation {
- target: iconItem
- property: "x"
- to: container.x
- easing.type: Easing.OutQuad
- duration: 300
- }
- NumberAnimation {
- target: iconItem
- property: "y"
- to: container.y - favoriteView.contentY
- easing.type: Easing.OutQuad
- duration: 300
- }
-
- onFinished: {
- iconItem.parent = container;
- iconItem.x = 0; iconItem.y = 0;
- }
+ sourceComponent: mainWindow.editMode && (type === DataType.Normal) ? editImage : null
}
}
}
diff --git a/qml/qml.qrc b/qml/qml.qrc
index 89e7a32..0d8ce87 100644
--- a/qml/qml.qrc
+++ b/qml/qml.qrc
@@ -24,6 +24,7 @@
AppControls2/LabelItem.qml
AppControls2/FolderItem.qml
extensions/FavoriteExtension.qml
+ extensions/FavoriteDelegate.qml
extensions/FavoriteGridView.qml
extensions/FolderGridView.qml
AppControls2/RoundButton.qml
diff --git a/src/extension/favorite/app-favorite-model.cpp b/src/extension/favorite/app-favorite-model.cpp
index 02437fd..132f509 100644
--- a/src/extension/favorite/app-favorite-model.cpp
+++ b/src/extension/favorite/app-favorite-model.cpp
@@ -103,6 +103,7 @@ void AppFavoritesModel::getFoldersId()
QVector foldersId;
for (const auto &folder : FavoriteFolderHelper::instance()->folderData()) {
foldersId.append(folder.getId());
+ FavoritesConfig::instance().insertValue(FOLDER_ID_SCHEME + QString::number(folder.getId()));
}
m_folders.swap(foldersId);
}
diff --git a/src/extension/favorite/favorite-folder-helper.cpp b/src/extension/favorite/favorite-folder-helper.cpp
index 4feff87..df09d4f 100644
--- a/src/extension/favorite/favorite-folder-helper.cpp
+++ b/src/extension/favorite/favorite-folder-helper.cpp
@@ -148,7 +148,17 @@ void FavoriteFolderHelper::addAppsToNewFolder(const QString &idFrom, const QStri
folder.apps.append(idTo);
insertFolder(folder);
- Q_EMIT folderAdded(folder.id, FavoritesConfig::instance().getOrderById(APP_ID_SCHEME + idTo));
+ // 确定folder位置
+ int orderTo = FavoritesConfig::instance().getOrderById(APP_ID_SCHEME + idTo);
+ int orderFrom = FavoritesConfig::instance().getOrderById(APP_ID_SCHEME + idFrom);
+ int folderOrder;
+ if (orderFrom > orderTo) {
+ folderOrder = orderTo;
+ } else {
+ folderOrder = orderTo - 1;
+ }
+
+ Q_EMIT folderAdded(folder.id, folderOrder);
forceSync();
}
diff --git a/src/extension/favorite/favorites-config.cpp b/src/extension/favorite/favorites-config.cpp
index efcb5d0..0403a94 100644
--- a/src/extension/favorite/favorites-config.cpp
+++ b/src/extension/favorite/favorites-config.cpp
@@ -138,11 +138,19 @@ void FavoritesConfig::initConfig()
m_favoritesList.clear();
QJsonArray array = jsonDocument.array();
+ QJsonArray newArray;
for (int i = 0; i < array.size(); i++) {
- if (array.at(i).toObject().contains("id")) {
+ if (array.at(i).isString()) {
m_favoritesList.append(array.at(i).toString());
+ newArray.append(array.at(i));
}
}
+
+ file.open(QFile::WriteOnly);
+ jsonDocument.setArray(newArray);
+ file.write(jsonDocument.toJson());
+ file.flush();
+ file.close();
}
} // UkuiMenu