diff --git a/chatterino.pro b/chatterino.pro index 8d477fc61..61f797d0b 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -9,6 +9,7 @@ message(----) QT += widgets core gui network multimedia svg CONFIG += communi COMMUNI += core model util +CONFIG += c++14 INCLUDEPATH += src/ TARGET = chatterino TEMPLATE = app @@ -16,12 +17,6 @@ DEFINES += QT_DEPRECATED_WARNINGS PRECOMPILED_HEADER = src/PrecompiledHeader.hpp CONFIG += precompile_header -win32-msvc* { - QMAKE_CXXFLAGS = /std=c++17 -} else { - QMAKE_CXXFLAGS = -std=c++17 -} - debug { DEFINES += QT_DEBUG } diff --git a/src/common/Common.hpp b/src/common/Common.hpp index 18548cb3b..c4abe043f 100644 --- a/src/common/Common.hpp +++ b/src/common/Common.hpp @@ -37,12 +37,4 @@ std::weak_ptr weakOf(T *element) return element->shared_from_this(); } -template -struct overloaded : Ts... { - using Ts::operator()...; -}; - -template -overloaded(Ts...)->overloaded; - } // namespace chatterino diff --git a/src/common/NullablePtr.hpp b/src/common/NullablePtr.hpp index ba08bb7f9..fb60af0d8 100644 --- a/src/common/NullablePtr.hpp +++ b/src/common/NullablePtr.hpp @@ -25,7 +25,7 @@ public: return element_; } - typename std::add_lvalue_reference::type &operator*() const + typename std::add_lvalue_reference::type operator*() const { assert(this->hasElement()); diff --git a/src/common/UniqueAccess.hpp b/src/common/UniqueAccess.hpp index ef7f0165f..529ac0623 100644 --- a/src/common/UniqueAccess.hpp +++ b/src/common/UniqueAccess.hpp @@ -1,47 +1,61 @@ #pragma once -#include #include #include namespace chatterino { template -class AccessGuard : boost::noncopyable +class AccessGuard { public: AccessGuard(T &element, std::mutex &mutex) - : element_(element) - , mutex_(mutex) + : element_(&element) + , mutex_(&mutex) { - this->mutex_.lock(); + this->mutex_->lock(); + } + + AccessGuard(AccessGuard &&other) + : element_(other.element_) + , mutex_(other.mutex_) + { + other.isValid_ = false; + } + + AccessGuard &operator=(AccessGuard &&other) + { + other.isValid_ = false; + this->element_ = other.element_; + this->mutex_ = other.element_; } ~AccessGuard() { - this->mutex_.unlock(); + if (this->isValid_) this->mutex_->unlock(); } T *operator->() const { - return &this->element_; + return this->element_; } T &operator*() const { - return this->element_; + return *this->element_; } private: - T &element_; - std::mutex &mutex_; + T *element_; + std::mutex *mutex_; + bool isValid_ = true; }; template class UniqueAccess { public: -// template + // template UniqueAccess() : element_(T()) { diff --git a/src/messages/Image.cpp b/src/messages/Image.cpp index b1fcf8787..309d2f0a0 100644 --- a/src/messages/Image.cpp +++ b/src/messages/Image.cpp @@ -19,13 +19,130 @@ #include namespace chatterino { +namespace { +// Frame +Frame::Frame(const QPixmap *nonOwning, int duration) + : nonOwning_(nonOwning) + , duration_(duration) +{ +} + +Frame::Frame(std::unique_ptr owning, int duration) + : owning_(std::move(owning)) + , duration_(duration) +{ +} + +int Frame::duration() const +{ + return this->duration_; +} + +const QPixmap *Frame::pixmap() const +{ + if (this->nonOwning_) return this->nonOwning_; + return this->owning_.get(); +} + +// Frames +Frames::Frames() +{ + DebugCount::increase("images"); +} + +Frames::Frames(std::vector &&frames) + : items_(std::move(frames)) +{ + DebugCount::increase("images"); + if (this->animated()) DebugCount::increase("animated images"); +} + +Frames::~Frames() +{ + DebugCount::decrease("images"); + if (this->animated()) DebugCount::decrease("animated images"); +} + +void Frames::advance() +{ + this->timeOffset_ += GIF_FRAME_LENGTH; + + while (true) { + this->index_ %= this->items_.size(); + if (this->timeOffset_ > this->items_[this->index_].duration()) { + this->timeOffset_ -= this->items_[this->index_].duration(); + this->index_ = (this->index_ + 1) % this->items_.size(); + } else { + break; + } + } +} + +bool Frames::animated() const +{ + return this->items_.size() > 1; +} + +const QPixmap *Frames::current() const +{ + if (this->items_.size() == 0) return nullptr; + return this->items_[this->index_].pixmap(); +} + +const QPixmap *Frames::first() const +{ + if (this->items_.size() == 0) return nullptr; + return this->items_.front().pixmap(); +} + +// functions +std::vector readFrames(QImageReader &reader, const Url &url) +{ + std::vector frames; + + if (reader.imageCount() <= 0) { + Log("Error while reading image {}: '{}'", url.string, reader.errorString()); + return frames; + } + + QImage image; + for (int index = 0; index < reader.imageCount(); ++index) { + if (reader.read(&image)) { + auto pixmap = std::make_unique(QPixmap::fromImage(image)); + + int duration = std::max(20, reader.nextImageDelay()); + frames.push_back(Frame(std::move(pixmap), duration)); + } + } + + if (frames.size() != 0) { + Log("Error while reading image {}: '{}'", url.string, reader.errorString()); + } + + return frames; +} + +void queueLoadedEvent() +{ + static auto eventQueued = false; + + if (!eventQueued) { + eventQueued = true; + + QTimer::singleShot(250, [] { + getApp()->windows->incGeneration(); + getApp()->windows->layoutChannelViews(); + eventQueued = false; + }); + } +} +} // namespace // IMAGE2 std::atomic Image::loadedEventQueued{false}; ImagePtr Image::fromUrl(const Url &url, qreal scale) { - // herb sutter cache static std::unordered_map> cache; static std::mutex mutex; @@ -59,237 +176,123 @@ ImagePtr Image::getEmpty() } Image::Image() + : empty_(true) { - this->isLoaded_ = true; - this->isNull_ = true; } Image::Image(const Url &url, qreal scale) + : url_(url) + , scale_(scale) + , shouldLoad_(true) { - this->url_ = url; - this->scale_ = scale; - - if (url.string.isEmpty()) { - this->isLoaded_ = true; - this->isNull_ = true; - } } Image::Image(std::unique_ptr owning, qreal scale) + : scale_(scale) { - this->frames_.push_back(Frame(std::move(owning))); - this->scale_ = scale; - this->isLoaded_ = true; - this->currentFramePixmap_ = this->frames_.front().getPixmap(); + std::vector vec; + vec.push_back(Frame(std::move(owning))); + this->frames_ = std::move(vec); } Image::Image(QPixmap *nonOwning, qreal scale) + : scale_(scale) { - this->frames_.push_back(Frame(nonOwning)); - this->scale_ = scale; - this->isLoaded_ = true; - this->currentFramePixmap_ = this->frames_.front().getPixmap(); + std::vector vec; + vec.push_back(Frame(nonOwning)); + this->frames_ = std::move(vec); } -const Url &Image::getUrl() const +const Url &Image::url() const { return this->url_; } -NullablePtr Image::getPixmap() const +const QPixmap *Image::pixmap() const { assertInGuiThread(); - if (!this->isLoaded_) { + if (this->shouldLoad_) { + const_cast(this)->shouldLoad_ = false; const_cast(this)->load(); } - return this->currentFramePixmap_; + return this->frames_.current(); } -qreal Image::getScale() const +qreal Image::scale() const { return this->scale_; } -bool Image::isAnimated() const +bool Image::empty() const { - return this->isAnimated_; + return this->empty_; } -int Image::getWidth() const +bool Image::animated() const { - if (!this->isLoaded_) return 16; + assertInGuiThread(); - return this->frames_.front().getPixmap()->width() * this->scale_; + return this->frames_.animated(); } -int Image::getHeight() const +int Image::width() const { - if (!this->isLoaded_) return 16; + assertInGuiThread(); - return this->frames_.front().getPixmap()->height() * this->scale_; + if (auto pixmap = this->frames_.first()) + return pixmap->width() * this->scale_; + else + return 16; } -bool Image::isLoaded() const +int Image::height() const { - return this->isLoaded_; -} + assertInGuiThread(); -bool Image::isValid() const -{ - return !this->isNull_; -} - -bool Image::isNull() const -{ - return this->isNull_; + if (auto pixmap = this->frames_.first()) + return pixmap->height() * this->scale_; + else + return 16; } void Image::load() { - // decrease debug count - if (this->isAnimated_) { - DebugCount::decrease("animated images"); - } - if (this->isLoaded_) { - DebugCount::decrease("loaded images"); - } - - this->isLoaded_ = false; - this->isLoading_ = true; - this->frames_.clear(); - - NetworkRequest req(this->getUrl().string); + NetworkRequest req(this->url().string); req.setCaller(&this->object_); req.setUseQuickLoadCache(true); req.onSuccess([this, weak = weakOf(this)](auto result) -> Outcome { + assertInGuiThread(); + auto shared = weak.lock(); if (!shared) return Failure; - auto &bytes = result.getData(); - QByteArray copy = QByteArray::fromRawData(bytes.constData(), bytes.length()); + // const cast since we are only reading from it + QBuffer buffer(const_cast(&result.getData())); + buffer.open(QIODevice::ReadOnly); + QImageReader reader(&buffer); - return this->parse(result.getData()); + this->frames_ = readFrames(reader, this->url()); + return Success; + }); + req.onError([this, weak = weakOf(this)](int) { + auto shared = weak.lock(); + if (!shared) return false; + + this->frames_ = std::vector(); + + return false; }); req.execute(); } -Outcome Image::parse(const QByteArray &data) -{ - // const cast since we are only reading from it - QBuffer buffer(const_cast(&data)); - buffer.open(QIODevice::ReadOnly); - QImageReader reader(&buffer); - - return this->setFrames(this->readFrames(reader)); -} - -std::vector Image::readFrames(QImageReader &reader) -{ - std::vector frames; - - if (reader.imageCount() <= 0) { - Log("Error while reading image {}: '{}'", this->url_.string, reader.errorString()); - return frames; - } - - QImage image; - for (int index = 0; index < reader.imageCount(); ++index) { - if (reader.read(&image)) { - auto pixmap = new QPixmap(QPixmap::fromImage(image)); - - int duration = std::max(20, reader.nextImageDelay()); - frames.push_back(Image::Frame(pixmap, duration)); - } - } - - if (frames.size() != 0) { - Log("Error while reading image {}: '{}'", this->url_.string, reader.errorString()); - } - - return frames; -} - -Outcome Image::setFrames(std::vector frames) -{ - std::lock_guard lock(this->framesMutex_); - - if (frames.size() > 0) { - this->currentFramePixmap_ = frames.front().getPixmap(); - - if (frames.size() > 1) { - if (!this->isAnimated_) { - getApp()->emotes->gifTimer.signal.connect([=]() { this->updateAnimation(); }); - } - - this->isAnimated_ = true; - DebugCount::increase("animated images"); - } - - this->isLoaded_ = true; - DebugCount::increase("loaded images"); - - return Success; - } - - this->frames_ = std::move(frames); - this->queueLoadedEvent(); - - return Failure; -} - -void Image::queueLoadedEvent() -{ - if (!loadedEventQueued) { - loadedEventQueued = true; - - QTimer::singleShot(250, [] { - getApp()->windows->incGeneration(); - getApp()->windows->layoutChannelViews(); - loadedEventQueued = false; - }); - } -} - -void Image::updateAnimation() -{ - if (this->isAnimated_) { - std::lock_guard lock(this->framesMutex_); - - this->currentFrameOffset_ += GIF_FRAME_LENGTH; - - while (true) { - this->currentFrameIndex_ %= this->frames_.size(); - if (this->currentFrameOffset_ > this->frames_[this->currentFrameIndex_].getDuration()) { - this->currentFrameOffset_ -= this->frames_[this->currentFrameIndex_].getDuration(); - this->currentFrameIndex_ = (this->currentFrameIndex_ + 1) % this->frames_.size(); - } else { - break; - } - } - - this->currentFramePixmap_ = this->frames_[this->currentFrameIndex_].getPixmap(); - } -} - bool Image::operator==(const Image &other) const { - if (this->isNull() && other.isNull()) { - return true; - } - - if (!this->url_.string.isEmpty() && this->url_ == other.url_) { - return true; - } - - assert(this->frames_.size() == 1); - assert(other.frames_.size() == 1); - - if (this->currentFramePixmap_ == other.currentFramePixmap_) { - return true; - } + if (this->empty() && other.empty()) return true; + if (!this->url_.string.isEmpty() && this->url_ == other.url_) return true; + if (this->frames_.first() == other.frames_.first()) return true; return false; } @@ -299,29 +302,4 @@ bool Image::operator!=(const Image &other) const return !this->operator==(other); } -// FRAME -Image::Frame::Frame(QPixmap *nonOwning, int duration) - : nonOwning_(nonOwning) - , duration_(duration) -{ -} - -Image::Frame::Frame(std::unique_ptr nonOwning, int duration) - : owning_(std::move(nonOwning)) - , duration_(duration) -{ -} - -int Image::Frame::getDuration() const -{ - return this->duration_; -} - -QPixmap *Image::Frame::getPixmap() const -{ - if (this->nonOwning_) return this->nonOwning_; - - return this->owning_.get(); -} - } // namespace chatterino diff --git a/src/messages/Image.hpp b/src/messages/Image.hpp index eec7ea9a9..7db43580c 100644 --- a/src/messages/Image.hpp +++ b/src/messages/Image.hpp @@ -12,6 +12,41 @@ #include "common/NullablePtr.hpp" namespace chatterino { +namespace { +class Frame +{ +public: + explicit Frame(const QPixmap *nonOwning, int duration = 1); + explicit Frame(std::unique_ptr owning, int duration = 1); + + const QPixmap *pixmap() const; + int duration() const; + +private: + const QPixmap *nonOwning_{nullptr}; + std::unique_ptr owning_{}; + int duration_{}; +}; +class Frames +{ +public: + Frames(); + Frames(std::vector &&frames); + ~Frames(); + Frames(Frames &&other) = default; + Frames &operator=(Frames &&other) = default; + + bool animated() const; + void advance(); + const QPixmap *current() const; + const QPixmap *first() const; + +private: + std::vector items_; + int index_{0}; + int timeOffset_{0}; +}; +} // namespace class Image; using ImagePtr = std::shared_ptr; @@ -24,62 +59,31 @@ public: static ImagePtr fromNonOwningPixmap(QPixmap *pixmap, qreal scale = 1); static ImagePtr getEmpty(); - const Url &getUrl() const; - NullablePtr getPixmap() const; - qreal getScale() const; - bool isAnimated() const; - int getWidth() const; - int getHeight() const; - bool isLoaded() const; - bool isError() const; - bool isValid() const; - bool isNull() const; + const Url &url() const; + const QPixmap *pixmap() const; + qreal scale() const; + bool empty() const; + int width() const; + int height() const; + bool animated() const; bool operator==(const Image &image) const; bool operator!=(const Image &image) const; private: - class Frame - { - public: - QPixmap *getPixmap() const; - int getDuration() const; - - Frame(QPixmap *nonOwning, int duration = 1); - Frame(std::unique_ptr nonOwning, int duration = 1); - - private: - QPixmap *nonOwning_; - std::unique_ptr owning_; - int duration_; - }; - Image(); Image(const Url &url, qreal scale); Image(std::unique_ptr owning, qreal scale); Image(QPixmap *nonOwning, qreal scale); void load(); - Outcome parse(const QByteArray &data); - std::vector readFrames(QImageReader &reader); - Outcome setFrames(std::vector frames); - void updateAnimation(); - void queueLoadedEvent(); - Url url_; - bool isLoaded_{false}; - bool isLoading_{false}; - bool isAnimated_{false}; - bool isError_{false}; - bool isNull_ = false; - qreal scale_ = 1; - QObject object_; - - std::vector frames_; - std::mutex framesMutex_; - NullablePtr currentFramePixmap_; - int currentFrameIndex_ = 0; - int currentFrameOffset_ = 0; + Url url_{}; + qreal scale_{1}; + bool empty_{false}; + bool shouldLoad_{false}; + Frames frames_{}; + QObject object_{}; static std::atomic loadedEventQueued; }; diff --git a/src/messages/ImageSet.cpp b/src/messages/ImageSet.cpp index 0a3e60802..ebb9b77c7 100644 --- a/src/messages/ImageSet.cpp +++ b/src/messages/ImageSet.cpp @@ -70,11 +70,11 @@ const ImagePtr &ImageSet::getImage(float scale) const scale = 1; } - if (this->imageX3_->isValid() && quality == 3) { + if (!this->imageX3_->empty() && quality == 3) { return this->imageX3_; } - if (this->imageX2_->isValid() && quality == 2) { + if (!this->imageX2_->empty() && quality == 2) { return this->imageX3_; } diff --git a/src/messages/Link.hpp b/src/messages/Link.hpp index a07d21cf3..a6c503540 100644 --- a/src/messages/Link.hpp +++ b/src/messages/Link.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace chatterino { diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index ed29957b9..ff62aca4e 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -70,8 +70,8 @@ ImageElement::ImageElement(ImagePtr image, MessageElement::Flags flags) void ImageElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags) { if (flags & this->getFlags()) { - auto size = QSize(this->image_->getWidth() * container.getScale(), - this->image_->getHeight() * container.getScale()); + auto size = QSize(this->image_->width() * container.getScale(), + this->image_->height() * container.getScale()); container.addElement( (new ImageLayoutElement(*this, this->image_, size))->setLink(this->getLink())); @@ -83,10 +83,7 @@ EmoteElement::EmoteElement(const EmotePtr &emote, MessageElement::Flags flags) : MessageElement(flags) , emote_(emote) { - auto image = emote->images.getImage1(); - if (image->isValid()) { - this->textElement_.reset(new TextElement(emote->getCopyString(), MessageElement::Misc)); - } + this->textElement_.reset(new TextElement(emote->getCopyString(), MessageElement::Misc)); this->setTooltip(emote->tooltip.string); } @@ -101,10 +98,10 @@ void EmoteElement::addToContainer(MessageLayoutContainer &container, MessageElem if (flags & this->getFlags()) { if (flags & MessageElement::EmoteImages) { auto image = this->emote_->images.getImage(container.getScale()); - if (!image->isValid()) return; + if (image->empty()) return; - QSize size(int(container.getScale() * image->getWidth()), - int(container.getScale() * image->getHeight())); + auto size = QSize(int(container.getScale() * image->width()), + int(container.getScale() * image->height())); container.addElement( (new ImageLayoutElement(*this, image, size))->setLink(this->getLink())); @@ -123,7 +120,7 @@ TextElement::TextElement(const QString &text, MessageElement::Flags flags, , color_(color) , style_(style) { - for (QString word : text.split(' ')) { + for (const auto &word : text.split(' ')) { this->words_.push_back({word, -1}); // fourtf: add logic to store multiple spaces after message } diff --git a/src/messages/layouts/MessageLayoutElement.cpp b/src/messages/layouts/MessageLayoutElement.cpp index 6d253e7a5..3e2c649d2 100644 --- a/src/messages/layouts/MessageLayoutElement.cpp +++ b/src/messages/layouts/MessageLayoutElement.cpp @@ -91,8 +91,8 @@ void ImageLayoutElement::paint(QPainter &painter) return; } - auto pixmap = this->image_->getPixmap(); - if (pixmap && !this->image_->isAnimated()) { + auto pixmap = this->image_->pixmap(); + if (pixmap && !this->image_->animated()) { // fourtf: make it use qreal values painter.drawPixmap(QRectF(this->getRect()), *pixmap, QRectF()); } @@ -104,8 +104,8 @@ void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset) return; } - if (this->image_->isAnimated()) { - if (auto pixmap = this->image_->getPixmap()) { + if (this->image_->animated()) { + if (auto pixmap = this->image_->pixmap()) { auto rect = this->getRect(); rect.moveTop(rect.y() + yOffset); painter.drawPixmap(QRectF(rect), *pixmap, QRectF()); diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index cd02c94ef..7460177ab 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -98,23 +98,24 @@ void IrcMessageHandler::handleRoomStateMessage(Communi::IrcMessage *message) // Room modes { - auto roomModes = twitchChannel->accessRoomModes(); + auto roomModes = *twitchChannel->accessRoomModes(); if ((it = tags.find("emote-only")) != tags.end()) { - roomModes->emoteOnly = it.value() == "1"; + roomModes.emoteOnly = it.value() == "1"; } if ((it = tags.find("subs-only")) != tags.end()) { - roomModes->submode = it.value() == "1"; + roomModes.submode = it.value() == "1"; } if ((it = tags.find("slow")) != tags.end()) { - roomModes->slowMode = it.value().toInt(); + roomModes.slowMode = it.value().toInt(); } if ((it = tags.find("r9k")) != tags.end()) { - roomModes->r9k = it.value() == "1"; + roomModes.r9k = it.value() == "1"; } if ((it = tags.find("broadcaster-lang")) != tags.end()) { - roomModes->broadcasterLang = it.value().toString(); + roomModes.broadcasterLang = it.value().toString(); } + twitchChannel->setRoomModes(roomModes); } twitchChannel->roomModesChanged.invoke(); diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index ea1d0e3ae..419a9a4a0 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -230,9 +230,9 @@ void TwitchChannel::setRoomId(const QString &id) this->loadRecentMessages(); } -const AccessGuard TwitchChannel::accessRoomModes() const +AccessGuard TwitchChannel::accessRoomModes() const { - return this->roomModes_.access(); + return this->roomModes_.accessConst(); } void TwitchChannel::setRoomModes(const RoomModes &_roomModes) @@ -247,9 +247,9 @@ bool TwitchChannel::isLive() const return this->streamStatus_.access()->live; } -const AccessGuard TwitchChannel::accessStreamStatus() const +AccessGuard TwitchChannel::accessStreamStatus() const { - return this->streamStatus_.access(); + return this->streamStatus_.accessConst(); } boost::optional TwitchChannel::getBttvEmote(const EmoteName &name) const diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 480b3d637..752fd9008 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -66,9 +66,9 @@ public: QString getRoomId() const; void setRoomId(const QString &id); - const AccessGuard accessRoomModes() const; + AccessGuard accessRoomModes() const; void setRoomModes(const RoomModes &roomModes_); - const AccessGuard accessStreamStatus() const; + AccessGuard accessStreamStatus() const; boost::optional getBttvEmote(const EmoteName &name) const; boost::optional getFfzEmote(const EmoteName &name) const; diff --git a/src/singletons/Updates.cpp b/src/singletons/Updates.cpp index 2a525106f..a251b39e1 100644 --- a/src/singletons/Updates.cpp +++ b/src/singletons/Updates.cpp @@ -67,7 +67,7 @@ void Updates::installUpdates() return true; }); - req.onSuccess([this](auto result) -> bool { + req.onSuccess([this](auto result) -> Outcome { QByteArray object = result.getData(); auto filename = combinePath(getPaths()->miscDirectory, "update.zip"); @@ -76,7 +76,7 @@ void Updates::installUpdates() if (file.write(object) == -1) { this->setStatus_(WriteFileFailed); - return false; + return Failure; } QProcess::startDetached( @@ -84,7 +84,7 @@ void Updates::installUpdates() {filename, "restart"}); QApplication::exit(0); - return false; + return Success; }); this->setStatus_(Downloading); req.execute(); @@ -98,7 +98,7 @@ void Updates::checkForUpdates() NetworkRequest req(url); req.setTimeout(30000); - req.onSuccess([this](auto result) -> bool { + req.onSuccess([this](auto result) -> Outcome { auto object = result.parseJson(); QJsonValue version_val = object.value("version"); QJsonValue update_val = object.value("update"); @@ -116,7 +116,7 @@ void Updates::checkForUpdates() box->show(); box->raise(); }); - return false; + return Failure; } this->onlineVersion_ = version_val.toString(); @@ -140,7 +140,7 @@ void Updates::checkForUpdates() } else { this->setStatus_(NoUpdateAvailable); } - return false; + return Failure; }); this->setStatus_(Searching); req.execute(); diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 47aa5b7f6..391a88a4d 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -50,11 +50,11 @@ void addEmoteContextMenuItems(const Emote &emote, MessageElement::Flags creatorF // Add copy and open links for 1x, 2x, 3x auto addImageLink = [&](const ImagePtr &image, char scale) { - if (image->isValid()) { - copyMenu->addAction(QString(scale) + "x link", [url = image->getUrl()] { + if (!image->empty()) { + copyMenu->addAction(QString(scale) + "x link", [url = image->url()] { QApplication::clipboard()->setText(url.string); }); - openMenu->addAction(QString(scale) + "x link", [url = image->getUrl()] { + openMenu->addAction(QString(scale) + "x link", [url = image->url()] { QDesktopServices::openUrl(QUrl(url.string)); }); }