diff --git a/CMakeLists.txt b/CMakeLists.txt index f803d56..ca71715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,66 +1,65 @@ project(plasma-phone-components) # minimal requirements cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR) set (QT_MIN_VERSION "5.12.0") set(KF5_MIN_VERSION "5.70.0") set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 14) find_package(ECM 5.41.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMOptionalAddSubdirectory) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMMarkNonGuiExecutable) include(ECMGenerateHeaders) include(GenerateExportHeader) include(FeatureSummary) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED Core Qml Quick) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS I18n KIO Plasma PlasmaQuick Service Notifications - WindowSystem ) find_package(KF5Wayland CONFIG) set_package_properties(KF5Wayland PROPERTIES TYPE REQUIRED PURPOSE "Required for interacting with the compositor") # torch find_package(GStreamer 1.1.90 REQUIRED) find_package(GLIB2 REQUIRED) find_package(GObject REQUIRED) include(CheckIncludeFiles) plasma_install_package(look-and-feel org.kde.plasma.phone look-and-feel) plasma_install_package(shell org.kde.plasma.phone shells) install(DIRECTORY wallpaper/ DESTINATION "${WALLPAPER_INSTALL_DIR}/org.kde.plasma.phone.lockers") install( DIRECTORY kwinmultitasking/ DESTINATION ${DATA_INSTALL_DIR}/kwin/scripts/org.kde.phone.multitasking ) install( FILES kwinmultitasking/metadata.desktop DESTINATION ${SERVICES_INSTALL_DIR} RENAME kwin-script-org.kde.phone.multitasking.desktop ) install( DIRECTORY qtvirtualkeyboardplugin/ DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/VirtualKeyboard/Styles/Plasma ) add_subdirectory(bin) add_subdirectory(applets) add_subdirectory(containments) add_subdirectory(sounds) #add_subdirectory(touchscreentest) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/containments/homescreen/CMakeLists.txt b/containments/homescreen/CMakeLists.txt index 7d4cb99..944cca6 100644 --- a/containments/homescreen/CMakeLists.txt +++ b/containments/homescreen/CMakeLists.txt @@ -1,26 +1,26 @@ set(homescreen_SRCS homescreen.cpp applicationlistmodel.cpp + colouraverage.cpp ) add_library(plasma_containment_phone_homescreen MODULE ${homescreen_SRCS}) kcoreaddons_desktop_to_json(plasma_containment_phone_homescreen package/metadata.desktop) target_link_libraries(plasma_containment_phone_homescreen Qt5::Gui KF5::Plasma Qt5::Qml Qt5::Quick KF5::I18n KF5::Service KF5::KIOGui KF5::Notifications - KF5::WindowSystem ) install(TARGETS plasma_containment_phone_homescreen DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/applets) plasma_install_package(package org.kde.phone.homescreen) diff --git a/containments/homescreen/applicationlistmodel.cpp b/containments/homescreen/applicationlistmodel.cpp index 5f2bdfc..6316558 100644 --- a/containments/homescreen/applicationlistmodel.cpp +++ b/containments/homescreen/applicationlistmodel.cpp @@ -1,388 +1,368 @@ /* * Copyright (C) 2014 Antonis Tsiapaliokas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Self #include "applicationlistmodel.h" // Qt #include #include #include #include // KDE #include #include #include #include #include #include #include constexpr int MAX_FAVOURITES = 5; ApplicationListModel::ApplicationListModel(HomeScreen *parent) : QAbstractListModel(parent), - m_homeScreen(parent), - m_startupInfo(new KStartupInfo(0, this)) + m_homeScreen(parent) { connect(KSycoca::self(), qOverload(&KSycoca::databaseChanged), this, &ApplicationListModel::sycocaDbChanged); - connect(m_startupInfo, &KStartupInfo::gotRemoveStartup, - this, &ApplicationListModel::applicationExited); - - connect(m_startupInfo, &KStartupInfo::gotNewStartup, - this, [=](const KStartupInfoId &, const KStartupInfoData &data) { - applicationStarted(data.name(), data.icon()); - }); - loadSettings(); - - // Debug - connect(this, &ApplicationListModel::applicationStarted, this, [=](const QString &name, const QString &icon) { - qDebug() << "Opening startup feedback for" << name << icon; - }); - - connect(this, &ApplicationListModel::applicationExited, this, []() { - qDebug() << "Removing startup feedback"; - }); - } ApplicationListModel::~ApplicationListModel() = default; void ApplicationListModel::loadSettings() { m_favorites = m_homeScreen->config().readEntry("Favorites", QStringList()); #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) const auto di = m_homeScreen->config().readEntry("DesktopItems", QStringList()); m_desktopItems = QSet(di.begin(), di.end()); #else m_desktopItems = m_homeScreen->config().readEntry("DesktopItems", QStringList()).toSet(); #endif m_appOrder = m_homeScreen->config().readEntry("AppOrder", QStringList()); m_maxFavoriteCount = m_homeScreen->config().readEntry("MaxFavoriteCount", MAX_FAVOURITES); int i = 0; for (const QString &app : qAsConst(m_appOrder)) { m_appPositions[app] = i; ++i; } loadApplications(); } QHash ApplicationListModel::roleNames() const { return { {ApplicationNameRole, QByteArrayLiteral("applicationName")}, {ApplicationIconRole, QByteArrayLiteral("applicationIcon")}, {ApplicationStorageIdRole, QByteArrayLiteral("applicationStorageId")}, {ApplicationEntryPathRole, QByteArrayLiteral("applicationEntryPath")}, {ApplicationOriginalRowRole, QByteArrayLiteral("applicationOriginalRow")}, {ApplicationStartupNotifyRole, QByteArrayLiteral("applicationStartupNotify")}, {ApplicationLocationRole, QByteArrayLiteral("applicationLocation")} }; } void ApplicationListModel::sycocaDbChanged(const QStringList &changes) { if (!changes.contains(QStringLiteral("apps")) && !changes.contains(QStringLiteral("xdgdata-apps"))) { return; } m_applicationList.clear(); loadApplications(); } bool appNameLessThan(const ApplicationData &a1, const ApplicationData &a2) { return a1.name.toLower() < a2.name.toLower(); } void ApplicationListModel::loadApplications() { auto cfg = KSharedConfig::openConfig(QStringLiteral("applications-blacklistrc")); auto blgroup = KConfigGroup(cfg, QStringLiteral("Applications")); // This is only temporary to get a clue what those apps' desktop files are called // I'll remove it once I've done a blacklist QStringList bl; QStringList blacklist = blgroup.readEntry("blacklist", QStringList()); beginResetModel(); m_applicationList.clear(); KServiceGroup::Ptr group = KServiceGroup::root(); - if (!group || !group->isValid()) - return; + if (!group || !group->isValid()) return; KServiceGroup::List subGroupList = group->entries(true); QMap orderedList; QList unorderedList; // Iterate over all entries in the group while (!subGroupList.isEmpty()) { KSycocaEntry::Ptr groupEntry = subGroupList.first(); subGroupList.pop_front(); if (groupEntry->isType(KST_KServiceGroup)) { KServiceGroup::Ptr serviceGroup(static_cast(groupEntry.data())); if (!serviceGroup->noDisplay()) { KServiceGroup::List entryGroupList = serviceGroup->entries(true); for(KServiceGroup::List::ConstIterator it = entryGroupList.constBegin(); it != entryGroupList.constEnd(); it++) { KSycocaEntry::Ptr entry = (*it); if (entry->isType(KST_KServiceGroup)) { KServiceGroup::Ptr serviceGroup(static_cast(entry.data())); subGroupList << serviceGroup; } else if (entry->property(QStringLiteral("Exec")).isValid()) { KService::Ptr service(static_cast(entry.data())); if (service->isApplication() && !blacklist.contains(service->desktopEntryName()) && service->showOnCurrentPlatform() && !service->property(QStringLiteral("Terminal"), QVariant::Bool).toBool()) { bl << service->desktopEntryName(); ApplicationData data; data.name = service->name(); data.icon = service->icon(); data.storageId = service->storageId(); data.entryPath = service->exec(); data.startupNotify = service->property(QStringLiteral("StartupNotify")).toBool(); if (m_favorites.contains(data.storageId)) { data.location = Favorites; } else if (m_desktopItems.contains(data.storageId)) { data.location = Desktop; } auto it = m_appPositions.constFind(service->storageId()); if (it != m_appPositions.constEnd()) { orderedList[*it] = data; } else { unorderedList << data; } } } } } } } blgroup.writeEntry("allapps", bl); blgroup.writeEntry("blacklist", blacklist); cfg->sync(); std::sort(unorderedList.begin(), unorderedList.end(), appNameLessThan); m_applicationList << orderedList.values(); m_applicationList << unorderedList; endResetModel(); emit countChanged(); } QVariant ApplicationListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } switch (role) { case Qt::DisplayRole: case ApplicationNameRole: return m_applicationList.at(index.row()).name; case ApplicationIconRole: return m_applicationList.at(index.row()).icon; case ApplicationStorageIdRole: return m_applicationList.at(index.row()).storageId; case ApplicationEntryPathRole: return m_applicationList.at(index.row()).entryPath; case ApplicationOriginalRowRole: return index.row(); case ApplicationStartupNotifyRole: return m_applicationList.at(index.row()).startupNotify; case ApplicationLocationRole: return m_applicationList.at(index.row()).location; default: return QVariant(); } } Qt::ItemFlags ApplicationListModel::flags(const QModelIndex &index) const { if (!index.isValid()) return {}; return Qt::ItemIsDragEnabled|QAbstractListModel::flags(index); } int ApplicationListModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_applicationList.count(); } void ApplicationListModel::moveRow(const QModelIndex& /* sourceParent */, int sourceRow, const QModelIndex& /* destinationParent */, int destinationChild) { moveItem(sourceRow, destinationChild); } void ApplicationListModel::setLocation(int row, LauncherLocation location) { if (row < 0 || row >= m_applicationList.length()) { return; } ApplicationData data = m_applicationList.at(row); if (data.location == location) { return; } if (location == Favorites) { qWarning() << "favoriting" << row << data.name; // Deny favorites when full if (row >= m_maxFavoriteCount || m_favorites.count() >= m_maxFavoriteCount) { return; } m_favorites.insert(row, data.storageId); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); // Out of favorites } else if (data.location == Favorites) { m_favorites.removeAll(data.storageId); m_homeScreen->config().writeEntry("Favorites", m_favorites); emit favoriteCountChanged(); } // In Desktop if (location == Desktop) { m_desktopItems.insert(data.storageId); m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.values()); // Out of Desktop } else if (data.location == Desktop) { m_desktopItems.remove(data.storageId); m_homeScreen->config().writeEntry(QStringLiteral("DesktopItems"), m_desktopItems.values()); } data.location = location; emit m_homeScreen->configNeedsSaving(); emit dataChanged(index(row, 0), index(row, 0)); } void ApplicationListModel::moveItem(int row, int destination) { if (row < 0 || destination < 0 || row >= m_applicationList.length() || destination >= m_applicationList.length() || row == destination) { return; } if (destination > row) { ++destination; } beginMoveRows(QModelIndex(), row, row, QModelIndex(), destination); if (destination > row) { ApplicationData data = m_applicationList.at(row); m_applicationList.insert(destination, data); m_applicationList.takeAt(row); } else { ApplicationData data = m_applicationList.takeAt(row); m_applicationList.insert(destination, data); } m_appOrder.clear(); m_appPositions.clear(); int i = 0; for (const ApplicationData &app : qAsConst(m_applicationList)) { m_appOrder << app.storageId; m_appPositions[app.storageId] = i; ++i; } m_homeScreen->config().writeEntry("AppOrder", m_appOrder); endMoveRows(); } void ApplicationListModel::runApplication(const QString &storageId) { if (storageId.isEmpty()) { return; } KService::Ptr service = KService::serviceByStorageId(storageId); KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service); job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled)); job->start(); } int ApplicationListModel::maxFavoriteCount() const { return m_maxFavoriteCount; } void ApplicationListModel::setMaxFavoriteCount(int count) { if (m_maxFavoriteCount == count) { return; } if (m_maxFavoriteCount > count) { while (m_favorites.size() > count && m_favorites.count() > 0) { m_favorites.pop_back(); } emit favoriteCountChanged(); int i = 0; for (auto &app : m_applicationList) { if (i >= count && app.location == Favorites) { app.location = Grid; emit dataChanged(index(i, 0), index(i, 0)); } ++i; } } m_maxFavoriteCount = count; m_homeScreen->config().writeEntry("MaxFavoriteCount", m_maxFavoriteCount); emit maxFavoriteCountChanged(); } #include "moc_applicationlistmodel.cpp" diff --git a/containments/homescreen/applicationlistmodel.h b/containments/homescreen/applicationlistmodel.h index 12721ee..f33d3fd 100644 --- a/containments/homescreen/applicationlistmodel.h +++ b/containments/homescreen/applicationlistmodel.h @@ -1,123 +1,117 @@ /* * Copyright (C) 2014 Antonis Tsiapaliokas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef APPLICATIONLISTMODEL_H #define APPLICATIONLISTMODEL_H // Qt #include #include #include #include -// KDE -#include - #include "homescreen.h" class QString; class ApplicationListModel; struct ApplicationData { QString name; QString icon; QString storageId; QString entryPath; int location = 0; //FIXME bool startupNotify = true; }; class ApplicationListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(int favoriteCount READ favoriteCount NOTIFY favoriteCountChanged) Q_PROPERTY(int maxFavoriteCount READ maxFavoriteCount WRITE setMaxFavoriteCount NOTIFY maxFavoriteCountChanged) public: enum LauncherLocation { Grid = 0, Favorites, Desktop }; Q_ENUM(LauncherLocation) enum Roles { ApplicationNameRole = Qt::UserRole + 1, ApplicationIconRole, ApplicationStorageIdRole, ApplicationEntryPathRole, ApplicationOriginalRowRole, ApplicationStartupNotifyRole, ApplicationLocationRole }; ApplicationListModel(HomeScreen *parent = nullptr); ~ApplicationListModel() override; void loadSettings(); int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; void moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild); int count() const { return m_applicationList.count(); } int favoriteCount() const { return m_favorites.count();} int maxFavoriteCount() const; void setMaxFavoriteCount(int count); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const override; QHash roleNames() const Q_DECL_OVERRIDE; Q_INVOKABLE void setLocation(int row, LauncherLocation location); Q_INVOKABLE void moveItem(int row, int destination); Q_INVOKABLE void runApplication(const QString &storageId); Q_INVOKABLE void loadApplications(); public Q_SLOTS: void sycocaDbChanged(const QStringList &change); Q_SIGNALS: void countChanged(); void favoriteCountChanged(); void maxFavoriteCountChanged(); - void applicationStarted(const QString &name, const QString &icon); - void applicationExited(); private: QList m_applicationList; HomeScreen *m_homeScreen = nullptr; int m_maxFavoriteCount = 0; QStringList m_appOrder; QStringList m_favorites; QSet m_desktopItems; QHash m_appPositions; - KStartupInfo *m_startupInfo; }; #endif // APPLICATIONLISTMODEL_H diff --git a/containments/homescreen/colouraverage.cpp b/containments/homescreen/colouraverage.cpp new file mode 100644 index 0000000..1e269ed --- /dev/null +++ b/containments/homescreen/colouraverage.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2019 Carson Black * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "colouraverage.h" + +ColourAverage::ColourAverage(QObject *parent) : QObject(parent) +{ +} + +QColor ColourAverage::averageColour(const QImage &img) { + int r = 0; + int g = 0; + int b = 0; + int c = 0; + + for (int i = 0; i < img.width(); i++) { + for (int ii = 0; ii < img.height(); ii++) { + QRgb pix = img.pixel(i, ii); + if (pix == 0) + continue; + + c++; + r += qRed(pix); + g += qGreen(pix); + b += qBlue(pix); + } + } + r = r / c; + g = g / c; + b = b / c; + + QColor color = QColor::fromRgb(r,g,b); + + color.setHsv(color.hue(), color.saturation() / 4, color.value()); + + return color; +} diff --git a/containments/homescreen/colouraverage.h b/containments/homescreen/colouraverage.h new file mode 100644 index 0000000..0d15f53 --- /dev/null +++ b/containments/homescreen/colouraverage.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2019 Carson Black * + * * + * 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 2 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ +#pragma once + +#include +#include +#include + +class ColourAverage : public QObject +{ + Q_OBJECT + +public: + explicit ColourAverage(QObject *parent = nullptr); + Q_INVOKABLE QColor averageColour(const QImage &img); +}; diff --git a/containments/homescreen/homescreen.cpp b/containments/homescreen/homescreen.cpp index 343695f..318b0e8 100644 --- a/containments/homescreen/homescreen.cpp +++ b/containments/homescreen/homescreen.cpp @@ -1,73 +1,77 @@ /*************************************************************************** * Copyright (C) 2015 Marco Martin * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "homescreen.h" #include "applicationlistmodel.h" +#include "colouraverage.h" #include #include #include HomeScreen::HomeScreen(QObject *parent, const QVariantList &args) : Plasma::Containment(parent, args) { qmlRegisterUncreatableType("org.kde.phone.homescreen", 1, 0, "ApplicationListModel", QStringLiteral("Cannot create item of type ApplicationListModel")); + qmlRegisterSingletonType("org.kde.phone.homescreen", 1, 0, "ColourAverage", [](QQmlEngine *, QJSEngine *) -> QObject * { + return new ColourAverage(); + }); setHasConfigurationInterface(true); } HomeScreen::~HomeScreen() = default; void HomeScreen::configChanged() { Plasma::Containment::configChanged(); if (m_applicationListModel) { m_applicationListModel->loadSettings(); } } ApplicationListModel *HomeScreen::applicationListModel() { if (!m_applicationListModel) { m_applicationListModel = new ApplicationListModel(this); } return m_applicationListModel; } void HomeScreen::stackBefore(QQuickItem *item1, QQuickItem *item2) { if (!item1 || !item2 || item1 == item2 || item1->parentItem() != item2->parentItem()) { return; } item1->stackBefore(item2); } void HomeScreen::stackAfter(QQuickItem *item1, QQuickItem *item2) { if (!item1 || !item2 || item1 == item2 || item1->parentItem() != item2->parentItem()) { return; } item1->stackAfter(item2); } K_EXPORT_PLASMA_APPLET_WITH_JSON(homescreen, HomeScreen, "metadata.json") #include "homescreen.moc" diff --git a/containments/homescreen/package/contents/ui/launcher/Delegate.qml b/containments/homescreen/package/contents/ui/launcher/Delegate.qml index 9af9508..85f39c1 100644 --- a/containments/homescreen/package/contents/ui/launcher/Delegate.qml +++ b/containments/homescreen/package/contents/ui/launcher/Delegate.qml @@ -1,158 +1,162 @@ /* * Copyright 2019 Marco Martin * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. */ import QtQuick 2.4 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.3 as Controls import QtGraphicalEffects 1.6 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager import org.kde.phone.homescreen 1.0 ContainmentLayoutManager.ItemContainer { id: delegate z: dragActive ? 1 : 0 property var modelData: typeof model !== "undefined" ? model : null Layout.minimumWidth: launcherGrid.cellWidth Layout.minimumHeight: launcherGrid.cellHeight opacity: dragActive ? 0.4 : 1 key: model.applicationStorageId property real dragCenterX property real dragCenterY property alias iconItem: icon editModeCondition: ContainmentLayoutManager.ItemContainer.AfterPressAndHold signal launch(int x, int y, var source, string title) Connections { target: mainFlickable onCancelEditModeForItemsRequested: cancelEdit() } onDragActiveChanged: { launcherDragManager.active = dragActive if (dragActive) { // Must be 0, 0 as at this point dragCenterX and dragCenterY are on the drag before" launcherDragManager.startDrag(delegate); launcherDragManager.currentlyDraggedDelegate = delegate; } else { launcherDragManager.dropItem(delegate, dragCenterX, dragCenterY); plasmoid.editMode = false; editMode = false; plasmoid.fullRepresentationItem.stopScroll(); launcherDragManager.currentlyDraggedDelegate = null; } } onUserDrag: { dragCenterX = dragCenter.x; dragCenterY = dragCenter.y; launcherDragManager.dragItem(delegate, dragCenter.x, dragCenter.y); delegate.width = launcherGrid.cellWidth; delegate.height = launcherGrid.cellHeight; var pos = plasmoid.fullRepresentationItem.mapFromItem(delegate, dragCenter.x, dragCenter.y); //SCROLL UP if (pos.y < plasmoid.availableScreenRect.y + units.gridUnit) { plasmoid.fullRepresentationItem.scrollUp(); //SCROLL DOWN } else if (pos.y > plasmoid.availableScreenRect.y + plasmoid.availableScreenRect.height - units.gridUnit) { plasmoid.fullRepresentationItem.scrollDown(); //DON't SCROLL } else { plasmoid.fullRepresentationItem.stopScroll(); } } contentItem: MouseArea { - onClicked: plasmoid.nativeInterface.applicationListModel.runApplication(modelData.applicationStorageId); + onClicked: { + delegate.launch(delegate.x + (units.smallSpacing * 2), delegate.y + (units.smallSpacing * 2), icon.source, modelData.applicationName) + + plasmoid.nativeInterface.applicationListModel.runApplication(modelData.applicationStorageId); + } //preventStealing: true ColumnLayout { anchors { fill: parent leftMargin: units.smallSpacing * 2 topMargin: units.smallSpacing * 2 rightMargin: units.smallSpacing * 2 bottomMargin: units.smallSpacing * 2 } spacing: 0 PlasmaCore.IconItem { id: icon Layout.alignment: Qt.AlignHCenter | Qt.AlignTop Layout.fillWidth: true Layout.minimumHeight: parent.height - root.reservedSpaceForLabel Layout.preferredHeight: Layout.minimumHeight usesPlasmaTheme: false source: modelData ? modelData.applicationIcon : "" Behavior on scale { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } PlasmaComponents.Label { id: label visible: text.length > 0 Layout.fillWidth: true Layout.preferredHeight: root.reservedSpaceForLabel wrapMode: Text.WordWrap Layout.leftMargin: -parent.anchors.leftMargin + units.smallSpacing Layout.rightMargin: -parent.anchors.rightMargin + units.smallSpacing horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignTop maximumLineCount: 2 elide: Text.ElideRight text: model.applicationName //FIXME: export smallestReadableFont font.pointSize: theme.defaultFont.pointSize * 0.9 color: "white"//model.applicationLocation == ApplicationListModel.Desktop ? "white" : theme.textColor layer.enabled: true//model.applicationLocation == ApplicationListModel.Desktop layer.effect: DropShadow { horizontalOffset: 0 verticalOffset: 2 radius: 8.0 samples: 16 cached: true color: Qt.rgba(0, 0, 0, 1) } } } } } diff --git a/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml b/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml index 44035da..4b75145 100644 --- a/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml +++ b/containments/homescreen/package/contents/ui/launcher/LauncherGrid.qml @@ -1,96 +1,93 @@ /* * Copyright 2019 Marco Martin * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. */ import QtQuick 2.4 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.3 as Controls import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 -import org.kde.kirigami 2.13 as Kirigami +import org.kde.kirigami 2.10 as Kirigami import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager import org.kde.plasma.private.nanoshell 2.0 as NanoShell import org.kde.phone.homescreen 1.0 LauncherContainer { id: root readonly property int columns: Math.floor(root.flow.width / cellWidth) readonly property int cellWidth: root.flow.width / Math.floor(root.flow.width / ((availableCellHeight - reservedSpaceForLabel) + units.smallSpacing*4)) readonly property int cellHeight: availableCellHeight launcherGrid: root frame.width: width - Connections { - target: plasmoid.nativeInterface.applicationListModel - onApplicationExited: NanoShell.StartupFeedback.close() - onApplicationStarted: (name, icon) => { - NanoShell.StartupFeedback.open( - icon, - name, - root.width * 0.5, - root.height * 0.5, - root.width * 0.2 - ); - } - } - Repeater { parent: root.flow model: plasmoid.nativeInterface.applicationListModel delegate: Delegate { id: delegate width: root.cellWidth height: root.cellHeight parent: parentFromLocation property Item parentFromLocation: { switch (model.applicationLocation) { case ApplicationListModel.Desktop: return appletsLayout; case ApplicationListModel.Favorites: return favoriteStrip.flow; default: return root.flow; } } Component.onCompleted: { if (model.applicationLocation === ApplicationListModel.Desktop) { appletsLayout.restoreItem(delegate); } } + onLaunch: (x, y, icon, title) => { + delegate.grabToImage((img) => { + NanoShell.StartupFeedback.open( + icon, + title, + delegate.iconItem.Kirigami.ScenePosition.x + delegate.iconItem.width/2, + delegate.iconItem.Kirigami.ScenePosition.y + delegate.iconItem.height/2, + Math.min(delegate.iconItem.width, delegate.iconItem.height), + ColourAverage.averageColour(img.image)); + }); + } onParentFromLocationChanged: { if (!launcherDragManager.active && parent != parentFromLocation) { parent = parentFromLocation; if (model.applicationLocation === ApplicationListModel.Favorites) { plasmoid.nativeInterface.stackBefore(delegate, parentFromLocation.children[index]); } else if (model.applicationLocation === ApplicationListModel.Grid) { plasmoid.nativeInterface.stackBefore(delegate, parentFromLocation.children[Math.max(0, index - plasmoid.nativeInterface.applicationListModel.favoriteCount)]); } } } } } } diff --git a/containments/panel/package/contents/ui/quicksettings/Delegate.qml b/containments/panel/package/contents/ui/quicksettings/Delegate.qml index 39cf229..339f526 100644 --- a/containments/panel/package/contents/ui/quicksettings/Delegate.qml +++ b/containments/panel/package/contents/ui/quicksettings/Delegate.qml @@ -1,110 +1,124 @@ /* * Copyright 2015 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.1 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.kirigami 2.10 as Kirigami import org.kde.plasma.private.nanoshell 2.0 as NanoShell ColumnLayout { id: delegateRoot property bool toggled: model.enabled spacing: units.smallSpacing signal closeRequested signal panelClosed Rectangle { Layout.preferredWidth: units.iconSizes.large + units.smallSpacing * 2 Layout.minimumHeight: width Layout.alignment: Qt.AlignHCenter radius: units.smallSpacing border.color: Qt.rgba(PlasmaCore.ColorScope.textColor.r, PlasmaCore.ColorScope.textColor.g, PlasmaCore.ColorScope.textColor.b, 0.2) color: toggled ? Qt.rgba(PlasmaCore.ColorScope.highlightColor.r, PlasmaCore.ColorScope.highlightColor.g, PlasmaCore.ColorScope.highlightColor.b, iconMouseArea.pressed ? 0.5 : 0.3) : Qt.rgba(PlasmaCore.ColorScope.textColor.r, PlasmaCore.ColorScope.textColor.g, PlasmaCore.ColorScope.textColor.b, iconMouseArea.pressed ? 0.5 : 0.1) PlasmaCore.IconItem { id: icon colorGroup: PlasmaCore.ColorScope.colorGroup anchors { fill: parent margins: units.smallSpacing * 2 } source: model.icon MouseArea { id: iconMouseArea anchors.fill: parent onClicked: { if (delegateRoot.toggle) { delegateRoot.toggle(); } else if (model.toggleFunction) { root[model.toggleFunction](); } else if (model.settingsCommand) { + NanoShell.StartupFeedback.open( + model.icon, + model.text, + icon.Kirigami.ScenePosition.x + icon.width/2, + icon.Kirigami.ScenePosition.y + icon.height/2, + Math.min(icon.width, icon.height), + theme.textColor); plasmoid.nativeInterface.executeCommand(model.settingsCommand); root.closeRequested(); } } } } } PlasmaComponents.Label { id: label Layout.maximumWidth: parent.width Layout.alignment: Qt.AlignHCenter text: model.text bottomPadding: units.smallSpacing * 2 horizontalAlignment: Text.AlignHCenter font.pixelSize: theme.defaultFont.pixelSize * 0.8 elide: Text.ElideRight verticalAlignment: Text.AlignVCenter PlasmaCore.SvgItem { anchors { left: parent.right verticalCenter: parent.verticalCenter verticalCenterOffset: -units.smallSpacing } visible: model.settingsCommand width: units.iconSizes.small/2 height: width elementId: "down-arrow" svg: PlasmaCore.Svg { imagePath: "widgets/arrows" } } MouseArea { id: labelMouseArea anchors.fill: parent onClicked: { if (model.settingsCommand) { + NanoShell.StartupFeedback.open( + model.icon, + model.text, + icon.Kirigami.ScenePosition.x + icon.width/2, + icon.Kirigami.ScenePosition.y + icon.height/2, + Math.min(icon.width, icon.height), + theme.textColor); //plasmoid.nativeInterface.executeCommand(model.settingsCommand); closeRequested(); } else if (model.toggleFunction) { root[model.toggleFunction](); } } } } }