get rid of old homescreen

This commit is contained in:
Marco Martin 2019-09-04 18:39:31 +02:00
parent 38b2f688bb
commit 843b01508f
36 changed files with 438 additions and 2389 deletions

View file

@ -1,5 +1,4 @@
add_subdirectory(panel)
add_subdirectory(homescreen)
add_subdirectory(homescreen2)
add_subdirectory(taskpanel)

View file

@ -11,6 +11,7 @@ target_link_libraries(plasma_containment_phone_homescreen
Qt5::Gui
KF5::Plasma
Qt5::Qml
Qt5::Quick
KF5::I18n
KF5::Service
KF5::KIOWidgets

View file

@ -37,12 +37,26 @@
#include <KIOWidgets/KRun>
#include <QDebug>
ApplicationListModel::ApplicationListModel(QObject *parent)
: QAbstractListModel(parent)
ApplicationListModel::ApplicationListModel(HomeScreen *parent)
: QAbstractListModel(parent),
m_homeScreen(parent)
{
//can't use the new syntax as this signal is overloaded
connect(KSycoca::self(), SIGNAL(databaseChanged(const QStringList &)),
this, SLOT(sycocaDbChanged(const QStringList &)));
m_favorites = m_homeScreen->config().readEntry("Favorites", QStringList());
m_desktopItems = m_homeScreen->config().readEntry("DesktopItems", QStringList()).toSet();
m_appOrder = m_homeScreen->config().readEntry("AppOrder", QStringList());
m_maxFavoriteCount = m_homeScreen->config().readEntry("MaxFavoriteCount", 5);
int i = 0;
for (auto app : m_appOrder) {
m_appPositions[app] = i;
++i;
}
//here or delayed?
loadApplications();
}
ApplicationListModel::~ApplicationListModel()
@ -56,6 +70,8 @@ QHash<int, QByteArray> ApplicationListModel::roleNames() const
roleNames[ApplicationStorageIdRole] = "ApplicationStorageIdRole";
roleNames[ApplicationEntryPathRole] = "ApplicationEntryPathRole";
roleNames[ApplicationOriginalRowRole] = "ApplicationOriginalRowRole";
roleNames[ApplicationStartupNotifyRole] = "ApplicationStartupNotifyRole";
roleNames[ApplicationLocationRole] = "ApplicationLocationRole";
return roleNames;
}
@ -120,8 +136,6 @@ void ApplicationListModel::loadApplications()
} else if (entry->property("Exec").isValid()) {
KService::Ptr service(static_cast<KService* >(entry.data()));
qDebug() << " desktopEntryName: " << service->desktopEntryName();
if (service->isApplication() &&
!blacklist.contains(service->desktopEntryName()) &&
service->showOnCurrentPlatform() &&
@ -134,6 +148,13 @@ void ApplicationListModel::loadApplications()
data.icon = service->icon();
data.storageId = service->storageId();
data.entryPath = service->exec();
data.startupNotify = service->property("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()) {
@ -178,6 +199,10 @@ QVariant ApplicationListModel::data(const QModelIndex &index, int role) const
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();
@ -205,7 +230,52 @@ void ApplicationListModel::moveRow(const QModelIndex& /* sourceParent */, int so
moveItem(sourceRow, destinationChild);
}
Q_INVOKABLE void ApplicationListModel::moveItem(int row, int destination)
void ApplicationListModel::setLocation(int row, LauncherLocation location)
{
if (row < 0 || row >= m_applicationList.length()) {
return;
}
ApplicationData &data = m_applicationList[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.toList());
// Out of Desktop
} else if (data.location == Desktop) {
m_desktopItems.remove(data.storageId);
m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList());
}
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) {
@ -220,6 +290,7 @@ Q_INVOKABLE void ApplicationListModel::moveItem(int row, int destination)
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);
@ -235,8 +306,8 @@ Q_INVOKABLE void ApplicationListModel::moveItem(int row, int destination)
++i;
}
m_homeScreen->config().writeEntry("AppOrder", m_appOrder);
emit appOrderChanged();
endMoveRows();
}
@ -251,23 +322,38 @@ void ApplicationListModel::runApplication(const QString &storageId)
KRun::runService(*service, QList<QUrl>(), nullptr);
}
QStringList ApplicationListModel::appOrder() const
int ApplicationListModel::maxFavoriteCount() const
{
return m_appOrder;
return m_maxFavoriteCount;
}
void ApplicationListModel::setAppOrder(const QStringList &order)
void ApplicationListModel::setMaxFavoriteCount(int count)
{
if (m_appOrder == order) {
if (m_maxFavoriteCount == count) {
return;
}
m_appOrder = order;
m_appPositions.clear();
int i = 0;
for (auto app : m_appOrder) {
m_appPositions[app] = i;
++i;
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;
}
}
emit appOrderChanged();
m_maxFavoriteCount = count;
m_homeScreen->config().writeEntry("MaxFavoriteCount", m_maxFavoriteCount);
emit maxFavoriteCountChanged();
}
#include "moc_applicationlistmodel.cpp"

View file

@ -25,30 +25,58 @@
#include <QAbstractListModel>
#include <QList>
#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(QStringList appOrder READ appOrder WRITE setAppOrder NOTIFY appOrderChanged)
Q_PROPERTY(int favoriteCount READ favoriteCount NOTIFY favoriteCountChanged)
Q_PROPERTY(int maxFavoriteCount READ maxFavoriteCount WRITE setMaxFavoriteCount NOTIFY maxFavoriteCountChanged)
public:
ApplicationListModel(QObject *parent = nullptr);
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;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
void moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild);
int count() { return m_applicationList.count(); }
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;
@ -56,16 +84,7 @@ public:
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
enum Roles {
ApplicationNameRole = Qt::UserRole + 1,
ApplicationIconRole = Qt::UserRole + 2,
ApplicationStorageIdRole = Qt::UserRole + 3,
ApplicationEntryPathRole = Qt::UserRole + 4,
ApplicationOriginalRowRole = Qt::UserRole + 6
};
QStringList appOrder() const;
void setAppOrder(const QStringList &order);
Q_INVOKABLE void setLocation(int row, LauncherLocation location);
Q_INVOKABLE void moveItem(int row, int order);
@ -78,12 +97,17 @@ public Q_SLOTS:
Q_SIGNALS:
void countChanged();
void appOrderChanged();
void favoriteCountChanged();
void maxFavoriteCountChanged();
private:
QList<ApplicationData> m_applicationList;
HomeScreen *m_homeScreen = nullptr;
int m_maxFavoriteCount = 0;
QStringList m_appOrder;
QStringList m_favorites;
QSet<QString> m_desktopItems;
QHash<QString, int> m_appPositions;
};

View file

@ -22,12 +22,13 @@
#include <QtQml>
#include <QDebug>
#include <QQuickItem>
HomeScreen::HomeScreen(QObject *parent, const QVariantList &args)
: Plasma::Containment(parent, args)
{
qmlRegisterType<ApplicationListModel>();
m_applicationListModel = new ApplicationListModel(this);
qmlRegisterUncreatableType<ApplicationListModel>("org.kde.phone.homescreen", 1, 0, "ApplicationListModel", QStringLiteral("Cannot create item of type ApplicationListModel"));
setHasConfigurationInterface(true);
}
@ -36,9 +37,30 @@ HomeScreen::~HomeScreen()
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->parentItem() != item2->parentItem()) {
return;
}
item1->stackBefore(item2);
}
void HomeScreen::stackAfter(QQuickItem *item1, QQuickItem *item2)
{
if (!item1 || !item2 || item1->parentItem() != item2->parentItem()) {
return;
}
item1->stackAfter(item2);
}
K_EXPORT_PLASMA_APPLET_WITH_JSON(homescreen, HomeScreen, "metadata.json")
#include "homescreen.moc"

View file

@ -24,6 +24,7 @@
#include <Plasma/Containment>
class QQuickItem;
class ApplicationListModel;
class HomeScreen : public Plasma::Containment
@ -37,8 +38,11 @@ public:
ApplicationListModel *applicationListModel();
Q_INVOKABLE void stackBefore(QQuickItem *item1, QQuickItem *item2);
Q_INVOKABLE void stackAfter(QQuickItem *item1, QQuickItem *item2);
private:
ApplicationListModel *m_applicationListModel;
ApplicationListModel *m_applicationListModel = nullptr;
};

View file

@ -1,187 +0,0 @@
/*
* Copyright 2013 Marco Martin <mart@kde.org>
*
* 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 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.
*/
var layout;
var root;
var plasmoid;
var lastSpacer;
function restore() {
var configString = String(plasmoid.configuration.AppletOrder)
//array, a cell for encoded item order
var itemsArray = configString.split(";");
//map applet id->order in panel
var idsOrder = new Object();
//map order in panel -> applet pointer
var appletsOrder = new Object();
for (var i = 0; i < itemsArray.length; i++) {
//property name: applet id
//property value: order
idsOrder[itemsArray[i]] = i;
}
for (var i = 0; i < plasmoid.applets.length; ++i) {
if (idsOrder[plasmoid.applets[i].id] !== undefined) {
appletsOrder[idsOrder[plasmoid.applets[i].id]] = plasmoid.applets[i];
//ones that weren't saved in AppletOrder go to the end
} else {
appletsOrder["unordered"+i] = plasmoid.applets[i];
}
}
//finally, restore the applets in the correct order
for (var i in appletsOrder) {
root.addApplet(appletsOrder[i], -1, -1)
}
//rewrite, so if in the orders there were now invalid ids or if some were missing creates a correct list instead
save();
}
function save() {
var ids = new Array();
for (var i = 0; i < layout.children.length; ++i) {
var child = layout.children[i];
if (child.applet) {
ids.push(child.applet.id);
}
}
plasmoid.configuration.AppletOrder = ids.join(';');
}
function removeApplet (applet) {
for (var i = layout.children.length - 1; i >= 0; --i) {
var child = layout.children[i];
if (child.applet === applet) {
child.destroy();
}
}
}
//insert item2 before item1
function insertBefore(item1, item2) {
if (item1 === item2) {
return;
}
var removed = new Array();
var child;
var i;
for (i = layout.children.length - 1; i >= 0; --i) {
child = layout.children[i];
removed.push(child);
child.parent = root;
if (child === item1) {
break;
}
}
item2.parent = layout;
for (var j = removed.length - 1; j >= 0; --j) {
removed[j].parent = layout;
}
return i;
}
//insert item2 after item1
function insertAfter(item1, item2) {
if (item1 === item2) {
return;
}
var removed = new Array();
var child;
var i;
for (i = layout.children.length - 1; i >= 0; --i) {
child = layout.children[i];
//never ever insert after lastSpacer
if (child === lastSpacer && item1 === lastSpacer) {
removed.push(child);
child.parent = root;
break;
} else if (child === item1) {
break;
}
removed.push(child);
child.parent = root;
}
item2.parent = layout;
for (var j = removed.length - 1; j >= 0; --j) {
removed[j].parent = layout;
}
return i;
}
function insertAtIndex(item, position) {
if (position < 0 || position >= layout.children.length) {
return;
}
//never ever insert after lastSpacer
if (layout.children[position] === lastSpacer) {
--position;
}
var removedItems = new Array();
for (var i = position; i < layout.children.length; ++i) {
var child = layout.children[position];
child.parent = root;
removedItems.push(child);
}
item.parent = layout;
for (var i in removedItems) {
removedItems[i].parent = layout;
}
}
function insertAtCoordinates(item, x, y) {
if (root.isHorizontal) {
y = layout.height / 2;
} else {
x = layout.width / 2;
}
var child = layout.childAt(x, y);
if (!child || child === item) {
child = layout.children[0];
}
item.parent = root;
//PlasmaCore.Types.Vertical = 3
if ((plasmoid.formFactor === 3 && y < child.y + child.height/2) ||
(plasmoid.formFactor !== 3 && x < child.x + child.width/2)) {
return insertBefore(child, item);
} else {
return insertAfter(child, item);
}
}

View file

@ -6,9 +6,6 @@
<kcfgfile name=""/>
<group name="General">
<entry name="AppletOrder" type="String">
<label>encoded order of items</label>
</entry>
<entry name="AppOrder" type="StringList">
<label>order of apps</label>
<default>org.kde.phone.dialer.desktop</default>

View file

@ -1,260 +0,0 @@
/*
* Copyright 2015 Marco Martin <mart@kde.org>
*
* 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 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
MouseArea {
id: headerItem
z: 999
property Item layout: appletsLayout
property Item lastSpacer: spacer
property Item favoritesStrip: favoritesView
width: root.width
height: Math.max(applicationsView.height - stripe.height, mainLayout.Layout.minimumHeight)
property int margin: stripe.height + units.gridUnit * 2
property Item draggingApplet
property int startMouseX
property int startMouseY
property int oldMouseX
property int oldMouseY
drag.filterChildren: true
EventGenerator {
id: eventGenerator
}
SequentialAnimation {
id: removeAnim
property Item target
property real to
NumberAnimation {
properties: "x"
duration: units.longDuration
easing.type: Easing.InOutQuad
target: removeAnim.target
to: removeAnim.to
}
ScriptAction {
script: removeAnim.target.applet.action("remove").trigger();
}
}
onPressed: {
startMouseX = mouse.x;
startMouseY = mouse.y;
}
onPressAndHold: {
var absolutePos = mapToItem(appletsLayout, mouse.x, mouse.y);
var absoluteStartPos = mapToItem(appletsLayout, startMouseX, startMouseY);
if (Math.abs(absolutePos.x - absoluteStartPos.x) > units.gridUnit*2 ||
Math.abs(absolutePos.y - absoluteStartPos.y) > units.gridUnit*2) {
print("finger moved too much, press and hold canceled")
return;
}
print(favoritesView.contains(mapToItem(favoritesView, mouse.x, mouse.y)))
if (!favoritesView.contains(mapToItem(favoritesView, mouse.x, mouse.y))) {
editOverlay.visible = true;
var pos = mapToItem(appletsLayout, mouse.x, mouse.y);
draggingApplet = appletsSpace.layout.childAt(absolutePos.x, absolutePos.y);
editOverlay.applet = draggingApplet;
oldMouseX = mouse.x;
oldMouseY = mouse.y;
eventGenerator.sendGrabEvent(draggingApplet, EventGenerator.UngrabMouse);
eventGenerator.sendGrabEvent(headerItem, EventGenerator.GrabMouse);
eventGenerator.sendMouseEvent(headerItem, EventGenerator.MouseButtonPress, mouse.x, mouse.y, Qt.LeftButton, Qt.LeftButton, 0)
if (draggingApplet) {
draggingApplet.animationsEnabled = false;
dndSpacer.height = draggingApplet.height;
root.layoutManager.insertBefore(draggingApplet, dndSpacer);
draggingApplet.parent = headerItem;
pos = mapToItem(headerItem, mouse.x, mouse.y);
draggingApplet.y = pos.y - draggingApplet.height/2;
applicationsView.interactive = false;
}
}
}
onPositionChanged: {
if (!draggingApplet) {
return;
}
applicationsView.interactive = false;
if (Math.abs(mouse.x - startMouseX) > units.gridUnit ||
Math.abs(mouse.y - startMouseY) > units.gridUnit) {
editOverlay.opacity = 0;
}
draggingApplet.x -= oldMouseX - mouse.x;
draggingApplet.y -= oldMouseY - mouse.y;
oldMouseX = mouse.x;
oldMouseY = mouse.y;
var pos = mapToItem(appletsLayout, mouse.x, mouse.y);
var itemUnderMouse = appletsSpace.layout.childAt(pos.x, pos.y);
if (itemUnderMouse && itemUnderMouse != dndSpacer) {
dndSpacer.parent = colorScope;
if (pos.y < itemUnderMouse.y + itemUnderMouse.height/2) {
root.layoutManager.insertBefore(itemUnderMouse, dndSpacer);
} else {
root.layoutManager.insertAfter(itemUnderMouse, dndSpacer);
}
}
pos = mapToItem(root, mouse.x, mouse.y);
//SCROLL UP
if (applicationsView.contentY > -applicationsView.headerItem.height + root.height && pos.y < root.height/4) {
root.scrollUp();
//SCROLL DOWN
} else if (applicationsView.contentY < 0 && pos.y > 3 * (root.height / 4)) {
root.scrollDown();
//DON't SCROLL
} else {
root.stopScroll();
}
}
onReleased: {
if (!draggingApplet) {
return;
}
if (draggingApplet.x > -draggingApplet.width/3 && draggingApplet.x < draggingApplet.width/3) {
draggingApplet.x = 0;
root.layoutManager.insertBefore( dndSpacer, draggingApplet);
} else {
removeAnim.target = draggingApplet;
removeAnim.to = (draggingApplet.x > 0) ? root.width : -root.width
removeAnim.running = true;
}
applicationsView.interactive = true;
dndSpacer.parent = colorScope;
draggingApplet = null;
}
ColumnLayout {
id: mainLayout
anchors {
fill: parent
}
Item {
Layout.minimumHeight: krunner.inputHeight
Layout.minimumWidth: Layout.minimumHeight
}
PlasmaCore.ColorScope {
id: colorScope
//TODO: decide what color we want applets
colorGroup: PlasmaCore.Theme.NormalColorGroup
Layout.fillWidth: true
Layout.minimumHeight: appletsLayout.implicitHeight
Layout.maximumHeight: appletsLayout.implicitHeight
Column {
id: appletsLayout
width: parent.width
move: Transition {
NumberAnimation {
properties: "x,y"
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
}
Item {
id: dndSpacer
width: parent.width
}
}
}
SatelliteStripe {
id: stripe
z: 99
property int viewPos: applicationsView.contentItem.height * applicationsView.visibleArea.yPosition
y: Math.max(viewPos + krunner.inputHeight - units.smallSpacing,
Math.min(parent.height, viewPos + plasmoid.availableScreenRect.height - height) )
PlasmaCore.IconItem {
id: goUp
source: "arrow-up"
width: units.iconSizes.medium
height: width
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.top
margins: units.largeSpacing
}
MouseArea {
anchors {
fill: parent
margins: -units.smallSpacing
}
onClicked: applicationsView.flick(0, -applicationsView.height/2)
}
}
GridView {
id: favoritesView
//FIXME: QQuickItem has a contains, but seems to not work
function contains(point) {
return point.x > 0 && point.x < width && point.y > 0 && point.y < height;
}
anchors.fill: parent
property int columns: 4
interactive: false
flow: GridView.FlowTopToBottom
cellWidth: root.width / 4
cellHeight: root.buttonHeight
model: plasmoid.nativeInterface.applicationListModel
delegate: HomeLauncher {
maximumLineCount: 1
iconSize: root.iconSize
}
move: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
moveDisplaced: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
}
}
}

View file

@ -1,134 +0,0 @@
/*
* Copyright (C) 2015 Marco Martin <mart@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
import QtQuick 2.2
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.milou 0.1 as Milou
Rectangle {
id: editOverlay
anchors.fill: parent
property Item applet
color: Qt.rgba(0, 0, 0, 0.8)
visible: false
onVisibleChanged: {
if (visible) {
opacity = 1;
}
}
opacity: 0
Behavior on opacity {
SequentialAnimation {
OpacityAnimator {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
ScriptAction {
script: {
if (editOverlay.opacity == 0) {
editOverlay.visible = false;
}
}
}
}
}
MouseArea {
enabled: listView.visible
anchors.fill: parent
preventStealing: true
onClicked: editOverlay.opacity = 0;
PlasmaComponents.ButtonRow {
visible: editOverlay.applet
spacing: 0
exclusive: false
anchors.horizontalCenter: parent.horizontalCenter
y: editOverlay.mapFromItem(editOverlay.applet.parent, 0, editOverlay.applet.y).y + editOverlay.applet.height/2 - height/2
PlasmaComponents.ToolButton {
iconSource: "configure"
text: i18n("Configure...")
flat: false
onClicked: {
editOverlay.applet.applet.action("configure").trigger();
editOverlay.opacity = 0;
}
}
PlasmaComponents.ToolButton {
iconSource: "window-close"
text: i18n("Remove")
flat: false
onClicked: {
editOverlay.applet.applet.action("remove").trigger();
editOverlay.opacity = 0;
}
}
}
}
PlasmaCore.FrameSvgItem {
id: background
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: editOverlay.height - (plasmoid.availableScreenRect.y + plasmoid.availableScreenRect.height)
}
height: buttonsLayout.height + fixedMargins.top + fixedMargins.bottom/2
imagePath: "widgets/background"
enabledBorders: PlasmaCore.FrameSvg.TopBorder
RowLayout {
id: buttonsLayout
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: parent.fixedMargins.top
leftMargin: parent.fixedMargins.left/2
rightMargin: parent.fixedMargins.right/2
bottomMargin: parent.fixedMargins.bottom/2
}
PlasmaComponents.ToolButton {
Layout.fillWidth: true
Layout.fillHeight:true
text: i18n("Wallpaper...")
onClicked: {
plasmoid.action("configure").trigger();
editOverlay.opacity = 0;
}
}
PlasmaComponents.ToolButton {
Layout.fillWidth: true
Layout.fillHeight:true
text: i18n("Add Widgets...")
onClicked: {
plasmoid.action("add widgets").trigger();
editOverlay.opacity = 0;
}
}
}
}
}

View file

@ -22,11 +22,13 @@ import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Window {
id: window
property alias state: background.state
property alias icon: icon.source
width: Screen.width
height: Screen.height
color: "transparent"
@ -41,19 +43,33 @@ Window {
}
}
PlasmaCore.ColorScope {
Item {
id: background
anchors.fill: parent
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
//colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
width: window.width
height: window.height
state: "closed"
Rectangle {
anchors.fill: parent
color: background.backgroundColor
PlasmaComponents.BusyIndicator {
ColumnLayout {
anchors.centerIn: parent
PlasmaCore.IconItem {
id: icon
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
Layout.preferredWidth: units.iconSizes.enormous
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignCenter
}
PlasmaExtras.Heading {
text: window.title
Layout.alignment: Qt.AlignCenter
}
/* PlasmaComponents.BusyIndicator {
Layout.alignment: Qt.AlignCenter
}*/
}
}

View file

@ -1,63 +0,0 @@
import QtQuick 2.5
import QtQuick.Layouts 1.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kio 1.0 as Kio
import org.kde.plasma.components 2.0 as PlasmaComponents
Item {
id: delegateRoot
property int iconSize
property var modelData: model
property bool isDropTarget: delegateRoot != dragDelegate && root.reorderingApps && applicationsView.dragData && applicationsView.dragData.ApplicationStorageIdRole == modelData.ApplicationStorageIdRole
property alias maximumLineCount: label.maximumLineCount
width: applicationsView.cellWidth
height: applicationsView.cellHeight
ColumnLayout {
anchors {
left: parent.left
right: parent.right
horizontalCenter: parent.horizonalCenter
verticalCenter: parent.verticalCenter
}
opacity: isDropTarget ? 0.3 : 1
PlasmaCore.IconItem {
id: icon
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: delegateRoot.iconSize
Layout.preferredHeight: delegateRoot.iconSize
usesPlasmaTheme: false
source: modelData.ApplicationIconRole
scale: root.reorderingApps && applicationsView.dragData && applicationsView.dragData.ApplicationStorageIdRole != modelData.ApplicationStorageIdRole ? 0.6 : 1
Behavior on scale {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
}
PlasmaComponents.Label {
id: label
visible: text.length > 0
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.leftMargin: units.gridUnit
Layout.rightMargin: units.gridUnit
wrapMode: Text.WordWrap
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
maximumLineCount: 1
elide: Text.ElideRight
text: modelData.ApplicationNameRole
font.pixelSize: theme.defaultFont.pixelSize
color: PlasmaCore.ColorScope.textColor
}
}
}

View file

@ -31,7 +31,6 @@ import org.kde.milou 0.1 as Milou
Rectangle {
id: krunner
anchors.fill: parent
height: childrenRect.height
color: listView.visible ? Qt.rgba(0, 0, 0, 0.8) : "transparent"
property alias showingResults: listView.visible
@ -53,7 +52,7 @@ Rectangle {
clip: true
imagePath: "widgets/background"
enabledBorders: PlasmaCore.FrameSvg.BottomBorder
height: childrenRect.height + fixedMargins.top/2 + fixedMargins.bottom
height: Math.min(krunner.height, childrenRect.height + fixedMargins.top/2 + fixedMargins.bottom)
Behavior on height {
NumberAnimation {
duration: units.longDuration
@ -71,7 +70,7 @@ Rectangle {
}
ColumnLayout {
height: Qt.inputMethod.keyboardRectangle.height > 0 ? (Math.min(implicitHeight, Qt.inputMethod.keyboardRectangle.y - plasmoid.availableScreenRect.y)) : implicitHeight
height: Qt.inputMethod.keyboardRectangle.height > 0 ? (Math.min(implicitHeight, background.height, Qt.inputMethod.keyboardRectangle.y - plasmoid.availableScreenRect.y)) : implicitHeight
anchors {
left: parent.left
right: parent.right

View file

@ -1,25 +0,0 @@
import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
PlasmaCore.ColorScope {
colorGroup: PlasmaCore.Theme.NormalColorGroup
PlasmaCore.FrameSvgItem {
z: -1
imagePath: "widgets/background"
enabledBorders: PlasmaCore.FrameSvgItem.TopBorder | PlasmaCore.FrameSvgItem.BottomBorder
anchors {
fill: parent
topMargin: -margins.top / 2
bottomMargin: -margins.bottom / 2
}
}
//cut away one line from the favorites bar
height: applicationsView.cellHeight
width: parent.width
y: parent.height / 2 - height / 2
x: 0
}

View file

@ -1,81 +1,45 @@
/*
* Copyright 2015 Marco Martin <mart@kde.org>
* Copyright 2019 Marco Martin <mart@kde.org>
*
* 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 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 General Public License for more details.
* 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 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.
* 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.4
import QtQuick 2.12
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
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.components 3.0 as PlasmaComponents
import org.kde.draganddrop 2.0 as DragDrop
import "LayoutManager.js" as LayoutManager
import "launcher" as Launcher
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
import org.kde.phone.homescreen 1.0
Item {
id: root
width: 480
height: 640
width: 640
height: 480
//BEGIN properties
property Item toolBox
property alias appletsSpace: applicationsView.headerItem
readonly property int iconSize: units.iconSizes.large
property int buttonHeight: dragDelegate.height
property bool reorderingApps: false
property var layoutManager: LayoutManager
//END properties
//BEGIN functions
function addApplet(applet, x, y) {
var container = appletContainerComponent.createObject(appletsSpace.layout)
container.visible = true
print("Applet added: " + applet)
var appletWidth = applet.width;
var appletHeight = applet.height;
applet.parent = container;
container.applet = applet;
applet.anchors.fill = container;
applet.visible = true;
container.visible = true;
// If the provided position is valid, use it.
if (x >= 0 && y >= 0) {
var index = LayoutManager.insertAtCoordinates(container, x , y);
// Fall through to determining an appropriate insert position.
} else {
var before = null;
//container.animationsEnabled = false;
if (before) {
LayoutManager.insertBefore(before, container);
// Fall through to adding at the end.
} else {
container.parent = appletsSpace.layout;
}
//event compress the enable of animations
//startupTimer.restart();
}
}
//Autoscroll related functions
function scrollUp() {
autoScrollTimer.scrollDown = false;
@ -97,122 +61,50 @@ Item {
scrollDownIndicator.opacity = 0;
}
function recalculateMaxFavoriteCount() {
if (!componentComplete) {
return;
}
plasmoid.nativeInterface.applicationListModel.maxFavoriteCount = Math.floor(Math.min(width, height) / launcher.cellWidth);
}
//END functions
//BEGIN slots
property bool componentComplete: false
onWidthChanged: recalculateMaxFavoriteCount()
onHeightChanged:recalculateMaxFavoriteCount()
Component.onCompleted: {
LayoutManager.plasmoid = plasmoid;
LayoutManager.root = root;
LayoutManager.layout = appletsSpace.layout;
LayoutManager.restore();
applicationsView.contentY = -applicationsView.headerItem.height*2;
plasmoid.nativeInterface.applicationListModel.appOrder = plasmoid.configuration.AppOrder;
plasmoid.nativeInterface.applicationListModel.loadApplications();
componentComplete = true;
recalculateMaxFavoriteCount()
}
Timer {
interval: 200
running: true
onTriggered: {
applicationsView.contentY = -applicationsView.headerItem.height;
}
}
Containment.onAppletAdded: {
addApplet(applet, x, y);
LayoutManager.save();
}
Connections {
target: plasmoid.nativeInterface.applicationListModel
onAppOrderChanged: {
plasmoid.configuration.AppOrder = plasmoid.nativeInterface.applicationListModel.appOrder;
}
}
//END slots
Timer {
id: autoScrollTimer
property bool scrollDown: true
repeat: true
interval: 1500
onTriggered: {
//reordering launcher icons
if (root.reorderingApps) {
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(applicationsView.contentItem.height - applicationsView.headerItem.height - root.height, applicationsView.contentY + root.height/2) :
//Scroll up
Math.max(0, applicationsView.contentY - root.height/2);
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(mainFlickable.contentItem.height - root.height, mainFlickable.contentY + root.height/2) :
//Scroll up
Math.max(0, mainFlickable.contentY - root.height/2);
//reordering applets
} else {
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(-root.height, applicationsView.contentY + root.height/2) :
//Scroll up
Math.max(-applicationsView.headerItem.height + root.height, applicationsView.contentY - root.height/2);
}
scrollAnim.running = true;
}
}
Component {
id: appletContainerComponent
MouseArea {
id: appletContainer
//not used yet
property bool animationsEnabled: true
property Item applet
z: applet && applet.compactRepresentationItem && applet.expanded ? 99 : 0
opacity: 1 - Math.abs(x/(width/2))
Layout.fillWidth: true
Layout.fillHeight: applet && applet.Layout.fillHeight
Connections {
target: plasmoid
onAppletRemoved: {
print("Applet removed Applet-" + applet.id)
if (applet.id == appletContainer.applet.id) {
appletContainer.destroy();
}
}
}
onAppletChanged: {
if (applet.backgroundHints == PlasmaCore.Types.StandardBackground) {
applet.anchors.margins = background.margins.top;
}
}
property int oldX: x
property int oldY: y
PlasmaCore.FrameSvgItem {
id: background
z: -1
anchors.fill: parent
imagePath: "widgets/background"
visible: applet.backgroundHints == PlasmaCore.Types.StandardBackground
}
width: parent.width
height: Math.max(applet.switchHeight + 1 + background.margins.top + background.margins.bottom, Math.max(applet.Layout.minimumHeight, (root.height-applicationsView.headerItem.margin) / 2))
PlasmaComponents.BusyIndicator {
z: 1000
visible: applet && applet.busy
running: visible
anchors.centerIn: parent
width: Math.min(parent.width, parent.height)
height: width
}
Connections {
target: plasmoid
onEditModeChanged: {
appletsLayout.editMode = plasmoid.editMode
}
}
FeedbackWindow {
id: feedbackWindow
}
SequentialAnimation {
id: clickFedbackAnimation
property Item target
@ -234,12 +126,205 @@ Item {
easing.type: Easing.InOutQuad
}
}
FeedbackWindow {
id: feedbackWindow
Launcher.LauncherDragManager {
id: launcherDragManager
anchors.fill: parent
z: 2
appletsLayout: appletsLayout
launcherGrid: launcher
favoriteStrip: favoriteStrip
}
Flickable {
id: mainFlickable
width: parent.width
anchors {
fill: parent
topMargin: plasmoid.availableScreenRect.y + krunner.inputHeight
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
}
bottomMargin: favoriteStrip.height
contentWidth: width
contentHeight: flickableContents.height
interactive: !plasmoid.editMode && !launcherDragManager.active
PlasmaComponents.ScrollBar.vertical: PlasmaComponents.ScrollBar {
id: scrollabr
opacity: mainFlickable.moving
interactive: false
Behavior on opacity {
OpacityAnimator {
duration: units.longDuration * 2
easing.type: Easing.InOutQuad
}
}
}
NumberAnimation {
id: scrollAnim
target: mainFlickable
properties: "contentY"
duration: units.longDuration
easing.type: Easing.InOutQuad
}
Column {
id: flickableContents
width: mainFlickable.width
spacing: Math.max(0, favoriteStrip.frame.height - mainFlickable.contentY)
DragDrop.DropArea {
anchors {
left: parent.left
right: parent.right
}
height: mainFlickable.height - favoriteStrip.frame.height //TODO: multiple widgets pages
onDragEnter: {
event.accept(event.proposedAction);
}
onDragMove: {
appletsLayout.showPlaceHolderAt(
Qt.rect(event.x - appletsLayout.defaultItemWidth / 2,
event.y - appletsLayout.defaultItemHeight / 2,
appletsLayout.defaultItemWidth,
appletsLayout.defaultItemHeight)
);
}
onDragLeave: {
appletsLayout.hidePlaceHolder();
}
preventStealing: true
onDrop: {
plasmoid.processMimeData(event.mimeData,
event.x - appletsLayout.placeHolder.width / 2, event.y - appletsLayout.placeHolder.height / 2);
event.accept(event.proposedAction);
appletsLayout.hidePlaceHolder();
}
PlasmaCore.Svg {
id: arrowsSvg
imagePath: "widgets/arrows"
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
}
PlasmaCore.IconItem {
z: 9
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
source: "arrow-up"
width: units.iconSizes.medium
height: width
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
MouseArea {
anchors {
fill: parent
margins: -units.smallSpacing
}
onClicked: mainFlickable.flick(0, -mainFlickable.height)
}
}
ContainmentLayoutManager.AppletsLayout {
id: appletsLayout
anchors.fill: parent
cellWidth: Math.floor(width / launcher.columns)
cellHeight: launcher.cellHeight
configKey: width > height ? "ItemGeometriesHorizontal" : "ItemGeometriesVertical"
containment: plasmoid
editModeCondition: plasmoid.immutable
? ContainmentLayoutManager.AppletsLayout.Manual
: ContainmentLayoutManager.AppletsLayout.AfterPressAndHold
// Sets the containment in edit mode when we go in edit mode as well
onEditModeChanged: plasmoid.editMode = editMode
minimumItemWidth: units.gridUnit * 3
minimumItemHeight: minimumItemWidth
defaultItemWidth: units.gridUnit * 6
defaultItemHeight: defaultItemWidth
//cellWidth: units.iconSizes.small
//cellHeight: cellWidth
acceptsAppletCallback: function(applet, x, y) {
print("Applet: "+applet+" "+x+" "+y)
return true;
}
appletContainerComponent: ContainmentLayoutManager.BasicAppletContainer {
id: appletContainer
configOverlayComponent: ConfigOverlay {}
onEditModeChanged: {
launcherDragManager.active = dragActive || editMode;
}
onDragActiveChanged: {
launcherDragManager.active = dragActive || editMode;
}
}
placeHolder: ContainmentLayoutManager.PlaceHolder {}
}
}
Launcher.LauncherGrid {
id: launcher
anchors {
left: parent.left
right: parent.right
}
favoriteStrip: favoriteStrip
appletsLayout: appletsLayout
}
}
}
ScrollIndicator {
id: scrollUpIndicator
anchors {
top: parent.top
topMargin: units.gridUnit * 2
}
elementId: "up-arrow"
}
ScrollIndicator {
id: scrollDownIndicator
anchors {
bottom: favoriteStrip.top
bottomMargin: units.gridUnit
}
elementId: "down-arrow"
}
Launcher.FavoriteStrip {
id: favoriteStrip
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
}
appletsLayout: appletsLayout
launcherGrid: launcher
//y: Math.max(krunner.inputHeight, root.height - height - mainFlickable.contentY)
}
KRunner {
id: krunner
z: 998
height: plasmoid.availableScreenRect.height
anchors {
top: parent.top
left: parent.left
@ -247,275 +332,5 @@ Item {
topMargin: plasmoid.availableScreenRect.y
}
}
EditOverlay {
id: editOverlay
z: 999
}
MouseEventListener {
id: mainListener
anchors.fill: parent
//Events handling: those events are about clicking and reordering of app icons
//applet related events are in AppeltsArea.qml
onPressAndHold: {
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//in favorites area?
var item;
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
item = applicationsView.headerItem.favoritesStrip.itemAt(pos.x, pos.y);
} else {
pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
item = applicationsView.itemAt(pos.x, pos.y)
}
if (!item) {
return;
}
applicationsView.dragData = new Object;
applicationsView.dragData.ApplicationNameRole = item.modelData.ApplicationNameRole;
applicationsView.dragData.ApplicationIconRole = item.modelData.ApplicationIconRole;
applicationsView.dragData.ApplicationStorageIdRole = item.modelData.ApplicationStorageIdRole;
applicationsView.dragData.ApplicationEntryPathRole = item.modelData.ApplicationEntryPathRole;
applicationsView.dragData.ApplicationOriginalRowRole = item.modelData.ApplicationOriginalRowRole;
dragDelegate.modelData = applicationsView.dragData;
applicationsView.interactive = false;
root.reorderingApps = true;
dragDelegate.x = Math.floor(mouse.x / root.buttonHeight) * root.buttonHeight
dragDelegate.y = Math.floor(mouse.y / root.buttonHeight) * root.buttonHeight
dragDelegate.xTarget = mouse.x - dragDelegate.width/2;
dragDelegate.yTarget = mouse.y - dragDelegate.width/2;
dragDelegate.opacity = 1;
}
onPositionChanged: {
if (!applicationsView.dragData) {
return;
}
dragDelegate.x = mouse.x - dragDelegate.width/2;
dragDelegate.y = mouse.y - dragDelegate.height/2;
var pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
//in favorites area?
if (applicationsView.headerItem.favoritesStrip.contains(mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y))) {
pos.y = 1;
}
var newRow = (Math.round(applicationsView.width / applicationsView.cellWidth) * Math.floor(pos.y / applicationsView.cellHeight) + Math.floor(pos.x / applicationsView.cellWidth));
if (applicationsView.dragData.ApplicationOriginalRowRole != newRow) {
plasmoid.nativeInterface.applicationListModel.moveItem(applicationsView.dragData.ApplicationOriginalRowRole, newRow);
applicationsView.dragData.ApplicationOriginalRowRole = newRow;
}
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//FAVORITES
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
root.stopScroll();
//SCROLL UP
} else if (applicationsView.contentY > 0 && mouse.y < root.buttonHeight + root.height / 4) {
root.scrollUp();
//SCROLL DOWN
} else if (!applicationsView.atYEnd && mouse.y > 3 * (root.height / 4)) {
root.scrollDown();
//DON't SCROLL
} else {
root.stopScroll();
}
}
onReleased: {
if (krunner.showingResults) {
return;
}
applicationsView.interactive = true;
dragDelegate.xTarget = Math.floor(mouse.x / root.buttonHeight) * root.buttonHeight;
dragDelegate.yTarget = Math.floor(mouse.y / root.buttonHeight) * root.buttonHeight;
dragDelegate.opacity = 0;
if (dragDelegate.modelData) {
dragDelegate.modelData.ApplicationIconRole = "";
dragDelegate.modelDataChanged();
}
applicationsView.dragData = null;
root.reorderingApps = false;
applicationsView.forceLayout();
root.stopScroll();
}
onClicked: {
if (krunner.showingResults) {
return;
}
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//in favorites area?
var item;
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
item = applicationsView.headerItem.favoritesStrip.itemAt(pos.x, pos.y);
} else {
pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
item = applicationsView.itemAt(pos.x, pos.y)
}
if (!item) {
return;
}
clickFedbackAnimation.target = item;
clickFedbackAnimation.running = true;
feedbackWindow.title = item.modelData.ApplicationNameRole;
feedbackWindow.state = "open";
plasmoid.nativeInterface.applicationListModel.runApplication(item.modelData.ApplicationStorageIdRole);
}
PlasmaCore.ColorScope {
anchors.fill: parent
//TODO: decide what color we want applets
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
Rectangle {
color: PlasmaCore.ColorScope.backgroundColor
opacity: 0.9 * (Math.min(applicationsView.contentY + root.height, root.height) / root.height)
anchors.fill: parent
}
PlasmaCore.Svg {
id: arrowsSvg
imagePath: "widgets/arrows"
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
}
PlasmaCore.SvgItem {
id: scrollUpIndicator
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 300
}
z: 2
opacity: 0
svg: arrowsSvg
elementId: "up-arrow"
width: units.iconSizes.large
height: width
Behavior on opacity {
OpacityAnimator {
duration: 1000
easing.type: Easing.InOutQuad
}
}
}
PlasmaCore.SvgItem {
id: scrollDownIndicator
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: units.gridUnit * 2
}
z: 2
opacity: 0
svg: arrowsSvg
elementId: "down-arrow"
width: units.iconSizes.large
height: width
Behavior on opacity {
OpacityAnimator {
duration: 1000
easing.type: Easing.InOutQuad
}
}
}
//This HomeLauncher is the placeholder for the "drag"
//delegate (that is not actual drag and drop
HomeLauncher {
id: dragDelegate
z: 999
property int xTarget
property int yTarget
iconSize: root.iconSize
Behavior on opacity {
ParallelAnimation {
OpacityAnimator {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PropertyAnimation {
properties: "x"
to: dragDelegate.xTarget
target: dragDelegate
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PropertyAnimation {
properties: "y"
to: dragDelegate.yTarget
target: dragDelegate
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
}
}
GridView {
id: applicationsView
anchors {
fill: parent
topMargin: plasmoid.availableScreenRect.y
bottomMargin: root.height - plasmoid.availableScreenRect.y - plasmoid.availableScreenRect.height
}
property var dragData
cellWidth: root.width / 4
cellHeight: root.buttonHeight
model: plasmoid.nativeInterface.applicationListModel
snapMode: GridView.SnapToRow
NumberAnimation {
id: scrollAnim
target: applicationsView
properties: "contentY"
duration: units.longDuration
easing.type: Easing.InOutQuad
}
move: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
moveDisplaced: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
//clip: true
delegate: HomeLauncher {
visible: index > 3
iconSize: root.iconSize
}
header: AppletsArea {}
footer: Item {
width: units. gridUnit * 4
height: width
}
}
PlasmaComponents.ScrollBar {
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
}
interactive: false
flickableItem: applicationsView
}
}
}
}

View file

@ -1,24 +0,0 @@
set(homescreen_SRCS
homescreen.cpp
applicationlistmodel.cpp
)
add_library(plasma_containment_phone_homescreen2 MODULE ${homescreen_SRCS})
kcoreaddons_desktop_to_json(plasma_containment_phone_homescreen2 package/metadata.desktop)
target_link_libraries(plasma_containment_phone_homescreen2
Qt5::Gui
KF5::Plasma
Qt5::Qml
Qt5::Quick
KF5::I18n
KF5::Service
KF5::KIOWidgets
)
install(TARGETS plasma_containment_phone_homescreen2 DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/applets)
plasma_install_package(package org.kde.phone.homescreen2)

View file

@ -1,4 +0,0 @@
#! /usr/bin/env bash
$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp
$XGETTEXT `find . -name \*.js -o -name \*.qml -o -name \*.cpp` -o $podir/plasma_applet_org.kde.phone.homescreen.pot
rm -f rc.cpp

View file

@ -1,359 +0,0 @@
/*
* Copyright (C) 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
*
* 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 <QByteArray>
#include <QModelIndex>
#include <QProcess>
// KDE
#include <KPluginInfo>
#include <KService>
#include <KServiceGroup>
#include <KServiceTypeTrader>
#include <KSharedConfig>
#include <KSycoca>
#include <KSycocaEntry>
#include <KShell>
#include <KIOWidgets/KRun>
#include <QDebug>
ApplicationListModel::ApplicationListModel(HomeScreen *parent)
: QAbstractListModel(parent),
m_homeScreen(parent)
{
//can't use the new syntax as this signal is overloaded
connect(KSycoca::self(), SIGNAL(databaseChanged(const QStringList &)),
this, SLOT(sycocaDbChanged(const QStringList &)));
m_favorites = m_homeScreen->config().readEntry("Favorites", QStringList());
m_desktopItems = m_homeScreen->config().readEntry("DesktopItems", QStringList()).toSet();
m_appOrder = m_homeScreen->config().readEntry("AppOrder", QStringList());
m_maxFavoriteCount = m_homeScreen->config().readEntry("MaxFavoriteCount", 5);
int i = 0;
for (auto app : m_appOrder) {
m_appPositions[app] = i;
++i;
}
//here or delayed?
loadApplications();
}
ApplicationListModel::~ApplicationListModel()
= default;
QHash<int, QByteArray> ApplicationListModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[ApplicationNameRole] = "ApplicationNameRole";
roleNames[ApplicationIconRole] = "ApplicationIconRole";
roleNames[ApplicationStorageIdRole] = "ApplicationStorageIdRole";
roleNames[ApplicationEntryPathRole] = "ApplicationEntryPathRole";
roleNames[ApplicationOriginalRowRole] = "ApplicationOriginalRowRole";
roleNames[ApplicationStartupNotifyRole] = "ApplicationStartupNotifyRole";
roleNames[ApplicationLocationRole] = "ApplicationLocationRole";
return roleNames;
}
void ApplicationListModel::sycocaDbChanged(const QStringList &changes)
{
if (!changes.contains("apps") && !changes.contains("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("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;
KServiceGroup::List subGroupList = group->entries(true);
QMap<int, ApplicationData> orderedList;
QList<ApplicationData> 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<KServiceGroup* >(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<KServiceGroup* >(entry.data()));
subGroupList << serviceGroup;
} else if (entry->property("Exec").isValid()) {
KService::Ptr service(static_cast<KService* >(entry.data()));
if (service->isApplication() &&
!blacklist.contains(service->desktopEntryName()) &&
service->showOnCurrentPlatform() &&
!service->property("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("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 nullptr;
return Qt::ItemIsDragEnabled|QAbstractItemModel::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[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.toList());
// Out of Desktop
} else if (data.location == Desktop) {
m_desktopItems.remove(data.storageId);
m_homeScreen->config().writeEntry("DesktopItems", m_desktopItems.toList());
}
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 (auto app : 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);
KRun::runService(*service, QList<QUrl>(), nullptr);
}
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"

View file

@ -1,114 +0,0 @@
/*
* Copyright (C) 2014 Antonis Tsiapaliokas <antonis.tsiapaliokas@kde.org>
*
* 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 <QObject>
#include <QAbstractListModel>
#include <QList>
#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;
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<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
Q_INVOKABLE void setLocation(int row, LauncherLocation location);
Q_INVOKABLE void moveItem(int row, int order);
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();
private:
QList<ApplicationData> m_applicationList;
HomeScreen *m_homeScreen = nullptr;
int m_maxFavoriteCount = 0;
QStringList m_appOrder;
QStringList m_favorites;
QSet<QString> m_desktopItems;
QHash<QString, int> m_appPositions;
};
#endif // APPLICATIONLISTMODEL_H

View file

@ -1,66 +0,0 @@
/***************************************************************************
* Copyright (C) 2015 Marco Martin <mart@kde.org> *
* *
* 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 <QtQml>
#include <QDebug>
#include <QQuickItem>
HomeScreen::HomeScreen(QObject *parent, const QVariantList &args)
: Plasma::Containment(parent, args)
{
qmlRegisterUncreatableType<ApplicationListModel>("org.kde.phone.homescreen", 1, 0, "ApplicationListModel", QStringLiteral("Cannot create item of type ApplicationListModel"));
setHasConfigurationInterface(true);
}
HomeScreen::~HomeScreen()
= default;
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->parentItem() != item2->parentItem()) {
return;
}
item1->stackBefore(item2);
}
void HomeScreen::stackAfter(QQuickItem *item1, QQuickItem *item2)
{
if (!item1 || !item2 || item1->parentItem() != item2->parentItem()) {
return;
}
item1->stackAfter(item2);
}
K_EXPORT_PLASMA_APPLET_WITH_JSON(homescreen, HomeScreen, "metadata.json")
#include "homescreen.moc"

View file

@ -1,49 +0,0 @@
/***************************************************************************
* Copyright (C) 2015 Marco Martin <mart@kde.org> *
*
* *
* 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 . *
***************************************************************************/
#ifndef HOMESCREEN_H
#define HOMESCREEN_H
#include <Plasma/Containment>
class QQuickItem;
class ApplicationListModel;
class HomeScreen : public Plasma::Containment
{
Q_OBJECT
Q_PROPERTY(ApplicationListModel *applicationListModel READ applicationListModel CONSTANT)
public:
HomeScreen( QObject *parent, const QVariantList &args );
~HomeScreen() override;
ApplicationListModel *applicationListModel();
Q_INVOKABLE void stackBefore(QQuickItem *item1, QQuickItem *item2);
Q_INVOKABLE void stackAfter(QQuickItem *item1, QQuickItem *item2);
private:
ApplicationListModel *m_applicationListModel = nullptr;
};
#endif

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="General">
<entry name="AppOrder" type="StringList">
<label>order of apps</label>
<default>org.kde.phone.dialer.desktop</default>
</entry>
</group>
</kcfg>

View file

@ -1,118 +0,0 @@
/*
* Copyright 2015 Marco Martin <notmart@gmail.com>
*
* 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.0
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Window {
id: window
property alias state: background.state
property alias icon: icon.source
width: Screen.width
height: Screen.height
color: "transparent"
onVisibleChanged: {
if (!visible) {
background.state = "closed";
}
}
onActiveChanged: {
if (!active) {
background.state = "closed";
}
}
Item {
id: background
anchors.fill: parent
//colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
width: window.width
height: window.height
state: "closed"
Rectangle {
anchors.fill: parent
color: background.backgroundColor
ColumnLayout {
anchors.centerIn: parent
PlasmaCore.IconItem {
id: icon
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
Layout.preferredWidth: units.iconSizes.enormous
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignCenter
}
PlasmaExtras.Heading {
text: window.title
Layout.alignment: Qt.AlignCenter
}
/* PlasmaComponents.BusyIndicator {
Layout.alignment: Qt.AlignCenter
}*/
}
}
states: [
State {
name: "closed"
PropertyChanges {
target: background
scale: 0
}
PropertyChanges {
target: window
visible: false
}
},
State {
name: "open"
PropertyChanges {
target: background
scale: 1
}
PropertyChanges {
target: window
visible: true
}
}
]
transitions: [
Transition {
from: "closed"
SequentialAnimation {
ScriptAction {
script: window.visible = true;
}
PropertyAnimation {
target: background
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "scale"
}
}
}
]
}
}

View file

@ -1,123 +0,0 @@
/*
* Copyright (C) 2015 Vishesh Handa <vhanda@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.milou 0.1 as Milou
Rectangle {
id: krunner
height: childrenRect.height
color: listView.visible ? Qt.rgba(0, 0, 0, 0.8) : "transparent"
property alias showingResults: listView.visible
property int inputHeight: queryField.height + background.fixedMargins.top/2 + background.fixedMargins.bottom
MouseArea {
enabled: listView.visible
anchors.fill: parent
preventStealing: true
onClicked: queryField.text = "";
}
PlasmaCore.FrameSvgItem {
id: background
anchors {
left: parent.left
right: parent.right
top: parent.top
}
clip: true
imagePath: "widgets/background"
enabledBorders: PlasmaCore.FrameSvg.BottomBorder
height: Math.min(krunner.height, childrenRect.height + fixedMargins.top/2 + fixedMargins.bottom)
Behavior on height {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
transform: Translate {
y: root.locked || editOverlay.visible ? -background.height : 0
Behavior on y {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
}
ColumnLayout {
height: Qt.inputMethod.keyboardRectangle.height > 0 ? (Math.min(implicitHeight, background.height, Qt.inputMethod.keyboardRectangle.y - plasmoid.availableScreenRect.y)) : implicitHeight
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: background.fixedMargins.top / 2
leftMargin: background.fixedMargins.left / 2
rightMargin: background.fixedMargins.right / 2
}
PlasmaComponents.TextField {
id: queryField
clearButtonShown: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Keys.onEscapePressed: runnerWindow.visible = false
placeholderText: "Search..."
}
PlasmaExtras.ScrollArea {
visible: listView.count > 0
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: listView.contentHeight
Layout.alignment: Qt.AlignTop
Milou.ResultsListView {
id: listView
queryString: queryField.text
highlight: null
onActivated: queryField.text = ""
onUpdateQueryString: {
queryField.text = text
queryField.cursorPosition = cursorPosition
}
}
}
Keys.onReturnPressed: {
if (queryField.texr.length == 0)
runnerWindow.visible = false;
}
Keys.onEnterPressed: {
if (queryField.texr.length == 0)
runnerWindow.visible = false;
}
}
}
}

View file

@ -1,336 +0,0 @@
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* 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.12
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.draganddrop 2.0 as DragDrop
import "launcher" as Launcher
import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
import org.kde.phone.homescreen 1.0
Item {
id: root
width: 640
height: 480
property Item toolBox
//BEGIN functions
//Autoscroll related functions
function scrollUp() {
autoScrollTimer.scrollDown = false;
autoScrollTimer.running = true;
scrollUpIndicator.opacity = 1;
scrollDownIndicator.opacity = 0;
}
function scrollDown() {
autoScrollTimer.scrollDown = true;
autoScrollTimer.running = true;
scrollUpIndicator.opacity = 0;
scrollDownIndicator.opacity = 1;
}
function stopScroll() {
autoScrollTimer.running = false;
scrollUpIndicator.opacity = 0;
scrollDownIndicator.opacity = 0;
}
function recalculateMaxFavoriteCount() {
if (!componentComplete) {
return;
}
plasmoid.nativeInterface.applicationListModel.maxFavoriteCount = Math.floor(Math.min(width, height) / launcher.cellWidth);
}
//END functions
property bool componentComplete: false
onWidthChanged: recalculateMaxFavoriteCount()
onHeightChanged:recalculateMaxFavoriteCount()
Component.onCompleted: {
componentComplete = true;
recalculateMaxFavoriteCount()
}
Timer {
id: autoScrollTimer
property bool scrollDown: true
repeat: true
interval: 1500
onTriggered: {
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(mainFlickable.contentItem.height - root.height, mainFlickable.contentY + root.height/2) :
//Scroll up
Math.max(0, mainFlickable.contentY - root.height/2);
scrollAnim.running = true;
}
}
Connections {
target: plasmoid
onEditModeChanged: {
appletsLayout.editMode = plasmoid.editMode
}
}
FeedbackWindow {
id: feedbackWindow
}
SequentialAnimation {
id: clickFedbackAnimation
property Item target
NumberAnimation {
target: clickFedbackAnimation.target
properties: "scale"
to: 2
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PauseAnimation {
duration: units.shortDuration
}
NumberAnimation {
target: clickFedbackAnimation.target
properties: "scale"
to: 1
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
Launcher.LauncherDragManager {
id: launcherDragManager
anchors.fill: parent
z: 2
appletsLayout: appletsLayout
launcherGrid: launcher
favoriteStrip: favoriteStrip
}
Flickable {
id: mainFlickable
width: parent.width
anchors {
fill: parent
topMargin: plasmoid.availableScreenRect.y + krunner.inputHeight
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
}
bottomMargin: favoriteStrip.height
contentWidth: width
contentHeight: flickableContents.height
interactive: !plasmoid.editMode && !launcherDragManager.active
PlasmaComponents.ScrollBar.vertical: PlasmaComponents.ScrollBar {
id: scrollabr
opacity: mainFlickable.moving
interactive: false
Behavior on opacity {
OpacityAnimator {
duration: units.longDuration * 2
easing.type: Easing.InOutQuad
}
}
}
NumberAnimation {
id: scrollAnim
target: mainFlickable
properties: "contentY"
duration: units.longDuration
easing.type: Easing.InOutQuad
}
Column {
id: flickableContents
width: mainFlickable.width
spacing: Math.max(0, favoriteStrip.frame.height - mainFlickable.contentY)
DragDrop.DropArea {
anchors {
left: parent.left
right: parent.right
}
height: mainFlickable.height - favoriteStrip.frame.height //TODO: multiple widgets pages
onDragEnter: {
event.accept(event.proposedAction);
}
onDragMove: {
appletsLayout.showPlaceHolderAt(
Qt.rect(event.x - appletsLayout.defaultItemWidth / 2,
event.y - appletsLayout.defaultItemHeight / 2,
appletsLayout.defaultItemWidth,
appletsLayout.defaultItemHeight)
);
}
onDragLeave: {
appletsLayout.hidePlaceHolder();
}
preventStealing: true
onDrop: {
plasmoid.processMimeData(event.mimeData,
event.x - appletsLayout.placeHolder.width / 2, event.y - appletsLayout.placeHolder.height / 2);
event.accept(event.proposedAction);
appletsLayout.hidePlaceHolder();
}
PlasmaCore.Svg {
id: arrowsSvg
imagePath: "widgets/arrows"
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
}
PlasmaCore.IconItem {
z: 9
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
source: "arrow-up"
width: units.iconSizes.medium
height: width
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
MouseArea {
anchors {
fill: parent
margins: -units.smallSpacing
}
onClicked: mainFlickable.flick(0, -mainFlickable.height)
}
}
ContainmentLayoutManager.AppletsLayout {
id: appletsLayout
anchors.fill: parent
cellWidth: Math.floor(width / launcher.columns)
cellHeight: launcher.cellHeight
configKey: width > height ? "ItemGeometriesHorizontal" : "ItemGeometriesVertical"
containment: plasmoid
editModeCondition: plasmoid.immutable
? ContainmentLayoutManager.AppletsLayout.Manual
: ContainmentLayoutManager.AppletsLayout.AfterPressAndHold
// Sets the containment in edit mode when we go in edit mode as well
onEditModeChanged: plasmoid.editMode = editMode
minimumItemWidth: units.gridUnit * 3
minimumItemHeight: minimumItemWidth
defaultItemWidth: units.gridUnit * 6
defaultItemHeight: defaultItemWidth
//cellWidth: units.iconSizes.small
//cellHeight: cellWidth
acceptsAppletCallback: function(applet, x, y) {
print("Applet: "+applet+" "+x+" "+y)
return true;
}
appletContainerComponent: ContainmentLayoutManager.BasicAppletContainer {
id: appletContainer
configOverlayComponent: ConfigOverlay {}
onEditModeChanged: {
launcherDragManager.active = dragActive || editMode;
}
onDragActiveChanged: {
launcherDragManager.active = dragActive || editMode;
}
}
placeHolder: ContainmentLayoutManager.PlaceHolder {}
}
}
Launcher.LauncherGrid {
id: launcher
anchors {
left: parent.left
right: parent.right
}
favoriteStrip: favoriteStrip
appletsLayout: appletsLayout
}
}
}
ScrollIndicator {
id: scrollUpIndicator
anchors {
top: parent.top
topMargin: units.gridUnit * 2
}
elementId: "up-arrow"
}
ScrollIndicator {
id: scrollDownIndicator
anchors {
bottom: favoriteStrip.top
bottomMargin: units.gridUnit
}
elementId: "down-arrow"
}
Launcher.FavoriteStrip {
id: favoriteStrip
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: plasmoid.screenGeometry.height - plasmoid.availableScreenRect.height - plasmoid.availableScreenRect.y
}
appletsLayout: appletsLayout
launcherGrid: launcher
//y: Math.max(krunner.inputHeight, root.height - height - mainFlickable.contentY)
}
KRunner {
id: krunner
z: 998
height: plasmoid.availableScreenRect.height
anchors {
top: parent.top
left: parent.left
right: parent.right
topMargin: plasmoid.availableScreenRect.y
}
}
}

View file

@ -1,37 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Keywords=
Name=Phone Homescreen
Name[ca]=Pantalla d'inici del telèfon
Name[ca@valencia]=Pantalla d'inici del telèfon
Name[cs]=Domácí obrazovka telefonu
Name[en_GB]=Phone Homescreen
Name[es]=Pantalla de inicio del teléfono
Name[fi]=Phonen aloitusnäyttö
Name[fr]=Page d'accueil du téléphone
Name[gl]=Pantalla de inicio do teléfono
Name[it]=Schermata home del telefono
Name[ko]=
Name[nl]=Standaardscherm van de telefoon
Name[nn]=Heimebilete for telefon
Name[pl]=Ekran domowy telefonu
Name[pt]=Ecrã Inicial
Name[sv]=Telefonens hemskärm
Name[tr]=Telefon Ana Ekranı
Name[uk]=Домашня сторінка телефону
Name[x-test]=xxPhone Homescreenxx
Name[zh_CN]=
Name[zh_TW]=
Type=Service
X-KDE-ServiceTypes=Plasma/Applet,Plasma/Containment
X-Plasma-API=declarativeappletscript
X-KDE-Library=plasma_containment_phone_homescreen2
X-KDE-PluginInfo-Author=Marco Martin
X-KDE-PluginInfo-Category=Containments
X-KDE-PluginInfo-Email=mart@kde.org
X-KDE-PluginInfo-License=GPLv2+
X-KDE-PluginInfo-Name=org.kde.phone.homescreen2
X-KDE-PluginInfo-Version=
X-KDE-PluginInfo-Website=
X-Plasma-MainScript=ui/main.qml

View file

@ -2,7 +2,7 @@
LookAndFeelPackage=org.kde.plasma.phone
[Desktop]
Containment=org.kde.phone.homescreen2
Containment=org.kde.phone.homescreen
ToolBox=org.kde.plasma.nano.desktoptoolbox
[Desktop][ContainmentActions]