Warning, /plasma/discover/discover/qml/ApplicationsListPage.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *   SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 import QtQuick 2.5
0008 import QtQuick.Controls 2.3
0009 import QtQuick.Layouts 1.1
0010 import QtQuick.Window 2.2
0011 import "navigation.js" as Navigation
0012 import org.kde.discover.app 1.0
0013 import org.kde.discover 2.0
0014 import org.kde.kirigami 2.14 as Kirigami
0015 
0016 DiscoverPage {
0017     id: page
0018     readonly property var model: appsModel
0019     property alias category: appsModel.filteredCategory
0020     property alias sortRole: appsModel.sortRole
0021     property alias sortOrder: appsModel.sortOrder
0022     property alias originFilter: appsModel.originFilter
0023     property alias mimeTypeFilter: appsModel.mimeTypeFilter
0024     property alias stateFilter: appsModel.stateFilter
0025     property alias extending: appsModel.extending
0026     property alias search: appsModel.search
0027     property alias resourcesUrl: appsModel.resourcesUrl
0028     property alias isBusy: appsModel.isBusy
0029     property alias allBackends: appsModel.allBackends
0030     property alias count: apps.count
0031     property alias listHeader: apps.header
0032     property alias listHeaderPositioning: apps.headerPositioning
0033     property string sortProperty: "appsListPageSorting"
0034     property bool compact: page.width < Kirigami.Units.gridUnit * 28 || !applicationWindow().wideScreen
0035     property bool showRating: true
0036     property bool showSize: false
0037     property bool searchPage: false
0038 
0039     property bool canNavigate: true
0040     readonly property alias subcategories: appsModel.subcategories
0041 
0042     function stripHtml(input) {
0043         var regex = /(<([^>]+)>)/ig
0044         return input.replace(regex, "");
0045     }
0046 
0047     property string name: category ? category.name : ""
0048     title: {
0049         const count = appsModel.count;
0050         if (search.length > 0) {
0051             if (count.valid) {
0052                 return i18np("Search: %2 - %3 item", "Search: %2 - %3 items", count.number, stripHtml(search), count.string)
0053             } else {
0054                 return i18n("Search: %1", stripHtml(search))
0055             }
0056         } else if (name.length > 0) {
0057             if (count.valid) {
0058                 return i18np("%2 - %1 item", "%2 - %1 items", count.number, name)
0059             } else {
0060                 return name
0061             }
0062         } else {
0063             if (count.valid) {
0064                 return i18np("Search - %1 item", "Search - %1 items", count.number)
0065             } else {
0066                 return i18n("Search")
0067             }
0068         }
0069     }
0070 
0071     signal clearSearch()
0072 
0073     supportsRefreshing: true
0074     onRefreshingChanged: if (refreshing) {
0075         appsModel.invalidateFilter()
0076         refreshing = false
0077     }
0078 
0079     ActionGroup {
0080         id: sortGroup
0081         exclusive: true
0082     }
0083 
0084     contextualActions: [
0085         Kirigami.Action {
0086             visible: !appsModel.sortByRelevancy
0087             text: i18n("Sort: %1", sortGroup.checkedAction.text)
0088             Action {
0089                 ActionGroup.group: sortGroup
0090                 text: i18n("Name")
0091                 onTriggered: {
0092                     DiscoverSettings[page.sortProperty] = ResourcesProxyModel.NameRole
0093                 }
0094                 checkable: true
0095                 checked: appsModel.sortRole === ResourcesProxyModel.NameRole
0096             }
0097             Action {
0098                 ActionGroup.group: sortGroup
0099                 text: i18n("Rating")
0100                 onTriggered: {
0101                     DiscoverSettings[page.sortProperty] = ResourcesProxyModel.SortableRatingRole
0102                 }
0103                 checkable: true
0104                 checked: appsModel.sortRole === ResourcesProxyModel.SortableRatingRole
0105             }
0106             Action {
0107                 ActionGroup.group: sortGroup
0108                 text: i18n("Size")
0109                 onTriggered: {
0110                     DiscoverSettings[page.sortProperty] = ResourcesProxyModel.SizeRole
0111                 }
0112                 checkable: true
0113                 checked: appsModel.sortRole === ResourcesProxyModel.SizeRole
0114             }
0115             Action {
0116                 ActionGroup.group: sortGroup
0117                 text: i18n("Release Date")
0118                 onTriggered: {
0119                     DiscoverSettings[page.sortProperty] = ResourcesProxyModel.ReleaseDateRole
0120                 }
0121                 checkable: true
0122                 checked: appsModel.sortRole === ResourcesProxyModel.ReleaseDateRole
0123             }
0124         }
0125     ]
0126 
0127     Kirigami.CardsListView {
0128         id: apps
0129         activeFocusOnTab: true
0130         currentIndex: -1
0131         onActiveFocusChanged: if (activeFocus && currentIndex === -1) {
0132             currentIndex = 0;
0133         }
0134 
0135         section.delegate: Label {
0136             text: section
0137             anchors {
0138                 right: parent.right
0139             }
0140         }
0141 
0142         model: ResourcesProxyModel {
0143             id: appsModel
0144             sortRole: DiscoverSettings.appsListPageSorting
0145             sortOrder: sortRole === ResourcesProxyModel.NameRole ? Qt.AscendingOrder : Qt.DescendingOrder
0146 
0147             onBusyChanged: if (isBusy) {
0148                 apps.currentIndex = -1
0149             }
0150         }
0151         delegate: ApplicationDelegate {
0152             application: model.application
0153             compact: !applicationWindow().wideScreen
0154             showRating: page.showRating
0155             showSize: page.showSize
0156         }
0157 
0158         Item {
0159             readonly property bool nothingFound: apps.count == 0 && !appsModel.isBusy && !ResourcesModel.isInitializing && (!page.searchPage || appsModel.search.length > 0)
0160 
0161             anchors.fill: parent
0162             opacity: nothingFound ? 1 : 0
0163             visible: opacity > 0
0164             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
0165 
0166             Kirigami.PlaceholderMessage {
0167                 visible: !searchedForThingNotFound.visible
0168                 anchors.centerIn: visible ? parent : undefined
0169                 width: parent.width - (Kirigami.Units.largeSpacing * 8)
0170 
0171                 icon.name: "edit-none"
0172                 text: i18n("Nothing found")
0173             }
0174 
0175             Kirigami.PlaceholderMessage {
0176                 id: searchedForThingNotFound
0177 
0178                 property var searchAllCategoriesAction: Kirigami.Action {
0179                     text: i18nc("@action:button", "Search in All Categories")
0180                     icon.name: "search"
0181                     onTriggered: {
0182                         window.globalDrawer.resetMenu();
0183                         Navigation.clearStack()
0184                         Navigation.openApplicationList( { search: page.search } );
0185                     }
0186                 }
0187                 property var searchTheWebAction: Kirigami.Action {
0188                     text: i18nc("@action:button %1 is the name of an application", "Search the Web for \"%1\"", appsModel.search)
0189                     icon.name: "internet-web-browser"
0190                     onTriggered: {
0191                         const searchTerm = encodeURIComponent("Linux " + appsModel.search);
0192                         Qt.openUrlExternally(i18nc("If appropriate, localize this URL to be something more relevant to the language. %1 is the text that will be searched for.", "https://duckduckgo.com/?q=%1", searchTerm));
0193                     }
0194                 }
0195 
0196                 anchors.centerIn: parent
0197                 width: parent.width - (Kirigami.Units.largeSpacing * 8)
0198 
0199                 visible: appsModel.search.length > 0 && stateFilter !== AbstractResource.Installed
0200 
0201                 icon.name: "edit-none"
0202                 text: page.category ? i18nc("@info:placeholder %1 is the name of an application; %2 is the name of a category of apps or add-ons",
0203                                             "\"%1\" was not found in the \"%2\" category", appsModel.search, page.category.name)
0204                                     : i18nc("@info:placeholder %1 is the name of an application",
0205                                             "\"%1\" was not found in the available sources", appsModel.search)
0206                 explanation: page.category ? "" : i18nc("@info:placeholder%1 is the name of an application", "\"%1\" may be available on the web. Software acquired from the web has not been reviewed by your distributor for functionality or stability. Use with caution.", appsModel.search)
0207 
0208                 // If we're in a category, first direct the user to search globally,
0209                 // because they might not have realized they were in a category and
0210                 // therefore the results were limited to just what was in the category
0211                 helpfulAction: page.category ? searchAllCategoriesAction : searchTheWebAction
0212             }
0213         }
0214 
0215         Kirigami.PlaceholderMessage {
0216             anchors.centerIn: parent
0217             width: parent.width - (Kirigami.Units.largeSpacing * 4)
0218 
0219             visible: opacity !== 0
0220             opacity: apps.count == 0 && page.searchPage && appsModel.search.length == 0 ? 1 : 0
0221             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } }
0222 
0223             icon.name: "search"
0224             text: i18n("Search")
0225         }
0226 
0227         footer: ColumnLayout {
0228             anchors.horizontalCenter: parent.horizontalCenter
0229             visible: appsModel.isBusy && apps.atYEnd
0230             opacity: visible ? 0.5 : 0
0231             height: visible ? Layout.preferredHeight : 0
0232 
0233             Item {
0234                 Layout.preferredHeight: Kirigami.Units.gridUnit
0235             }
0236             Kirigami.Heading {
0237                 level: 2
0238                 Layout.alignment: Qt.AlignCenter
0239                 text: i18n("Still looking…")
0240             }
0241             BusyIndicator {
0242                 running: parent.visible
0243                 Layout.alignment: Qt.AlignCenter
0244                 Layout.preferredWidth: Kirigami.Units.gridUnit * 4
0245                 Layout.preferredHeight: Kirigami.Units.gridUnit * 4
0246             }
0247             Behavior on opacity {
0248                 PropertyAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
0249             }
0250         }
0251     }
0252 }