diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-24 16:01:07 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-24 16:01:07 +0200 |
| commit | e10498e1e721ce67475e3d239412b0396ea2acde (patch) | |
| tree | 380b03ce4947c5cb3532b31232ada7ae46924b0d /src/calendarstore.cpp | |
| parent | 0a26a0b3968486b3769ab42b2966fff6d2db1fb0 (diff) | |
| download | qtmaildir-e10498e1e721ce67475e3d239412b0396ea2acde.tar.gz qtmaildir-e10498e1e721ce67475e3d239412b0396ea2acde.zip | |
feat: read every time form and load a calendar vdir
Diffstat (limited to 'src/calendarstore.cpp')
| -rw-r--r-- | src/calendarstore.cpp | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/src/calendarstore.cpp b/src/calendarstore.cpp index 6cc2bcd..fac5bc2 100644 --- a/src/calendarstore.cpp +++ b/src/calendarstore.cpp @@ -19,8 +19,14 @@ #include "calendarstore.h" #include "icalraii.h" +#include <QCryptographicHash> +#include <QDir> +#include <QFile> +#include <QFileInfo> #include <QTimeZone> +#include <algorithm> + namespace { QString str(const char *s) { return s ? QString::fromUtf8(s) : QString(); } @@ -118,6 +124,28 @@ QDateTime endOf(icalcomponent *c, const QDateTime &start, bool allDay, bool *unk } // namespace +namespace { + +QString readTrimmed(const QString &path) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return {}; + return QString::fromUtf8(file.readAll()).trimmed(); +} + +/// A colour for a collection with no `color` file, derived from its directory +/// name so it is the same on every load and on every machine. +QColor hashedColour(const QString &dir) +{ + const QByteArray hash = QCryptographicHash::hash(dir.toUtf8(), QCryptographicHash::Md5); + const int hue = (static_cast<unsigned char>(hash[0]) * 256 + + static_cast<unsigned char>(hash[1])) % 360; + return QColor::fromHsl(hue, 150, 140); +} + +} // namespace + namespace CalendarStore { CalEvent parseEvent(const QByteArray &text, const QString &filePath, @@ -160,7 +188,50 @@ CalEvent parseEvent(const QByteArray &text, const QString &filePath, return event; } -LoadResult load(const QString &) { return {}; } +LoadResult load(const QString &dir) +{ + LoadResult result; + const QFileInfoList subdirs = + QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for (const QFileInfo &sub : subdirs) { + CalCollection collection; + collection.dir = sub.fileName(); + collection.path = sub.absoluteFilePath(); + collection.displayName = readTrimmed(collection.path + QStringLiteral("/displayname")); + if (collection.displayName.isEmpty()) + collection.displayName = collection.dir; + collection.color = QColor(readTrimmed(collection.path + QStringLiteral("/color"))); + if (!collection.color.isValid()) + collection.color = hashedColour(collection.dir); + collection.readOnly = !sub.isWritable(); + result.collections.append(collection); + + const QFileInfoList files = + QDir(collection.path).entryInfoList({ QStringLiteral("*.ics") }, QDir::Files, QDir::Name); + for (const QFileInfo &file : files) { + QFile f(file.absoluteFilePath()); + if (!f.open(QIODevice::ReadOnly)) { + ++result.unparsable; + continue; + } + bool unknown = false; + CalEvent event = parseEvent(f.readAll(), file.absoluteFilePath(), + collection.dir, &unknown); + if (event.uid.isEmpty() || !event.start.isValid()) { + ++result.unparsable; + continue; + } + if (unknown) + ++result.unknownZones; + result.events.append(event); + } + } + std::sort(result.collections.begin(), result.collections.end(), + [](const CalCollection &a, const CalCollection &b) { + return a.displayName.localeAwareCompare(b.displayName) < 0; + }); + return result; +} QList<Occurrence> occurrences(const QList<CalEvent> &, const QDateTime &, const QDateTime &) { return {}; } bool isEditable(const CalEvent &, const CalCollection &, const QStringList &) { return false; } QByteArray applyEdit(const QByteArray &, const EventEdit &, Scope, const QDateTime &) { return {}; } |
