diff --git a/discover/qml/ApplicationsListPage.qml b/discover/qml/ApplicationsListPage.qml index dbb9a242..91c1d602 100644 --- a/discover/qml/ApplicationsListPage.qml +++ b/discover/qml/ApplicationsListPage.qml @@ -1,176 +1,171 @@ /* * Copyright (C) 2012 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser 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 Library/Lesser 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.5 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import "navigation.js" as Navigation import org.kde.discover.app 1.0 import org.kde.discover 2.0 import org.kde.kirigami 2.12 as Kirigami DiscoverPage { id: page readonly property var model: appsModel property alias category: appsModel.filteredCategory property alias sortRole: appsModel.sortRole property alias sortOrder: appsModel.sortOrder property alias originFilter: appsModel.originFilter property alias mimeTypeFilter: appsModel.mimeTypeFilter property alias stateFilter: appsModel.stateFilter property alias extending: appsModel.extending property alias search: appsModel.search property alias resourcesUrl: appsModel.resourcesUrl property alias isBusy: appsModel.isBusy property alias allBackends: appsModel.allBackends property alias count: apps.count property alias listHeader: apps.header property alias listHeaderPositioning: apps.headerPositioning property string sortProperty: "appsListPageSorting" property bool compact: page.width < 550 || !applicationWindow().wideScreen property bool showRating: true property bool canNavigate: true readonly property alias subcategories: appsModel.subcategories function stripHtml(input) { var regex = /(<([^>]+)>)/ig return input.replace(regex, ""); } - background: Rectangle { - color: Kirigami.Theme.backgroundColor - Kirigami.Theme.colorSet: Kirigami.Theme.Window - Kirigami.Theme.inherit: false - } title: search.length>0 ? i18n("Search: %1", stripHtml(search)) : category ? category.name : "" signal clearSearch() supportsRefreshing: true onRefreshingChanged: if (refreshing) { appsModel.invalidateFilter() refreshing = false } ActionGroup { id: sortGroup exclusive: true } contextualActions: [ Kirigami.Action { visible: !appsModel.sortByRelevancy text: i18n("Sort: %1", sortGroup.checkedAction.text) Action { ActionGroup.group: sortGroup text: i18n("Name") onTriggered: { DiscoverSettings[page.sortProperty] = ResourcesProxyModel.NameRole } checkable: true checked: appsModel.sortRole === ResourcesProxyModel.NameRole } Action { ActionGroup.group: sortGroup text: i18n("Rating") onTriggered: { DiscoverSettings[page.sortProperty] = ResourcesProxyModel.SortableRatingRole } checkable: true checked: appsModel.sortRole === ResourcesProxyModel.SortableRatingRole } Action { ActionGroup.group: sortGroup text: i18n("Size") onTriggered: { DiscoverSettings[page.sortProperty] = ResourcesProxyModel.SizeRole } checkable: true checked: appsModel.sortRole === ResourcesProxyModel.SizeRole } Action { ActionGroup.group: sortGroup text: i18n("Release Date") onTriggered: { DiscoverSettings[page.sortProperty] = ResourcesProxyModel.ReleaseDateRole } checkable: true checked: appsModel.sortRole === ResourcesProxyModel.ReleaseDateRole } } ] Kirigami.CardsListView { id: apps section.delegate: Label { text: section anchors { right: parent.right } } model: ResourcesProxyModel { id: appsModel sortRole: DiscoverSettings.appsListPageSorting sortOrder: sortRole === ResourcesProxyModel.SortableRatingRole || sortRole === ResourcesProxyModel.ReleaseDateRole ? Qt.DescendingOrder : Qt.AscendingOrder onBusyChanged: if (isBusy) { apps.currentIndex = -1 } } currentIndex: -1 delegate: ApplicationDelegate { application: model.application compact: !applicationWindow().wideScreen showRating: page.showRating } Kirigami.PlaceholderMessage { anchors.centerIn: parent width: parent.width - (Kirigami.Units.largeSpacing * 4) opacity: apps.count == 0 && !appsModel.isBusy ? 1 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } icon.name: "edit-none" text: i18n("Sorry, nothing found") } footer: BusyIndicator { anchors.horizontalCenter: parent.horizontalCenter visible: appsModel.isBusy && apps.atYEnd running: visible opacity: visible ? 1 : 0 Behavior on opacity { PropertyAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } } Label { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.top } text: i18n("Still looking...") } } } } diff --git a/discover/qml/BrowsingPage.qml b/discover/qml/BrowsingPage.qml index edb61c97..30b7e815 100644 --- a/discover/qml/BrowsingPage.qml +++ b/discover/qml/BrowsingPage.qml @@ -1,82 +1,76 @@ /* * Copyright (C) 2015 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library/Lesser 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 Library/Lesser 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.Controls 2.4 import QtQuick.Layouts 1.1 import org.kde.discover 2.0 import org.kde.discover.app 1.0 import "navigation.js" as Navigation import org.kde.kirigami 2.12 as Kirigami DiscoverPage { id: page title: i18n("Featured") leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 readonly property bool isHome: true function searchFor(text) { if (text.length === 0) return; Navigation.openCategory(null, "") } BusyIndicator { id: indicator anchors.centerIn: parent width: Kirigami.Units.gridUnit * 8 height: width visible: apps.count === 0 && apps.model.isFetching } Kirigami.PlaceholderMessage { anchors.centerIn: parent width: parent.width - (Kirigami.Units.largeSpacing * 4) visible: apps.count === 0 && !apps.model.isFetching icon.name: "network-disconnect" text: xi18nc("@info", "Unable to load applications.Please verify Internet connectivity.") } - background: Rectangle { - color: Kirigami.Theme.backgroundColor - Kirigami.Theme.colorSet: Kirigami.Theme.Window - Kirigami.Theme.inherit: false - } - signal clearSearch() readonly property bool compact: page.width < 550 || !applicationWindow().wideScreen Kirigami.CardsListView { id: apps model: FeaturedModel {} currentIndex: -1 delegate: ApplicationDelegate { application: model.application compact: page.compact } } } diff --git a/discover/qml/SourcesPage.qml b/discover/qml/SourcesPage.qml index 6c0d3619..12bae7c5 100644 --- a/discover/qml/SourcesPage.qml +++ b/discover/qml/SourcesPage.qml @@ -1,262 +1,256 @@ import QtQuick 2.4 import QtQuick.Controls 2.1 import QtQuick.Layouts 1.1 import org.kde.discover 2.0 import org.kde.discover.app 1.0 import org.kde.kirigami 2.10 as Kirigami import "navigation.js" as Navigation DiscoverPage { id: page clip: true title: i18n("Settings") property string search: "" - background: Rectangle { - color: Kirigami.Theme.backgroundColor - Kirigami.Theme.colorSet: Kirigami.Theme.Window - Kirigami.Theme.inherit: false - } - contextualActions: feedbackLoader.item ? feedbackLoader.item.actions : [] mainItem: ListView { id: sourcesView model: SourcesModel Component.onCompleted: Qt.callLater(SourcesModel.showingNow) currentIndex: -1 section.property: "sourceName" section.delegate: Kirigami.ListSectionHeader { id: backendItem readonly property QtObject backend: SourcesModel.sourcesBackendByName(section) readonly property QtObject resourcesBackend: backend.resourcesBackend readonly property bool isDefault: ResourcesModel.currentApplicationBackend === resourcesBackend width: sourcesView.width label: backendItem.isDefault ? i18n("%1 (Default)", resourcesBackend.displayName) : resourcesBackend.displayName readonly property var p0: Connections { target: backendItem.backend function onPassiveMessage(message) { window.showPassiveNotification(message) } function onProceedRequest(title, description) { var dialog = sourceProceedDialog.createObject(window, {sourcesBackend: backendItem.backend, title: title, description: description}) dialog.open() } } Kirigami.ActionToolBar { id: actionBar Layout.fillWidth: true alignment: Qt.AlignRight Kirigami.Action { id: addSource text: i18n("Add Source...") icon.name: "list-add" visible: backendItem.backend && backendItem.backend.supportsAdding readonly property Component p0: Component { id: dialogComponent AddSourceDialog { source: backendItem.backend onVisibleChanged: if (!visible) { destroy() } } } onTriggered: { var addSourceDialog = dialogComponent.createObject(null, {displayName: backendItem.backend.resourcesBackend.displayName }) addSourceDialog.open() } } Kirigami.Action { id: makeDefault visible: resourcesBackend && resourcesBackend.hasApplications enabled: !backendItem.isDefault text: i18n("Make default") icon.name: "favorite" onTriggered: ResourcesModel.currentApplicationBackend = backendItem.backend.resourcesBackend } Component { id: kirigamiAction Kirigami.Action { property QtObject action text: action.text tooltip: action.toolTip onTriggered: action.trigger() } } function mergeActions(moreActions) { var actions = [makeDefault, addSource] for(var i in moreActions) { actions.push(kirigamiAction.createObject(null, {action: moreActions[i]})) } return actions; } actions: mergeActions(backendItem.backend.actions) } } Component { id: sourceProceedDialog Kirigami.OverlaySheet { id: sheet showCloseButton: false property QtObject sourcesBackend property alias title: heading.text property alias description: desc.text property bool acted: false header: Kirigami.Heading { id: heading wrapMode: Text.WordWrap } ColumnLayout { Label { id: desc Layout.fillWidth: true textFormat: Text.StyledText wrapMode: Text.WordWrap } RowLayout { Layout.alignment: Qt.AlignRight Button { text: i18n("Proceed") icon.name: "dialog-ok" onClicked: { sourcesBackend.proceed() sheet.acted = true sheet.close() } } Button { Layout.alignment: Qt.AlignRight text: i18n("Cancel") icon.name: "dialog-cancel" onClicked: { sourcesBackend.cancel() sheet.acted = true sheet.close() } } } } onSheetOpenChanged: if(!sheetOpen) { sheet.destroy(1000) if (!sheet.acted) sourcesBackend.cancel() } } } delegate: Kirigami.SwipeListItem { enabled: model.display.length>0 && model.enabled highlighted: ListView.isCurrentItem supportsMouseEvents: false visible: model.display.indexOf(page.search)>=0 height: visible ? implicitHeight : 0 Keys.onReturnPressed: clicked() actions: [ Kirigami.Action { iconName: "go-up" enabled: sourcesBackend.firstSourceId !== sourceId visible: sourcesBackend.canMoveSources onTriggered: { var ret = sourcesBackend.moveSource(sourceId, -1) if (!ret) window.showPassiveNotification(i18n("Failed to increase '%1' preference", model.display)) } }, Kirigami.Action { iconName: "go-down" enabled: sourcesBackend.lastSourceId !== sourceId visible: sourcesBackend.canMoveSources onTriggered: { var ret = sourcesBackend.moveSource(sourceId, +1) if (!ret) window.showPassiveNotification(i18n("Failed to decrease '%1' preference", model.display)) } }, Kirigami.Action { iconName: "edit-delete" tooltip: i18n("Delete the origin") visible: sourcesBackend.supportsAdding onTriggered: { var backend = sourcesBackend if (!backend.removeSource(sourceId)) { console.warn("Failed to remove the source", model.display) } } }, Kirigami.Action { iconName: "view-filter" tooltip: i18n("Show contents") visible: sourcesBackend.canFilterSources onTriggered: { Navigation.openApplicationListSource(sourceId) } } ] RowLayout { CheckBox { id: enabledBox readonly property variant idx: sourcesView.model.index(index, 0) readonly property variant modelChecked: sourcesView.model.data(idx, Qt.CheckStateRole) checked: modelChecked !== Qt.Unchecked enabled: modelChecked !== undefined onClicked: { sourcesView.model.setData(idx, checkState, Qt.CheckStateRole) checked = Qt.binding(function() { return modelChecked !== Qt.Unchecked; }) } } Label { text: model.display + (model.toolTip ? " - " + model.toolTip + "" : "") elide: Text.ElideRight textFormat: Text.StyledText Layout.fillWidth: true } } } footer: ColumnLayout { id: foot anchors { right: parent.right left: parent.left margins: Kirigami.Units.smallSpacing } Kirigami.Heading { Layout.fillWidth: true text: i18n("Missing Backends") visible: back.count>0 } spacing: 0 Repeater { id: back model: ResourcesProxyModel { extending: "org.kde.discover.desktop" filterMinimumState: false } delegate: Kirigami.BasicListItem { supportsMouseEvents: false label: name icon: model.icon InstallApplicationButton { application: model.application } } } } } } diff --git a/discover/qml/UpdatesPage.qml b/discover/qml/UpdatesPage.qml index 2b941bbd..1ce00756 100644 --- a/discover/qml/UpdatesPage.qml +++ b/discover/qml/UpdatesPage.qml @@ -1,407 +1,405 @@ import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtQuick 2.4 import org.kde.discover 2.0 import org.kde.discover.app 1.0 import "navigation.js" as Navigation import org.kde.kirigami 2.10 as Kirigami DiscoverPage { id: page title: i18n("Updates") property string footerLabel: "" property int footerProgress: 0 property bool isBusy: false readonly property var resourcesUpdatesModel: ResourcesUpdatesModel { id: resourcesUpdatesModel onPassiveMessage: { desc.text += message + "
\n" sheet.sheetOpen = true } onIsProgressingChanged: { if (!isProgressing) { resourcesUpdatesModel.prepare() } } Component.onCompleted: { if (!isProgressing) { resourcesUpdatesModel.prepare() } } } readonly property var sheet: Kirigami.OverlaySheet { id: sheet header: Kirigami.Heading { text: i18n("Update Issue") } ColumnLayout { Label { id: desc Layout.fillWidth: true textFormat: Text.StyledText wrapMode: Text.WordWrap } Button { id: okButton Layout.alignment: Qt.AlignRight text: i18n("OK") icon.name: "dialog-ok" onClicked: { sheet.sheetOpen = false } } } onSheetOpenChanged: if(!sheetOpen) { desc.text = "" } else { okButton.focus = true } } readonly property var updateModel: UpdateModel { id: updateModel backend: resourcesUpdatesModel } readonly property var updateAction: Kirigami.Action { id: updateAction text: page.unselected>0 ? i18n("Update Selected") : i18n("Update All") visible: updateModel.toUpdateCount iconName: "update-none" enabled: !resourcesUpdatesModel.isProgressing && !ResourcesModel.isFetching onTriggered: resourcesUpdatesModel.updateAll() } footer: ScrollView { id: scv width: parent.width height: visible ? Kirigami.Units.gridUnit * 10 : 0 visible: log.contents.length > 0 TextArea { readOnly: true text: log.contents cursorPosition: text.length - 1 font.family: "monospace" ReadFile { id: log filter: ".*ALPM-SCRIPTLET\\] .*" path: "/var/log/pacman.log" } } } Kirigami.Action { id: cancelUpdateAction iconName: "dialog-cancel" text: i18n("Cancel") enabled: resourcesUpdatesModel.transaction && resourcesUpdatesModel.transaction.isCancellable onTriggered: resourcesUpdatesModel.transaction.cancel() } readonly property int unselected: (updateModel.totalUpdatesCount - updateModel.toUpdateCount) header: ToolBar { anchors.left: page.left anchors.right: page.right - Kirigami.Theme.colorSet: Kirigami.Theme.Button - Kirigami.Theme.inherit: false visible: (updateModel.totalUpdatesCount > 0 && resourcesUpdatesModel.isProgressing) || updateModel.hasUpdates CheckBox { anchors.left: parent.left anchors.leftMargin: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing anchors.right: parent.right text: page.unselected === 0 ? i18n("All updates selected (%1)", updateModel.updateSize) : i18np("%1/%2 update selected (%3)", "%1/%2 updates selected (%3)", updateModel.toUpdateCount, updateModel.totalUpdatesCount, updateModel.updateSize) enabled: updateAction.enabled && !resourcesUpdatesModel.isProgressing && !ResourcesModel.isFetching tristate: true checkState: updateModel.toUpdateCount === 0 ? Qt.Unchecked : updateModel.toUpdateCount === updateModel.totalUpdatesCount ? Qt.Checked : Qt.PartiallyChecked onClicked: { if (updateModel.toUpdateCount === 0) updateModel.checkAll() else updateModel.uncheckAll() } } } supportsRefreshing: true onRefreshingChanged: { ResourcesModel.updateAction.triggered() refreshing = false } readonly property Item report: ColumnLayout { parent: page anchors.fill: parent Item { Layout.fillHeight: true width: 1 } ProgressBar { Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: Kirigami.Units.gridUnit * 20 value: page.footerProgress from: 0 to: 100 visible: page.isBusy } Kirigami.Icon { Layout.alignment: Qt.AlignHCenter visible: page.footerProgress === 0 && page.footerLabel !== "" && !page.isBusy source: "update-none" width: Kirigami.Units.gridUnit * 4 height: width enabled: false } Kirigami.Heading { id: statusLabel Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter text: page.footerLabel level: 3 } Button { Layout.alignment: Qt.AlignHCenter text: i18n("Restart") visible: resourcesUpdatesModel.needsReboot onClicked: app.reboot() } Item { Layout.fillHeight: true width: 1 } } ListView { id: updatesView currentIndex: -1 displaced: Transition { YAnimator { duration: Kirigami.Units.longDuration easing.type: Easing.InOutQuad } } model: QSortFilterProxyModel { sourceModel: updateModel sortRole: UpdateModel.SectionResourceProgressRole } section { property: "section" delegate: Kirigami.ListSectionHeader { width: updatesView.width label: section } } delegate: Kirigami.AbstractListItem { id: listItem backgroundColor: Kirigami.Theme.backgroundColor highlighted: ListView.isCurrentItem onEnabledChanged: if (!enabled) { layout.extended = false; } visible: resourceState < 3 //3=AbstractBackendUpdater.Done Keys.onReturnPressed: { itemChecked.clicked() } Keys.onPressed: if (event.key===Qt.Key_Alt) layout.extended = true Keys.onReleased: if (event.key===Qt.Key_Alt) layout.extended = false ColumnLayout { id: layout property bool extended: false onExtendedChanged: if (extended) { updateModel.fetchUpdateDetails(index) } RowLayout { Layout.fillWidth: true Layout.fillHeight: true CheckBox { id: itemChecked Layout.leftMargin: Kirigami.Units.gridUnit Layout.alignment: Qt.AlignVCenter checked: model.checked === Qt.Checked onClicked: model.checked = (model.checked===Qt.Checked ? Qt.Unchecked : Qt.Checked) enabled: !resourcesUpdatesModel.isProgressing } Kirigami.Icon { width: Kirigami.Units.gridUnit * 2 Layout.preferredHeight: width source: decoration smooth: true } ColumnLayout { // App name Kirigami.Heading { Layout.fillWidth: true text: i18n("%1", display) level: 3 elide: Text.ElideRight } // Version numbers Label { Layout.fillWidth: true elide: truncated ? Text.ElideLeft : Text.ElideRight text: { if (installedVersion == availableVersion) { // Update of the same version; show when old and new are // the same (common with Flatpak runtimes) return i18n("Update to version %1", availableVersion); } else if (installedVersion && availableVersion) { // Old and new version numbers // This thing with \x9C is a fancy feature in QML text handling: // when the string will be elided, it shows the string after // the last \x9C. This allows us to show a smaller string // when there's now enough room // All of this is mostly for the benefit of KDE Neon users, // since the version strings there are really really long return i18nc("Do not translate or alter \\x9C", "%1 → %2\x9C%1 → %2\x9C%2", installedVersion, availableVersion); } else { // Available version only, for when the installed version // isn't available for some reason return availableVersion; } } opacity: listItem.hovered? 0.8 : 0.6 } } LabelBackground { Layout.minimumWidth: Kirigami.Units.gridUnit * 6 text: resourceState == 2 ? i18n("Installing") : size progress: resourceProgress/100 } } Frame { Layout.fillWidth: true implicitHeight: view.contentHeight visible: layout.extended && changelog.length>0 Label { id: view anchors { right: parent.right left: parent.left } text: changelog textFormat: Text.StyledText wrapMode: Text.WordWrap onLinkActivated: Qt.openUrlExternally(link) } //This saves a binding loop on implictHeight, as the Label //height is updated twice (first time with the wrong value) Behavior on implicitHeight { PropertyAnimation { duration: Kirigami.Units.shortDuration } } } Button { Layout.alignment: Qt.AlignRight text: i18n("More Information...") visible: layout.extended enabled: !resourcesUpdatesModel.isProgressing onClicked: Navigation.openApplication(resource) } } onClicked: { layout.extended = !layout.extended } } } readonly property alias secSinceUpdate: resourcesUpdatesModel.secsToLastUpdate state: ( resourcesUpdatesModel.isProgressing ? "progressing" : ResourcesModel.isFetching ? "fetching" : updateModel.hasUpdates ? "has-updates" : resourcesUpdatesModel.needsReboot ? "reboot" : secSinceUpdate < 0 ? "unknown" : secSinceUpdate === 0 ? "now-uptodate" : secSinceUpdate < 1000 * 60 * 60 * 24 ? "uptodate" : secSinceUpdate < 1000 * 60 * 60 * 24 * 7 ? "medium" : "low" ) states: [ State { name: "fetching" PropertyChanges { target: page; footerLabel: i18nc("@info", "Fetching updates...") } PropertyChanges { target: statusLabel; enabled: true } PropertyChanges { target: page; footerProgress: ResourcesModel.fetchingUpdatesProgress } PropertyChanges { target: page; isBusy: true } PropertyChanges { target: updatesView; opacity: 0 } }, State { name: "progressing" PropertyChanges { target: page; supportsRefreshing: false } PropertyChanges { target: page.actions; main: cancelUpdateAction } }, State { name: "has-updates" PropertyChanges { target: page; title: i18nc("@info", "Updates") } PropertyChanges { target: page.actions; main: updateAction } PropertyChanges { target: page.actions; left: refreshAction } }, State { name: "reboot" PropertyChanges { target: page; footerLabel: i18nc("@info", "The system requires a restart to apply updates") } PropertyChanges { target: statusLabel; enabled: true } }, State { name: "now-uptodate" PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to date") } PropertyChanges { target: statusLabel; enabled: false } PropertyChanges { target: page.actions; main: refreshAction } }, State { name: "uptodate" PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to date") } PropertyChanges { target: statusLabel; enabled: false } PropertyChanges { target: page.actions; main: refreshAction } }, State { name: "medium" PropertyChanges { target: page; title: i18nc("@info", "Up to date") } PropertyChanges { target: statusLabel; enabled: false } PropertyChanges { target: page.actions; main: refreshAction } }, State { name: "low" PropertyChanges { target: page; title: i18nc("@info", "Should check for updates") } PropertyChanges { target: statusLabel; enabled: true } PropertyChanges { target: page.actions; main: refreshAction } }, State { name: "unknown" PropertyChanges { target: page; title: i18nc("@info", "It is unknown when the last check for updates was") } PropertyChanges { target: statusLabel; enabled: true } PropertyChanges { target: page.actions; main: refreshAction } } ] }