diff --git a/CMakeLists.txt b/CMakeLists.txt index 6037207..f99538c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ set(SOURCE_FILES src/menu/menu-provider.h src/menu/menu-manager.cpp src/menu/menu-manager.h src/items/theme-icon.h src/items/theme-icon.cpp + src/settings/user-config.cpp src/settings/user-config.h ) # library sources diff --git a/data/ukui-menu-global-config.conf b/data/ukui-menu-global-config.conf index 8b6914f..7b3eea3 100644 --- a/data/ukui-menu-global-config.conf +++ b/data/ukui-menu-global-config.conf @@ -18,3 +18,10 @@ kylin-user-guide.desktop=0 ukui-control-center.desktop=0 peony.desktop=0 engrampa.desktop=0 + +[Default Favorite Apps] +0=/usr/share/applications/peony.desktop +1=/usr/share/applications/ukui-control-center.desktop +2=/usr/share/applications/kylin-weather.desktop +3=/usr/share/applications/kylin-software-center.desktop +4=/usr/share/applications/kylin-screenshot.desktop diff --git a/qml/AppControls2/FolderItem.qml b/qml/AppControls2/FolderItem.qml index 92c7dc7..01523a5 100644 --- a/qml/AppControls2/FolderItem.qml +++ b/qml/AppControls2/FolderItem.qml @@ -10,7 +10,7 @@ MouseArea { property bool truncate: false property bool isSelect: false hoverEnabled: true - ToolTip.visible: editStatus && truncate && control.containsMouse + ToolTip.visible: !editStatus && truncate && control.containsMouse ToolTip.text: name states: State { when: control.activeFocus @@ -19,6 +19,7 @@ MouseArea { alpha: 0.55 } } + StyleBackground { id: controlBase anchors.fill: parent @@ -54,7 +55,7 @@ MouseArea { horizontalAlignment: Text.AlignLeft elide: Text.ElideRight text: name - Component.onCompleted: { + onWidthChanged: { control.truncate = textShow.truncated } } @@ -84,9 +85,9 @@ MouseArea { selectByMouse: true maximumLength: 14 - onEditingFinished: { - modelManager.getAppModel().renameFolder(id, text); + function editStatusEnd() { control.editStatus = false; + control.focus = true; } function updateTextInputColor() { @@ -94,12 +95,15 @@ MouseArea { selectionColor = themePalette.paletteColor(Palette.Highlight); } + onEditingFinished: { + modelManager.getAppModel().renameFolder(id, text); + textChange.editStatusEnd(); + } Component.onCompleted: { updateTextInputColor(); themePalette.styleColorChanged.connect(updateTextInputColor); forceActiveFocus(); } - Component.onDestruction: themePalette.styleColorChanged.disconnect(updateTextInputColor); } @@ -120,12 +124,10 @@ MouseArea { onClicked: { textChange.text = name; - control.editStatus = false; + textChange.editStatusEnd(); } } - } - } Loader { diff --git a/qml/AppControls2/IconLabel.qml b/qml/AppControls2/IconLabel.qml index b9ed242..3c6fc7d 100644 --- a/qml/AppControls2/IconLabel.qml +++ b/qml/AppControls2/IconLabel.qml @@ -66,7 +66,6 @@ Item { StyleText { id: iconText text: root.appName - font.pixelSize: 14 elide: Text.ElideRight paletteRole: root.textHighLight ? Palette.HighlightedText : Palette.Text } diff --git a/qml/AppControls2/LabelItem.qml b/qml/AppControls2/LabelItem.qml index dcbfc72..436bddb 100644 --- a/qml/AppControls2/LabelItem.qml +++ b/qml/AppControls2/LabelItem.qml @@ -30,7 +30,6 @@ MouseArea { horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter - font.pixelSize: 14 font.bold: true text: name } diff --git a/qml/AppControls2/StyleText.qml b/qml/AppControls2/StyleText.qml index 8f23661..de4b127 100644 --- a/qml/AppControls2/StyleText.qml +++ b/qml/AppControls2/StyleText.qml @@ -3,24 +3,31 @@ import org.ukui.menu.core 1.0 Text { property int paletteRole: Palette.Text - property real alpha: 1.0 + property real alpha: 1 + property real systemFontSize: 10 + property real textUltra: 2*systemFontSize + font.pointSize: systemFontSize function updateColor() { - color = themePalette.paletteColorWithCustomTransparency(paletteRole, Palette.Active, alpha) + color = themePalette.paletteColorWithCustomTransparency(paletteRole, Palette.Active, alpha); + } + function updateFontSize() { + systemFontSize = themePalette.systemFontSize(); } - Component.onCompleted: { - updateColor() - themePalette.styleColorChanged.connect(updateColor) + updateColor(); + updateFontSize(); + themePalette.styleColorChanged.connect(updateColor); + themePalette.systemFontSizeChanged.connect(updateFontSize); } Component.onDestruction: { - themePalette.styleColorChanged.disconnect(updateColor) + themePalette.styleColorChanged.disconnect(updateColor); + themePalette.systemFontSizeChanged.disconnect(updateFontSize); } - onPaletteRoleChanged: { - updateColor() + updateColor(); } onAlphaChanged: { - updateColor() + updateColor(); } } diff --git a/qml/AppUI/AppList.qml b/qml/AppUI/AppList.qml index 9505500..eac31e0 100644 --- a/qml/AppUI/AppList.qml +++ b/qml/AppUI/AppList.qml @@ -24,11 +24,12 @@ import AppControls2 1.0 as AppControls2 import org.ukui.menu.core 1.0 Item { + id: appListRoot property string title: "" property string idSelect: "" + property bool folderEditStatus: false signal labelItemClicked() - signal openFolderPageSignal(string folderId, string folderName); - + signal openFolderPageSignal(string folderId, string folderName) function labelSelection(labelId) { appListView.view.positionViewAtIndex(appListView.model.getLabelIndex(labelId), ListView.Beginning) } @@ -41,6 +42,16 @@ Item { id: appListView anchors.fill: parent + // 在listview区域,鼠标进出和移动事件都会清空原有的按键焦点 + // 鼠标不移动,原有的鼠标悬浮三态会保留 + onContainsMouseChanged: clearViewFocus() + onPositionChanged: clearViewFocus() + function clearViewFocus() { + if(!folderEditStatus) { + appListView.listFocus = false + } + } + model: modelManager.getAppModel() delegate: Component { Loader { @@ -68,6 +79,17 @@ Item { } } } + + view.onContentYChanged: { + if (appPageHeaderUtils.currentPluginId() === "all") { + return; + } + + var obj = view.itemAt(10, view.contentY); + if (obj !== null && obj.type === DataType.Label) { + appListRoot.title = obj.name; + } + } } Component { @@ -90,9 +112,6 @@ Item { } if (mouse.button === Qt.LeftButton) { appManager.launchApp(id); - if (recentInstall) { - appManager.appLaunched(id); - } return; } } @@ -118,9 +137,6 @@ Item { Keys.onPressed: { if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { appManager.launchApp(id); - if (recentInstall) { - appManager.appLaunched(id); - } } } } @@ -176,6 +192,7 @@ Item { appListView.model.renameText.disconnect(toEditText); } + onEditStatusChanged: folderEditStatus = editStatus; function toEditText(idOfIndex){ if (id === idOfIndex) { editStatus = true; diff --git a/qml/AppUI/AppListView.qml b/qml/AppUI/AppListView.qml index 05dd6a6..98823c4 100644 --- a/qml/AppUI/AppListView.qml +++ b/qml/AppUI/AppListView.qml @@ -32,7 +32,7 @@ MouseArea { property int itemHeight: 40 hoverEnabled: true clip: true - onContainsMouseChanged: listView.focus = false + AppControls2.StyleBackground { anchors.top: parent.top width: parent.width @@ -57,6 +57,7 @@ MouseArea { highlightMoveDuration: 0 boundsBehavior: Flickable.StopAtBounds ScrollBar.vertical: listViewScrollBar + // 焦点切换后,listView按键导航重新开始 onActiveFocusChanged: currentIndex = 0 onCountChanged: currentIndex = 0 diff --git a/qml/AppUI/AppPage.qml b/qml/AppUI/AppPage.qml index 1de6cf3..181d5bb 100644 --- a/qml/AppUI/AppPage.qml +++ b/qml/AppUI/AppPage.qml @@ -37,7 +37,7 @@ AppControls2.StyleBackground { id: appPageHeader Layout.fillWidth: true Layout.preferredHeight: 40 - focusToListView: appPageContent + focusToPageContent: appPageContent } AppPageContent { diff --git a/qml/AppUI/AppPageContent.qml b/qml/AppUI/AppPageContent.qml index fc658da..dae0063 100644 --- a/qml/AppUI/AppPageContent.qml +++ b/qml/AppUI/AppPageContent.qml @@ -44,6 +44,9 @@ SwipeView { appList.visible = false; selectionPage.viewShowStart(); } + onTitleChanged: { + appPageHeader.title = title; + } } SelectionPage { diff --git a/qml/AppUI/AppPageHeader.qml b/qml/AppUI/AppPageHeader.qml index 970ed71..16567f1 100644 --- a/qml/AppUI/AppPageHeader.qml +++ b/qml/AppUI/AppPageHeader.qml @@ -26,13 +26,13 @@ import org.ukui.menu.utils 1.0 Item { id: appPageHeaderRoot property string title: "" - required property Item focusToListView + property Item focusToPageContent property Component content: null clip: true - function changeToSearch() { + function changeToSearch(keyEvent) { if (appPageHeaderRoot.content === null) { - loader.item.state = "search"; + loader.item.changeToSearchState(keyEvent); } } @@ -50,6 +50,11 @@ Item { Item { id: root + function changeToSearchState(keyEvent) { + state = "search"; + searchInputBar.text = keyEvent; + } + state: "normal" states: [ State { @@ -128,7 +133,7 @@ Item { Layout.fillWidth: true Layout.fillHeight: true radius: 16 - keyDownTarget: focusToListView + changeFocusTarget: focusToPageContent onTextChanged: { if (text === "") { pluginSelectMenu.model.reactivateProvider(); @@ -145,6 +150,7 @@ Item { activeFocusOnTab: true onClicked: { + normalUI.focusToFalse(); searchInputBar.clear(); root.state = "normal"; } @@ -166,7 +172,7 @@ Item { anchors.fill: parent anchors.leftMargin: 16 spacing: 12 - Text { + AppControls2.StyleText { Layout.fillWidth: true Layout.fillHeight: true verticalAlignment: Qt.AlignVCenter @@ -178,6 +184,7 @@ Item { id: searchListView Layout.preferredWidth: childrenRect.width Layout.preferredHeight: 32 + Layout.minimumWidth: 32 Layout.maximumWidth: 68 Layout.alignment: Qt.AlignVCenter @@ -209,11 +216,25 @@ Item { Layout.preferredWidth: childrenRect.width Layout.preferredHeight: 32 Layout.maximumHeight: 32 + Layout.minimumWidth: 32 Layout.rightMargin: 8 Layout.alignment: Qt.AlignVCenter } } } + + function updateTitle(id) { + appPageHeaderRoot.title = appPageHeaderUtils.getPluginTitle(id); + } + + Component.onCompleted: { + updateTitle(""); + appPageHeaderUtils.pluginChanged.connect(updateTitle); + } + + Component.onDestruction: { + appPageHeaderUtils.pluginChanged.disconnect(updateTitle); + } } } } diff --git a/qml/AppUI/EditText.qml b/qml/AppUI/EditText.qml index 740a0de..8fa96c5 100644 --- a/qml/AppUI/EditText.qml +++ b/qml/AppUI/EditText.qml @@ -28,6 +28,7 @@ Item { property bool editStatus: false property string textEdited: title property bool isFullScreenFolder: false + property real textInputSize: 14 Component { id: unEditText @@ -39,12 +40,15 @@ Item { text: contain.textEdited paletteRole: isFullScreenFolder ? Palette.HighlightedText : Palette.Text font.bold: !isFullScreenFolder - font.pixelSize: isFullScreenFolder ? 32 : 14 + font.pointSize: isFullScreenFolder ? textUltra : systemFontSize MouseArea { id: textArea anchors.fill: parent - onDoubleClicked: contain.editStatus = true; + onDoubleClicked: { + contain.editStatus = true; + contain.textInputSize = textShow.font.pointSize; + } } } } @@ -74,7 +78,7 @@ Item { selectByMouse: true maximumLength: 14 font.bold: !isFullScreenFolder - font.pixelSize: isFullScreenFolder ? 32 : 14 + font.pointSize: contain.textInputSize onEditingFinished: { modelManager.getFolderModel().renameFolder(text); diff --git a/qml/AppUI/FullScreenContent.qml b/qml/AppUI/FullScreenContent.qml index c56736b..1942c33 100644 --- a/qml/AppUI/FullScreenContent.qml +++ b/qml/AppUI/FullScreenContent.qml @@ -266,7 +266,6 @@ RowLayout { anchors.bottomMargin: 20 anchors.horizontalCenter: parent.horizontalCenter text: name - font.pixelSize: 14 elide: Text.ElideRight paletteRole: Palette.HighlightedText } @@ -369,7 +368,6 @@ RowLayout { anchors.horizontalCenter: parent.horizontalCenter elide: Text.ElideRight text: name - font.pixelSize: 14 paletteRole: Palette.HighlightedText } } diff --git a/qml/AppUI/FullScreenFolder.qml b/qml/AppUI/FullScreenFolder.qml index 4b1c40a..a6faa27 100644 --- a/qml/AppUI/FullScreenFolder.qml +++ b/qml/AppUI/FullScreenFolder.qml @@ -268,7 +268,6 @@ Loader { anchors.topMargin: folderIconBase.iconSpacing anchors.horizontalCenter: parent.horizontalCenter text: name - font.pixelSize: 14 elide: Text.ElideRight paletteRole: Palette.HighlightedText } diff --git a/qml/AppUI/NormalUI.qml b/qml/AppUI/NormalUI.qml index 17b0630..87c355e 100644 --- a/qml/AppUI/NormalUI.qml +++ b/qml/AppUI/NormalUI.qml @@ -4,20 +4,21 @@ import AppControls2 1.0 as AppControls2 import org.ukui.menu.core 1.0 FocusScope { + id: normalUI anchors.fill: parent function focusToFalse() { focus = false; } function keyPressed(event) { // 任意字符键焦点切换到搜索(0-9 a-z) - if ((0x2f < event.key && event.key < 0x3a )||(0x40 < event.key && event.key < 0x5b)) { + if ((0x2f < event.key && event.key < 0x3a)||(0x40 < event.key && event.key < 0x5b)) { focus = true; - appPage.header.changeToSearch(); - // 任意方向键切换至搜索结果 - } else if ( 0x01000011 < event.key && event.key < 0x01000016) { + appPage.header.changeToSearch(event.text); + // 任意方向键切换至应用列表 + } else if ((0x01000011 < event.key)&&(event.key < 0x01000016)) { focus = true; - appPage.content.resetFocus(); appPage.content.focus = true; + appPage.content.resetFocus(); } } diff --git a/qml/AppUI/PluginSelectMenu.qml b/qml/AppUI/PluginSelectMenu.qml index 16ba4f8..01cdfec 100644 --- a/qml/AppUI/PluginSelectMenu.qml +++ b/qml/AppUI/PluginSelectMenu.qml @@ -28,6 +28,11 @@ RowLayout { id: pluginSelectMenuRoot property var model: appPageHeaderUtils.model(PluginGroup.SortMenuItem) spacing: 2 + function resetFocus() { + if(!mainWindow.isFullScreen) { + normalUI.focusToFalse(); + } + } AppControls2.RoundButton { id: pluginSelectButton @@ -39,7 +44,10 @@ RowLayout { highlight: mainWindow.isFullScreen autoHighLight: !mainWindow.isFullScreen buttonIcon: "image://appicon/ukui-selected" - onClicked: pluginSelectMenuRoot.model.autoSwitchProvider() + onClicked: { + resetFocus(); + pluginSelectMenuRoot.model.autoSwitchProvider(); + } Keys.onPressed: { if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { pluginSelectMenuRoot.model.autoSwitchProvider(); @@ -62,6 +70,7 @@ RowLayout { } } onClicked: { + resetFocus(); sortMenuClicked(); } function sortMenuClicked() { diff --git a/qml/AppUI/SearchInputBar.qml b/qml/AppUI/SearchInputBar.qml index a47a2ef..9415cef 100644 --- a/qml/AppUI/SearchInputBar.qml +++ b/qml/AppUI/SearchInputBar.qml @@ -23,8 +23,8 @@ import org.ukui.menu.core 1.0 import AppControls2 1.0 as AppControls2 AppControls2.StyleBackground { - property Item keyDownTarget - readonly property string text: textInput.text; + property Item changeFocusTarget + property alias text: textInput.text; alpha: 0.04 useStyleTransparent: false @@ -68,7 +68,6 @@ AppControls2.StyleBackground { anchors.left: searchIcon.right text: qsTr("Search App") visible: textInput.contentWidth === 0 - font.pixelSize: 14 paletteRole: mainWindow.isFullScreen ? Palette.HighlightedText : Palette.Text verticalAlignment: TextInput.AlignVCenter alpha: 0.25 @@ -96,11 +95,19 @@ AppControls2.StyleBackground { height: parent.height selectByMouse: true verticalAlignment: TextInput.AlignVCenter - font.pixelSize: 14 + font.pointSize: defaultText.font.pointSize focus: parent.visible || mainWindow.isFullScreen - KeyNavigation.down: keyDownTarget - onEditingFinished: KeyNavigation.down = keyDownTarget + activeFocusOnTab: true + function changeFocusToListView() { + if (!mainWindow.isFullScreen) { + normalUI.focus = true; + changeFocusTarget.focus = true; + appPage.content.resetFocus(); + } + } + onEditingFinished: changeFocusToListView() + Keys.onDownPressed: changeFocusToListView() //字体选中跟随主题高亮 property int textColor: mainWindow.isFullScreen ? Palette.HighlightedText : Palette.Text diff --git a/qml/AppUI/Sidebar.qml b/qml/AppUI/Sidebar.qml index c4fa80a..b017a68 100644 --- a/qml/AppUI/Sidebar.qml +++ b/qml/AppUI/Sidebar.qml @@ -99,6 +99,9 @@ Item { onLoaded: { item.send.connect(extensionListView.send); } + Keys.onTabPressed: { + extensionListView.focus = true + } } } @@ -170,6 +173,7 @@ Item { height: ListView.view ? ListView.view.height : 0 activeFocusOnTab: true + KeyNavigation.down: extensionLoader Keys.onPressed: { if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { ListView.view.currentIndex = model.index; @@ -194,7 +198,6 @@ Item { verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.bold: parent.ListView.isCurrentItem - wrapMode: Text.ElideRight paletteRole: parent.ListView.isCurrentItem ? Palette.Highlight: Palette.Text text: model.name @@ -203,6 +206,7 @@ Item { MouseArea { anchors.fill: parent onClicked: { + normalUI.focusToFalse(); parent.ListView.view.currentIndex = model.index; } } diff --git a/qml/extensions/FavoriteExtension.qml b/qml/extensions/FavoriteExtension.qml index 663a841..d1a0669 100644 --- a/qml/extensions/FavoriteExtension.qml +++ b/qml/extensions/FavoriteExtension.qml @@ -53,6 +53,38 @@ UkuiMenuExtension { property int exchangedStartIndex: 0 property int spacing: 4 property int itemHeight: 104 + property int column: Math.floor(width / cellWidth) + + // 按键导航处理(左右键可以循环) + focus: true + onActiveFocusChanged: currentIndex = 0 + onCountChanged: currentIndex = 0 + Keys.onRightPressed: { + if(currentIndex === count - 1) { + currentIndex = 0; + return; + } + currentIndex++; + } + Keys.onLeftPressed: { + if(currentIndex === 0) { + currentIndex = count - 1; + return; + } + currentIndex--; + } + Keys.onDownPressed: { + if(currentIndex > count - 1 - column) { + return; + } + currentIndex = currentIndex + column; + } + Keys.onUpPressed: { + if(currentIndex < column) { + return; + } + currentIndex = currentIndex - column; + } ScrollBar.vertical: AppControls2.ScrollBar { id: scrollBar @@ -73,16 +105,26 @@ UkuiMenuExtension { onEntered: { visualModel.items.move(drag.source.visualIndex, icon.visualIndex) } - Binding { target: icon; property: "visualIndex"; value: visualIndex } + focus: true + Keys.onReturnPressed: { + var data = {"id": model.id}; + send(data); + } + states: State { + when: delegateRoot.activeFocus + PropertyChanges { + target: icon + alpha: 0.6 + } + } AppControls2.StyleBackground { id: icon height: favoriteView.itemHeight; width: height property bool hold: false property int visualIndex: 0 x: 0; y: 0 - radius: 8 useStyleTransparent: false scale: icon.hold ? 1.1 :1.0 @@ -91,7 +133,6 @@ UkuiMenuExtension { Behavior on scale { NumberAnimation { duration: 300; easing.type: Easing.InOutCubic } } - AppControls2.IconLabel { height: icon.height width: icon.width - 14 diff --git a/src/appdata/app-data-manager.cpp b/src/appdata/app-data-manager.cpp index e1d2c98..81594e4 100644 --- a/src/appdata/app-data-manager.cpp +++ b/src/appdata/app-data-manager.cpp @@ -17,8 +17,11 @@ */ #include "app-data-manager.h" +#include "user-config.h" +#include "settings.h" #include +#include #define APP_ICON_PREFIX "image://appicon/" @@ -85,6 +88,13 @@ AppDataWorker::AppDataWorker(AppDataManager *appManager) : QObject(nullptr), m_a void AppDataWorker::initAppData() { + if (UserConfig::instance()->isFirstStartUp()) { + // 默认收藏应用 + for (const auto &appid : GlobalSetting::instance()->defaultFavoriteApps()) { + m_applicationInfo->setAppToFavorites(appid); + } + } + m_appProperties << UkuiSearch::ApplicationProperty::Property::Top << UkuiSearch::ApplicationProperty::Property::Lock << UkuiSearch::ApplicationProperty::Property::Favorites @@ -95,6 +105,7 @@ void AppDataWorker::initAppData() << UkuiSearch::ApplicationProperty::Property::Category << UkuiSearch::ApplicationProperty::Property::FirstLetterAll << UkuiSearch::ApplicationProperty::Property::DontDisplay + << UkuiSearch::ApplicationProperty::Property::AutoStart << UkuiSearch::ApplicationProperty::Property::InsertTime << UkuiSearch::ApplicationProperty::Property::Launched; m_appPropertyMap.insert(UkuiSearch::ApplicationProperty::Property::DontDisplay, 0); @@ -111,6 +122,7 @@ void AppDataWorker::initAppData() addInfoToApp(info, app); m_appManager->m_normalApps.insert(app.id(), app); } + updateFavoriteApps(); } @@ -158,13 +170,19 @@ void AppDataWorker::appendApps(const QStringList &infos, QList &apps { QMutexLocker locker(&m_appManager->m_mutex); for (const QString &info : infos) { - UkuiSearch::ApplicationPropertyMap appinfo = m_applicationInfo->getInfo(info, m_appProperties); - if (appinfo.value(UkuiSearch::ApplicationProperty::Property::DontDisplay).toInt() == 0) { - DataEntity app; - addInfoToApp(appinfo, app); - m_appManager->m_normalApps.insert(app.id(), app); - apps.append(app); + const UkuiSearch::ApplicationPropertyMap appInfo = m_applicationInfo->getInfo(info, m_appProperties); + if (appInfo.value(UkuiSearch::ApplicationProperty::Property::DontDisplay).toInt() != 0) { + continue; } + + if (appInfo.value(UkuiSearch::ApplicationProperty::Property::AutoStart).toInt() != 0) { + continue; + } + + DataEntity app; + addInfoToApp(appInfo, app); + m_appManager->m_normalApps.insert(app.id(), app); + apps.append(app); } } @@ -296,6 +314,11 @@ void AppDataWorker::onAppDeleted(QStringList infos) Q_EMIT appDeleted(removedIdList); updateFavoriteApps(); + + for (const auto &appid : removedIdList) { + UserConfig::instance()->removePreInstalledApp(appid); + } + UserConfig::instance()->sync(); } void AppDataWorker::fixToFavoriteSlot(const QString &path, const int &num) @@ -323,7 +346,9 @@ void AppDataWorker::fixToTopSlot(const QString &path, const int &num) void AppDataWorker::setAppLaunched(const QString &path) { - m_applicationInfo->setAppLaunchedState(path); + if (m_appManager->m_normalApps.value(path).launched() == 0) { + m_applicationInfo->setAppLaunchedState(path); + } } void AppDataWorker::removeApps(QStringList &appIdList, QStringList &removedIdList) diff --git a/src/appdata/app-data-manager.h b/src/appdata/app-data-manager.h index 03625e5..8e6ba77 100644 --- a/src/appdata/app-data-manager.h +++ b/src/appdata/app-data-manager.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "commons.h" diff --git a/src/appdata/data-provider-manager.cpp b/src/appdata/data-provider-manager.cpp index f5189cd..3a9ea2b 100644 --- a/src/appdata/data-provider-manager.cpp +++ b/src/appdata/data-provider-manager.cpp @@ -129,6 +129,24 @@ QVector DataProviderManager::providers(PluginGroup::Group group) c return infos; } +ProviderInfo DataProviderManager::providerInfo(const QString &id) const +{ + ProviderInfo info; + DataProviderPluginIFace* provider = m_providers.value(id, nullptr); + if (provider) { + info = { + provider->index(), + provider->id(), + provider->name(), + provider->icon(), + provider->title(), + provider->group() + }; + } + + return info; +} + void DataProviderManager::activateProvider(const QString &id) { if (!m_providers.contains(id) || m_activatedPlugin == id) { diff --git a/src/appdata/data-provider-manager.h b/src/appdata/data-provider-manager.h index 6c3e30a..10afb18 100644 --- a/src/appdata/data-provider-manager.h +++ b/src/appdata/data-provider-manager.h @@ -47,6 +47,7 @@ public: QStringList providers() const; QVector providers(PluginGroup::Group group) const; + ProviderInfo providerInfo(const QString &id) const; QString activatedProvider() const; void activateProvider(const QString &id); QVector data() const; diff --git a/src/appdata/plugin/all-app-data-provider.cpp b/src/appdata/plugin/all-app-data-provider.cpp index bdf2986..1dab92e 100644 --- a/src/appdata/plugin/all-app-data-provider.cpp +++ b/src/appdata/plugin/all-app-data-provider.cpp @@ -19,6 +19,7 @@ #include "all-app-data-provider.h" #include "app-data-manager.h" #include "app-folder-helper.h" +#include "user-config.h" #include #include @@ -60,7 +61,7 @@ QString AllAppDataProvider::icon() QString AllAppDataProvider::title() { - return "Recently installed"; + return tr("All applications"); } PluginGroup::Group AllAppDataProvider::group() @@ -151,6 +152,22 @@ void AllAppDataProvider::updateData(const QList &apps) std::sort(m_appData.begin(), m_appData.end(), appDataSort); } +void AllAppDataProvider::updateFolderData(QStringList &idList) +{ + QList folders = AppFolderHelper::instance()->folderData(); + if (folders.isEmpty()) { + return; + } + for (const auto &folder : folders) { + for (const auto &app : folder.getApps()) { + if (idList.contains(app)) { + AppFolderHelper::instance()->removeAppFromFolder(app, folder.getId()); + } + } + } + AppFolderHelper::instance()->forceSync(); +} + bool AllAppDataProvider::appDataSort(const DataEntity &a, const DataEntity &b) { if ((a.top() != 0) && (b.top() != 0)) { @@ -184,13 +201,15 @@ bool AllAppDataProvider::appDataSort(const DataEntity &a, const DataEntity &b) void AllAppDataProvider::setRecentState(DataEntity &app) { - if (app.launched() == 0) { - QDateTime installTime = QDateTime::fromString(app.insertTime(), "yyyy-MM-dd hh:mm:ss"); - if (installTime.isValid()) { - int appTime = installTime.secsTo(QDateTime::currentDateTime()); - if ((appTime >= 0 ) && (appTime <= 3600*48)) { - app.setRecentInstall(true); - return; + if (!UserConfig::instance()->isPreInstalledApps(app.id())) { + if (app.launched() == 0) { + QDateTime installTime = QDateTime::fromString(app.insertTime(), "yyyy-MM-dd hh:mm:ss"); + if (installTime.isValid()) { + int appTime = installTime.secsTo(QDateTime::currentDateTime()); + if ((appTime >= 0 ) && (appTime <= 3600*48)) { + app.setRecentInstall(true); + return; + } } } } @@ -234,6 +253,7 @@ void AllAppDataProvider::onAppDeleted(QStringList idList) { removeApps(idList); reloadFolderData(); + updateFolderData(idList); sendData(); } diff --git a/src/appdata/plugin/all-app-data-provider.h b/src/appdata/plugin/all-app-data-provider.h index 90ef01a..083d174 100644 --- a/src/appdata/plugin/all-app-data-provider.h +++ b/src/appdata/plugin/all-app-data-provider.h @@ -53,6 +53,7 @@ private: void reloadFolderData(); void mergeData(QVector &data); void updateData(const QList& apps); + void updateFolderData(QStringList& idList); static bool appDataSort(const DataEntity &a, const DataEntity &b); static void setRecentState(DataEntity &app); static bool letterSort(const QString &a, const QString &b); diff --git a/src/appdata/plugin/app-category-plugin.cpp b/src/appdata/plugin/app-category-plugin.cpp index 8228e42..62c4183 100644 --- a/src/appdata/plugin/app-category-plugin.cpp +++ b/src/appdata/plugin/app-category-plugin.cpp @@ -84,7 +84,7 @@ QString AppCategoryPlugin::icon() QString AppCategoryPlugin::title() { - return "Category"; + return tr("Category"); } PluginGroup::Group AppCategoryPlugin::group() diff --git a/src/menu/menu-manager.cpp b/src/menu/menu-manager.cpp index ebc0737..e3fa060 100644 --- a/src/menu/menu-manager.cpp +++ b/src/menu/menu-manager.cpp @@ -19,6 +19,7 @@ #include "menu-manager.h" #include "app-manager.h" #include "app-data-manager.h" +#include "settings.h" #include #include @@ -49,18 +50,11 @@ private: void addToPanelAction(QObject *parent, const QString &appId, QList &list); void addToDesktopAction(QObject *parent, const QString &appId, QList &list); void addUninstall(QObject *parent, const QString &appId, QList &list); -private: - QStringList m_systemApps; }; AppMenuProvider::AppMenuProvider() { - if (QFile::exists(UKUI_MENU_GLOBAL_CONFIG_FILE)) { - QSettings settings(UKUI_MENU_GLOBAL_CONFIG_FILE, QSettings::IniFormat); - settings.beginGroup("System Apps"); - m_systemApps.append(settings.allKeys()); - settings.endGroup(); - } + } bool AppMenuProvider::isSupport(const MenuProvider::RequestType &type) @@ -180,9 +174,7 @@ void AppMenuProvider::addToDesktopAction(QObject *parent, const QString &appId, void AppMenuProvider::addUninstall(QObject *parent, const QString &appId, QList &list) { - bool isSystemApp = std::any_of(m_systemApps.constBegin(), m_systemApps.constEnd(), [&appId](const QString &appName) { - return appId.contains(appName); - }); + bool isSystemApp = GlobalSetting::instance()->isSystemApp(appId); if (!isSystemApp) { list << new QAction(QObject::tr("Uninstall"), parent); //QIcon::fromTheme("edit-delete-symbolic") QObject::connect(list.last(), &QAction::triggered, parent, [appId] { diff --git a/src/settings/settings.cpp b/src/settings/settings.cpp index 5290be4..9d08987 100644 --- a/src/settings/settings.cpp +++ b/src/settings/settings.cpp @@ -30,6 +30,7 @@ #define UKUI_STYLE_SCHEMA "org.ukui.style" #define UKUI_STYLE_NAME_KEY "styleName" #define UKUI_STYLE_THEME_COLOR_KEY "themeColor" +#define UKUI_STYLE_SYSTEM_FONT_SIZE "systemFontSize" namespace UkuiMenu { @@ -48,12 +49,14 @@ GlobalSetting *GlobalSetting::instance() GlobalSetting::GlobalSetting(QObject *parent) : QObject(parent) { initStyleSetting(); + initGlobalSettings(); } void GlobalSetting::initStyleSetting() { m_cache.insert(StyleName, UKUI_STYLE_VALUE_LIGHT); m_cache.insert(ThemeColor, UKUI_STYLE_THEME_COLOR_KEY); + m_cache.insert(SystemFontSize, UKUI_STYLE_SYSTEM_FONT_SIZE); m_cache.insert(Transparency, 1); m_cache.insert(EffectEnabled, false); @@ -67,7 +70,9 @@ void GlobalSetting::initStyleSetting() if (keys.contains(UKUI_STYLE_THEME_COLOR_KEY)) { m_cache.insert(ThemeColor,settings->get(UKUI_STYLE_THEME_COLOR_KEY)); } - + if (keys.contains(UKUI_STYLE_SYSTEM_FONT_SIZE)) { + m_cache.insert(SystemFontSize,settings->get(UKUI_STYLE_SYSTEM_FONT_SIZE)); + } connect(settings, &QGSettings::changed, this, [this, settings] (const QString &key) { if (key == UKUI_STYLE_NAME_KEY) { updateData(StyleName, settings->get(key)); @@ -75,6 +80,9 @@ void GlobalSetting::initStyleSetting() } else if (key == UKUI_STYLE_THEME_COLOR_KEY) { updateData(ThemeColor, settings->get(key)); Q_EMIT styleChanged(ThemeColor); + } else if (key == UKUI_STYLE_SYSTEM_FONT_SIZE) { + updateData(SystemFontSize, settings->get(key)); + Q_EMIT styleChanged(SystemFontSize); } }); } @@ -115,6 +123,47 @@ void GlobalSetting::updateData(const GlobalSetting::Key &key, const QVariant &va m_cache.insert(key, value); } +bool GlobalSetting::isSystemApp(const QString &appid) const +{ + return std::any_of(m_systemApps.constBegin(), m_systemApps.constEnd(), [&appid](const QString &appName) { + return appid.contains(appName); + }); +} + +QStringList GlobalSetting::systemApps() const +{ + return m_systemApps; +} + +bool GlobalSetting::isDefaultFavoriteApp(const QString &appid) const +{ + return std::any_of(m_defaultFavoriteApps.constBegin(), m_defaultFavoriteApps.constEnd(), [&appid](const QString &id) { + return appid == id; + }); +} + +QStringList GlobalSetting::defaultFavoriteApps() const +{ + return m_defaultFavoriteApps; +} + +void GlobalSetting::initGlobalSettings() +{ + if (QFile::exists(UKUI_MENU_GLOBAL_CONFIG_FILE)) { + QSettings settings(UKUI_MENU_GLOBAL_CONFIG_FILE, QSettings::IniFormat); + settings.beginGroup("System Apps"); + m_systemApps.append(settings.allKeys()); + settings.endGroup(); + + //= + settings.beginGroup("Default Favorite Apps"); + for (const auto &key : settings.allKeys()) { + m_defaultFavoriteApps.append(settings.value(key).toString()); + } + settings.endGroup(); + } +} + MenuSetting *MenuSetting::instance() { static MenuSetting setting(nullptr); diff --git a/src/settings/settings.h b/src/settings/settings.h index 30994f2..5bf4cc3 100644 --- a/src/settings/settings.h +++ b/src/settings/settings.h @@ -53,7 +53,8 @@ public: StyleName, ThemeColor, Transparency, - EffectEnabled + EffectEnabled, + SystemFontSize }; Q_ENUM(Key) @@ -64,17 +65,26 @@ public: QVariant get(const GlobalSetting::Key& key); + bool isSystemApp(const QString &appid) const; + QStringList systemApps() const; + + bool isDefaultFavoriteApp(const QString &appid) const; + QStringList defaultFavoriteApps() const; + Q_SIGNALS: void styleChanged(const GlobalSetting::Key& key); private: explicit GlobalSetting(QObject *parent = nullptr); void initStyleSetting(); + void initGlobalSettings(); void updateData(const GlobalSetting::Key& key, const QVariant &value); private: QMutex mutex; QMap m_cache; + QStringList m_systemApps; + QStringList m_defaultFavoriteApps; }; class MenuSetting : public QObject diff --git a/src/settings/user-config.cpp b/src/settings/user-config.cpp new file mode 100644 index 0000000..de211a9 --- /dev/null +++ b/src/settings/user-config.cpp @@ -0,0 +1,185 @@ +/* + * 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 "user-config.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PRE_INSTALLED_APPS_KEY "PreInstalledApps" + +namespace UkuiMenu { + +const QString UserConfig::configFilePath = QDir::homePath() + "/.config/ukui-menu/"; +const QString UserConfig::configFileName = "config.json"; + +UserConfig *UserConfig::instance() +{ + static UserConfig userConfig; + return &userConfig; +} + +UserConfig::UserConfig(QObject *parent) : QObject(parent) +{ + init(); +} + +bool UserConfig::isFirstStartUp() const +{ + return m_isFirstStartUp; +} + +void UserConfig::init() +{ + QFile configFile(configFilePath + configFileName); + if ((m_isFirstStartUp = !configFile.exists())) { + if (!QDir(configFilePath).exists() && !QDir().mkdir(configFilePath)) { + qWarning() << "Could not create the user profile directory"; + return; + } + + initConfigFile(); + return; + } + + // read + readConfigFile(); +} + +void UserConfig::initConfigFile() +{ + QFile configFile(configFilePath + configFileName); + configFile.open(QFile::WriteOnly); + configFile.close(); + + // 已安装应用 + QStringList defaultPaths; + defaultPaths << "/usr/share/applications/"; + defaultPaths << QDir::homePath() + "/.local/share/applications/"; + + for (const auto &path : defaultPaths) { + QDir dir(path); + QStringList desktopFiles = dir.entryList(QStringList() << "*.desktop", QDir::Files); + for (const auto &desktopFile : desktopFiles) { + m_preInstalledApps.insert(path + desktopFile); + } + } + + sync(); +} + +void UserConfig::sync() +{ + writeConfigFile(); +} + +QSet UserConfig::preInstalledApps() const +{ + return m_preInstalledApps; +} + +void UserConfig::addPreInstalledApp(const QString &appid) +{ + QMutexLocker mutexLocker(&m_mutex); + m_preInstalledApps.insert(appid); +} + +bool UserConfig::isPreInstalledApps(const QString &appid) const +{ + return m_preInstalledApps.contains(appid); +} + +void UserConfig::removePreInstalledApp(const QString &appid) +{ + QMutexLocker mutexLocker(&m_mutex); + m_preInstalledApps.remove(appid); +} + +void UserConfig::readConfigFile() +{ + { + QMutexLocker locker(&m_mutex); + m_preInstalledApps.clear(); + } + + QFile file(configFilePath + configFileName); + if (!file.open(QFile::ReadOnly)) { + return; + } + + QByteArray byteArray = file.readAll(); + file.close(); + + QJsonDocument jsonDocument(QJsonDocument::fromJson(byteArray)); + if (jsonDocument.isNull() || jsonDocument.isEmpty() || !jsonDocument.isArray()) { + qWarning() << "UserConfig: Incorrect configuration files are ignored."; + return; + } + + QJsonArray jsonArray = jsonDocument.array(); + for (const auto &value : jsonArray) { + QJsonObject object = value.toObject(); + // 预装app + if (object.contains(PRE_INSTALLED_APPS_KEY)) { + QJsonArray apps = object.value(QLatin1String(PRE_INSTALLED_APPS_KEY)).toArray(); + for (const auto &app : apps) { + m_preInstalledApps.insert(app.toString()); + } + } + } +} + +void UserConfig::writeConfigFile() +{ + QFile file(configFilePath + configFileName); + if (!file.open(QFile::WriteOnly)) { + return; + } + + QJsonDocument jsonDocument; + QJsonArray configArray; + + { + // preInstalledApps + QMutexLocker locker(&m_mutex); + QJsonObject preInstalledAppsObject; + + QJsonArray apps; + for (const auto &appid : m_preInstalledApps) { + apps.append(appid); + } + + preInstalledAppsObject.insert(PRE_INSTALLED_APPS_KEY, apps); + configArray.append(preInstalledAppsObject); + } + + jsonDocument.setArray(configArray); + + if (file.write(jsonDocument.toJson()) == -1) { + qWarning() << "Error saving configuration file."; + } + file.flush(); + file.close(); +} + +} // UkuiMenu diff --git a/src/settings/user-config.h b/src/settings/user-config.h new file mode 100644 index 0000000..1d0a7ca --- /dev/null +++ b/src/settings/user-config.h @@ -0,0 +1,64 @@ +/* + * 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_USER_CONFIG_H +#define UKUI_MENU_USER_CONFIG_H + +#include +#include +#include +#include + +namespace UkuiMenu { + +class UserConfig : public QObject +{ + Q_OBJECT +public: + static const QString configFilePath; + static const QString configFileName; + + static UserConfig *instance(); + + bool isFirstStartUp() const; + + QSet preInstalledApps() const; + void addPreInstalledApp(const QString &appid); + void removePreInstalledApp(const QString &appid); + bool isPreInstalledApps(const QString &appid) const; + + void sync(); + +private: + explicit UserConfig(QObject *parent=nullptr); + + void init(); + void initConfigFile(); + void readConfigFile(); + void writeConfigFile(); + +private: + bool m_isFirstStartUp {false}; + QMutex m_mutex; + + QSet m_preInstalledApps; +}; + +} // UkuiMenu + +#endif //UKUI_MENU_USER_CONFIG_H diff --git a/src/uiconfig/theme-palette.cpp b/src/uiconfig/theme-palette.cpp index e436ec8..05bb1a9 100644 --- a/src/uiconfig/theme-palette.cpp +++ b/src/uiconfig/theme-palette.cpp @@ -188,7 +188,9 @@ void ThemePalette::initStyleSetting() { GlobalSetting *setting = GlobalSetting::instance(); m_transparency = setting->get(GlobalSetting::Transparency).toReal(); + m_fontSize = setting->get(GlobalSetting::SystemFontSize).toReal(); connect(setting, &GlobalSetting::styleChanged, this, &ThemePalette::styleChangedSlot); + connect(setting, &GlobalSetting::styleChanged, this, &ThemePalette::systemFontSizeChangedSlot); } void ThemePalette::styleChangedSlot(const GlobalSetting::Key& key) @@ -199,3 +201,17 @@ void ThemePalette::styleChangedSlot(const GlobalSetting::Key& key) Q_EMIT styleColorChanged(); } + +void ThemePalette::systemFontSizeChangedSlot(const GlobalSetting::Key &key) +{ + if (key & GlobalSetting::SystemFontSize) { + m_fontSize = GlobalSetting::instance()->get(GlobalSetting::SystemFontSize).toReal(); + } + + Q_EMIT systemFontSizeChanged(); +} + +qreal ThemePalette::systemFontSize() const +{ + return m_fontSize; +} diff --git a/src/uiconfig/theme-palette.h b/src/uiconfig/theme-palette.h index d26c7d0..a558546 100644 --- a/src/uiconfig/theme-palette.h +++ b/src/uiconfig/theme-palette.h @@ -92,11 +92,15 @@ public: Q_INVOKABLE QColor highlightedText(Palette::ColorGroup colorGroup = Palette::Active) const; Q_INVOKABLE QColor separator(Palette::ColorGroup colorGroup = Palette::Active) const; + Q_INVOKABLE qreal systemFontSize() const; + Q_SIGNALS: void styleColorChanged(); + void systemFontSizeChanged(); private Q_SLOTS: void styleChangedSlot(const GlobalSetting::Key& key); + void systemFontSizeChangedSlot(const GlobalSetting::Key& key); private: explicit ThemePalette(QObject *parent = nullptr); @@ -105,6 +109,7 @@ private: private: qreal m_transparency = 1.0; + qreal m_fontSize = 12; }; } diff --git a/src/utils/app-manager.cpp b/src/utils/app-manager.cpp index 72502fc..abef7ff 100644 --- a/src/utils/app-manager.cpp +++ b/src/utils/app-manager.cpp @@ -50,6 +50,8 @@ AppManager::AppManager(QObject *parent) : QObject(parent) bool AppManager::launchApp(const QString &desktopFilePath) { Q_EMIT request(UkuiMenuApplication::Hide); + AppDataManager::instance()->appLaunch(desktopFilePath); + if (launchAppWithDBus(desktopFilePath)) { return true; } @@ -78,11 +80,6 @@ bool AppManager::launchBinaryApp(const QString &app, const QString &args) return QProcess::startDetached(cmd); } -void AppManager::appLaunched(const QString &desktopFilePath) -{ - AppDataManager::instance()->appLaunch(desktopFilePath); -} - bool AppManager::launchAppWithDBus(const QString &app) { if (!m_appManagerDbusInterface) { diff --git a/src/utils/app-manager.h b/src/utils/app-manager.h index 7a26d85..028ff55 100644 --- a/src/utils/app-manager.h +++ b/src/utils/app-manager.h @@ -35,7 +35,6 @@ public: Q_INVOKABLE bool launchApp(const QString &desktopFilePath); Q_INVOKABLE bool launchBinaryApp(const QString &app, const QString &args = QString()); - Q_INVOKABLE void appLaunched(const QString &desktopFilePath); private: explicit AppManager(QObject *parent = nullptr); diff --git a/src/utils/app-page-header-utils.cpp b/src/utils/app-page-header-utils.cpp index 4ee6940..0a6d86d 100644 --- a/src/utils/app-page-header-utils.cpp +++ b/src/utils/app-page-header-utils.cpp @@ -196,24 +196,42 @@ AppPageHeaderUtils::AppPageHeaderUtils(QObject *parent) : QObject(parent) void AppPageHeaderUtils::onPluginChanged(const QString &id, PluginGroup::Group group) { - m_models.value(group)->updateCurrentPId(id); + ProviderModel *model = m_models.value(group); + if (model) { + model->updateCurrentPId(id); + Q_EMIT pluginChanged(id); + } } -ProviderModel *AppPageHeaderUtils::model(PluginGroup::Group group) +ProviderModel *AppPageHeaderUtils::model(PluginGroup::Group group) const { return m_models.value(group); } -void AppPageHeaderUtils::activateProvider(const QString &name) +void AppPageHeaderUtils::activateProvider(const QString &name) const { DataProviderManager::instance()->activateProvider(name); } -void AppPageHeaderUtils::startSearch(QString key) +void AppPageHeaderUtils::startSearch(QString key) const { DataProviderManager::instance()->forceUpdate(key); } +QString AppPageHeaderUtils::getPluginTitle(QString id) const +{ + if (id.isEmpty()) { + id = DataProviderManager::instance()->activatedProvider(); + } + + return DataProviderManager::instance()->providerInfo(id).title; +} + +QString AppPageHeaderUtils::currentPluginId() const +{ + return DataProviderManager::instance()->activatedProvider(); +} + } // UkuiMenu #include "app-page-header-utils.moc" diff --git a/src/utils/app-page-header-utils.h b/src/utils/app-page-header-utils.h index 1e51cb8..f6c87af 100644 --- a/src/utils/app-page-header-utils.h +++ b/src/utils/app-page-header-utils.h @@ -35,11 +35,16 @@ public: explicit AppPageHeaderUtils(QObject *parent = nullptr); // 激活某插件 - Q_INVOKABLE void activateProvider(const QString &name); + Q_INVOKABLE void activateProvider(const QString &name) const; // 获取不同的model - Q_INVOKABLE ProviderModel *model(PluginGroup::Group group); + Q_INVOKABLE ProviderModel *model(PluginGroup::Group group) const; - Q_INVOKABLE void startSearch(QString key); + Q_INVOKABLE void startSearch(QString key) const; + Q_INVOKABLE QString getPluginTitle(QString id) const; + Q_INVOKABLE QString currentPluginId() const; + +Q_SIGNALS: + void pluginChanged(const QString &id); private Q_SLOTS: void onPluginChanged(const QString &id, PluginGroup::Group group); diff --git a/translations/ukui-menu_bo_CN.ts b/translations/ukui-menu_bo_CN.ts index 67f25f2..aa0dac7 100644 --- a/translations/ukui-menu_bo_CN.ts +++ b/translations/ukui-menu_bo_CN.ts @@ -88,6 +88,10 @@ All + + All applications + + UkuiMenu::AppCategoryPlugin diff --git a/translations/ukui-menu_zh_CN.ts b/translations/ukui-menu_zh_CN.ts index 6bf9f0b..e13df9c 100644 --- a/translations/ukui-menu_zh_CN.ts +++ b/translations/ukui-menu_zh_CN.ts @@ -96,11 +96,17 @@ All 所有应用 + + All applications + 所有应用 + 所有应用 + UkuiMenu::AppCategoryPlugin Category + 功能排序 功能排序