Merge tag 'upstream/4.0.0.2' into openkylin/yangtze

4.0.0.2-release
This commit is contained in:
hewenfei 2023-05-24 17:58:32 +08:00
commit 375eaf0db9
39 changed files with 634 additions and 98 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -66,7 +66,6 @@ Item {
StyleText {
id: iconText
text: root.appName
font.pixelSize: 14
elide: Text.ElideRight
paletteRole: root.textHighLight ? Palette.HighlightedText : Palette.Text
}

View File

@ -30,7 +30,6 @@ MouseArea {
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
font.pixelSize: 14
font.bold: true
text: name
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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

View File

@ -37,7 +37,7 @@ AppControls2.StyleBackground {
id: appPageHeader
Layout.fillWidth: true
Layout.preferredHeight: 40
focusToListView: appPageContent
focusToPageContent: appPageContent
}
AppPageContent {

View File

@ -44,6 +44,9 @@ SwipeView {
appList.visible = false;
selectionPage.viewShowStart();
}
onTitleChanged: {
appPageHeader.title = title;
}
}
SelectionPage {

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -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
}
}

View File

@ -268,7 +268,6 @@ Loader {
anchors.topMargin: folderIconBase.iconSpacing
anchors.horizontalCenter: parent.horizontalCenter
text: name
font.pixelSize: 14
elide: Text.ElideRight
paletteRole: Palette.HighlightedText
}

View File

@ -4,6 +4,7 @@ import AppControls2 1.0 as AppControls2
import org.ukui.menu.core 1.0
FocusScope {
id: normalUI
anchors.fill: parent
function focusToFalse() {
focus = false;
@ -12,12 +13,12 @@ FocusScope {
// 0-9 a-z
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();
}
}

View File

@ -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() {

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -17,8 +17,11 @@
*/
#include "app-data-manager.h"
#include "user-config.h"
#include "settings.h"
#include <application-info.h>
#include <QDebug>
#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,15 +170,21 @@ void AppDataWorker::appendApps(const QStringList &infos, QList<DataEntity> &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) {
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);
addInfoToApp(appInfo, app);
m_appManager->m_normalApps.insert(app.id(), app);
apps.append(app);
}
}
}
void AppDataWorker::addInfoToApp(const UkuiSearch::ApplicationPropertyMap &info, DataEntity &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,8 +346,10 @@ void AppDataWorker::fixToTopSlot(const QString &path, const int &num)
void AppDataWorker::setAppLaunched(const QString &path)
{
if (m_appManager->m_normalApps.value(path).launched() == 0) {
m_applicationInfo->setAppLaunchedState(path);
}
}
void AppDataWorker::removeApps(QStringList &appIdList, QStringList &removedIdList)
{

View File

@ -26,6 +26,7 @@
#include <QMutexLocker>
#include <QList>
#include <QMap>
#include <QSet>
#include "commons.h"

View File

@ -129,6 +129,24 @@ QVector<ProviderInfo> 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) {

View File

@ -47,6 +47,7 @@ public:
QStringList providers() const;
QVector<ProviderInfo> providers(PluginGroup::Group group) const;
ProviderInfo providerInfo(const QString &id) const;
QString activatedProvider() const;
void activateProvider(const QString &id);
QVector<DataEntity> data() const;

View File

@ -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 <QDebug>
#include <QDateTime>
@ -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<DataEntity> &apps)
std::sort(m_appData.begin(), m_appData.end(), appDataSort);
}
void AllAppDataProvider::updateFolderData(QStringList &idList)
{
QList<Folder> 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,6 +201,7 @@ bool AllAppDataProvider::appDataSort(const DataEntity &a, const DataEntity &b)
void AllAppDataProvider::setRecentState(DataEntity &app)
{
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()) {
@ -194,6 +212,7 @@ void AllAppDataProvider::setRecentState(DataEntity &app)
}
}
}
}
app.setRecentInstall(false);
}
@ -234,6 +253,7 @@ void AllAppDataProvider::onAppDeleted(QStringList idList)
{
removeApps(idList);
reloadFolderData();
updateFolderData(idList);
sendData();
}

View File

@ -53,6 +53,7 @@ private:
void reloadFolderData();
void mergeData(QVector<DataEntity> &data);
void updateData(const QList<DataEntity>& 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);

View File

@ -84,7 +84,7 @@ QString AppCategoryPlugin::icon()
QString AppCategoryPlugin::title()
{
return "Category";
return tr("Category");
}
PluginGroup::Group AppCategoryPlugin::group()

View File

@ -19,6 +19,7 @@
#include "menu-manager.h"
#include "app-manager.h"
#include "app-data-manager.h"
#include "settings.h"
#include <QMenu>
#include <QCursor>
@ -49,18 +50,11 @@ private:
void addToPanelAction(QObject *parent, const QString &appId, QList<QAction *> &list);
void addToDesktopAction(QObject *parent, const QString &appId, QList<QAction *> &list);
void addUninstall(QObject *parent, const QString &appId, QList<QAction *> &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<QAction *> &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] {

View File

@ -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);

View File

@ -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<GlobalSetting::Key, QVariant> m_cache;
QStringList m_systemApps;
QStringList m_defaultFavoriteApps;
};
class MenuSetting : public QObject

View File

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#include "user-config.h"
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QMutexLocker>
#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<QString> 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

View File

@ -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 <https://www.gnu.org/licenses/>.
*
*/
#ifndef UKUI_MENU_USER_CONFIG_H
#define UKUI_MENU_USER_CONFIG_H
#include <QSet>
#include <QVector>
#include <QObject>
#include <QMutex>
namespace UkuiMenu {
class UserConfig : public QObject
{
Q_OBJECT
public:
static const QString configFilePath;
static const QString configFileName;
static UserConfig *instance();
bool isFirstStartUp() const;
QSet<QString> 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<QString> m_preInstalledApps;
};
} // UkuiMenu
#endif //UKUI_MENU_USER_CONFIG_H

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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) {

View File

@ -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);

View File

@ -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"

View File

@ -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);

View File

@ -88,6 +88,10 @@
<source>All</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>All applications</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UkuiMenu::AppCategoryPlugin</name>

View File

@ -96,11 +96,17 @@
<source>All</source>
<translation></translation>
</message>
<message>
<source>All applications</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
</context>
<context>
<name>UkuiMenu::AppCategoryPlugin</name>
<message>
<source>Category</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
<message>