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 pragma ComponentBehavior: Bound
0008 
0009 import QtQuick
0010 import QtQuick.Controls as QQC2
0011 import QtQuick.Layouts
0012 import org.kde.kirigami as Kirigami
0013 import org.kde.discover as Discover
0014 import org.kde.discover.app as DiscoverApp
0015 
0016 DiscoverPage {
0017     id: page
0018 
0019     readonly property var model: appsModel
0020     property alias category: appsModel.filteredCategory
0021     property alias sortRole: appsModel.sortRole
0022     property alias sortOrder: appsModel.sortOrder
0023     property alias originFilter: appsModel.originFilter
0024     property alias mimeTypeFilter: appsModel.mimeTypeFilter
0025     property alias stateFilter: appsModel.stateFilter
0026     property alias extending: appsModel.extending
0027     property alias search: appsModel.search
0028     property alias resourcesUrl: appsModel.resourcesUrl
0029     property alias busy: appsModel.busy
0030     property alias allBackends: appsModel.allBackends
0031     property alias count: appsView.count
0032     property alias listHeader: appsView.header
0033     property alias listHeaderPositioning: appsView.headerPositioning
0034     property string sortProperty: "appsListPageSorting"
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?.name ?? ""
0048 
0049     title: {
0050         const count = appsModel.count;
0051         if (search.length > 0 && count.number > 0) {
0052             if (count.valid) {
0053                 return i18np("Search: %2 - %3 item", "Search: %2 - %3 items", count.number, stripHtml(search), count.string)
0054             } else {
0055                 return i18n("Search: %1", stripHtml(search))
0056             }
0057         } else if (name.length > 0 && count.number > 0) {
0058             if (count.valid) {
0059                 return i18np("%2 - %1 item", "%2 - %1 items", count.number, name)
0060             } else {
0061                 return name
0062             }
0063         } else {
0064             if (count.valid && count.number > 0) {
0065                 return i18np("Search - %1 item", "Search - %1 items", count.number)
0066             } else {
0067                 return i18n("Search")
0068             }
0069         }
0070     }
0071 
0072     signal clearSearch()
0073 
0074     Kirigami.Theme.colorSet: Kirigami.Theme.Window
0075     Kirigami.Theme.inherit: false
0076 
0077     onSearchChanged: {
0078         if (search.length > 0) {
0079             appsModel.tempSortRole = Discover.ResourcesProxyModel.SearchRelevanceRole
0080         } else {
0081             appsModel.tempSortRole = -1
0082         }
0083     }
0084 
0085     supportsRefreshing: true
0086     onRefreshingChanged: if (refreshing) {
0087         appsModel.invalidateFilter()
0088         refreshing = false
0089     }
0090 
0091     QQC2.ActionGroup {
0092         id: sortGroup
0093         exclusive: true
0094     }
0095 
0096     actions: [
0097         Kirigami.Action {
0098             text: i18n("Sort: %1", sortGroup.checkedAction.text)
0099             icon.name: "view-sort"
0100             Kirigami.Action {
0101                 visible: appsModel.search.length > 0
0102                 QQC2.ActionGroup.group: sortGroup
0103                 text: i18nc("Search results most relevant to the search query", "Relevance")
0104                 icon.name: "file-search-symbolic"
0105                 onTriggered: {
0106                     // Do *not* save the sort role on searches
0107                     appsModel.tempSortRole = Discover.ResourcesProxyModel.SearchRelevanceRole
0108                 }
0109                 checkable: true
0110                 checked: appsModel.sortRole === Discover.ResourcesProxyModel.SearchRelevanceRole
0111             }
0112             Kirigami.Action {
0113                 QQC2.ActionGroup.group: sortGroup
0114                 text: i18n("Name")
0115                 icon.name: "sort-name"
0116                 onTriggered: {
0117                     DiscoverApp.DiscoverSettings[page.sortProperty] = Discover.ResourcesProxyModel.NameRole
0118                     appsModel.tempSortRole = -1
0119                 }
0120                 checkable: true
0121                 checked: appsModel.sortRole === Discover.ResourcesProxyModel.NameRole
0122             }
0123             Kirigami.Action {
0124                 QQC2.ActionGroup.group: sortGroup
0125                 text: i18n("Rating")
0126                 icon.name: "rating"
0127                 onTriggered: {
0128                     DiscoverApp.DiscoverSettings[page.sortProperty] = Discover.ResourcesProxyModel.SortableRatingRole
0129                     appsModel.tempSortRole = -1
0130                 }
0131                 checkable: true
0132                 checked: appsModel.sortRole === Discover.ResourcesProxyModel.SortableRatingRole
0133             }
0134             Kirigami.Action {
0135                 QQC2.ActionGroup.group: sortGroup
0136                 text: i18n("Size")
0137                 icon.name: "download"
0138                 onTriggered: {
0139                     DiscoverApp.DiscoverSettings[page.sortProperty] = Discover.ResourcesProxyModel.SizeRole
0140                     appsModel.tempSortRole = -1
0141                 }
0142                 checkable: true
0143                 checked: appsModel.sortRole === Discover.ResourcesProxyModel.SizeRole
0144             }
0145             Kirigami.Action {
0146                 QQC2.ActionGroup.group: sortGroup
0147                 text: i18n("Release Date")
0148                 icon.name: "change-date-symbolic"
0149                 onTriggered: {
0150                     DiscoverApp.DiscoverSettings[page.sortProperty] = Discover.ResourcesProxyModel.ReleaseDateRole
0151                     appsModel.tempSortRole = -1
0152                 }
0153                 checkable: true
0154                 checked: appsModel.sortRole === Discover.ResourcesProxyModel.ReleaseDateRole
0155             }
0156         }
0157     ]
0158 
0159     Kirigami.CardsListView {
0160         id: appsView
0161         activeFocusOnTab: true
0162         currentIndex: -1
0163         onActiveFocusChanged: if (activeFocus && currentIndex === -1) {
0164             currentIndex = 0;
0165         }
0166 
0167         model: Discover.ResourcesProxyModel {
0168             id: appsModel
0169             property int tempSortRole: -1
0170             sortRole: tempSortRole >= 0 ? tempSortRole : DiscoverApp.DiscoverSettings.appsListPageSorting
0171             sortOrder: sortRole === Discover.ResourcesProxyModel.NameRole ? Qt.AscendingOrder : Qt.DescendingOrder
0172 
0173             onBusyChanged: {
0174                 if (busy) {
0175                     appsView.currentIndex = -1
0176                 }
0177             }
0178         }
0179 
0180         delegate: ApplicationDelegate {
0181             compact: !applicationWindow().wideScreen
0182             showRating: page.showRating
0183             showSize: page.showSize
0184         }
0185 
0186         Item {
0187             readonly property bool nothingFound: appsView.count == 0 && !appsModel.busy && !Discover.ResourcesModel.isInitializing && (!page.searchPage || appsModel.search.length > 0)
0188 
0189             anchors.fill: parent
0190             opacity: nothingFound ? 1 : 0
0191             visible: opacity > 0
0192             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
0193 
0194             Kirigami.PlaceholderMessage {
0195                 visible: !searchedForThingNotFound.visible
0196                 anchors.centerIn: visible ? parent : undefined
0197                 width: parent.width - (Kirigami.Units.largeSpacing * 8)
0198 
0199                 icon.name: "edit-none"
0200                 text: i18n("Nothing found")
0201             }
0202 
0203             Kirigami.PlaceholderMessage {
0204                 id: searchedForThingNotFound
0205 
0206                 Kirigami.Action {
0207                     id: searchAllCategoriesAction
0208                     text: i18nc("@action:button", "Search in All Categories")
0209                     icon.name: "search"
0210                     onTriggered: {
0211                         window.globalDrawer.resetMenu();
0212                         Navigation.clearStack()
0213                         Navigation.openApplicationList({ search: page.search });
0214                     }
0215                 }
0216                 Kirigami.Action {
0217                     id: searchTheWebAction
0218                     text: i18nc("@action:button %1 is the name of an application", "Search the Web for \"%1\"", appsModel.search)
0219                     icon.name: "internet-web-browser"
0220                     onTriggered: {
0221                         const searchTerm = encodeURIComponent("Linux " + appsModel.search);
0222                         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));
0223                     }
0224                 }
0225 
0226                 anchors.centerIn: parent
0227                 width: parent.width - (Kirigami.Units.largeSpacing * 8)
0228 
0229                 visible: appsModel.search.length > 0 && stateFilter !== Discover.AbstractResource.Installed
0230 
0231                 icon.name: "edit-none"
0232                 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",
0233                                             "\"%1\" was not found in the \"%2\" category", appsModel.search, page.category.name)
0234                                     : i18nc("@info:placeholder %1 is the name of an application",
0235                                             "\"%1\" was not found in the available sources", appsModel.search)
0236                 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)
0237 
0238                 // If we're in a category, first direct the user to search globally,
0239                 // because they might not have realized they were in a category and
0240                 // therefore the results were limited to just what was in the category
0241                 helpfulAction: page.category ? searchAllCategoriesAction : searchTheWebAction
0242             }
0243         }
0244 
0245         Kirigami.PlaceholderMessage {
0246             anchors.centerIn: parent
0247             width: parent.width - (Kirigami.Units.largeSpacing * 4)
0248 
0249             visible: opacity !== 0
0250             opacity: appsView.count === 0 && page.searchPage && appsModel.search.length === 0 ? 1 : 0
0251             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } }
0252 
0253             icon.name: "search"
0254             text: i18n("Search")
0255         }
0256 
0257         footer: ColumnLayout {
0258             visible: appsModel.busy && appsView.atYEnd
0259             opacity: visible ? 0.5 : 0
0260             height: visible ? Layout.preferredHeight : 0
0261             width: appsView.width
0262 
0263             Item {
0264                 Layout.preferredHeight: Kirigami.Units.gridUnit
0265             }
0266             Kirigami.Heading {
0267                 level: 2
0268                 Layout.alignment: Qt.AlignCenter
0269                 text: i18n("Still looking…")
0270             }
0271             QQC2.BusyIndicator {
0272                 running: parent.visible
0273                 Layout.alignment: Qt.AlignCenter
0274                 Layout.preferredWidth: Kirigami.Units.gridUnit * 4
0275                 Layout.preferredHeight: Kirigami.Units.gridUnit * 4
0276             }
0277             Behavior on opacity {
0278                 PropertyAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
0279             }
0280         }
0281     }
0282 }