File indexing completed on 2024-05-12 05:21:34

0001 /*
0002    SPDX-FileCopyrightText: 2017-2021 Volker Krause <vkrause@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "field.h"
0008 #include "pass.h"
0009 #include "pass_p.h"
0010 
0011 #include <QGuiApplication>
0012 #include <QJsonObject>
0013 
0014 using namespace KPkPass;
0015 
0016 namespace KPkPass
0017 {
0018 class FieldPrivate
0019 {
0020 public:
0021     const Pass *pass = nullptr;
0022     QJsonObject obj;
0023 };
0024 }
0025 
0026 Field::Field()
0027     : d(new FieldPrivate)
0028 {
0029 }
0030 
0031 Field::Field(const Field &) = default;
0032 Field::Field(Field &&) = default;
0033 Field::~Field() = default;
0034 Field &Field::operator=(const Field &) = default;
0035 
0036 Field::Field(const QJsonObject &obj, const Pass *pass)
0037     : d(new FieldPrivate)
0038 {
0039     d->pass = pass;
0040     d->obj = obj;
0041 }
0042 
0043 QString Field::key() const
0044 {
0045     return d->obj.value(QLatin1StringView("key")).toString();
0046 }
0047 
0048 QString Field::label() const
0049 {
0050     if (d->pass) {
0051         return d->pass->d->message(d->obj.value(QLatin1StringView("label")).toString());
0052     }
0053     return {};
0054 }
0055 
0056 QVariant Field::value() const
0057 {
0058     if (!d->pass) {
0059         return {};
0060     }
0061     auto v = d->pass->d->message(d->obj.value(QLatin1StringView("attributedValue")).toString());
0062     if (v.isEmpty()) {
0063         v = d->pass->d->message(d->obj.value(QLatin1StringView("value")).toString());
0064     }
0065 
0066     const auto dt = QDateTime::fromString(v, Qt::ISODate);
0067     if (dt.isValid()) {
0068         return dt;
0069     }
0070 
0071     // TODO number detection
0072     return v;
0073 }
0074 
0075 QString Field::valueDisplayString() const
0076 {
0077     const auto v = value();
0078     // see
0079     // https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/FieldDictionary.html#//apple_ref/doc/uid/TP40012026-CH4-SW6
0080     // however, real-world data doesn't strictly follow that, so we have to guess a bit here...
0081     if (v.userType() == QMetaType::QDateTime) {
0082         const auto dt = v.toDateTime();
0083         auto fmt = QLocale::ShortFormat;
0084         const auto dtStyle = d->obj.value(QLatin1StringView("dateStyle")).toString();
0085         if (dtStyle == QLatin1StringView("PKDateStyleLong") || dtStyle == QLatin1StringView("PKDateStyleFull")) {
0086             fmt = QLocale::LongFormat;
0087         }
0088         const auto timeStyle = d->obj.value(QLatin1StringView("timeStyle")).toString();
0089         if (timeStyle == QLatin1StringView("PKDateStyleNone") || (timeStyle.isEmpty() && !dtStyle.isEmpty() && dt.time() == QTime(0, 0))) {
0090             return QLocale().toString(dt.date(), fmt);
0091         }
0092 
0093         return QLocale().toString(dt, fmt);
0094     }
0095 
0096     // TODO respect number formatting options
0097     return value().toString().trimmed();
0098 }
0099 
0100 QString Field::changeMessage() const
0101 {
0102     if (!d->pass) {
0103         return {};
0104     }
0105     auto msg = d->pass->d->message(d->obj.value(QLatin1StringView("changeMessage")).toString());
0106     msg.replace(QLatin1StringView("%@"), valueDisplayString());
0107     return msg;
0108 }
0109 
0110 Qt::Alignment Field::textAlignment() const
0111 {
0112     const auto alignStr = d->obj.value(QLatin1StringView("textAlignment")).toString();
0113     if (alignStr == QLatin1StringView("PKTextAlignmentLeft")) {
0114         return Qt::AlignLeft;
0115     } else if (alignStr == QLatin1StringView("PKTextAlignmentCenter")) {
0116         return Qt::AlignHCenter;
0117     } else if (alignStr == QLatin1StringView("PKTextAlignmentRight")) {
0118         return Qt::AlignRight;
0119     }
0120     return QGuiApplication::layoutDirection() == Qt::LeftToRight ? Qt::AlignLeft : Qt::AlignRight;
0121 }
0122 
0123 #include "moc_field.cpp"