Commit 4132f015 authored by Marco Martin's avatar Marco Martin
Browse files

use a repeater

add a view for recent apps
parent 7d33e772
......@@ -20,6 +20,8 @@ include(ECMInstallIcons)
# Locate plasma_install_package macro.
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
Activities
ActivitiesStats
Plasma
I18n
Kirigami2
......
......@@ -44,6 +44,8 @@ void ImagePalette::setSource(const QVariant &source)
setSourceItem(source.value<QQuickItem *>());
} else if (source.canConvert<QImage>()) {
setSourceImage(source.value<QImage>());
} else if (source.canConvert<QIcon>()) {
setSourceImage(source.value<QIcon>().pixmap(32,32).toImage());
} else if (source.canConvert<QString>()) {
setSourceImage(QIcon::fromTheme(source.toString()).pixmap(32,32).toImage());
} else {
......
......@@ -29,8 +29,19 @@ import org.kde.mycroft.bigscreen 1.0 as BigScreen
PlasmaComponents.ItemDelegate {
id: delegate
readonly property ListView listView: ListView.view
readonly property bool isCurrent: listView.currentIndex == index && activeFocus && !listView.moving
readonly property Flickable listView: {
var candidate = parent;
while (candidate) {
if (candidate instanceof Flickable) {
return candidate;
}
candidate = candidate.parent;
}
return null;
}
readonly property bool isCurrent: {//print(text+index+" "+listView.currentIndex+activeFocus+" "+listView.moving)
listView.currentIndex == index && activeFocus && !listView.moving
}
z: isCurrent ? 2 : 0
......
......@@ -32,6 +32,7 @@ AbstractDelegate {
implicitWidth: listView.cellWidth
implicitHeight: listView.height
property var iconImage
property string comment
Kirigami.Theme.inherit: !imagePalette.useColors
......@@ -66,7 +67,7 @@ AbstractDelegate {
z: 1
width: Kirigami.Units.iconSizes.huge
height: width
source: delegate.icon.name || delegate.icon.source
source: delegate.iconImage || delegate.icon.name || delegate.icon.source
}
ColumnLayout {
......
/*
* Copyright 2020 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.12
import QtQuick.Layouts 1.4
import QtQuick.Window 2.2
import QtQuick.Controls 2.12 as Controls
import org.kde.kirigami 2.10 as Kirigami
import org.kde.mycroft.bigscreen 1.0 as BigScreen
FocusScope {
id: root
signal activated
property string title
property alias view: view
property alias delegate: view.delegate
property alias model: view.model
property alias currentIndex: view.currentIndex
property alias currentItem: view.currentItem
Layout.fillWidth: true
implicitHeight: view.implicitHeight + header.implicitHeight
//TODO:dynamic
property int columns: Math.max(3, Math.floor(width / (units.gridUnit * 8)))
property alias cellWidth: view.cellWidth
readonly property real screenRatio: view.Window.window ? view.Window.window.width / view.Window.window.height : 1.6
property Item navigationUp
property Item navigationDown
Kirigami.Heading {
id: header
anchors {
left: parent.left
right: parent.right
top: parent.top
}
text: title
layer.enabled: true
color: "white"
}
Flickable {
id: view
anchors {
left: parent.left
right: parent.right
top: header.baseline
bottom: parent.bottom
topMargin: Kirigami.Units.largeSpacing*2
leftMargin: -Kirigami.Units.largeSpacing
}
readonly property int cellWidth: (Kirigami.Units.iconSizes.huge + Kirigami.Units.largeSpacing*4)
property int currentIndex: 0
property alias count: repeater.count
property alias model: repeater.model
property alias delegate: repeater.delegate
readonly property Item currentItem: layout.children[currentIndex]
function indexAt(x,y) {
return Math.max(0, Math.min(count - 1, Math.round(x/cellWidth)));
}
focus: true
implicitHeight: cellWidth + units.gridUnit * 3
contentWidth: layout.width
contentHeight: height
onCurrentIndexChanged: {
if (!currentItem) {
return;
}
// currentItem didn't update yet
layout.children[currentIndex].forceActiveFocus();
slideAnim.slideToIndex(currentIndex);
}
onActiveFocusChanged: {
if (!activeFocus || !currentItem) {
return;
}
currentItem.forceActiveFocus();
}
onMovementEnded: currentIndex = Math.min(count-1, Math.round((contentX + cellWidth) / cellWidth))
onFlickEnded: movementEnded()
NumberAnimation {
id: slideAnim
target: view
property: "contentX"
duration: 250
function slideToIndex(index) {
slideAnim.running = false;
slideAnim.from = view.contentX;
slideAnim.to = Math.max(0, view.cellWidth * (view.currentIndex-1));
slideAnim.restart();
}
}
Row {
id: layout
anchors {
top: parent.top
bottom: parent.bottom
}
spacing: 0
Repeater {
id: repeater
}
// Spacer
Item {
width: view.width - view.cellWidth*2
height: 1
}
}
Keys.onLeftPressed: currentIndex = Math.max(0, currentIndex - 1)
Keys.onRightPressed: currentIndex = Math.min(count - 1, currentIndex + 1)
Keys.onDownPressed: {
if (!root.navigationDown) {
return;
}
if (root.navigationDown instanceof TileView ||
root.navigationDown instanceof TileRepeater) {
root.navigationDown.currentIndex = Math.min(Math.floor(root.navigationDown.view.indexAt(root.navigationDown.view.contentX + cellWidth/2, height/2)) + (view.currentIndex - view.indexAt(view.contentX + cellWidth/2, height/2)), root.navigationDown.view.count - 1);
if (root.navigationDown.currentIndex < 0) {
root.navigationDown.currentIndex = view.currentIndex > 0 ? root.navigationDown.view.count - 1 : 0
}
}
root.navigationDown.forceActiveFocus();
}
Keys.onUpPressed: {
if (!root.navigationUp) {
return;
}
if (root.navigationUp instanceof TileView ||
root.navigationUp instanceof TileRepeater) {
root.navigationUp.currentIndex = Math.min(Math.floor(root.navigationUp.view.indexAt(root.navigationUp.view.contentX + cellWidth/2, height/2)) + (view.currentIndex - view.indexAt(view.contentX + cellWidth/2, height/2)), root.navigationUp.view.count - 1);
if (root.navigationUp.currentIndex < 0) {
root.navigationUp.currentIndex = view.currentIndex > 0 ? root.navigationUp.view.count - 1 : 0
}
}
root.navigationUp.forceActiveFocus();
}
}
}
......@@ -2,6 +2,7 @@ module org.kde.mycroft.bigscreen
plugin bigscreenplugin
TileView 1.0 TileView.qml
TileRepeater 1.0 TileRepeater.qml
AbstractDelegate 1.0 AbstractDelegate.qml
IconDelegate 1.0 IconDelegate.qml
singleton Hack 1.0 Hack.qml
......@@ -32,6 +32,7 @@ import org.kde.kitemmodels 1.0 as KItemModels
import "delegates" as Delegates
import org.kde.mycroft.bigscreen 1.0 as BigScreen
import org.kde.private.biglauncher 1.0
import org.kde.plasma.private.kicker 0.1 as Kicker
FocusScope {
anchors {
......@@ -58,8 +59,31 @@ FocusScope {
spacing: Kirigami.Units.largeSpacing*3
BigScreen.TileView {
id: gridView
BigScreen.TileRepeater {
id: recentView
title: i18n("Recent Apps")
model: Kicker.RecentUsageModel {
shownItems: Kicker.RecentUsageModel.OnlyApps
}
visible: count > 0
currentIndex: 0
focus: true
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = recentView
delegate: Delegates.AppDelegate {
property var modelData: typeof model !== "undefined" ? model : null
iconImage: model.decoration
text: model.display
comment: model.description
onClicked: recentView.model.trigger(index, "", null);
}
navigationUp: shutdownIndicator
navigationDown: voiceAppsView
}
BigScreen.TileRepeater {
id: voiceAppsView
title: i18n("Voice Apps")
model: KItemModels.KSortFilterProxyModel {
sourceModel: plasmoid.nativeInterface.applicationListModel
......@@ -70,19 +94,19 @@ FocusScope {
}
currentIndex: 0
focus: true
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = gridView
focus: false
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = voiceAppsView
delegate: Delegates.VoiceAppDelegate {
property var modelData: typeof model !== "undefined" ? model : null
}
navigationUp: shutdownIndicator
navigationDown: gridView2
navigationUp: recentView
navigationDown: appsView
}
BigScreen.TileView {
id: gridView2
BigScreen.TileRepeater {
id: appsView
title: i18n("Applications")
model: KItemModels.KSortFilterProxyModel {
sourceModel: plasmoid.nativeInterface.applicationListModel
......@@ -95,18 +119,18 @@ FocusScope {
currentIndex: 0
focus: false
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = gridView2
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = appsView
delegate: Delegates.AppDelegate {
property var modelData: typeof model !== "undefined" ? model : null
comment: model.ApplicationCommentRole
}
navigationUp: gridView
navigationDown: gridView3
navigationUp: voiceAppsView
navigationDown: gamesView
}
BigScreen.TileView {
id: gridView3
BigScreen.TileRepeater {
id: gamesView
title: i18n("Games")
model: KItemModels.KSortFilterProxyModel {
sourceModel: plasmoid.nativeInterface.applicationListModel
......@@ -118,17 +142,17 @@ FocusScope {
currentIndex: 0
focus: false
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = gridView2
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = appsView
delegate: Delegates.AppDelegate {
property var modelData: typeof model !== "undefined" ? model : null
}
navigationUp: gridView2
navigationDown: gridView4
navigationUp: appsView
navigationDown: settingsView
}
BigScreen.TileView {
id: gridView4
BigScreen.TileRepeater {
id: settingsView
title: i18n("Settings")
model: actions
......@@ -156,23 +180,27 @@ FocusScope {
}
]
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = gridView3
onActiveFocusChanged: if (activeFocus) launcherHomeColumn.currentSection = gamesView
delegate: Delegates.SettingDelegate {
property var modelData: typeof model !== "undefined" ? model : null
}
navigationUp: gridView3
navigationUp: gamesView
navigationDown: null
}
Component.onCompleted: {
gridView.forceActiveFocus();
if (recentView.visible) {
recentView.forceActiveFocus();
} else {
voiceAppsView.forceActiveFocus();
}
}
Connections {
target: root
onActivateAppView: {
gridView.forceActiveFocus();
voiceAppsView.forceActiveFocus();
}
}
}
......
......@@ -29,7 +29,5 @@ BigScreen.IconDelegate {
onClicked: {
feedbackWindow.open(modelData.ApplicationNameRole, modelData.ApplicationIconRole);
plasmoid.nativeInterface.applicationListModel.runApplication(modelData.ApplicationStorageIdRole)
plasmoid.nativeInterface.applicationListModel.moveItem(modelData.ApplicationOriginalRowRole, 0);
ListView.view.currentIndex = 0
}
}
......@@ -23,12 +23,10 @@ import org.kde.mycroft.bigscreen 1.0 as BigScreen
BigScreen.IconDelegate {
readonly property var vAppStorageIdRole: modelData.ApplicationStorageIdRole
icon.name: modelData ? modelData.ApplicationIconRole : ""
icon.name: modelData && modelData.ApplicationIconRole ? modelData.ApplicationIconRole : ""
text: modelData ? modelData.ApplicationNameRole : ""
onClicked: {
plasmoid.nativeInterface.applicationListModel.runApplication(modelData.ApplicationStorageIdRole)
plasmoid.nativeInterface.applicationListModel.moveItem(modelData.ApplicationOriginalRowRole, 0);
ListView.view.currentIndex = 0
}
}
......@@ -11,7 +11,18 @@ add_library(plasma_containment_biglauncherhomescreen MODULE ${biglauncherhomescr
kcoreaddons_desktop_to_json(plasma_containment_biglauncherhomescreen ../package/metadata.desktop)
target_link_libraries(plasma_containment_biglauncherhomescreen Qt5::Gui Qt5::Core Qt5::Qml Qt5::DBus Qt5::Network KF5::Plasma KF5::I18n KF5::Notifications KF5::Service KF5::KIOWidgets)
target_link_libraries(plasma_containment_biglauncherhomescreen
Qt5::Gui
Qt5::Core
Qt5::Qml
Qt5::DBus
Qt5::Network
KF5::Plasma
KF5::I18n
KF5::Notifications
KF5::Service KF5::KIOWidgets
KF5::Activities
KF5::ActivitiesStats)
install(TARGETS plasma_containment_biglauncherhomescreen DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/applets)
......@@ -24,6 +24,7 @@
#include <QByteArray>
#include <QModelIndex>
#include <QProcess>
#include <QDebug>
// KDE
#include <KPluginInfo>
......@@ -35,7 +36,7 @@
#include <KSycocaEntry>
#include <KShell>
#include <KIOWidgets/KRun>
#include <QDebug>
#include <KActivities/ResourceInstance>
ApplicationListModel::ApplicationListModel(QObject *parent)
: QAbstractListModel(parent)
......@@ -276,6 +277,9 @@ void ApplicationListModel::runApplication(const QString &storageId)
KService::Ptr service = KService::serviceByStorageId(storageId);
KRun::runApplication(*service, QList<QUrl>(), nullptr);
KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + service->storageId()),
QStringLiteral("org.kde.plasma.kicker"));
}
QStringList ApplicationListModel::appOrder() const
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment