diff --git a/CMakeLists.txt b/CMakeLists.txt index 023a3a4..d0a6fe4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ set(SOURCE_FILES src/utils/app-page-header-utils.cpp src/utils/app-page-header-utils.h src/utils/power-button.cpp src/utils/power-button.h src/utils/app-manager.cpp src/utils/app-manager.h + src/model/label-model.cpp src/model/label-model.h ) # qrc文件 diff --git a/qml/AppControls2/AppItem.qml b/qml/AppControls2/AppItem.qml index cc399e9..c2b3523 100644 --- a/qml/AppControls2/AppItem.qml +++ b/qml/AppControls2/AppItem.qml @@ -4,7 +4,6 @@ import QtQuick.Controls 2.5 import org.ukui.menu.core 1.0 StyleBackground { - anchors.fill: parent radius: 4 useStyleTransparent: false alpha: control.containsPress ? 0.82 : control.containsMouse ? 0.55 : 0.00 diff --git a/qml/AppControls2/LabelItem.qml b/qml/AppControls2/LabelItem.qml index 273c04b..ec7d9cb 100644 --- a/qml/AppControls2/LabelItem.qml +++ b/qml/AppControls2/LabelItem.qml @@ -1,24 +1,43 @@ import QtQuick 2.0 import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.5 + +StyleBackground { + radius: 4 + useStyleTransparent: false + alpha: control.containsPress ? 0.82 : control.containsMouse ? 0.55 : 0.00 + ToolTip.text: qsTr("Open the label selection interface") + ToolTip.visible: control.containsMouse -Item { RowLayout { anchors.fill: parent - Text { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.leftMargin: 5 + StyleText { + Layout.preferredHeight: parent.height + Layout.preferredWidth: contentWidth + Layout.leftMargin: 12 horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter + font.pixelSize: 14 + font.bold: true text: name } Image { - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - Layout.preferredWidth: 32 - Layout.preferredHeight: 32 - source: icon + visible: control.containsMouse + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.preferredWidth: 24 + Layout.preferredHeight: 24 + Layout.rightMargin: 16 + source: "image://appicon/open-menu-symbolic" + } + } + MouseArea { + id: control + hoverEnabled: true + anchors.fill: parent + onClicked: { + appList.labelItemClicked(); } } } diff --git a/qml/AppControls2/StyleText.qml b/qml/AppControls2/StyleText.qml index 89422c2..8f23661 100644 --- a/qml/AppControls2/StyleText.qml +++ b/qml/AppControls2/StyleText.qml @@ -3,9 +3,10 @@ import org.ukui.menu.core 1.0 Text { property int paletteRole: Palette.Text + property real alpha: 1.0 function updateColor() { - color = themePalette.paletteColor(paletteRole) + color = themePalette.paletteColorWithCustomTransparency(paletteRole, Palette.Active, alpha) } Component.onCompleted: { @@ -19,4 +20,7 @@ Text { onPaletteRoleChanged: { updateColor() } + onAlphaChanged: { + updateColor() + } } diff --git a/qml/AppUI/AppList.qml b/qml/AppUI/AppList.qml index bae67b8..42ffdff 100644 --- a/qml/AppUI/AppList.qml +++ b/qml/AppUI/AppList.qml @@ -26,6 +26,10 @@ import org.ukui.menu.core 1.0 Item { property string title: "" + function labelSelection(labelId) { + appListView.positionViewAtIndex(appListView.model.currentAppIndex(labelId), ListView.Beginning) + } + MouseArea { id: appListArea hoverEnabled: true @@ -51,8 +55,11 @@ Item { Layout.fillHeight: true Layout.fillWidth: true ScrollBar.vertical: appListScrollBar - model: modelManager.getAppModel() + highlightMoveDuration: 0 + boundsBehavior: Flickable.StopAtBounds + + model: modelManager.getAppModel() delegate: Component { Loader { width: ListView.view ? ListView.view.width : 0 @@ -80,7 +87,7 @@ Item { id: appListScrollBar Layout.fillHeight: true Layout.preferredWidth: 14 - visible: appListArea.containsMouse + visual: appListArea.containsMouse } } } diff --git a/qml/AppUI/AppPage.qml b/qml/AppUI/AppPage.qml index d43a934..21063db 100644 --- a/qml/AppUI/AppPage.qml +++ b/qml/AppUI/AppPage.qml @@ -36,8 +36,7 @@ AppControls2.StyleBackground { Layout.preferredHeight: 40 } - AppList { - clip: true + AppPageContent { Layout.fillWidth: true Layout.fillHeight: true } diff --git a/qml/AppUI/AppPageContent.qml b/qml/AppUI/AppPageContent.qml new file mode 100644 index 0000000..d0e3574 --- /dev/null +++ b/qml/AppUI/AppPageContent.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.5 +import AppControls2 1.0 as AppControls2 +import org.ukui.menu.core 1.0 + +Item { + AppList { + id: appList + clip: true + anchors.fill: parent + anchors.leftMargin: 4 + function labelItemClicked() { + appList.visible = false; + selectionPage.viewShowStart(); + } + } + + SelectionPage { + id: selectionPage + anchors.fill: parent + anchors.bottomMargin: 54 + visible: !appList.visible + onViewHideFinished: appList.visible = true + onLabelSelected: appList.labelSelection(labelId) + } +} diff --git a/qml/AppUI/AppPageHeader.qml b/qml/AppUI/AppPageHeader.qml index e69b3c2..b2c3ef1 100644 --- a/qml/AppUI/AppPageHeader.qml +++ b/qml/AppUI/AppPageHeader.qml @@ -78,8 +78,7 @@ Item { Layout.fillHeight: true radius: 16 useStyleTransparent: false - onTextChanged: - { + onTextChanged: { if (text === "") { sortMenu.sortMenuModel.reactivateProvider(); } else { @@ -87,7 +86,6 @@ Item { appPageHeaderUtils.startSearch(text); } } - } AppControls2.RoundButton { @@ -109,6 +107,7 @@ Item { RowLayout { anchors.fill: parent anchors.leftMargin: 16 + spacing: 12 Text { Layout.fillWidth: true Layout.fillHeight: true diff --git a/qml/AppUI/SelectionPage.qml b/qml/AppUI/SelectionPage.qml new file mode 100644 index 0000000..1b28a37 --- /dev/null +++ b/qml/AppUI/SelectionPage.qml @@ -0,0 +1,85 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.2 +import org.ukui.menu.core 1.0 +import AppControls2 1.0 as AppControls2 + +Item { + id: root + signal viewHideFinished() + signal labelSelected(string labelId) + + function viewShowStart() { + viewShow.start(); + } + + ParallelAnimation { + id: viewShow + NumberAnimation { target: selectionArea; property: "scale"; easing.type: Easing.InOutCubic; from: 1.5; to: 1.0; duration: 300} + NumberAnimation { target: selectionArea; property: "opacity"; easing.type: Easing.InOutCubic; from: 0; to: 1.0; duration: 300} + } + + ParallelAnimation { + id: viewHide + NumberAnimation { target: selectionArea; property: "scale"; easing.type: Easing.InOutCubic; from: 1.0; to: 1.5 ;duration: 300} + NumberAnimation { target: selectionArea; property: "opacity"; easing.type: Easing.InOutCubic; from: 1.0; to: 0 ;duration: 300} + onFinished: { + viewHideFinished(); + } + } + + GridView { + id: selectionArea + anchors.centerIn: parent + interactive: false + property int itemWidth: 0 + property int itemHeight: 40 + cellWidth: itemWidth; cellHeight: itemHeight + + state: count < 20 ? "functionArea" : "AlphabetArea" + states: [ + State { + name: "functionArea" + PropertyChanges { target: selectionArea; itemWidth: 80; width: itemWidth * 2; height: itemHeight * 7 } + }, + State { + name: "AlphabetArea" + PropertyChanges { target: selectionArea; itemWidth: 40; width: itemWidth * 5; height: itemHeight * 6 } + } + ] + + model: modelManager.getLabelModel() + onCountChanged: { + if (count === 0) { + viewHide.start(); + } + } + + delegate: AppControls2.StyleBackground { + height: selectionArea.itemHeight; width: selectionArea.itemWidth + alpha: itemMouseArea.containsPress ? 0.82 : itemMouseArea.containsMouse ? 0.55 : 0.00 + useStyleTransparent: false + radius: 8 + + AppControls2.StyleText { + anchors.fill: parent + text: model.displayName + alpha: model.isDisable ? 0.2 : 0.9 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + MouseArea { + id: itemMouseArea + anchors.fill: parent + hoverEnabled: true + visible: !model.isDisable + onClicked: { + viewHide.start(); + root.labelSelected(model.id); + } + } + } + } +} + diff --git a/qml/qml.qrc b/qml/qml.qrc index f51be11..3e3d069 100644 --- a/qml/qml.qrc +++ b/qml/qml.qrc @@ -25,5 +25,7 @@ extensions/RecentFileExtension.qml extensions/FavoriteExtension.qml AppControls2/RoundButton.qml + AppUI/SelectionPage.qml + AppUI/AppPageContent.qml diff --git a/src/appdata/data-provider-manager.cpp b/src/appdata/data-provider-manager.cpp index 0bf306a..db6de64 100644 --- a/src/appdata/data-provider-manager.cpp +++ b/src/appdata/data-provider-manager.cpp @@ -78,6 +78,11 @@ void DataProviderManager::registerProvider(DataProviderPluginIFace *provider) Q_EMIT dataChanged(data, mode, index); }); + + connect(provider, &AllAppDataProvider::labelChanged, this, [this, provider]() { + if (m_activatedPlugin != provider->id()) { return; } + Q_EMIT labelChanged(); + }); } QVector DataProviderManager::data() const @@ -85,6 +90,11 @@ QVector DataProviderManager::data() const return m_providers.value(m_activatedPlugin)->data(); } +QVector DataProviderManager::labels() const +{ + return m_providers.value(m_activatedPlugin)->labels(); +} + QString DataProviderManager::activatedProvider() const { return m_activatedPlugin; diff --git a/src/appdata/data-provider-manager.h b/src/appdata/data-provider-manager.h index e05ac3c..6c3e30a 100644 --- a/src/appdata/data-provider-manager.h +++ b/src/appdata/data-provider-manager.h @@ -50,12 +50,14 @@ public: QString activatedProvider() const; void activateProvider(const QString &id); QVector data() const; + QVector labels() const; void forceUpdate() const; void forceUpdate(QString &key) const; Q_SIGNALS: void pluginChanged(const QString &id, PluginGroup::Group group); void dataChanged(QVector data, DataUpdateMode::Mode mode, quint32 index); + void labelChanged(); private: DataProviderManager(); diff --git a/src/commons.h b/src/commons.h index 7302e5b..003fb5b 100644 --- a/src/commons.h +++ b/src/commons.h @@ -29,6 +29,12 @@ class LabelItem { Q_GADGET public: + enum PropertyName { + IsDisable = 0, + Index, + Id, + DisplayName + }; LabelItem() = default; explicit LabelItem(bool disable, int index, QString id, QString displayName); diff --git a/src/model/label-model.cpp b/src/model/label-model.cpp new file mode 100644 index 0000000..14a2d6c --- /dev/null +++ b/src/model/label-model.cpp @@ -0,0 +1,77 @@ +/* + * 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 . + * + */ + +#include "label-model.h" +#include "data-provider-manager.h" + +namespace UkuiMenu { + +LabelModel::LabelModel(QObject *parent) : QAbstractListModel(parent) +{ + reloadLabelData(); + connect(DataProviderManager::instance(),&DataProviderManager::pluginChanged, this,&LabelModel::reloadLabelData); + connect(DataProviderManager::instance(),&DataProviderManager::labelChanged, this,&LabelModel::reloadLabelData); +} + +int LabelModel::rowCount(const QModelIndex &parent) const +{ + return m_labels.size(); +} + +QVariant LabelModel::data(const QModelIndex &index, int role) const +{ + int i = index.row(); + if (i < 0 || i >= m_labels.size()) { + return {}; + } + + switch (role) { + case LabelItem::IsDisable: + return m_labels.at(i).isDisable(); + case LabelItem::Id: + return m_labels.at(i).id(); + case LabelItem::Index: + return m_labels.at(i).index(); + case LabelItem::DisplayName: + return m_labels.at(i).displayName(); + default: + break; + } + + return {}; +} + +QHash LabelModel::roleNames() const +{ + QHash names; + names.insert(LabelItem::IsDisable, "isDisable"); + names.insert(LabelItem::Id, "id"); + names.insert(LabelItem::Index, "index"); + names.insert(LabelItem::DisplayName, "displayName"); + return names; +} + +void LabelModel::reloadLabelData() +{ + QVector labels = DataProviderManager::instance()->labels(); + Q_EMIT beginResetModel(); + m_labels.swap(labels); + Q_EMIT endResetModel(); +} + +} // UkuiMenu diff --git a/src/model/label-model.h b/src/model/label-model.h new file mode 100644 index 0000000..757aa9e --- /dev/null +++ b/src/model/label-model.h @@ -0,0 +1,46 @@ +/* + * 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 . + * + */ + +#ifndef UKUI_MENU_LABEL_MODEL_H +#define UKUI_MENU_LABEL_MODEL_H + +#include + +#include "commons.h" + +namespace UkuiMenu { + +class LabelModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit LabelModel(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + +private Q_SLOTS: + void reloadLabelData(); + +private: + QVector m_labels; +}; + +} // UkuiMenu + +#endif //UKUI_MENU_LABEL_MODEL_H diff --git a/src/model/model-manager.cpp b/src/model/model-manager.cpp index 1756f4f..9d16dad 100644 --- a/src/model/model-manager.cpp +++ b/src/model/model-manager.cpp @@ -17,6 +17,7 @@ */ #include "model-manager.h" +#include "label-model.h" #include "model.h" namespace UkuiMenu { @@ -24,11 +25,13 @@ namespace UkuiMenu { void ModelManager::registerMetaTypes() { qRegisterMetaType("AppModel*"); + qRegisterMetaType("LabelModel*"); } ModelManager::ModelManager(QObject *parent) : QObject(parent) { appModel = new AppModel(this); + labelModel = new LabelModel(this); } AppModel *ModelManager::getAppModel() @@ -39,4 +42,12 @@ AppModel *ModelManager::getAppModel() return nullptr; } +LabelModel *ModelManager::getLabelModel() +{ + if (labelModel) { + return labelModel; + } + return nullptr; +} + } // UkuiMenu diff --git a/src/model/model-manager.h b/src/model/model-manager.h index 6f80aa4..1aae278 100644 --- a/src/model/model-manager.h +++ b/src/model/model-manager.h @@ -24,6 +24,7 @@ namespace UkuiMenu { class AppModel; +class LabelModel; class ModelManager : public QObject { @@ -34,9 +35,11 @@ public: ~ModelManager() override = default; Q_INVOKABLE AppModel *getAppModel(); + Q_INVOKABLE LabelModel *getLabelModel(); private: AppModel *appModel{nullptr}; + LabelModel *labelModel{nullptr}; }; } // UkuiMenu diff --git a/src/model/model.cpp b/src/model/model.cpp index f243c55..131b84c 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -73,6 +73,16 @@ QHash AppModel::roleNames() const return names; } +int AppModel::currentAppIndex(const QString &id) +{ + for (int index = 0; index < m_apps.count(); ++index) { + if (m_apps.at(index).type() == DataType::Label && m_apps.at(index).id() == id) { + return index; + } + } + return -1; +} + QVariantList AppModel::folderApps(const QString &folderName) { DataEntity item1{DataType::Normal, "name 1", "icon", "comment", "extra"}; diff --git a/src/model/model.h b/src/model/model.h index 0dae383..391bf60 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -37,6 +37,7 @@ public: QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; + Q_INVOKABLE int currentAppIndex(const QString &id); Q_INVOKABLE QVariantList folderApps(const QString &folderName); Q_INVOKABLE void appClicked(const int &index);