/** SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>* SPDX-License-Identifier: LGPL-2.0-or-later*/pragma ComponentBehavior: Boundimport QtQuickimport QtQuick.Templates as Timport org.kde.plasma.private.kicker as Kickerimport org.kde.kirigami as Kirigamiimport org.kde.plasma.plasmoidimport org.kde.plasma.extras as PlasmaExtrasBasePage {id: rootproperty real flashFavorite: 0// Flash favorites when adding one.SequentialAnimation {id: flashFavoriteAnimationloops: 2alwaysRunToEnd: trueNumberAnimation {target: rootproperty: "flashFavorite"from: 0to: 1duration: Kirigami.Units.veryLongDurationeasing.type: Easing.OutCubic}NumberAnimation {target: rootproperty: "flashFavorite"to: 0duration: Kirigami.Units.veryLongDurationeasing.type: Easing.OutCubic}}Connections {target: kickoff.rootModel.favoritesModelfunction onFavoriteAdded() : void {flashFavoriteAnimation.restart();}}sideBarComponent: KickoffListView {id: sideBarfocus: true // needed for Loadersmodel: kickoff.rootModelisSidebar: true// needed otherwise app displayed at top-level will show a first character as group.section.property: ""delegate: KickoffListDelegate {id: sideBarDelegatewidth: view.availableWidthisCategoryListItem: truebackground: PlasmaExtras.Highlight {// I have to do this for it to actually fill the item for some reasonanchors.fill: parentactive: falsehovered: sideBarDelegate.mouseArea.containsMouse || (flashFavoriteAnimation.running && sideBarDelegate.index === 0) || ((dropAreaLoader.item as DropArea)?.containsAcceptableDrag ?? false) || sideBarDelegate.ListView.isCurrentItemvisible: !sideBarDelegate.isSeparator && hoveredopacity: flashFavoriteAnimation.running && sideBarDelegate.index === 0 ? root.flashFavorite : 1}component FavoritesDropArea: DropArea {// should be "as AbstractKickoffItemDelegate", but the type system gets confused when changing view style at runtimereadonly property Item draggedItem: kickoff.dragSource.sourceItemreadonly property bool acceptableDrag: draggedItem && !kickoff.rootModel.favoritesModel.isFavorite(draggedItem.model.favoriteId)readonly property bool containsAcceptableDrag: acceptableDrag && containsDragfunction evaluateEvent(event: DragEvent) : void {if (acceptableDrag) {event.accept(Qt.CopyAction)} else {event.accept(Qt.IgnoreAction)}}}Loader {id: dropAreaLoaderanchors.fill: parentactive: sideBarDelegate.index === 0 && !!kickoff.dragSource.sourceItemsourceComponent: FavoritesDropArea {onPositionChanged: event => evaluateEvent(event)onEntered: event => evaluateEvent(event)onDropped: event => {if (acceptableDrag && !sideBarDelegate.ListView.isCurrentItem) {kickoff.rootModel.favoritesModel.addFavorite(draggedItem.model.favoriteId, sideBar.model.favoritesModel.count)event.accept(Qt.CopyAction)} else {event.accept(Qt.IgnoreAction)}}}}}}contentAreaComponent: VerticalStackView {id: stackViewpopEnter: Transition {NumberAnimation {property: "x"from: 0.5 * root.widthto: 0duration: Kirigami.Units.longDurationeasing.type: Easing.OutCubic}NumberAnimation {property: "opacity"from: 0.0to: 1.0duration: Kirigami.Units.longDurationeasing.type: Easing.OutCubic}}pushEnter: Transition {NumberAnimation {property: "x"from: 0.5 * -root.widthto: 0duration: Kirigami.Units.longDurationeasing.type: Easing.OutCubic}NumberAnimation {property: "opacity"from: 0.0to: 1.0duration: Kirigami.Units.longDurationeasing.type: Easing.OutCubic}}readonly property string preferredFavoritesViewObjectName: Plasmoid.configuration.favoritesDisplay === 0 ? "favoritesGridView" : "favoritesListView"readonly property Component preferredFavoritesViewComponent: Plasmoid.configuration.favoritesDisplay === 0 ? favoritesGridViewComponent : favoritesListViewComponentreadonly property string preferredAllAppsViewObjectName: Plasmoid.configuration.applicationsDisplay === 0 ? "listOfGridsView" : "applicationsListView"readonly property Component preferredAllAppsViewComponent: Plasmoid.configuration.applicationsDisplay === 0 ? listOfGridsViewComponent : applicationsListViewComponentreadonly property string preferredAppsViewObjectName: Plasmoid.configuration.applicationsDisplay === 0 ? "applicationsGridView" : "applicationsListView"readonly property Component preferredAppsViewComponent: Plasmoid.configuration.applicationsDisplay === 0 ? applicationsGridViewComponent : applicationsListViewComponent// NOTE: The 0 index modelForRow isn't supposed to be used. That's just how it works.// But to trigger model data update, set initial value to 0property int appsModelRow: 0readonly property Kicker.AppsModel appsModel: kickoff.rootModel.modelForRow(appsModelRow)Connections {target: kickoff.rootModelfunction onRefreshed() { // recalculate appsModel binding on rootModel refresh;stackView.appsModelRowChanged() // modelForRow does not create dependency}}focus: trueinitialItem: preferredFavoritesViewComponentfunction showSectionView(sectionName: string, parentView: KickoffListView): void {stackView.push(applicationsSectionViewComponent, {currentSection: sectionName,parentView,});}Component {id: favoritesListViewComponentDropAreaListView {id: favoritesListViewobjectName: "favoritesListView"mainContentView: truefocus: truemodel: kickoff.rootModel.favoritesModel}}Component {id: favoritesGridViewComponentDropAreaGridView {id: favoritesGridViewobjectName: "favoritesGridView"focus: truemodel: kickoff.rootModel.favoritesModel}}Component {id: applicationsListViewComponentKickoffListView {id: applicationsListViewobjectName: "applicationsListView"mainContentView: truemodel: stackView.appsModel// we want to semantically switch between group and "", disabling grouping, workaround for QTBUG-121797section.property: model && model.description === "KICKER_ALL_MODEL" ? "group" : "_unset"section.criteria: ViewSection.FirstCharacterhasSectionView: stackView.appsModelRow === 1onShowSectionViewRequested: sectionName => {stackView.showSectionView(sectionName, this);}}}Component {id: applicationsSectionViewComponentSectionView {id: sectionViewmodel: stackView.appsModel.sectionsonHideSectionViewRequested: index => {stackView.pop();stackView.currentItem.view.positionViewAtIndex(index, ListView.Beginning);// Loading distant delegates can change the estimated scroll extent.// See also QTBUG-132454stackView.currentItem.view.positionViewAtIndex(index, ListView.Beginning);stackView.currentItem.currentIndex = index;}}}Component {id: applicationsGridViewComponentKickoffGridView {id: applicationsGridViewobjectName: "applicationsGridView"model: stackView.appsModel}}Component {id: listOfGridsViewComponentListOfGridsView {id: listOfGridsViewobjectName: "listOfGridsView"mainContentView: truegridModel: stackView.appsModelonShowSectionViewRequested: sectionName => {stackView.showSectionView(sectionName, this);}}}onPreferredFavoritesViewComponentChanged: {if (root.sideBarItem !== null && root.sideBarItem.currentIndex === 0) {stackView.replace(stackView.preferredFavoritesViewComponent)}}onPreferredAllAppsViewComponentChanged: {if (root.sideBarItem !== null && root.sideBarItem.currentIndex === 1) {stackView.replace(stackView.preferredAllAppsViewComponent)}}onPreferredAppsViewComponentChanged: {if (root.sideBarItem !== null && root.sideBarItem.currentIndex > 1) {stackView.replace(stackView.preferredAppsViewComponent)}}Connections {target: root.sideBarItemfunction onCurrentIndexChanged() {// Only update row index if the condition is met.// The 0 index modelForRow isn't supposed to be used. That's just how it works.if (root.sideBarItem.currentIndex > 0) {stackView.appsModelRow = root.sideBarItem.currentIndex}if (root.sideBarItem.currentIndex === 0&& stackView.currentItem.objectName !== stackView.preferredFavoritesViewObjectName) {stackView.replace(stackView.preferredFavoritesViewComponent)} else if (root.sideBarItem.currentIndex === 1&& stackView.currentItem.objectName !== stackView.preferredAllAppsViewObjectName) {stackView.replace(stackView.preferredAllAppsViewComponent)} else if (root.sideBarItem.currentIndex > 1&& stackView.currentItem.objectName !== stackView.preferredAppsViewObjectName) {stackView.replace(stackView.preferredAppsViewComponent)}}}Connections {target: kickofffunction onExpandedChanged() {if (!kickoff.expanded && kickoff.contentArea.currentItem) {kickoff.contentArea.currentItem.forceActiveFocus()}}}}// NormalPage doesn't get destroyed when deactivated, so the binding uses// StackView.status and visible. This way the bindings are reset when// NormalPage is Activated again.Binding {target: kickoffproperty: "sideBar"value: root.sideBarItemwhen: root.T.StackView.status === T.StackView.Active && root.visiblerestoreMode: Binding.RestoreBinding}Binding {target: kickoffproperty: "contentArea"value: root.contentAreaItem.currentItem // NOT just root.contentAreaItemwhen: root.T.StackView.status === T.StackView.Active && root.visiblerestoreMode: Binding.RestoreBinding}}