Commit e965d8ba authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧 Committed by Aleix Pol Gonzalez
Browse files

Support OARS in AppStream-based backends

Allows users know what kind of content they are going to find coming
from an app.
parent 162fedf9
......@@ -221,7 +221,19 @@ DiscoverPage {
Layout.rightMargin: appInfo.internalSpacings
// This centers the Flow in the page, no matter how many items have
// flowed onto other rows
Layout.maximumWidth: ((itemWidth + spacing) * Math.min(children.length, Math.floor(headerLayout.width / (itemWidth + spacing)))) - spacing
readonly property int visibleChildren: countVisibleChildren(children)
function countVisibleChildren(items) {
let ret = 0;
for (const itemPos in items) {
const item = items[itemPos];
ret += item.visible;
}
return ret;
}
onImplicitWidthChanged: visibleChildrenChanged()
Layout.maximumWidth: ((itemWidth + spacing) * Math.min(visibleChildren, Math.floor(headerLayout.width / (itemWidth + spacing)))) - spacing
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
......@@ -385,6 +397,61 @@ DiscoverPage {
}
}
// Content Rating
ColumnLayout {
width: metadataLayout.itemWidth
visible: appInfo.application.contentRatingText.length > 0
spacing: Kirigami.Units.smallSpacing
Label {
Layout.fillWidth: true
opacity: 0.7
text: i18n("Content Rating")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
wrapMode: Text.Wrap
maximumLineCount: 2
}
Label {
Layout.fillWidth: true
visible: text.length > 0
text: appInfo.application.contentRatingMinimumAge === 0 ? "" : i18n("Age: %1+", appInfo.application.contentRatingMinimumAge)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
wrapMode: Text.Wrap
maximumLineCount: 3
elide: Text.ElideRight
}
Label {
Layout.fillWidth: true
text: appInfo.application.contentRatingText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
wrapMode: Text.Wrap
maximumLineCount: 3
elide: Text.ElideRight
readonly property var colors: [ Kirigami.Theme.textColor, Kirigami.Theme.neutralTextColor ]
color: colors[appInfo.application.contentRatingIntensity]
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
visible: appInfo.application.contentRatingDescription.length > 0
Kirigami.LinkButton {
Layout.fillWidth: true
text: i18n("Show more...")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
elide: Text.ElideRight
onClicked: contentRatingSheet.open();
}
}
}
}
}
......@@ -729,6 +796,18 @@ DiscoverPage {
}
}
Kirigami.OverlaySheet {
id: contentRatingSheet
parent: applicationWindow().overlay
title: i18n("Content Rating")
Label {
text: appInfo.application.contentRatingDescription
textFormat: Text.MarkdownText
}
}
Kirigami.OverlaySheet {
id: properietarySoftwareRiskExplanationSheet
parent: applicationWindow().overlay
......
......@@ -9,12 +9,13 @@
#include "utils.h"
#include <AppStreamQt/release.h>
#include <AppStreamQt/screenshot.h>
#include <AppStreamQt/spdx.h>
#include <AppStreamQt/version.h>
#include <KLocalizedString>
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QUrlQuery>
#include <AppStreamQt/spdx.h>
using namespace AppStreamUtils;
......@@ -137,3 +138,87 @@ QString AppStreamUtils::versionString(const QString &version, const AppStream::C
}
}
}
QString AppStreamUtils::contentRatingDescription(const AppStream::Component &appdata)
{
#if ASQ_CHECK_VERSION(0, 15, 6)
const auto ratings = appdata.contentRatings();
QStringList ret;
for (const auto &r : ratings) {
const auto ratingIds = r.ratingIds();
for (const auto &id : ratingIds) {
if (r.value(id) != AppStream::ContentRating::RatingValueNone) {
ret += r.description(id);
}
}
}
return "* " + ret.join("\n* ");
#else
return {};
#endif
}
QString AppStreamUtils::contentRatingText(const AppStream::Component &appdata)
{
#if ASQ_CHECK_VERSION(0, 15, 6)
const auto ratings = appdata.contentRatings();
AppStream::ContentRating::RatingValue intensity = AppStream::ContentRating::RatingValueUnknown;
for (const auto &r : ratings) {
const auto ratingIds = r.ratingIds();
for (const auto &id : ratingIds) {
intensity = std::max(r.value(id), intensity);
}
}
static QStringList texts = {
{},
i18n("All Audiences"),
i18nc("As specified in OARS, intensity of contents", "Mild Content"),
i18nc("As specified in OARS, intensity of contents", "Moderate Content"),
i18nc("As specified in OARS, intensity of contents", "Intense Content"),
};
return texts[intensity];
#else
return {};
#endif
}
AbstractResource::ContentIntensity AppStreamUtils::contentRatingIntensity(const AppStream::Component &appdata)
{
#if ASQ_CHECK_VERSION(0, 15, 6)
const auto ratings = appdata.contentRatings();
AppStream::ContentRating::RatingValue intensity = AppStream::ContentRating::RatingValueUnknown;
for (const auto &r : ratings) {
const auto ratingIds = r.ratingIds();
for (const auto &id : ratingIds) {
intensity = std::max(r.value(id), intensity);
}
}
static QVector<AbstractResource::ContentIntensity> intensities = {
AbstractResource::Mild,
AbstractResource::Mild,
AbstractResource::Mild,
AbstractResource::Intense,
AbstractResource::Intense,
};
return intensities[intensity];
#else
return {};
#endif
}
uint AppStreamUtils::contentRatingMinimumAge(const AppStream::Component &appdata)
{
#if ASQ_CHECK_VERSION(0, 15, 6)
const auto ratings = appdata.contentRatings();
uint minimumAge = 0;
for (const auto &r : ratings) {
minimumAge = std::max(r.minimumAge(), minimumAge);
}
return minimumAge;
#else
return 0;
#endif
}
......@@ -9,8 +9,10 @@
#include <AppStreamQt/component.h>
#include <AppStreamQt/image.h>
#include <QColor>
#include <QList>
#include <QUrl>
#include <resources/AbstractResource.h>
namespace AppStreamUtils
{
......@@ -30,6 +32,11 @@ Q_DECL_EXPORT QStringList appstreamIds(const QUrl &appstreamUrl);
/// Helps implement AbstractResource::versionString
Q_DECL_EXPORT QString versionString(const QString &version, const AppStream::Component &appdata);
Q_DECL_EXPORT QString contentRatingText(const AppStream::Component &appdata);
Q_DECL_EXPORT QString contentRatingDescription(const AppStream::Component &appdata);
Q_DECL_EXPORT AbstractResource::ContentIntensity contentRatingIntensity(const AppStream::Component &appdata);
Q_DECL_EXPORT uint contentRatingMinimumAge(const AppStream::Component &appdata);
}
#endif
......@@ -867,3 +867,23 @@ bool FlatpakResource::isOlderThan(FlatpakResource *resource) const
const QString other = resource->availableVersion();
return AppStream::Utils::vercmpSimple(installedVersion(), other) < 0;
}
QString FlatpakResource::contentRatingDescription() const
{
return AppStreamUtils::contentRatingDescription(m_appdata);
}
QString FlatpakResource::contentRatingText() const
{
return AppStreamUtils::contentRatingText(m_appdata);
}
AbstractResource::ContentIntensity FlatpakResource::contentRatingIntensity() const
{
return AppStreamUtils::contentRatingIntensity(m_appdata);
}
uint FlatpakResource::contentRatingMinimumAge() const
{
return AppStreamUtils::contentRatingMinimumAge(m_appdata);
}
......@@ -199,6 +199,11 @@ public:
return m_appdata;
}
QString contentRatingText() const override;
QString contentRatingDescription() const override;
ContentIntensity contentRatingIntensity() const override;
uint contentRatingMinimumAge() const override;
Q_SIGNALS:
void hasDataButUninstalledChanged();
void propertyStateChanged(FlatpakResource::PropertyKind kind, FlatpakResource::PropertyState state);
......
......@@ -248,3 +248,23 @@ bool AppPackageKitResource::isCritical() const
{
return m_appdata.isCompulsoryForDesktop(qEnvironmentVariable("XDG_CURRENT_DESKTOP"));
}
QString AppPackageKitResource::contentRatingDescription() const
{
return AppStreamUtils::contentRatingDescription(m_appdata);
}
QString AppPackageKitResource::contentRatingText() const
{
return AppStreamUtils::contentRatingText(m_appdata);
}
AbstractResource::ContentIntensity AppPackageKitResource::contentRatingIntensity() const
{
return AppStreamUtils::contentRatingIntensity(m_appdata);
}
uint AppPackageKitResource::contentRatingMinimumAge() const
{
return AppStreamUtils::contentRatingMinimumAge(m_appdata);
}
......@@ -45,6 +45,11 @@ public:
QSet<QString> alternativeAppstreamIds() const override;
bool isCritical() const override;
QString contentRatingText() const override;
QString contentRatingDescription() const override;
ContentIntensity contentRatingIntensity() const override;
uint contentRatingMinimumAge() const override;
private:
const AppStream::Component m_appdata;
mutable QString m_name;
......
......@@ -292,4 +292,22 @@ QString AbstractResource::versionString()
}
}
#include "moc_AbstractResource.cpp"
QString AbstractResource::contentRatingDescription() const
{
return {};
}
AbstractResource::ContentIntensity AbstractResource::contentRatingIntensity() const
{
return Mild;
}
QString AbstractResource::contentRatingText() const
{
return {};
}
uint AbstractResource::contentRatingMinimumAge() const
{
return 0;
}
......@@ -8,6 +8,7 @@
#define ABSTRACTRESOURCE_H
#include <QCollatorSortKey>
#include <QColor>
#include <QDate>
#include <QJsonArray>
#include <QJsonObject>
......@@ -72,6 +73,10 @@ class DISCOVERCOMMON_EXPORT AbstractResource : public QObject
Q_PROPERTY(QString upgradeText READ upgradeText NOTIFY versionsChanged)
Q_PROPERTY(bool isRemovable READ isRemovable CONSTANT)
Q_PROPERTY(QString versionString READ versionString NOTIFY versionsChanged)
Q_PROPERTY(QString contentRatingText READ contentRatingText CONSTANT)
Q_PROPERTY(QString contentRatingDescription READ contentRatingDescription CONSTANT)
Q_PROPERTY(ContentIntensity contentRatingIntensity READ contentRatingIntensity CONSTANT)
Q_PROPERTY(uint contentRatingMinimumAge READ contentRatingMinimumAge CONSTANT)
public:
/**
* This describes the state of the resource
......@@ -96,6 +101,12 @@ public:
};
Q_ENUM(State)
enum ContentIntensity {
Mild,
Intense,
};
Q_ENUM(ContentIntensity)
/**
* Constructs the AbstractResource with its corresponding backend
*/
......@@ -230,6 +241,11 @@ public:
virtual QString versionString();
virtual QString contentRatingText() const;
virtual ContentIntensity contentRatingIntensity() const;
virtual QString contentRatingDescription() const;
virtual uint contentRatingMinimumAge() const;
public Q_SLOTS:
virtual void fetchScreenshots();
virtual void fetchChangelog() = 0;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment