Commit db370b87 authored by Volker Krause's avatar Volker Krause
Browse files

Add support for handling time-less pkpass files

That is, passes that the extractor fails to put into the timeline. Flat
rate tickets or membership cards for example.
parent d7d480f0
......@@ -10,6 +10,7 @@ target_sources(itinerary PRIVATE
documentmanager.cpp
favoritelocationmodel.cpp
filehelper.cpp
genericpkpass.cpp
gpxexport.cpp
healthcertificatemanager.cpp
importexport.cpp
......
......@@ -19,6 +19,10 @@ Kirigami.ScrollablePage {
id: programMembershipPage
App.ProgramMembershipPage {}
}
Component {
id: pkpassComponent
App.PkPassPage {}
}
Models.DelegateChooser {
id: chooser
......@@ -27,6 +31,7 @@ Kirigami.ScrollablePage {
roleValue: PassManager.ProgramMembership
Kirigami.BasicListItem {
highlighted: false
icon: "meeting-attending"
text: model.pass.programName
subtitle: {
if (!model.pass.member.name)
......@@ -38,6 +43,19 @@ Kirigami.ScrollablePage {
onClicked: applicationWindow().pageStack.push(programMembershipPage, { programMembership: model.pass, passId: model.passId })
}
}
Models.DelegateChoice {
roleValue: PassManager.PkPass
Kirigami.BasicListItem {
readonly property string pkPassId: PkPassManager.passId(model.pass)
readonly property var pkPass: PkPassManager.pass(pkPassId)
highlighted: false
text: pkPass.description
subtitle: pkPass.organizationName
icon: "image://org.kde.pkpass/" + pkPassId + "/icon"
reserveSpaceForIcon: true
onClicked: applicationWindow().pageStack.push(pkpassComponent, { passId: pkPassId, pass: pkPass });
}
}
}
ListView {
......
......@@ -8,6 +8,7 @@
#include "documentmanager.h"
#include "favoritelocationmodel.h"
#include "filehelper.h"
#include "genericpkpass.h"
#include "gpxexport.h"
#include "healthcertificatemanager.h"
#include "importexport.h"
......@@ -431,7 +432,7 @@ void ApplicationController::importData(const QByteArray &data, const QString &fi
}
// look for time-less passes/program memberships/etc
if (m_passMgr->import(extractorResult)) {
if (m_passMgr->import(extractorResult) || importGenericPkPass(engine.rootDocumentNode())) {
Q_EMIT infoMessage(i18n("Pass imported."));
return;
}
......@@ -462,6 +463,31 @@ void ApplicationController::importNode(const KItinerary::ExtractorDocumentNode &
}
}
bool ApplicationController::importGenericPkPass(const KItinerary::ExtractorDocumentNode &node)
{
#ifdef NEW_PKPASS_IMPORT
if (node.mimeType() == QLatin1String("application/vnd.apple.pkpass")) {
const auto pass = node.content<KPkPass::Pass*>();
GenericPkPass wrapper;
wrapper.setPkpassPassTypeIdentifier(pass->passTypeIdentifier());
wrapper.setPkpassSerialNumber(pass->serialNumber());
QScopedValueRollback importLocker(m_importLock, true);
m_pkPassMgr->importPassFromData(pass->rawData());
m_passMgr->import(wrapper);
return true;
}
#endif
bool res = false;
for (const auto &child : node.childNodes()) {
res |= importGenericPkPass(child);
}
return res;
}
void ApplicationController::checkCalendar()
{
#ifdef Q_OS_ANDROID
......
......@@ -98,6 +98,7 @@ private:
void importPass(const QString &passId);
void importMimeMessage(KMime::Message *msg);
void importNode(const KItinerary::ExtractorDocumentNode &node);
bool importGenericPkPass(const KItinerary::ExtractorDocumentNode &node);
static ApplicationController *s_instance;
......
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "genericpkpass.h"
class GenericPkPassPrivate : public QSharedData
{
public:
QString pkpassPassTypeIdentifier;
QString pkpassSerialNumber;
};
// TODO replace this by the use of the KITINERARY_XXX implementation macros,
// once those are installed
GenericPkPass::GenericPkPass() : d(new GenericPkPassPrivate) {}
GenericPkPass::GenericPkPass(const GenericPkPass&) = default;
GenericPkPass::~GenericPkPass() = default;
GenericPkPass& GenericPkPass::operator=(const GenericPkPass &other) = default;
QString GenericPkPass::className() const { return QStringLiteral("GenericPkPass"); }
GenericPkPass::operator QVariant() const { return QVariant::fromValue(*this); }
const char* GenericPkPass::typeName() { return "GenericPkPass"; }
QString GenericPkPass::pkpassPassTypeIdentifier() const
{
return d->pkpassPassTypeIdentifier;
}
void GenericPkPass::setPkpassPassTypeIdentifier(const QString &value)
{
d.detach();
d->pkpassPassTypeIdentifier = value;
}
QString GenericPkPass::pkpassSerialNumber() const
{
return d->pkpassSerialNumber;
}
void GenericPkPass::setPkpassSerialNumber(const QString &value)
{
d.detach();
d->pkpassSerialNumber = value;
}
bool GenericPkPass::operator==(const GenericPkPass &other) const
{
return d->pkpassPassTypeIdentifier == other.pkpassPassTypeIdentifier() && d->pkpassSerialNumber == other.pkpassSerialNumber();
}
#include "moc_genericpkpass.cpp"
/*
SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef GENERICPKPASS_H
#define GENERICPKPASS_H
#include <KItinerary/Datatypes>
class GenericPkPassPrivate;
/** Pseudo-schema.org wrapper for generic/uninterpreted pkpass files. */
class GenericPkPass
{
KITINERARY_GADGET(GenericPkPass)
KITINERARY_PROPERTY(QString, pkpassPassTypeIdentifier, setPkpassPassTypeIdentifier)
KITINERARY_PROPERTY(QString, pkpassSerialNumber, setPkpassSerialNumber)
private:
QExplicitlySharedDataPointer<GenericPkPassPrivate> d;
};
Q_DECLARE_METATYPE(GenericPkPass)
#endif // GENERICPKPASS_H
......@@ -14,6 +14,7 @@
#include "documentmanager.h"
#include "documentsmodel.h"
#include "favoritelocationmodel.h"
#include "genericpkpass.h"
#include "healthcertificatemanager.h"
#include "livedatamanager.h"
#include "localizer.h"
......@@ -44,7 +45,9 @@
#include <weatherforecastmanager.h>
#include <kitinerary_version.h>
#include <KItinerary/CountryDb>
#include <KItinerary/JsonLdDocument>
#include <KItinerary/Ticket>
#include <KPkPass/Field>
......@@ -112,6 +115,12 @@ void registerKItineraryTypes()
qRegisterMetaType<KItinerary::KnowledgeDb::DrivingSide>();
qmlRegisterUncreatableType<KItinerary::Ticket>("org.kde.kitinerary", 1, 0, "Ticket", {});
qmlRegisterUncreatableMetaObject(KItinerary::KnowledgeDb::staticMetaObject, "org.kde.kitinerary", 1, 0, "KnowledgeDb", {});
#if KITINERARY_VERSION < QT_VERSION_CHECK(5, 20, 41)
KItinerary::JsonLdDocument().registerType<GenericPkPass>();
#else
KItinerary::JsonLdDocument::registerType<GenericPkPass>();
#endif
}
void registerApplicationTypes()
......
......@@ -4,6 +4,7 @@
*/
#include "passmanager.h"
#include "genericpkpass.h"
#include "logging.h"
#include <KItinerary/ExtractorPostprocessor>
......@@ -42,7 +43,7 @@ int PassManager::rowCount(const QModelIndex &parent) const
bool PassManager::import(const QVariant &pass, const QString &id)
{
if (JsonLd::isA<KItinerary::ProgramMembership>(pass)) {
if (JsonLd::isA<KItinerary::ProgramMembership>(pass) || JsonLd::isA<GenericPkPass>(pass)) {
Entry entry;
entry.id = id.isEmpty() ? QUuid::createUuid().toString() : id;
entry.data = pass;
......@@ -107,6 +108,9 @@ QVariant PassManager::data(const QModelIndex &index, int role) const
if (JsonLd::isA<KItinerary::ProgramMembership>(entry.data)) {
return ProgramMembership;
}
if (JsonLd::isA<GenericPkPass>(entry.data)) {
return PkPass;
}
return {};
case PassDataRole:
return rawData(entry);
......
......@@ -5,6 +5,7 @@
*/
#include "pkpassmanager.h"
#include "genericpkpass.h"
#include "logging.h"
#include <KItinerary/Reservation>
......@@ -78,12 +79,18 @@ KPkPass::Pass* PkPassManager::pass(const QString& passId)
QString PkPassManager::passId(const QVariant &reservation) const
{
if (!JsonLd::canConvert<Reservation>(reservation)) {
return {};
QString passTypeId, serialNum;
if (JsonLd::canConvert<Reservation>(reservation)) {
const auto res = JsonLd::convert<Reservation>(reservation);
passTypeId = res.pkpassPassTypeIdentifier();
serialNum = res.pkpassSerialNumber();
} else if (JsonLd::isA<GenericPkPass>(reservation)) {
const auto p = JsonLd::convert<GenericPkPass>(reservation);
passTypeId = p.pkpassPassTypeIdentifier();
serialNum = p.pkpassSerialNumber();
}
const auto res = JsonLd::convert<Reservation>(reservation);
const auto passTypeId = res.pkpassPassTypeIdentifier();
const auto serialNum = res.pkpassSerialNumber();
if (passTypeId.isEmpty() || serialNum.isEmpty()) {
return {};
}
......
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