Commit 95ef0d1c authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

When opening by url, show a list rather than a resource directly

It's more realistic.
Prepares ResourcesProxyModel for other useful use-cases
parent 8a2e6dfd
......@@ -57,6 +57,7 @@
#include <MuonDataSources.h>
#include <resources/AbstractResource.h>
#include <resources/ResourcesModel.h>
#include <resources/ResourcesProxyModel.h>
#include <Category/Category.h>
#include <Category/CategoryModel.h>
......@@ -214,31 +215,10 @@ void DiscoverMainWindow::openLocalPackage(const QUrl& localfile)
}
}
void DiscoverMainWindow::openApplication(const QUrl& app)
void DiscoverMainWindow::openApplication(const QUrl& url)
{
Q_ASSERT(!app.isEmpty());
rootObject()->setProperty("defaultStartup", false);
auto action = new OneTimeAction(
[this, app]() {
StoredResultsStream* stream = new StoredResultsStream({ResourcesModel::global()->findResourceByPackageName(app)});
connect(stream, &StoredResultsStream::finishedResources, stream, [this, stream, app](const QVector<AbstractResource*> &resources) {
if (!resources.isEmpty()) {
if (resources.size() > 1)
qWarning() << "many resources found for" << app;
emit openApplicationInternal(resources.first());
} else {
rootObject()->setProperty("defaultStartup", true);
showPassiveNotification(i18n("Couldn't open %1", app.toDisplayString()));
}
});
}
, this);
if (ResourcesModel::global()->backends().isEmpty()) {
connect(ResourcesModel::global(), &ResourcesModel::backendsChanged, action, &OneTimeAction::trigger);
} else {
action->trigger();
}
Q_ASSERT(!url.isEmpty());
Q_EMIT openUrl(url);
}
QUrl DiscoverMainWindow::featuredSource() const
......
......@@ -30,6 +30,7 @@ class Category;
class QWindow;
class QQmlApplicationEngine;
class CachedNetworkAccessManagerFactory;
class ResourcesProxyModel;
class DiscoverMainWindow : public QObject
{
......@@ -81,6 +82,7 @@ class DiscoverMainWindow : public QObject
Q_SIGNALS:
void openApplicationInternal(AbstractResource* app);
void openUrl(const QUrl& url);
void listMimeInternal(const QString& mime);
void listCategoryInternal(Category* cat);
......
......@@ -37,6 +37,7 @@ DiscoverPage {
property alias stateFilter: appsModel.stateFilter
property alias extend: appsModel.extends
property alias search: appsModel.search
property alias resourcesUrl: appsModel.resourcesUrl
property alias count: apps.count
property alias listHeader: apps.header
property bool compact: page.width < 500 || Helpers.isCompact
......
......@@ -81,6 +81,10 @@ Kirigami.ApplicationWindow
Navigation.clearStack()
Navigation.openApplication(app)
}
onOpenUrl: {
currentTopLevel = topBrowsingComp;
Navigation.openUrlResources(url)
}
onListMimeInternal: {
currentTopLevel = topBrowsingComp;
Navigation.openApplicationMime(mime)
......
......@@ -27,9 +27,14 @@ function openApplicationListSource(origin) {
openApplicationList({ originFilter: origin, title: origin })
}
function openUrlResources(uri) {
clearStack()
openApplicationList({ resourcesUrl: uri, title: uri })
}
function openApplicationMime(mime) {
clearStack()
openApplicationList({ mimeTypeFilter: mime , title: i18n("Resources for '%1'", mime) })
openApplicationList({ mimeTypeFilter: mime, title: i18n("Resources for '%1'", mime) })
}
function openApplicationList(props) {
......
......@@ -909,14 +909,19 @@ int FlatpakBackend::updatesCount() const
ResultsStream * FlatpakBackend::search(const AbstractResourcesBackend::Filters &filter)
{
QVector<AbstractResource*> ret;
if (!filter.resourceUrl.isEmpty() && filter.resourceUrl.scheme() != QLatin1String("appstream"))
return new ResultsStream(QStringLiteral("FlatpakStream-void"), {});
QVector<AbstractResource*> ret;
foreach(AbstractResource* r, m_resources) {
if (qobject_cast<FlatpakResource*>(r)->type() == FlatpakResource::Runtime && filter.state != AbstractResource::Upgradeable) {
if (r->isTechnical() && filter.state != AbstractResource::Upgradeable) {
continue;
}
if (r->name().contains(filter.search, Qt::CaseInsensitive) || r->comment().contains(filter.search, Qt::CaseInsensitive)) {
if (!filter.resourceUrl.isEmpty() && r->appstreamId() != filter.resourceUrl.host())
continue;
if (filter.search.isEmpty() || (r->name().contains(filter.search, Qt::CaseInsensitive) || r->comment().contains(filter.search, Qt::CaseInsensitive))) {
ret += r;
}
}
......
......@@ -302,7 +302,12 @@ static ResultsStream* voidStream()
ResultsStream* KNSBackend::search(const AbstractResourcesBackend::Filters& filter)
{
if (filter.state >= AbstractResource::Installed) {
if ((!filter.resourceUrl.isEmpty() && filter.resourceUrl.scheme() != QLatin1String("kns")) || !filter.mimetype.isEmpty())
return voidStream();
if (filter.resourceUrl.scheme() == QLatin1String("kns")) {
return findResourceByPackageName(filter.resourceUrl);
} else if (filter.state >= AbstractResource::Installed) {
QVector<AbstractResource*> ret;
foreach(AbstractResource* r, m_resourcesByName) {
if(r->state()>=filter.state && (r->name().contains(filter.search, Qt::CaseInsensitive) || r->comment().contains(filter.search, Qt::CaseInsensitive)))
......@@ -353,7 +358,6 @@ ResultsStream * KNSBackend::findResourceByPackageName(const QUrl& search)
const auto entryid = pathParts.at(1);
auto stream = new ResultsStream(QStringLiteral("KNS-byname-")+entryid);
auto start = [this, entryid, stream, providerid]() {
m_responsePending = true;
m_engine->fetchEntryById(entryid);
......
......@@ -207,7 +207,7 @@ QStringList KNSResource::executables() const
return {};
}
QUrl KNSResource::knsUrl() const
QUrl KNSResource::url() const
{
return QUrl(QStringLiteral("kns://")+knsBackend()->name() + QLatin1Char('/') + QUrl(m_entry.providerId()).host() + QLatin1Char('/') + m_entry.uniqueId());
}
......@@ -63,7 +63,7 @@ public:
QStringList executables() const override;
QUrl knsUrl() const;
QUrl url() const override;
private:
const QStringList m_categories;
......
......@@ -135,6 +135,13 @@ void KNSBackendTest::reviewsArrived(AbstractResource* r, const QVector<ReviewPtr
void KNSBackendTest::testResourceByUrl()
{
const auto res = getResources(m_backend->findResourceByPackageName(QUrl(QStringLiteral("kns://") + m_backend->name() + QStringLiteral("/api.kde-look.org/1136471"))));
const QUrl url(QStringLiteral("kns://") + m_backend->name() + QStringLiteral("/api.kde-look.org/1136471"));
const auto res = getResources(m_backend->findResourceByPackageName(url));
QCOMPARE(res.count(), 1);
QCOMPARE(url, res[0]->url());
AbstractResourcesBackend::Filters f;
f.resourceUrl = url;
const auto res2 = getResources(m_backend->search(f));
QCOMPARE(res, res2);
}
......@@ -389,12 +389,14 @@ void PackageKitBackend::refreshDatabase()
ResultsStream* PackageKitBackend::search(const AbstractResourcesBackend::Filters& filter)
{
if (filter.search.isEmpty()) {
return new ResultsStream(QStringLiteral("PackageKitStream"), kFilter<QVector<AbstractResource*>>(m_packages.packages, [](AbstractResource* res) { return !res->isTechnical(); }));
if (!filter.resourceUrl.isEmpty()) {
return findResourceByPackageName(filter.resourceUrl);
} else if (filter.search.isEmpty()) {
return new ResultsStream(QStringLiteral("PackageKitStream-all"), kFilter<QVector<AbstractResource*>>(m_packages.packages, [](AbstractResource* res) { return !res->isTechnical(); }));
} else {
const QList<AppStream::Component> components = m_appdata.search(filter.search);
const QStringList ids = kTransform<QStringList>(components, [](const AppStream::Component& comp) { return comp.id(); });
auto stream = new ResultsStream(QStringLiteral("PackageKitStream"));
auto stream = new ResultsStream(QStringLiteral("PackageKitStream-search"));
if (!ids.isEmpty()) {
const auto resources = resourcesByPackageNames<QVector<AbstractResource*>>(ids);
QTimer::singleShot(0, this, [stream, resources, this] () {
......@@ -431,7 +433,7 @@ ResultsStream * PackageKitBackend::findResourceByPackageName(const QUrl& url)
else
pkg = m_packages.packages.value(url.host());
}
return new ResultsStream(QStringLiteral("PackageKitStream"), pkg ? QVector<AbstractResource*>{pkg} : QVector<AbstractResource*>{});
return new ResultsStream(QStringLiteral("PackageKitStream-url"), pkg ? QVector<AbstractResource*>{pkg} : QVector<AbstractResource*>{});
}
int PackageKitBackend::updatesCount() const
......
......@@ -243,3 +243,9 @@ QString AbstractResource::categoryDisplay() const
ret.sort();
return ret.join(QStringLiteral(", "));
}
QUrl AbstractResource::url() const
{
const QString asid = appstreamId();
return asid.isEmpty() ? QUrl() : QUrl(QStringLiteral("appstream://") + asid);
}
......@@ -73,6 +73,7 @@ class DISCOVERCOMMON_EXPORT AbstractResource : public QObject
Q_PROPERTY(Rating* rating READ rating NOTIFY ratingFetched)
Q_PROPERTY(QString appstreamId READ appstreamId CONSTANT)
Q_PROPERTY(QString categoryDisplay READ categoryDisplay CONSTANT)
Q_PROPERTY(QUrl url READ url CONSTANT)
public:
/**
* This describes the state of the resource
......@@ -188,6 +189,11 @@ class DISCOVERCOMMON_EXPORT AbstractResource : public QObject
QSet<Category*> categoryObjects() const;
/**
* @returns a url that uniquely identifies the application
*/
virtual QUrl url() const;
public Q_SLOTS:
virtual void fetchScreenshots();
virtual void fetchChangelog() = 0;
......
......@@ -103,6 +103,9 @@ bool AbstractResourcesBackend::Filters::shouldFilter(AbstractResource* res) cons
if(!extends.isEmpty() && !res->extends().contains(extends)) {
return false;
}
if(!resourceUrl.isEmpty() && res->url() != resourceUrl) {
return false;
}
for(QHash<QByteArray, QVariant>::const_iterator it=roles.constBegin(), itEnd=roles.constEnd(); it!=itEnd; ++it) {
Q_ASSERT(AbstractResource::staticMetaObject.indexOfProperty(it.key().constData())>=0);
......
......@@ -97,6 +97,7 @@ class DISCOVERCOMMON_EXPORT AbstractResourcesBackend : public QObject
QString mimetype;
QString search;
QString extends;
QUrl resourceUrl;
QHash<QByteArray, QVariant> roles;
bool shouldFilter(AbstractResource* res) const;
......
......@@ -286,9 +286,9 @@ AggregatedResultsStream::AggregatedResultsStream(const QSet<ResultsStream*>& str
void AggregatedResultsStream::addResults(const QVector<AbstractResource *>& res)
{
m_results += res;
m_results += res;
m_delayedEmission.start();
m_delayedEmission.start();
}
void AggregatedResultsStream::emitResults()
......@@ -324,7 +324,7 @@ AggregatedResultsStream* ResourcesModel::search(const AbstractResourcesBackend::
{
QSet<ResultsStream*> streams;
const bool allBackends = search.roles.contains("origin");
const bool allBackends = search.roles.contains("origin") || !search.resourceUrl.isEmpty();
foreach(auto backend, m_backends) {
if (!backend->hasApplications() || ResourcesModel::global()->currentApplicationBackend() == backend || allBackends)
streams << backend->search(search);
......
......@@ -302,6 +302,19 @@ void ResourcesProxyModel::setExtends(const QString& extends)
}
}
QUrl ResourcesProxyModel::resourcesUrl() const
{
return m_filters.resourceUrl;
}
void ResourcesProxyModel::setResourcesUrl(const QUrl& resourcesUrl)
{
if (m_filters.resourceUrl != resourcesUrl) {
m_filters.resourceUrl = resourcesUrl;
invalidateFilter();
}
}
QVariant ResourcesProxyModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
......
......@@ -47,6 +47,7 @@ class DISCOVERCOMMON_EXPORT ResourcesProxyModel : public QAbstractListModel, pub
Q_PROPERTY(AbstractResource::State stateFilter READ stateFilter WRITE setStateFilter NOTIFY stateFilterChanged)
Q_PROPERTY(QString mimeTypeFilter READ mimeTypeFilter WRITE setMimeTypeFilter)
Q_PROPERTY(QString search READ lastSearch WRITE setSearch NOTIFY searchChanged)
Q_PROPERTY(QUrl resourcesUrl READ resourcesUrl WRITE setResourcesUrl NOTIFY resourcesUrlChanged)
Q_PROPERTY(QString extends READ extends WRITE setExtends)
Q_PROPERTY(QVariantList subcategories READ subcategories NOTIFY subcategoriesChanged)
Q_PROPERTY(bool isBusy READ isBusy NOTIFY busyChanged)
......@@ -98,6 +99,9 @@ public:
QString extends() const;
void setExtends(const QString &extends);
QUrl resourcesUrl() const;
void setResourcesUrl(const QUrl& resourcesUrl);
QVariantList subcategories() const;
QVariant data(const QModelIndex & index, int role) const override;
......@@ -145,6 +149,7 @@ Q_SIGNALS:
void stateFilterChanged();
void searchChanged(const QString &search);
void subcategoriesChanged(const QVariantList &subcategories);
void resourcesUrlChanged(const QUrl &url);
};
#endif
Markdown is supported
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