diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c7217a9..12a90d45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,98 +1,98 @@
project(discover)
set(PROJECT_VERSION "5.16.80")
set(PROJECT_VERSION_MAJOR 5)
cmake_minimum_required(VERSION 2.8.12)
set(QT_MIN_VERSION "5.12.0")
-set(KF5_MIN_VERSION "5.58.0")
+set(KF5_MIN_VERSION "5.62.0")
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_SOURCE_DIR}/cmake")
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED CONFIG COMPONENTS Widgets Test Network Xml Concurrent DBus Quick)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(ECMInstallIcons)
include(ECMMarkAsTest)
include(ECMAddTests)
include(GenerateExportHeader)
include(ECMQtDeclareLoggingCategory)
find_package(PkgConfig REQUIRED)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED CoreAddons Config Crash DBusAddons I18n Archive XmlGui ItemModels KIO Declarative)
find_package(KF5Kirigami2 2.7.0)
find_package(packagekitqt5 1.0.1 CONFIG)
find_package(AppStreamQt 0.11.1 CONFIG)
find_package(KF5Attica 5.23 CONFIG)
find_package(KF5NewStuff 5.53 CONFIG)
set(CMAKE_AUTORCC ON)
pkg_check_modules(Flatpak IMPORTED_TARGET flatpak>=0.11.8)
pkg_check_modules(Fwupd IMPORTED_TARGET fwupd>=1.0.6)
pkg_check_modules(Markdown IMPORTED_TARGET libmarkdown)
if(NOT CMAKE_VERSION VERSION_LESS "3.10.0")
# CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros.
# 3.10+ lets us provide more macro names that require automoc.
list(APPEND CMAKE_AUTOMOC_MACRO_NAMES "DISCOVER_BACKEND_PLUGIN")
endif()
configure_file(DiscoverVersion.h.in DiscoverVersion.h)
add_subdirectory(libdiscover)
add_subdirectory(discover)
add_subdirectory(exporter)
option(WITH_NOTIFIER "Build and install the notifier plasmoid" ON)
if(WITH_NOTIFIER)
find_package(KF5 REQUIRED Notifications KIO)
add_subdirectory(notifier)
endif()
set_package_properties(KF5Attica PROPERTIES
DESCRIPTION "KDE Framework that implements the Open Collaboration Services API"
PURPOSE "Required to build the KNewStuff3 backend"
TYPE OPTIONAL)
set_package_properties(KF5Kirigami2 PROPERTIES
DESCRIPTION "KDE's lightweight user interface framework for mobile and convergent applications"
URL "https://techbase.kde.org/Kirigami"
PURPOSE "Required by discover qml components"
TYPE RUNTIME)
set_package_properties(KF5NewStuff PROPERTIES
DESCRIPTION "Qt library that allows to interact with KNewStuff implementations"
PURPOSE "Required to build the KNS backend"
TYPE OPTIONAL)
set_package_properties(packagekitqt5 PROPERTIES
DESCRIPTION "Library that exposes PackageKit resources"
URL "https://www.freedesktop.org/software/PackageKit/"
PURPOSE "Required to build the PackageKit backend"
TYPE OPTIONAL)
set_package_properties(AppStreamQt PROPERTIES
DESCRIPTION "Library that lists Appstream resources"
URL "https://www.freedesktop.org"
PURPOSE "Required to build the PackageKit and Flatpak backends"
TYPE OPTIONAL)
set_package_properties(FLATPAK PROPERTIES
DESCRIPTION "Library that exposes flatpak repositories"
URL "https://www.freedesktop.org"
PURPOSE "Required to build the Flatpak backend"
TYPE OPTIONAL)
set_package_properties(LIBFWUPD PROPERTIES
DESCRIPTION "Library that exposes fwupd"
URL "https://www.fwupd.org"
PURPOSE "Required to build the Fwupd backend"
TYPE OPTIONAL)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
if (${ECM_VERSION} STRGREATER "5.58.0")
install(FILES discover.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR})
else()
install(FILES discover.categories DESTINATION ${KDE_INSTALL_CONFDIR})
endif()
diff --git a/discover/qml/SourcesPage.qml b/discover/qml/SourcesPage.qml
index bbc01bb2..21df5211 100644
--- a/discover/qml/SourcesPage.qml
+++ b/discover/qml/SourcesPage.qml
@@ -1,260 +1,255 @@
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.2 as Kirigami
+import org.kde.kirigami 2.10 as Kirigami
import "navigation.js" as Navigation
DiscoverPage {
id: page
clip: true
title: i18n("Sources")
property string search: ""
background: Rectangle {
color: Kirigami.Theme.backgroundColor
Kirigami.Theme.colorSet: Kirigami.Theme.Window
Kirigami.Theme.inherit: false
}
mainItem: ListView {
id: sourcesView
model: QSortFilterProxyModel {
filterRegExp: new RegExp(page.search, 'i')
dynamicSortFilter: false //We don't want to sort, as sorting can have some semantics on some backends
sourceModel: SourcesModel
}
currentIndex: -1
section.property: "sourceName"
- section.delegate: Kirigami.AbstractListItem {
+ section.delegate: Kirigami.ListSectionHeader {
id: backendItem
- hoverEnabled: false
- supportsMouseEvents: false
+
readonly property QtObject backend: SourcesModel.sourcesBackendByName(section)
readonly property QtObject resourcesBackend: backend.resourcesBackend
readonly property bool isDefault: ResourcesModel.currentApplicationBackend === resourcesBackend
- RowLayout {
- id: sourceTitleLayout
- Layout.fillHeight: true
- Connections {
- target: backendItem.backend
- onPassiveMessage: window.showPassiveNotification(message)
- onProceedRequest: {
- var dialog = sourceProceedDialog.createObject(window, {sourcesBackend: backendItem.backend, title: title, description: description})
- dialog.open()
+ width: sourcesView.width
+ label: backendItem.isDefault ? i18n("%1 (Default)", resourcesBackend.displayName) : resourcesBackend.displayName
+
+ customItems: [
+ RowLayout {
+ id: sourceTitleLayout
+ Connections {
+ target: backendItem.backend
+ onPassiveMessage: window.showPassiveNotification(message)
+ onProceedRequest: {
+ var dialog = sourceProceedDialog.createObject(window, {sourcesBackend: backendItem.backend, title: title, description: description})
+ dialog.open()
+ }
}
- }
- Kirigami.Heading {
- Layout.fillWidth: true
- Layout.leftMargin: Kirigami.Units.smallSpacing
- Layout.alignment: Qt.AlignVCenter
- text: backendItem.isDefault ? i18n("%1 (Default)", resourcesBackend.displayName) : resourcesBackend.displayName
- level: 3
- }
-
- Instantiator {
- id: backendActionsInst
- model: ActionsModel {
- actions: backendItem.backend ? backendItem.backend.actions : undefined
- }
- delegate: Button {
- parent: sourceTitleLayout
- Layout.column: 1
- text: modelData.text
- icon.name: app.iconName(modelData.icon)
- ToolTip.visible: hovered
- ToolTip.text: modelData.toolTip
- onClicked: modelData.trigger()
- }
- onObjectRemoved: {
- object.destroy()
+ Instantiator {
+ id: backendActionsInst
+ model: ActionsModel {
+ actions: backendItem.backend ? backendItem.backend.actions : undefined
+ }
+ delegate: Button {
+ parent: sourceTitleLayout
+ Layout.column: 1
+ text: modelData.text
+ icon.name: app.iconName(modelData.icon)
+ ToolTip.visible: hovered
+ ToolTip.text: modelData.toolTip
+ onClicked: modelData.trigger()
+ }
+ onObjectRemoved: {
+ object.destroy()
+ }
}
- }
- Button {
- text: i18n("Add Source...")
- icon.name: "list-add"
- visible: backendItem.backend && backendItem.backend.supportsAdding
-
- Component {
- id: dialogComponent
- AddSourceDialog {
- source: backendItem.backend
- onVisibleChanged: if (!visible) {
- destroy()
+ Button {
+ text: i18n("Add Source...")
+ icon.name: "list-add"
+ visible: backendItem.backend && backendItem.backend.supportsAdding
+
+ Component {
+ id: dialogComponent
+ AddSourceDialog {
+ source: backendItem.backend
+ onVisibleChanged: if (!visible) {
+ destroy()
+ }
}
}
- }
- onClicked: {
- var addSourceDialog = dialogComponent.createObject(null, {displayName: backendItem.backend.resourcesBackend.displayName })
- addSourceDialog.open()
+ onClicked: {
+ var addSourceDialog = dialogComponent.createObject(null, {displayName: backendItem.backend.resourcesBackend.displayName })
+ addSourceDialog.open()
+ }
}
- }
- Button {
- visible: resourcesBackend && resourcesBackend.hasApplications
+ Button {
+ visible: resourcesBackend && resourcesBackend.hasApplications
- enabled: !backendItem.isDefault
- text: i18n("Make default")
- icon.name: "favorite"
- onClicked: ResourcesModel.currentApplicationBackend = backendItem.backend.resourcesBackend
+ enabled: !backendItem.isDefault
+ text: i18n("Make default")
+ icon.name: "favorite"
+ onClicked: ResourcesModel.currentApplicationBackend = backendItem.backend.resourcesBackend
+ }
}
- }
+ ]
}
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
ColumnLayout {
Kirigami.Heading {
id: heading
}
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: display.length>0 && model.enabled
highlighted: ListView.isCurrentItem
supportsMouseEvents: false
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", 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", display))
}
},
Kirigami.Action {
iconName: "edit-delete"
tooltip: i18n("Delete the origin")
visible: sourcesBackend.supportsAdding
onTriggered: {
var backend = sourcesBackend
if (!backend.removeSource(sourceId)) {
window.showPassiveNotification(i18n("Failed to remove the source '%1'", 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: display + (toolTip ? " - " + 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 d763cc33..1f183eb6 100644
--- a/discover/qml/UpdatesPage.qml
+++ b/discover/qml/UpdatesPage.qml
@@ -1,402 +1,400 @@
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.3 as Kirigami
+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
ResourcesUpdatesModel {
id: resourcesUpdatesModel
onPassiveMessage: {
desc.text += message + "
\n"
sheet.sheetOpen = true
}
onIsProgressingChanged: {
if (!isProgressing) {
resourcesUpdatesModel.prepare()
}
}
Component.onCompleted: {
if (!isProgressing) {
resourcesUpdatesModel.prepare()
}
}
}
Kirigami.OverlaySheet {
id: sheet
ColumnLayout {
Label {
id: desc
Layout.fillWidth: true
textFormat: Text.StyledText
wrapMode: Text.WordWrap
}
Button {
id: okButton
Layout.alignment: Qt.AlignRight
text: i18n("Proceed")
icon.name: "dialog-ok"
onClicked: {
sheet.sheetOpen = false
}
}
}
onSheetOpenChanged: if(!sheetOpen) {
desc.text = ""
} else {
okButton.focus = true
}
}
UpdateModel {
id: updateModel
backend: resourcesUpdatesModel
}
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 {
Kirigami.Theme.colorSet: Kirigami.Theme.Button
Kirigami.Theme.inherit: false
visible: (updateModel.totalUpdatesCount > 0 && resourcesUpdatesModel.isProgressing) || updateModel.hasUpdates
RowLayout {
anchors.fill: parent
enabled: updateAction.enabled
CheckBox {
Layout.leftMargin: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing
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()
}
}
Label {
Layout.fillWidth: true
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)
elide: Text.ElideRight
}
}
}
supportsRefreshing: true
onRefreshingChanged: {
ResourcesModel.updateAction.triggered()
refreshing = false
}
readonly property Item report: ColumnLayout {
parent: page
anchors.fill: parent
Item {
Layout.fillHeight: true
width: 1
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
text: page.footerLabel
level: 3
}
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 !== ""
source: "update-none"
opacity: 0.1
width: Kirigami.Units.gridUnit * 8
height: width
}
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.Heading {
- x: Kirigami.Units.gridUnit
- level: 2
- text: section
- height: implicitHeight + Kirigami.Units.largeSpacing * 2
+ 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
}
// Old and new version numbers; show when there's enough room
Label {
id: oldAndNewVersions
Layout.fillWidth: true
elide: Text.ElideRight
text: i18n("%1 → %2", installedVersion, availableVersion)
visible: installedVersion && !truncated
opacity: listItem.hovered? 0.8 : 0.6
}
// Available version only, for when old+new would be elided.
// Use squeezey text to gain more room, and if it's still so
// so long that it would be elided, elide from the left so
// the most important part on the right is still visible
// All of this is mostly for the benefit of KDE Neon users,
// since the version strings there are really really long
Label {
Layout.fillWidth: true
elide: Text.ElideLeft
text: availableVersion
visible: !oldAndNewVersions.visible
font.letterSpacing: -0.5
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
LinkLabel {
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"
: updateModel.hasUpdates ? "has-updates"
: ResourcesModel.isFetching ? "fetching"
: 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: page; footerProgress: ResourcesModel.fetchingUpdatesProgress }
PropertyChanges { target: page; isBusy: true }
},
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") }
},
State {
name: "now-uptodate"
PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to Date") }
PropertyChanges { target: page.actions; main: refreshAction }
},
State {
name: "uptodate"
PropertyChanges { target: page; footerLabel: i18nc("@info", "Up to Date") }
PropertyChanges { target: page.actions; main: refreshAction }
},
State {
name: "medium"
PropertyChanges { target: page; title: i18nc("@info", "Up to Date") }
PropertyChanges { target: page.actions; main: refreshAction }
},
State {
name: "low"
PropertyChanges { target: page; title: i18nc("@info", "Should check for updates") }
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: page.actions; main: refreshAction }
}
]
}