Commit b41e1f2b authored by Devin Lin's avatar Devin Lin 🎨
Browse files

homescreen: Start refactoring and cleaning

fix
parent 25f36c40
......@@ -17,8 +17,6 @@ set(mobileshellplugin_SRCS
components/direction.cpp
notifications/notificationthumbnailer.cpp
notifications/notificationfilemenu.cpp
homescreen/applicationlistmodel.cpp
homescreen/favoritesmodel.cpp
taskswitcher/displaysmodel.cpp
)
if (QT_MAJOR_VERSION STREQUAL "5")
......
/*
* SPDX-FileCopyrightText: 2021 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
// Qt
#include <QAbstractListModel>
#include <QList>
#include <QObject>
#include <QSet>
#include "applicationlistmodel.h"
class QString;
namespace KWayland
{
namespace Client
{
class PlasmaWindowManagement;
class PlasmaWindow;
}
}
class FavoritesModel;
class FavoritesModel : public ApplicationListModel
{
Q_OBJECT
public:
FavoritesModel(QObject *parent = nullptr);
~FavoritesModel() override;
static FavoritesModel *instance()
{
static FavoritesModel *model = new FavoritesModel;
return model;
}
QString storageToUniqueId(const QString &storageId) const;
QString uniqueToStorageId(const QString &uniqueId) const;
Q_INVOKABLE void addFavorite(const QString &storageId, int row, LauncherLocation location);
Q_INVOKABLE void removeFavorite(int row);
Q_INVOKABLE void loadApplications() override;
};
......@@ -14,9 +14,6 @@
#include "notifications/notificationfilemenu.h"
#include "notifications/notificationthumbnailer.h"
#include "homescreen/applicationlistmodel.h"
#include "homescreen/favoritesmodel.h"
#include "taskswitcher/displaysmodel.h"
#include "mobileshellsettings.h"
......@@ -55,14 +52,6 @@ void MobileShellPlugin::registerTypes(const char *uri)
// components
qmlRegisterType<Direction>(uri, 1, 0, "Direction");
// homescreen
qmlRegisterSingletonType<ApplicationListModel>(uri, 1, 0, "ApplicationListModel", [](QQmlEngine *, QJSEngine *) -> QObject * {
return ApplicationListModel::instance();
});
qmlRegisterSingletonType<FavoritesModel>(uri, 1, 0, "FavoritesModel", [](QQmlEngine *, QJSEngine *) -> QObject * {
return FavoritesModel::instance();
});
// notifications
qmlRegisterType<NotificationThumbnailer>(uri, 1, 0, "NotificationThumbnailer");
qmlRegisterType<NotificationFileMenu>(uri, 1, 0, "NotificationFileMenu");
......
......@@ -48,6 +48,10 @@ MouseArea { // use mousearea to ensure clicks don't go behind
MobileShell.HomeScreenControls.taskSwitcher.minimizeAll();
}
function close() {
visible = false;
}
// close when an app opens
property bool windowActive: Window.active
......
......@@ -213,12 +213,4 @@ Item {
z: 999999
anchors.fill: parent
}
// listen to app launch errors
Connections {
target: MobileShell.ApplicationListModel
function onLaunchError(msg) {
MobileShell.HomeScreenControls.closeAppLaunchAnimation()
}
}
}
......@@ -3,6 +3,8 @@
set(homescreen_SRCS
homescreen.cpp
desktopmodel.cpp
applicationlistmodel.cpp
)
add_library(plasma_containment_phone_homescreen MODULE ${homescreen_SRCS})
......
......@@ -7,7 +7,6 @@
// Self
#include "applicationlistmodel.h"
#include "../windowutil.h"
// Qt
#include <QByteArray>
......@@ -19,6 +18,7 @@
// KDE
#include <KApplicationTrader>
#include <KConfigGroup>
#include <KIO/ApplicationLauncherJob>
#include <KNotificationJobUiDelegate>
#include <KService>
......@@ -30,10 +30,6 @@
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
#include <Plasma/Applet>
constexpr int MAX_FAVOURITES = 5;
ApplicationListModel::ApplicationListModel(QObject *parent)
: QAbstractListModel(parent)
{
......@@ -42,50 +38,49 @@ ApplicationListModel::ApplicationListModel(QObject *parent)
#else
connect(KSycoca::self(), &KSycoca::databaseChanged, this, &ApplicationListModel::sycocaDbChanged);
#endif
connect(WindowUtil::instance(), &WindowUtil::windowCreated, this, &ApplicationListModel::windowCreated);
loadSettings();
}
ApplicationListModel::~ApplicationListModel() = default;
void ApplicationListModel::loadSettings()
{
if (!m_applet) {
// initialize wayland window checking
KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this);
if (!connection) {
return;
}
m_favorites = m_applet->applet()->config().readEntry("Favorites", QStringList());
const auto di = m_applet->applet()->config().readEntry("DesktopItems", QStringList());
m_desktopItems = QSet<QString>(di.begin(), di.end());
m_appOrder = m_applet->applet()->config().readEntry("AppOrder", QStringList());
m_maxFavoriteCount = m_applet->applet()->config().readEntry("MaxFavoriteCount", MAX_FAVOURITES);
int i = 0;
for (const QString &app : qAsConst(m_appOrder)) {
m_appPositions[app] = i;
++i;
}
// loadApplications();
auto *registry = new KWayland::Client::Registry(this);
registry->create(connection);
connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [this, registry](quint32 name, quint32 version) {
m_windowManagement = registry->createPlasmaWindowManagement(name, version, this);
qRegisterMetaType<QVector<int>>("QVector<int>");
connect(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated, this, &ApplicationListModel::windowCreated);
});
registry->setup();
connection->roundtrip();
}
ApplicationListModel::~ApplicationListModel() = default;
QHash<int, QByteArray> 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")},
{ApplicationRunningRole, QByteArrayLiteral("applicationRunning")},
{ApplicationUniqueIdRole, QByteArrayLiteral("applicationUniqueId")}};
{ApplicationUniqueIdRole, QByteArrayLiteral("applicationUniqueId")},
{ApplicationLocationRole, QByteArrayLiteral("applicationLocation")}};
}
ApplicationListModel *ApplicationListModel::instance()
{
static ApplicationListModel *model = new ApplicationListModel;
return model;
}
void ApplicationListModel::sycocaDbChanged()
{
m_applicationList.clear();
loadApplications();
}
......@@ -116,11 +111,6 @@ void ApplicationListModel::windowCreated(KWayland::Client::PlasmaWindow *window)
}
}
bool appNameLessThan(const ApplicationListModel::ApplicationData &a1, const ApplicationListModel::ApplicationData &a2)
{
return a1.name.compare(a2.name, Qt::CaseInsensitive) < 0;
}
void ApplicationListModel::loadApplications()
{
auto cfg = KSharedConfig::openConfig(QStringLiteral("applications-blacklistrc"));
......@@ -132,9 +122,7 @@ void ApplicationListModel::loadApplications()
m_applicationList.clear();
QMap<int, ApplicationData> orderedList;
QList<ApplicationData> unorderedList;
QSet<QString> foundFavorites;
auto filter = [blacklist](const KService::Ptr &service) -> bool {
if (service->noDisplay()) {
......@@ -162,45 +150,16 @@ void ApplicationListModel::loadApplications()
data.uniqueId = service->storageId();
data.entryPath = service->exec();
data.startupNotify = service->property(QStringLiteral("StartupNotify")).toBool();
if (m_favorites.contains(data.uniqueId)) {
data.location = Favorites;
foundFavorites.insert(data.uniqueId);
} else if (m_desktopItems.contains(data.uniqueId)) {
data.location = Desktop;
}
auto it = m_appPositions.constFind(data.uniqueId);
if (it != m_appPositions.constEnd()) {
orderedList[*it] = data;
} else {
unorderedList << data;
}
unorderedList << data;
}
blgroup.writeEntry("blacklist", blacklist);
cfg->sync();
std::sort(unorderedList.begin(), unorderedList.end(), [](const ApplicationListModel::ApplicationData &a1, const ApplicationListModel::ApplicationData &a2) {
return a1.name.compare(a2.name, Qt::CaseInsensitive) < 0;
});
std::sort(unorderedList.begin(), unorderedList.end(), appNameLessThan);
m_applicationList << orderedList.values();
m_applicationList << unorderedList;
endResetModel();
emit countChanged();
bool favChanged = false;
for (const auto &item : m_favorites) {
if (!foundFavorites.contains(item)) {
favChanged = true;
m_favorites.removeAll(item);
}
}
if (favChanged) {
if (m_applet) {
m_applet->applet()->config().writeEntry("Favorites", m_favorites);
}
emit favoriteCountChanged();
}
}
QVariant ApplicationListModel::data(const QModelIndex &index, int role) const
......@@ -219,29 +178,19 @@ QVariant ApplicationListModel::data(const QModelIndex &index, int role) const
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;
case ApplicationRunningRole:
return m_applicationList.at(index.row()).window != nullptr;
case ApplicationUniqueIdRole:
return m_applicationList.at(index.row()).uniqueId;
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()) {
......@@ -251,103 +200,6 @@ int ApplicationListModel::rowCount(const QModelIndex &parent) const
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 || m_favorites.contains(data.uniqueId)) {
return;
}
m_favorites.insert(row, data.uniqueId);
if (m_applet) {
m_applet->applet()->config().writeEntry("Favorites", m_favorites);
}
emit favoriteCountChanged();
// Out of favorites
} else if (data.location == Favorites) {
m_favorites.removeAll(data.uniqueId);
if (m_applet) {
m_applet->applet()->config().writeEntry("Favorites", m_favorites);
}
emit favoriteCountChanged();
}
// In Desktop
if (location == Desktop) {
m_desktopItems.insert(data.uniqueId);
if (m_applet) {
m_applet->applet()->config().writeEntry("DesktopItems", m_desktopItems.values());
}
// Out of Desktop
} else if (data.location == Desktop) {
m_desktopItems.remove(data.uniqueId);
if (m_applet) {
m_applet->applet()->config().writeEntry(QStringLiteral("DesktopItems"), m_desktopItems.values());
}
}
data.location = location;
if (m_applet) {
emit m_applet->applet()->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.uniqueId;
m_appPositions[app.uniqueId] = i;
++i;
}
if (m_applet) {
m_applet->applet()->config().writeEntry("AppOrder", m_appOrder);
}
endMoveRows();
}
void ApplicationListModel::runApplication(const QString &storageId)
{
if (storageId.isEmpty()) {
......@@ -373,56 +225,6 @@ void ApplicationListModel::runApplication(const QString &storageId)
});
}
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;
if (m_applet) {
m_applet->applet()->config().writeEntry("MaxFavoriteCount", m_maxFavoriteCount);
}
emit maxFavoriteCountChanged();
}
PlasmaQuick::AppletQuickItem *ApplicationListModel::applet() const
{
return m_applet;
}
void ApplicationListModel::setApplet(PlasmaQuick::AppletQuickItem *applet)
{
if (m_applet == applet) {
return;
}
m_applet = applet;
loadSettings();
emit appletChanged();
}
void ApplicationListModel::setMinimizedDelegate(int row, QQuickItem *delegate)
{
if (row < 0 || row >= m_applicationList.count()) {
......
......@@ -8,7 +8,6 @@
#pragma once
// Qt
#include <PlasmaQuick/AppletQuickItem>
#include <QAbstractListModel>
#include <QList>
#include <QObject>
......@@ -26,20 +25,18 @@ class PlasmaWindow;
}
}
class ApplicationListModel;
/**
* @short The base application list, used directly by the app drawer.
*
* Items that are displayed on the desktop/pinned are done by DesktopModel, which is a subclass.
*/
class ApplicationListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(PlasmaQuick::AppletQuickItem *applet READ applet WRITE setApplet NOTIFY appletChanged)
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 };
// this enum is solely used by DesktopModel
enum LauncherLocation { None = 0, Favorites, Desktop };
Q_ENUM(LauncherLocation)
struct ApplicationData {
......@@ -48,9 +45,9 @@ public:
QString icon;
QString storageId;
QString entryPath;
LauncherLocation location = LauncherLocation::Grid;
bool startupNotify = true;
KWayland::Client::PlasmaWindow *window = nullptr;
LauncherLocation location = LauncherLocation::None; // only for DesktopModel
};
enum Roles {
......@@ -58,56 +55,23 @@ public:
ApplicationIconRole,
ApplicationStorageIdRole,
ApplicationEntryPathRole,
ApplicationOriginalRowRole,
ApplicationStartupNotifyRole,
ApplicationLocationRole,
ApplicationRunningRole,
ApplicationUniqueIdRole
ApplicationUniqueIdRole,
ApplicationLocationRole // only valid for DesktopModel
};
ApplicationListModel(QObject *parent = nullptr);
~ApplicationListModel() override;
static ApplicationListModel *instance()
{
static ApplicationListModel *model = new ApplicationListModel;
return model;
}
void loadSettings();
static ApplicationListModel *instance();
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);
void setApplet(PlasmaQuick::AppletQuickItem *applet);
PlasmaQuick::AppletQuickItem *applet() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QHash<int, QByteArray> 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 virtual void loadApplications();
Q_INVOKABLE void runApplication(const QString &storageId);
Q_INVOKABLE void setMinimizedDelegate(int row, QQuickItem *delegate);
Q_INVOKABLE void unsetMinimizedDelegate(int row, QQuickItem *delegate);
......@@ -117,19 +81,10 @@ public Q_SLOTS:
void windowCreated(KWayland::Client::PlasmaWindow *window);