#pragma once #include "Cache.h" #include "RoomInfoListItem.h" #include "timeline/widgets/AudioItem.h" #include "timeline/widgets/FileItem.h" #include "timeline/widgets/ImageItem.h" #include "timeline/widgets/VideoItem.h" #include #include namespace utils { using TimelineEvent = mtx::events::collections::TimelineEvents; //! Human friendly timestamp representation. QString descriptiveTime(const QDateTime &then); //! Generate a message description from the event to be displayed //! in the RoomList. DescInfo getMessageDescription(const TimelineEvent &event, const QString &localUser, const QString &room_id); //! Get the first character of a string, taking into account that //! surrogate pairs might be in use. QString firstChar(const QString &input); //! Get a human readable file size with the appropriate units attached. QString humanReadableFileSize(uint64_t bytes); QString event_body(const mtx::events::collections::TimelineEvents &event); //! Match widgets/events with a description message. template QString messageDescription(const QString &username = "", const QString &body = "") { using Audio = mtx::events::RoomEvent; using Emote = mtx::events::RoomEvent; using File = mtx::events::RoomEvent; using Image = mtx::events::RoomEvent; using Notice = mtx::events::RoomEvent; using Sticker = mtx::events::Sticker; using Text = mtx::events::RoomEvent; using Video = mtx::events::RoomEvent; if (std::is_same::value || std::is_same::value) return QString("sent an audio clip"); else if (std::is_same::value || std::is_same::value) return QString("sent an image"); else if (std::is_same::value || std::is_same::value) return QString("sent a file"); else if (std::is_same::value || std::is_same::value) return QString("sent a video clip"); else if (std::is_same::value || std::is_same::value) return QString("sent a sticker"); else if (std::is_same::value) return QString("sent a notification"); else if (std::is_same::value) return QString(": %1").arg(body); else if (std::is_same::value) return QString("* %1 %2").arg(username).arg(body); } template DescInfo createDescriptionInfo(const Event &event, const QString &localUser, const QString &room_id) { using Text = mtx::events::RoomEvent; using Emote = mtx::events::RoomEvent; const auto msg = mpark::get(event); const auto sender = QString::fromStdString(msg.sender); const auto username = Cache::displayName(room_id, sender); const auto ts = QDateTime::fromMSecsSinceEpoch(msg.origin_server_ts); bool isText = std::is_same::value; bool isEmote = std::is_same::value; return DescInfo{ isEmote ? "" : (sender == localUser ? "You" : username), sender, (isText || isEmote) ? messageDescription(username, QString::fromStdString(msg.content.body).trimmed()) : QString(" %1").arg(messageDescription()), utils::descriptiveTime(ts), ts}; } //! Scale down an image to fit to the given width & height limitations. template ImageType scaleDown(uint64_t max_width, uint64_t max_height, const ImageType &source) { if (source.isNull()) return QPixmap(); auto width_ratio = (double)max_width / (double)source.width(); auto height_ratio = (double)max_height / (double)source.height(); auto min_aspect_ratio = std::min(width_ratio, height_ratio); int final_width = 0; int final_height = 0; if (min_aspect_ratio > 1) { final_width = source.width(); final_height = source.height(); } else { final_width = source.width() * min_aspect_ratio; final_height = source.height() * min_aspect_ratio; } return source.scaled( final_width, final_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } //! Delete items in a container based on a predicate. template void erase_if(ContainerT &items, const PredicateT &predicate) { for (auto it = items.begin(); it != items.end();) { if (predicate(*it)) it = items.erase(it); else ++it; } } inline mtx::events::EventType event_type(const mtx::events::collections::TimelineEvents &event) { return mpark::visit([](auto msg) { return msg.type; }, event); } inline std::string event_id(const mtx::events::collections::TimelineEvents &event) { return mpark::visit([](auto msg) { return msg.event_id; }, event); } inline QString eventId(const mtx::events::collections::TimelineEvents &event) { return QString::fromStdString(event_id(event)); } inline QString event_sender(const mtx::events::collections::TimelineEvents &event) { return mpark::visit([](auto msg) { return QString::fromStdString(msg.sender); }, event); } template QString message_body(const mtx::events::collections::TimelineEvents &event) { return QString::fromStdString(mpark::get(event).content.body); } //! Calculate the Levenshtein distance between two strings with character skipping. int levenshtein_distance(const std::string &s1, const std::string &s2); }