diff --git a/src/ImagePackListModel.cpp b/src/ImagePackListModel.cpp index 368acd8c..4cf807a9 100644 --- a/src/ImagePackListModel.cpp +++ b/src/ImagePackListModel.cpp @@ -82,8 +82,10 @@ SingleImagePackModel * ImagePackListModel::newPack(bool inRoom) { ImagePackInfo info{}; - if (inRoom) + if (inRoom) { info.source_room = room_id; + info.state_key = SingleImagePackModel::unconflictingStatekey(room_id, ""); + } return new SingleImagePackModel(info); } diff --git a/src/SingleImagePackModel.cpp b/src/SingleImagePackModel.cpp index b26396ba..99338f2e 100644 --- a/src/SingleImagePackModel.cpp +++ b/src/SingleImagePackModel.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include "Cache_p.h" @@ -237,6 +239,12 @@ SingleImagePackModel::setStatekey(QString val) auto val_ = val.toStdString(); if (val_ != statekey_) { statekey_ = val_; + + // prevent deleting current pack + if (!roomid_.empty() && statekey_ != old_statekey_) { + statekey_ = unconflictingStatekey(roomid_, statekey_); + } + emit statekeyChanged(); } } @@ -290,6 +298,7 @@ SingleImagePackModel::save() tr("Failed to delete old image pack: %1") .arg(QString::fromStdString(e->matrix_error.error))); }); + old_statekey_ = statekey_; } http::client()->send_state_event( @@ -398,6 +407,7 @@ std::string SingleImagePackModel::unconflictingShortcode(const std::string &shortcode) { if (pack.images.count(shortcode)) { + // more images won't fit in an event anyway for (int i = 0; i < 64'000; i++) { auto tempCode = shortcode + std::to_string(i); if (!pack.images.count(tempCode)) { @@ -408,6 +418,38 @@ SingleImagePackModel::unconflictingShortcode(const std::string &shortcode) return shortcode; } +std::string +SingleImagePackModel::unconflictingStatekey(const std::string &roomid, const std::string &key) +{ + if (roomid.empty()) + return key; + + std::unordered_set statekeys; + auto currentPacks = + cache::client()->getStateEventsWithType(roomid); + for (const auto &pack : currentPacks) { + if (!pack.content.images.empty()) + statekeys.insert(pack.state_key); + } + auto defaultPack = cache::client()->getStateEvent(roomid); + if (defaultPack && defaultPack->content.images.size()) { + statekeys.insert(defaultPack->state_key); + } + + if (statekeys.count(key)) { + // arbitrary count. More than 64k image packs in a room are unlikely and if you have that, + // you probably know what you are doing :) + for (int i = 0; i < 64'000; i++) { + auto tempCode = key + std::to_string(i); + if (!statekeys.count(tempCode)) { + return tempCode; + } + } + } + + return key; +} + void SingleImagePackModel::addImageCb(std::string uri, std::string filename, mtx::common::ImageInfo info) { diff --git a/src/SingleImagePackModel.h b/src/SingleImagePackModel.h index 65a27bcf..595f5a78 100644 --- a/src/SingleImagePackModel.h +++ b/src/SingleImagePackModel.h @@ -71,6 +71,8 @@ public: Q_INVOKABLE void remove(int index); Q_INVOKABLE void setAvatar(QUrl file); + static std::string unconflictingStatekey(const std::string &roomid, const std::string &key); + signals: void globallyEnabledChanged(); void statekeyChanged();