fix(labels): 标签界面基于新后端实现
This commit is contained in:
parent
fba597ce54
commit
e29052607f
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024, 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
|
||||||
|
import org.ukui.menu.core 1.0
|
||||||
|
|
||||||
|
import org.ukui.quick.items 1.0 as UkuiItems
|
||||||
|
import org.ukui.quick.platform 1.0 as Platform
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
property var labelBottle: null
|
||||||
|
property int labelColum: labelBottle === null ? 0 : labelBottle.column
|
||||||
|
property int labelRow: Math.ceil(count / labelColum)
|
||||||
|
|
||||||
|
signal labelSelected(string label)
|
||||||
|
|
||||||
|
// 默认为小屏幕下尺寸
|
||||||
|
width: 200
|
||||||
|
height: childrenRect.height
|
||||||
|
cellWidth: width / labelColum
|
||||||
|
cellHeight: 40
|
||||||
|
|
||||||
|
model: labelBottle === null ? [] : labelBottle.labels
|
||||||
|
delegate: MouseArea {
|
||||||
|
width: GridView.view.cellWidth
|
||||||
|
height: GridView.view.cellHeight
|
||||||
|
focus: true
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
GridView.view.labelSelected(modelData.label);
|
||||||
|
GridView.view.currentIndex = model.index
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: (event) => {
|
||||||
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
|
GridView.view.labelSelected(modelData.label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UkuiItems.StyleBackground {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
radius: Platform.Theme.normalRadius
|
||||||
|
useStyleTransparency: false
|
||||||
|
paletteRole: Platform.Theme.WindowText
|
||||||
|
alpha: parent.containsPress ? 0.15 : parent.containsMouse ? 0.08 : 0.0
|
||||||
|
|
||||||
|
border.width: (parent.GridView.isCurrentItem && !mainWindow.isFullScreen) ? 2 : 0
|
||||||
|
borderColor: Platform.Theme.Highlight
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: modelData.type === LabelItem.Text
|
||||||
|
text: modelData.display
|
||||||
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
UkuiItems.Icon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.height/2
|
||||||
|
height: parent.height/2
|
||||||
|
visible: modelData.type === LabelItem.Icon
|
||||||
|
source: modelData.type === LabelItem.Icon ? modelData.display : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onRightPressed: {
|
||||||
|
if(currentIndex === count - 1) {
|
||||||
|
currentIndex = 0;
|
||||||
|
} else {
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keys.onLeftPressed: {
|
||||||
|
if(currentIndex === 0) {
|
||||||
|
currentIndex = count - 1;
|
||||||
|
} else {
|
||||||
|
currentIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keys.onDownPressed: {
|
||||||
|
if(Math.floor(currentIndex / labelColum) < labelRow - 1) {
|
||||||
|
currentIndex = currentIndex + labelColum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keys.onUpPressed: {
|
||||||
|
if(Math.floor(currentIndex / labelColum) > 0) {
|
||||||
|
currentIndex = currentIndex - labelColum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,7 +70,7 @@ UkuiItems.StyleBackground {
|
||||||
}
|
}
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
pluginSortButtonRoot.model.changeProvider(0);
|
modelData.trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ MouseArea {
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
cacheBuffer: itemHeight * listView.count
|
cacheBuffer: count * root.itemHeight
|
||||||
spacing: 4
|
spacing: 4
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
|
@ -29,7 +29,8 @@ Item {
|
||||||
if (appList.visible) {
|
if (appList.visible) {
|
||||||
appList.resetListFocus();
|
appList.resetListFocus();
|
||||||
} else {
|
} else {
|
||||||
selectionPage.viewFocusEnable();
|
selectionPage.focus = true;
|
||||||
|
labelPage.focus = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ Item {
|
||||||
AppList {
|
AppList {
|
||||||
id: appList
|
id: appList
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: true
|
visible: !selectionPage.visible
|
||||||
model: AppPageBackend.appModel
|
model: AppPageBackend.appModel
|
||||||
|
|
||||||
view.onContentYChanged: {
|
view.onContentYChanged: {
|
||||||
|
@ -61,15 +62,95 @@ Item {
|
||||||
appListHeader.title = view.currentSection;
|
appListHeader.title = view.currentSection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function positionLabel(label) {
|
||||||
|
let index = model.findLabelIndex(label);
|
||||||
|
if (index >= 0) {
|
||||||
|
view.positionViewAtIndex(index, ListView.Beginning)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionPage {
|
onLabelItemClicked: {
|
||||||
|
labelPage.labelBottle = AppPageBackend.appModel.labelBottle;
|
||||||
|
labelPage.currentIndex = 0;
|
||||||
|
selectionPage.state = "viewShowed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
id: selectionPage
|
id: selectionPage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.bottomMargin: 54
|
visible: false
|
||||||
visible: !appList.visible
|
|
||||||
onViewHideFinished: appList.visible = true
|
onClicked: state = "viewHid";
|
||||||
onLabelSelected: appList.labelSelection(labelId)
|
|
||||||
|
state: "viewHid"
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "viewShowed"
|
||||||
|
changes: [
|
||||||
|
PropertyChanges {target: selectionPage; scale: 1; opacity: 1; focus: true }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "viewHid"
|
||||||
|
changes: [
|
||||||
|
PropertyChanges {target: selectionPage; scale: 1.5; opacity: 0; focus: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: "*"; to: "viewShowed"
|
||||||
|
SequentialAnimation {
|
||||||
|
ScriptAction { script: selectionPage.visible = true; }
|
||||||
|
NumberAnimation { properties: "scale,opacity"; easing.type: Easing.InOutCubic; duration: 300}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"; to: "viewHid"
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation { properties: "scale,opacity"; easing.type: Easing.InOutCubic; duration: 300}
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
selectionPage.visible = false;
|
||||||
|
labelPage.labelBottle = null;
|
||||||
|
labelPage.focus = false;
|
||||||
|
appList.focus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
AppLabelPage {
|
||||||
|
id: labelPage
|
||||||
|
anchors.centerIn: parent
|
||||||
|
interactive: height > parent.height
|
||||||
|
|
||||||
|
onLabelSelected: (label) => {
|
||||||
|
appList.positionLabel(label);
|
||||||
|
selectionPage.state = "viewHid";
|
||||||
|
}
|
||||||
|
|
||||||
|
onModelChanged: {
|
||||||
|
currentIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePage() {
|
||||||
|
state = "viewHid";
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
mainWindow.visibleChanged.connect(hidePage)
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
mainWindow.visibleChanged.disconnect(hidePage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,17 +107,60 @@ UkuiItems.StyleBackground {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: 120
|
width: 120
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
|
AppLabelPage {
|
||||||
|
id: appLabelPage
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
labelBottle: AppPageBackend.appModel.labelBottle
|
||||||
|
labelColum: 1
|
||||||
|
cellHeight: 34
|
||||||
|
|
||||||
|
interactive: height > parent.height
|
||||||
|
highlightMoveDuration: 300
|
||||||
|
highlight: UkuiItems.StyleBackground {
|
||||||
|
width: appLabelPage.cellWidth
|
||||||
|
height: appLabelPage.cellHeight
|
||||||
|
useStyleTransparency: false
|
||||||
|
radius: Platform.Theme.minRadius
|
||||||
|
paletteRole: Platform.Theme.Light
|
||||||
|
alpha: 0.15; borderAlpha: 0.5
|
||||||
|
border.width: 1
|
||||||
|
borderColor: Platform.Theme.Highlight
|
||||||
|
}
|
||||||
|
|
||||||
|
onLabelSelected: (label) => {
|
||||||
|
fullScreenAppList.positionLabel(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用列表: [row: 1, column: 1]
|
// 应用列表: [row: 1, column: 1]
|
||||||
FullScreenAppList {
|
FullScreenAppList {
|
||||||
|
id: fullScreenAppList
|
||||||
Layout.row: 1
|
Layout.row: 1
|
||||||
Layout.column: 1
|
Layout.column: 1
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
sourceModel: AppPageBackend.appModel
|
sourceModel: AppPageBackend.appModel
|
||||||
|
|
||||||
|
function positionLabel(label) {
|
||||||
|
let index = model.findLabelIndex(label);
|
||||||
|
if (index >= 0) {
|
||||||
|
positionViewAtIndex(index, ListView.Beginning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onContentYChanged: {
|
||||||
|
// 向下偏移200
|
||||||
|
let index = indexAt(10, contentY + 200);
|
||||||
|
if (index >= 0) {
|
||||||
|
appLabelPage.currentIndex = index + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,4 +15,5 @@ FullScreenContent 1.0 FullScreenContent.qml
|
||||||
FullScreenFooter 1.0 FullScreenFooter.qml
|
FullScreenFooter 1.0 FullScreenFooter.qml
|
||||||
FullScreenAppList 1.0 FullScreenAppList.qml
|
FullScreenAppList 1.0 FullScreenAppList.qml
|
||||||
FullScreenAppItem 1.0 FullScreenAppItem.qml
|
FullScreenAppItem 1.0 FullScreenAppItem.qml
|
||||||
|
AppLabelPage 1.0 AppLabelPage.qml
|
||||||
Folder 1.0 Folder.qml
|
Folder 1.0 Folder.qml
|
||||||
|
|
|
@ -36,5 +36,6 @@
|
||||||
<file>AppUI/AppPageSearch.qml</file>
|
<file>AppUI/AppPageSearch.qml</file>
|
||||||
<file>AppUI/FullScreenAppList.qml</file>
|
<file>AppUI/FullScreenAppList.qml</file>
|
||||||
<file>AppUI/FullScreenAppItem.qml</file>
|
<file>AppUI/FullScreenAppItem.qml</file>
|
||||||
|
<file>AppUI/AppLabelPage.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -17,49 +17,3 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
// ====== LabelItem ====== //
|
|
||||||
UkuiMenu::LabelItem::LabelItem(bool disable, int index, QString id, QString displayName)
|
|
||||||
: m_disable(disable), m_index(index), m_id(std::move(id)), m_displayName(std::move(displayName)) {}
|
|
||||||
|
|
||||||
bool UkuiMenu::LabelItem::isDisable() const
|
|
||||||
{
|
|
||||||
return m_disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UkuiMenu::LabelItem::setDisable(bool disable)
|
|
||||||
{
|
|
||||||
LabelItem::m_disable = disable;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UkuiMenu::LabelItem::index() const
|
|
||||||
{
|
|
||||||
return m_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UkuiMenu::LabelItem::setIndex(int index)
|
|
||||||
{
|
|
||||||
LabelItem::m_index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &UkuiMenu::LabelItem::displayName() const
|
|
||||||
{
|
|
||||||
return m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UkuiMenu::LabelItem::setDisplayName(const QString &name)
|
|
||||||
{
|
|
||||||
LabelItem::m_id = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &UkuiMenu::LabelItem::id() const
|
|
||||||
{
|
|
||||||
return m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UkuiMenu::LabelItem::setId(const QString &id)
|
|
||||||
{
|
|
||||||
m_id = id;
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,43 +23,6 @@
|
||||||
|
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
// 标签项
|
|
||||||
class LabelItem
|
|
||||||
{
|
|
||||||
Q_GADGET
|
|
||||||
public:
|
|
||||||
enum PropertyName {
|
|
||||||
IsDisable = 0,
|
|
||||||
Index,
|
|
||||||
Id,
|
|
||||||
DisplayName
|
|
||||||
};
|
|
||||||
LabelItem() = default;
|
|
||||||
explicit LabelItem(bool disable, int index, QString id, QString displayName);
|
|
||||||
|
|
||||||
friend inline bool operator==(const LabelItem& a, const LabelItem& b) {
|
|
||||||
return QString::compare(a.id(), b.id(), Qt::CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDisable() const;
|
|
||||||
void setDisable(bool disable);
|
|
||||||
|
|
||||||
int index() const;
|
|
||||||
void setIndex(int index);
|
|
||||||
|
|
||||||
const QString &id() const;
|
|
||||||
void setId(const QString &id);
|
|
||||||
|
|
||||||
const QString &displayName() const;
|
|
||||||
void setDisplayName(const QString &name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_disable{true};
|
|
||||||
int m_index{0};
|
|
||||||
QString m_id;
|
|
||||||
QString m_displayName;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Display {
|
class Display {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "combined-list-model.h"
|
#include "combined-list-model.h"
|
||||||
#include "app-category-model.h"
|
#include "app-category-model.h"
|
||||||
#include "recently-installed-model.h"
|
#include "recently-installed-model.h"
|
||||||
|
#include "data-entity.h"
|
||||||
#include "event-track.h"
|
#include "event-track.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
@ -30,13 +31,13 @@
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
AppCategoryPlugin::AppCategoryPlugin(QObject *parent) : AppListPluginInterface(parent)
|
AppCategoryPlugin::AppCategoryPlugin(QObject *parent) : AppListPluginInterface(parent)
|
||||||
, m_dataModel(new CombinedListModel(this))
|
, m_dataModel(new CombinedListModel(this)), m_labelBottle(new LabelBottle(this))
|
||||||
{
|
{
|
||||||
auto categoryModel = new AppCategoryModel(this);
|
m_categoryModel = new AppCategoryModel(this);
|
||||||
auto recentlyModel = new RecentlyInstalledModel(this);
|
m_recentlyModel = new RecentlyInstalledModel(this);
|
||||||
|
|
||||||
m_dataModel->insertSubModel(recentlyModel);
|
m_dataModel->insertSubModel(m_recentlyModel);
|
||||||
m_dataModel->insertSubModel(categoryModel);
|
m_dataModel->insertSubModel(m_categoryModel);
|
||||||
|
|
||||||
auto categoryAction = new QAction(QIcon::fromTheme("applications-utilities-symbolic"), tr("Category"), this);
|
auto categoryAction = new QAction(QIcon::fromTheme("applications-utilities-symbolic"), tr("Category"), this);
|
||||||
auto firstLatterAction = new QAction(QIcon::fromTheme("ukui-capslock-symbolic"), tr("Letter Sort"), this);
|
auto firstLatterAction = new QAction(QIcon::fromTheme("ukui-capslock-symbolic"), tr("Letter Sort"), this);
|
||||||
|
@ -45,20 +46,22 @@ AppCategoryPlugin::AppCategoryPlugin(QObject *parent) : AppListPluginInterface(p
|
||||||
firstLatterAction->setCheckable(true);
|
firstLatterAction->setCheckable(true);
|
||||||
|
|
||||||
connect(categoryAction, &QAction::triggered, this, [=] {
|
connect(categoryAction, &QAction::triggered, this, [=] {
|
||||||
categoryModel->setMode(AppCategoryModel::Category);
|
m_categoryModel->setMode(AppCategoryModel::Category);
|
||||||
categoryAction->setChecked(true);
|
categoryAction->setChecked(true);
|
||||||
firstLatterAction->setChecked(false);
|
firstLatterAction->setChecked(false);
|
||||||
setTitle(categoryAction->text());
|
setTitle(categoryAction->text());
|
||||||
|
updateLabelBottle();
|
||||||
|
|
||||||
QMap<QString, QVariant> map;
|
QMap<QString, QVariant> map;
|
||||||
map.insert(QStringLiteral("viewName"), QStringLiteral("category"));
|
map.insert(QStringLiteral("viewName"), QStringLiteral("category"));
|
||||||
EventTrack::instance()->sendClickEvent("switch_app_view", "AppView", map);
|
EventTrack::instance()->sendClickEvent("switch_app_view", "AppView", map);
|
||||||
});
|
});
|
||||||
connect(firstLatterAction, &QAction::triggered, this, [=] {
|
connect(firstLatterAction, &QAction::triggered, this, [=] {
|
||||||
categoryModel->setMode(AppCategoryModel::FirstLatter);
|
m_categoryModel->setMode(AppCategoryModel::FirstLatter);
|
||||||
categoryAction->setChecked(false);
|
categoryAction->setChecked(false);
|
||||||
firstLatterAction->setChecked(true);
|
firstLatterAction->setChecked(true);
|
||||||
setTitle(firstLatterAction->text());
|
setTitle(firstLatterAction->text());
|
||||||
|
updateLabelBottle();
|
||||||
|
|
||||||
QMap<QString, QVariant> map;
|
QMap<QString, QVariant> map;
|
||||||
map.insert(QStringLiteral("viewName"), QStringLiteral("letter"));
|
map.insert(QStringLiteral("viewName"), QStringLiteral("letter"));
|
||||||
|
@ -70,6 +73,7 @@ AppCategoryPlugin::AppCategoryPlugin(QObject *parent) : AppListPluginInterface(p
|
||||||
|
|
||||||
categoryAction->setChecked(true);
|
categoryAction->setChecked(true);
|
||||||
setTitle(categoryAction->text());
|
setTitle(categoryAction->text());
|
||||||
|
m_labelBottle->setColumn(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AppCategoryPlugin::name()
|
QString AppCategoryPlugin::name()
|
||||||
|
@ -107,4 +111,33 @@ void AppCategoryPlugin::setTitle(const QString &title)
|
||||||
Q_EMIT titleChanged();
|
Q_EMIT titleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelBottle *AppCategoryPlugin::labelBottle()
|
||||||
|
{
|
||||||
|
updateLabelBottle();
|
||||||
|
return m_labelBottle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppCategoryPlugin::updateLabelBottle()
|
||||||
|
{
|
||||||
|
QList<LabelItem> labels;
|
||||||
|
if (m_recentlyModel->rowCount() > 0) {
|
||||||
|
labels << LabelItem(tr("Recently Installed"), "search-symbolic", LabelItem::Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, int> groups;
|
||||||
|
int rowCount = m_categoryModel->rowCount();
|
||||||
|
for (int row = 0; row < rowCount; ++row) {
|
||||||
|
QString group = m_categoryModel->index(row, 0, QModelIndex()).data(DataEntity::Group).toString();
|
||||||
|
if (groups.contains(group)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.insert(group, 0);
|
||||||
|
labels.append(LabelItem(group, group));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_labelBottle->setLabels(labels);
|
||||||
|
m_labelBottle->setColumn(m_categoryModel->mode() == AppCategoryModel::FirstLatter ? 5 : 2);
|
||||||
|
}
|
||||||
|
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
class CombinedListModel;
|
class CombinedListModel;
|
||||||
|
class AppCategoryModel;
|
||||||
|
class RecentlyInstalledModel;
|
||||||
|
|
||||||
class AppCategoryPlugin : public AppListPluginInterface
|
class AppCategoryPlugin : public AppListPluginInterface
|
||||||
{
|
{
|
||||||
|
@ -38,13 +40,20 @@ public:
|
||||||
QString title() override;
|
QString title() override;
|
||||||
QList<QAction *> actions() override;
|
QList<QAction *> actions() override;
|
||||||
QAbstractItemModel *dataModel() override;
|
QAbstractItemModel *dataModel() override;
|
||||||
|
LabelBottle *labelBottle() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setTitle(const QString &title);
|
void setTitle(const QString &title);
|
||||||
|
void updateLabelBottle();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QList<QAction *> m_actions;
|
QList<QAction *> m_actions;
|
||||||
|
LabelBottle *m_labelBottle {nullptr};
|
||||||
|
|
||||||
|
AppCategoryModel *m_categoryModel {nullptr};
|
||||||
|
RecentlyInstalledModel *m_recentlyModel {nullptr};
|
||||||
|
|
||||||
CombinedListModel *m_dataModel {nullptr};
|
CombinedListModel *m_dataModel {nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ QVariant AppGroupModel::data(const QModelIndex &proxyIndex, int role) const
|
||||||
return QAbstractProxyModel::data(proxyIndex, role);
|
return QAbstractProxyModel::data(proxyIndex, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == DataEntity::Name) {
|
if (role == DataEntity::Name || role == DataEntity::Group) {
|
||||||
return sourceModel()->index(m_groups.at(proxyIndex.row())->first(), 0).data(DataEntity::Group);
|
return sourceModel()->index(m_groups.at(proxyIndex.row())->first(), 0).data(DataEntity::Group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,4 +345,16 @@ void AppGroupModel::onRowsAboutToBeRemoved(const QModelIndex &parent, int first,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AppGroupModel::findLabelIndex(const QString &label) const
|
||||||
|
{
|
||||||
|
int rowCount = AppGroupModel::rowCount(QModelIndex());
|
||||||
|
for (int i = 0; i < rowCount; ++i) {
|
||||||
|
if (index(i, 0, QModelIndex()).data(DataEntity::Group).toString() == label) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
|
@ -54,6 +54,8 @@ public:
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE int findLabelIndex(const QString &label) const;
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
|
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
|
||||||
void onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
|
void onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
|
||||||
|
|
|
@ -128,6 +128,8 @@ void AppListModel::installPlugin(AppListPluginInterface *plugin)
|
||||||
connect(m_plugin, &AppListPluginInterface::titleChanged, this, [this, plugin] {
|
connect(m_plugin, &AppListPluginInterface::titleChanged, this, [this, plugin] {
|
||||||
m_header->setTitle(plugin->title());
|
m_header->setTitle(plugin->title());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Q_EMIT labelBottleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::unInstallPlugin()
|
void AppListModel::unInstallPlugin()
|
||||||
|
@ -141,6 +143,8 @@ void AppListModel::unInstallPlugin()
|
||||||
QSortFilterProxyModel::setSourceModel(nullptr);
|
QSortFilterProxyModel::setSourceModel(nullptr);
|
||||||
disconnect(m_plugin, nullptr, this, nullptr);
|
disconnect(m_plugin, nullptr, this, nullptr);
|
||||||
m_plugin = nullptr;
|
m_plugin = nullptr;
|
||||||
|
|
||||||
|
Q_EMIT labelBottleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::openMenu(const int &index, MenuInfo::Location location) const
|
void AppListModel::openMenu(const int &index, MenuInfo::Location location) const
|
||||||
|
@ -151,4 +155,26 @@ void AppListModel::openMenu(const int &index, MenuInfo::Location location) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelBottle *AppListModel::labelBottle() const
|
||||||
|
{
|
||||||
|
if (m_plugin) {
|
||||||
|
return m_plugin->labelBottle();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppListModel::findLabelIndex(const QString &label) const
|
||||||
|
{
|
||||||
|
// TODO: 潜在的优化空间
|
||||||
|
int count = AppListModel::rowCount();
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
if (AppListModel::sourceModel()->index(i, 0).data(DataEntity::Group).toString() == label) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
|
@ -71,6 +71,7 @@ class AppListModel : public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(UkuiMenu::AppListHeader *header READ getHeader NOTIFY headerChanged)
|
Q_PROPERTY(UkuiMenu::AppListHeader *header READ getHeader NOTIFY headerChanged)
|
||||||
|
Q_PROPERTY(UkuiMenu::LabelBottle *labelBottle READ labelBottle NOTIFY labelBottleChanged)
|
||||||
public:
|
public:
|
||||||
explicit AppListModel(QObject *parent = nullptr);
|
explicit AppListModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
@ -81,15 +82,18 @@ public:
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
AppListHeader *getHeader() const;
|
AppListHeader *getHeader() const;
|
||||||
|
LabelBottle *labelBottle() const;
|
||||||
|
|
||||||
void installPlugin(AppListPluginInterface *plugin);
|
void installPlugin(AppListPluginInterface *plugin);
|
||||||
// reset
|
// reset
|
||||||
void unInstallPlugin();
|
void unInstallPlugin();
|
||||||
|
|
||||||
Q_INVOKABLE void openMenu(const int &index, MenuInfo::Location location) const;
|
Q_INVOKABLE void openMenu(const int &index, MenuInfo::Location location) const;
|
||||||
|
Q_INVOKABLE int findLabelIndex(const QString &label) const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void headerChanged();
|
void headerChanged();
|
||||||
|
void labelBottleChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AppListHeader *m_header {nullptr};
|
AppListHeader *m_header {nullptr};
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
|
|
||||||
#include "app-list-plugin.h"
|
#include "app-list-plugin.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
// ====== AppListPluginInterface ====== //
|
// ====== AppListPluginInterface ====== //
|
||||||
AppListPluginInterface::AppListPluginInterface(QObject *parent) : QObject(parent)
|
AppListPluginInterface::AppListPluginInterface(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
qRegisterMetaType<UkuiMenu::LabelItem>("LabelItem");
|
||||||
|
qRegisterMetaType<UkuiMenu::LabelBottle*>("LabelBottle*");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListPluginInterface::search(const QString &keyword)
|
void AppListPluginInterface::search(const QString &keyword)
|
||||||
|
@ -34,4 +36,64 @@ void AppListPluginInterface::search(const QString &keyword)
|
||||||
Q_UNUSED(keyword)
|
Q_UNUSED(keyword)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelBottle *AppListPluginInterface::labelBottle()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== LabelItem ====== //
|
||||||
|
LabelItem::LabelItem(QString labelName, QString displayName, LabelItem::Type type)
|
||||||
|
: m_type(type), m_labelName(std::move(labelName)), m_displayName(std::move(displayName))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LabelItem::labelName() const
|
||||||
|
{
|
||||||
|
return m_labelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelItem::Type LabelItem::type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LabelItem::displayName() const
|
||||||
|
{
|
||||||
|
return m_displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== LabelBottle ====== //
|
||||||
|
LabelBottle::LabelBottle(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int LabelBottle::column() const
|
||||||
|
{
|
||||||
|
return m_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<UkuiMenu::LabelItem> LabelBottle::labels() const
|
||||||
|
{
|
||||||
|
return m_labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelBottle::setColumn(int column)
|
||||||
|
{
|
||||||
|
if (m_column == column) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_column = column;
|
||||||
|
Q_EMIT columnChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelBottle::setLabels(const QList<UkuiMenu::LabelItem> &labels)
|
||||||
|
{
|
||||||
|
m_labels.clear();
|
||||||
|
m_labels.append(labels);
|
||||||
|
Q_EMIT labelsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
|
@ -29,6 +29,54 @@ class QAbstractItemModel;
|
||||||
|
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
|
class LabelItem
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(UkuiMenu::LabelItem::Type type READ type)
|
||||||
|
Q_PROPERTY(QString label READ labelName)
|
||||||
|
Q_PROPERTY(QString display READ displayName)
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
Text,
|
||||||
|
Icon
|
||||||
|
};
|
||||||
|
Q_ENUM(Type)
|
||||||
|
|
||||||
|
explicit LabelItem(QString labelName = "", QString displayName = "", Type type = Text);
|
||||||
|
|
||||||
|
Type type() const;
|
||||||
|
QString labelName() const;
|
||||||
|
QString displayName() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type m_type;
|
||||||
|
QString m_labelName;
|
||||||
|
QString m_displayName;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LabelBottle : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int column READ column NOTIFY columnChanged)
|
||||||
|
Q_PROPERTY(QList<UkuiMenu::LabelItem> labels READ labels NOTIFY labelsChanged)
|
||||||
|
public:
|
||||||
|
explicit LabelBottle(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int column() const;
|
||||||
|
QList<UkuiMenu::LabelItem> labels() const;
|
||||||
|
|
||||||
|
void setColumn(int column);
|
||||||
|
void setLabels(const QList<UkuiMenu::LabelItem> &labels);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void columnChanged();
|
||||||
|
void labelsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_column {2};
|
||||||
|
QList<LabelItem> m_labels;
|
||||||
|
};
|
||||||
|
|
||||||
class AppListPluginGroup
|
class AppListPluginGroup
|
||||||
{
|
{
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
|
@ -52,6 +100,7 @@ public:
|
||||||
virtual QList<QAction*> actions() = 0;
|
virtual QList<QAction*> actions() = 0;
|
||||||
virtual QAbstractItemModel *dataModel() = 0;
|
virtual QAbstractItemModel *dataModel() = 0;
|
||||||
virtual void search(const QString &keyword);
|
virtual void search(const QString &keyword);
|
||||||
|
virtual LabelBottle *labelBottle();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void titleChanged();
|
void titleChanged();
|
||||||
|
@ -60,5 +109,7 @@ Q_SIGNALS:
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(UkuiMenu::AppListPluginGroup::Group)
|
Q_DECLARE_METATYPE(UkuiMenu::AppListPluginGroup::Group)
|
||||||
|
Q_DECLARE_METATYPE(UkuiMenu::LabelItem)
|
||||||
|
Q_DECLARE_METATYPE(UkuiMenu::LabelBottle*)
|
||||||
|
|
||||||
#endif //UKUI_MENU_APP_LIST_PLUGIN_H
|
#endif //UKUI_MENU_APP_LIST_PLUGIN_H
|
||||||
|
|
|
@ -86,7 +86,7 @@ bool RecentlyInstalledModel::event(QEvent *event)
|
||||||
QVariant RecentlyInstalledModel::data(const QModelIndex &index, int role) const
|
QVariant RecentlyInstalledModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (role == DataEntity::Group) {
|
if (role == DataEntity::Group) {
|
||||||
return QStringLiteral("RecentlyInstalled");
|
return tr("Recently Installed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSortFilterProxyModel::data(index, role);
|
return QSortFilterProxyModel::data(index, role);
|
||||||
|
|
|
@ -74,6 +74,7 @@ void UkuiMenuApplication::registerQmlTypes()
|
||||||
qmlRegisterUncreatableType<Display>(uri, versionMajor, versionMinor, "Display", "Use enums only.");
|
qmlRegisterUncreatableType<Display>(uri, versionMajor, versionMinor, "Display", "Use enums only.");
|
||||||
qmlRegisterUncreatableType<UkuiMenu::DataType>(uri, versionMajor, versionMinor, "DataType", "Use enums only");
|
qmlRegisterUncreatableType<UkuiMenu::DataType>(uri, versionMajor, versionMinor, "DataType", "Use enums only");
|
||||||
qmlRegisterUncreatableType<UkuiMenu::MenuInfo>(uri, versionMajor, versionMinor, "MenuInfo", "Use enums only.");
|
qmlRegisterUncreatableType<UkuiMenu::MenuInfo>(uri, versionMajor, versionMinor, "MenuInfo", "Use enums only.");
|
||||||
|
qmlRegisterUncreatableType<UkuiMenu::LabelItem>(uri, versionMajor, versionMinor, "LabelItem", "Use enums only.");
|
||||||
// qmlRegisterUncreatableType<UkuiMenu::DataEntity>(uri, versionMajor, versionMinor, "DataEntity", "unknown");
|
// qmlRegisterUncreatableType<UkuiMenu::DataEntity>(uri, versionMajor, versionMinor, "DataEntity", "unknown");
|
||||||
|
|
||||||
qmlRegisterUncreatableType<EventTrack>(uri, versionMajor, versionMinor, "EventTrack", "Attached only.");
|
qmlRegisterUncreatableType<EventTrack>(uri, versionMajor, versionMinor, "EventTrack", "Attached only.");
|
||||||
|
|
Loading…
Reference in New Issue