mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
simplified Image
This commit is contained in:
parent
6344fa6b23
commit
edfae49cc9
22 changed files with 146 additions and 314 deletions
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
message(----)
|
message(----)
|
||||||
|
|
||||||
QT += widgets core gui network multimedia svg
|
QT += widgets core gui network multimedia svg concurrent
|
||||||
CONFIG += communi
|
CONFIG += communi
|
||||||
COMMUNI += core model util
|
COMMUNI += core model util
|
||||||
CONFIG += c++14
|
CONFIG += c++14
|
||||||
|
@ -105,7 +105,6 @@ SOURCES += \
|
||||||
src/Application.cpp \
|
src/Application.cpp \
|
||||||
src/common/Channel.cpp \
|
src/common/Channel.cpp \
|
||||||
src/common/CompletionModel.cpp \
|
src/common/CompletionModel.cpp \
|
||||||
src/common/Emotemap.cpp \
|
|
||||||
src/common/NetworkData.cpp \
|
src/common/NetworkData.cpp \
|
||||||
src/common/NetworkManager.cpp \
|
src/common/NetworkManager.cpp \
|
||||||
src/common/NetworkRequest.cpp \
|
src/common/NetworkRequest.cpp \
|
||||||
|
@ -258,7 +257,6 @@ HEADERS += \
|
||||||
src/common/Channel.hpp \
|
src/common/Channel.hpp \
|
||||||
src/common/Common.hpp \
|
src/common/Common.hpp \
|
||||||
src/common/CompletionModel.hpp \
|
src/common/CompletionModel.hpp \
|
||||||
src/common/Emotemap.hpp \
|
|
||||||
src/common/FlagsEnum.hpp \
|
src/common/FlagsEnum.hpp \
|
||||||
src/common/LockedObject.hpp \
|
src/common/LockedObject.hpp \
|
||||||
src/common/MutexValue.hpp \
|
src/common/MutexValue.hpp \
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
#include "Emotemap.hpp"
|
|
||||||
|
|
||||||
#include "Application.hpp"
|
|
||||||
#include "singletons/Settings.hpp"
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
// EmoteData::EmoteData(Image *image)
|
|
||||||
// : image1x(image)
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
|
|
||||||
//// Emotes must have a 1x image to be valid
|
|
||||||
// bool EmoteData::isValid() const
|
|
||||||
//{
|
|
||||||
// return this->image1x != nullptr;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Image *EmoteData::getImage(float scale) const
|
|
||||||
//{
|
|
||||||
// int quality = getApp()->settings->preferredEmoteQuality;
|
|
||||||
|
|
||||||
// if (quality == 0) {
|
|
||||||
// scale *= getApp()->settings->emoteScale.getValue();
|
|
||||||
// quality = [&] {
|
|
||||||
// if (scale <= 1)
|
|
||||||
// return 1;
|
|
||||||
// if (scale <= 2)
|
|
||||||
// return 2;
|
|
||||||
// return 3;
|
|
||||||
// }();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Image *_image;
|
|
||||||
// if (quality == 3 && this->image3x != nullptr) {
|
|
||||||
// _image = this->image3x;
|
|
||||||
// } else if (quality >= 2 && this->image2x != nullptr) {
|
|
||||||
// _image = this->image2x;
|
|
||||||
// } else {
|
|
||||||
// _image = this->image1x;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return _image;
|
|
||||||
//}
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "messages/Image.hpp"
|
|
||||||
#include "util/ConcurrentMap.hpp"
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
// struct EmoteData {
|
|
||||||
// EmoteData() = default;
|
|
||||||
|
|
||||||
// EmoteData(Image *image);
|
|
||||||
|
|
||||||
// // Emotes must have a 1x image to be valid
|
|
||||||
// bool isValid() const;
|
|
||||||
// Image *getImage(float scale) const;
|
|
||||||
|
|
||||||
// // Link to the emote page i.e.
|
|
||||||
// https://www.frankerfacez.com/emoticon/144722-pajaCringe QString pageLink;
|
|
||||||
|
|
||||||
// Image *image1x = nullptr;
|
|
||||||
// Image *image2x = nullptr;
|
|
||||||
// Image *image3x = nullptr;
|
|
||||||
//};
|
|
||||||
|
|
||||||
// using EmoteMap = ConcurrentMap<QString, EmoteData>;
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
|
@ -4,19 +4,17 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
// = std::enable_if<std::is_enum<T>::value>::type
|
|
||||||
|
|
||||||
template <typename T, typename Q = typename std::underlying_type<T>::type>
|
template <typename T, typename Q = typename std::underlying_type<T>::type>
|
||||||
class FlagsEnum
|
class FlagsEnum
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FlagsEnum()
|
FlagsEnum()
|
||||||
: value(static_cast<T>(0))
|
: value_(static_cast<T>(0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FlagsEnum(T value)
|
FlagsEnum(T value)
|
||||||
: value(value)
|
: value_(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,22 +27,22 @@ public:
|
||||||
|
|
||||||
bool operator==(const FlagsEnum<T> &other)
|
bool operator==(const FlagsEnum<T> &other)
|
||||||
{
|
{
|
||||||
return this->value == other.value;
|
return this->value_ == other.value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const FlagsEnum &other)
|
bool operator!=(const FlagsEnum &other)
|
||||||
{
|
{
|
||||||
return this->value != other.value;
|
return this->value_ != other.value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(T flag)
|
void set(T flag)
|
||||||
{
|
{
|
||||||
reinterpret_cast<Q &>(this->value) |= static_cast<Q>(flag);
|
reinterpret_cast<Q &>(this->value_) |= static_cast<Q>(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unset(T flag)
|
void unset(T flag)
|
||||||
{
|
{
|
||||||
reinterpret_cast<Q &>(this->value) &= ~static_cast<Q>(flag);
|
reinterpret_cast<Q &>(this->value_) &= ~static_cast<Q>(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(T flag, bool value)
|
void set(T flag, bool value)
|
||||||
|
@ -57,33 +55,17 @@ public:
|
||||||
|
|
||||||
bool has(T flag) const
|
bool has(T flag) const
|
||||||
{
|
{
|
||||||
return static_cast<Q>(this->value) & static_cast<Q>(flag);
|
return static_cast<Q>(this->value_) & static_cast<Q>(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool hasAny(std::initializer_list<T> flags) const
|
|
||||||
//{
|
|
||||||
// for (auto flag : flags) {
|
|
||||||
// if (this->has(flag)) return true;
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
|
|
||||||
bool hasAny(FlagsEnum flags) const
|
bool hasAny(FlagsEnum flags) const
|
||||||
{
|
{
|
||||||
return static_cast<Q>(this->value) & static_cast<Q>(flags.value);
|
return static_cast<Q>(this->value_) & static_cast<Q>(flags.value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool hasAll(std::initializer_list<T> flags) const
|
|
||||||
//{
|
|
||||||
// for (auto flag : flags) {
|
|
||||||
// if (!this->has(flag)) return false;
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
bool hasAll(FlagsEnum<T> flags) const
|
bool hasAll(FlagsEnum<T> flags) const
|
||||||
{
|
{
|
||||||
return (static_cast<Q>(this->value) & static_cast<Q>(flags.value)) &&
|
return (static_cast<Q>(this->value_) & static_cast<Q>(flags.value_)) &&
|
||||||
static_cast<Q>(flags->value);
|
static_cast<Q>(flags->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +75,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T value;
|
T value_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct NetworkData {
|
||||||
QNetworkRequest request_;
|
QNetworkRequest request_;
|
||||||
const QObject *caller_ = nullptr;
|
const QObject *caller_ = nullptr;
|
||||||
bool useQuickLoadCache_{};
|
bool useQuickLoadCache_{};
|
||||||
|
bool executeConcurrently{};
|
||||||
|
|
||||||
NetworkReplyCreatedCallback onReplyCreated_;
|
NetworkReplyCreatedCallback onReplyCreated_;
|
||||||
NetworkErrorCallback onError_;
|
NetworkErrorCallback onError_;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "util/DebugCount.hpp"
|
#include "util/DebugCount.hpp"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QtConcurrent>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
@ -80,6 +81,11 @@ void NetworkRequest::setTimeout(int ms)
|
||||||
this->timer->timeoutMS_ = ms;
|
this->timer->timeoutMS_ = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkRequest::setExecuteConcurrently(bool value)
|
||||||
|
{
|
||||||
|
this->data->executeConcurrently = value;
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkRequest::makeAuthorizedV5(const QString &clientID,
|
void NetworkRequest::makeAuthorizedV5(const QString &clientID,
|
||||||
const QString &oauthToken)
|
const QString &oauthToken)
|
||||||
{
|
{
|
||||||
|
@ -228,7 +234,16 @@ void NetworkRequest::doRequest()
|
||||||
NetworkResult result(bytes);
|
NetworkResult result(bytes);
|
||||||
|
|
||||||
DebugCount::increase("http request success");
|
DebugCount::increase("http request success");
|
||||||
|
Log("starting {}", data->request_.url().toString());
|
||||||
|
if (data->onSuccess_) {
|
||||||
|
if (data->executeConcurrently)
|
||||||
|
QtConcurrent::run(
|
||||||
|
[onSuccess = std::move(data->onSuccess_),
|
||||||
|
result = std::move(result)] { onSuccess(result); });
|
||||||
|
else
|
||||||
data->onSuccess_(result);
|
data->onSuccess_(result);
|
||||||
|
}
|
||||||
|
Log("finished {}", data->request_.url().toString());
|
||||||
|
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,19 +27,15 @@ class NetworkRequest
|
||||||
bool executed_ = false;
|
bool executed_ = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NetworkRequest() = delete;
|
|
||||||
NetworkRequest(const NetworkRequest &other) = delete;
|
|
||||||
NetworkRequest &operator=(const NetworkRequest &other) = delete;
|
|
||||||
|
|
||||||
NetworkRequest(NetworkRequest &&other) = default;
|
|
||||||
NetworkRequest &operator=(NetworkRequest &&other) = default;
|
|
||||||
|
|
||||||
explicit NetworkRequest(
|
explicit NetworkRequest(
|
||||||
const std::string &url,
|
const std::string &url,
|
||||||
NetworkRequestType requestType = NetworkRequestType::Get);
|
NetworkRequestType requestType = NetworkRequestType::Get);
|
||||||
explicit NetworkRequest(
|
explicit NetworkRequest(
|
||||||
QUrl url, NetworkRequestType requestType = NetworkRequestType::Get);
|
QUrl url, NetworkRequestType requestType = NetworkRequestType::Get);
|
||||||
|
|
||||||
|
NetworkRequest(NetworkRequest &&other) = default;
|
||||||
|
NetworkRequest &operator=(NetworkRequest &&other) = default;
|
||||||
|
|
||||||
~NetworkRequest();
|
~NetworkRequest();
|
||||||
|
|
||||||
void setRequestType(NetworkRequestType newRequestType);
|
void setRequestType(NetworkRequestType newRequestType);
|
||||||
|
@ -55,6 +51,7 @@ public:
|
||||||
void setRawHeader(const char *headerName, const QByteArray &value);
|
void setRawHeader(const char *headerName, const QByteArray &value);
|
||||||
void setRawHeader(const char *headerName, const QString &value);
|
void setRawHeader(const char *headerName, const QString &value);
|
||||||
void setTimeout(int ms);
|
void setTimeout(int ms);
|
||||||
|
void setExecuteConcurrently(bool value);
|
||||||
void makeAuthorizedV5(const QString &clientID,
|
void makeAuthorizedV5(const QString &clientID,
|
||||||
const QString &oauthToken = QString());
|
const QString &oauthToken = QString());
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,7 @@ ModerationAction::ModerationAction(const QString &action)
|
||||||
// str);
|
// str);
|
||||||
// }
|
// }
|
||||||
} else if (action.startsWith("/ban ")) {
|
} else if (action.startsWith("/ban ")) {
|
||||||
this->image_ =
|
this->image_ = Image::fromPixmap(getApp()->resources->buttons.ban);
|
||||||
Image::fromNonOwningPixmap(&getApp()->resources->buttons.ban);
|
|
||||||
} else {
|
} else {
|
||||||
QString xD = action;
|
QString xD = action;
|
||||||
|
|
||||||
|
|
|
@ -37,29 +37,4 @@ using EmoteIdMap = std::unordered_map<EmoteId, EmotePtr>;
|
||||||
using WeakEmoteMap = std::unordered_map<EmoteName, std::weak_ptr<const Emote>>;
|
using WeakEmoteMap = std::unordered_map<EmoteName, std::weak_ptr<const Emote>>;
|
||||||
using WeakEmoteIdMap = std::unordered_map<EmoteId, std::weak_ptr<const Emote>>;
|
using WeakEmoteIdMap = std::unordered_map<EmoteId, std::weak_ptr<const Emote>>;
|
||||||
|
|
||||||
// struct EmoteData2 {
|
|
||||||
// EmoteName name;
|
|
||||||
// ImageSet images;
|
|
||||||
// Tooltip tooltip;
|
|
||||||
// Url homePage;
|
|
||||||
//};
|
|
||||||
//
|
|
||||||
// class Emote
|
|
||||||
//{
|
|
||||||
// public:
|
|
||||||
// Emote(EmoteData2 &&data);
|
|
||||||
// Emote(const EmoteData2 &data);
|
|
||||||
//
|
|
||||||
// const Url &getHomePage() const;
|
|
||||||
// const EmoteName &getName() const;
|
|
||||||
// const Tooltip &getTooltip() const;
|
|
||||||
// const ImageSet &getImages() const;
|
|
||||||
// const QString &getCopyString() const;
|
|
||||||
// bool operator==(const Emote &other) const;
|
|
||||||
// bool operator!=(const Emote &other) const;
|
|
||||||
//
|
|
||||||
// private:
|
|
||||||
// EmoteData2 data_;
|
|
||||||
//};
|
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -21,22 +21,14 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace {
|
namespace {
|
||||||
const QPixmap *getPixmap(const Pixmap &pixmap)
|
|
||||||
{
|
|
||||||
if (pixmap.which() == 0)
|
|
||||||
return boost::get<const QPixmap *>(pixmap);
|
|
||||||
else
|
|
||||||
return boost::get<std::unique_ptr<QPixmap>>(pixmap).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frames
|
// Frames
|
||||||
Frames::Frames()
|
Frames::Frames()
|
||||||
{
|
{
|
||||||
DebugCount::increase("images");
|
DebugCount::increase("images");
|
||||||
}
|
}
|
||||||
|
|
||||||
Frames::Frames(std::vector<Frame> &&frames)
|
Frames::Frames(const QVector<Frame<QPixmap>> &frames)
|
||||||
: items_(std::move(frames))
|
: items_(frames)
|
||||||
{
|
{
|
||||||
DebugCount::increase("images");
|
DebugCount::increase("images");
|
||||||
if (this->animated()) DebugCount::increase("animated images");
|
if (this->animated()) DebugCount::increase("animated images");
|
||||||
|
@ -68,22 +60,22 @@ bool Frames::animated() const
|
||||||
return this->items_.size() > 1;
|
return this->items_.size() > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPixmap *Frames::current() const
|
boost::optional<QPixmap> Frames::current() const
|
||||||
{
|
{
|
||||||
if (this->items_.size() == 0) return nullptr;
|
if (this->items_.size() == 0) return boost::none;
|
||||||
return getPixmap(this->items_[this->index_].pixmap);
|
return this->items_[this->index_].image;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPixmap *Frames::first() const
|
boost::optional<QPixmap> Frames::first() const
|
||||||
{
|
{
|
||||||
if (this->items_.size() == 0) return nullptr;
|
if (this->items_.size() == 0) return boost::none;
|
||||||
return getPixmap(this->items_.front().pixmap);
|
return this->items_.front().image;
|
||||||
}
|
}
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
QVector<Frame<QImage>> readFrames(QImageReader &reader, const Url &url)
|
||||||
{
|
{
|
||||||
std::vector<ParseFrame> frames;
|
QVector<Frame<QImage>> frames;
|
||||||
|
|
||||||
if (reader.imageCount() == 0) {
|
if (reader.imageCount() == 0) {
|
||||||
Log("Error while reading image {}: '{}'", url.string,
|
Log("Error while reading image {}: '{}'", url.string,
|
||||||
|
@ -97,7 +89,7 @@ std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
||||||
QPixmap::fromImage(image);
|
QPixmap::fromImage(image);
|
||||||
|
|
||||||
int duration = std::max(20, reader.nextImageDelay());
|
int duration = std::max(20, reader.nextImageDelay());
|
||||||
frames.push_back(ParseFrame{image, duration});
|
frames.push_back(Frame<QImage>{image, duration});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,36 +101,22 @@ std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void queueLoadedEvent()
|
|
||||||
{
|
|
||||||
static auto eventQueued = false;
|
|
||||||
|
|
||||||
if (!eventQueued) {
|
|
||||||
eventQueued = true;
|
|
||||||
|
|
||||||
QTimer::singleShot(250, [] {
|
|
||||||
getApp()->windows->incGeneration();
|
|
||||||
getApp()->windows->layoutChannelViews();
|
|
||||||
eventQueued = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsed
|
// parsed
|
||||||
template <typename Assign>
|
template <typename Assign>
|
||||||
void asd(std::queue<std::pair<Assign, std::vector<Frame>>> &queued,
|
void assignDelayed(
|
||||||
|
std::queue<std::pair<Assign, QVector<Frame<QPixmap>>>> &queued,
|
||||||
std::mutex &mutex, std::atomic_bool &loadedEventQueued)
|
std::mutex &mutex, std::atomic_bool &loadedEventQueued)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (!queued.empty()) {
|
while (!queued.empty()) {
|
||||||
queued.front().first(std::move(queued.front().second));
|
queued.front().first(queued.front().second);
|
||||||
queued.pop();
|
queued.pop();
|
||||||
|
|
||||||
if (++i > 50) {
|
if (++i > 50) {
|
||||||
QTimer::singleShot(3,
|
QTimer::singleShot(
|
||||||
[&] { asd(queued, mutex, loadedEventQueued); });
|
3, [&] { assignDelayed(queued, mutex, loadedEventQueued); });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,34 +126,31 @@ void asd(std::queue<std::pair<Assign, std::vector<Frame>>> &queued,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Assign>
|
template <typename Assign>
|
||||||
auto makeConvertCallback(std::vector<ParseFrame> parsed, Assign assign)
|
auto makeConvertCallback(const QVector<Frame<QImage>> &parsed, Assign assign)
|
||||||
{
|
{
|
||||||
return [parsed = std::move(parsed), assign] {
|
return [parsed, assign] {
|
||||||
// BenchmarkGuard guard("convert image");
|
|
||||||
|
|
||||||
// convert to pixmap
|
// convert to pixmap
|
||||||
auto frames = std::vector<Frame>();
|
auto frames = QVector<Frame<QPixmap>>();
|
||||||
std::transform(parsed.begin(), parsed.end(), std::back_inserter(frames),
|
std::transform(parsed.begin(), parsed.end(), std::back_inserter(frames),
|
||||||
[](auto &frame) {
|
[](auto &frame) {
|
||||||
return Frame{std::make_unique<QPixmap>(
|
return Frame<QPixmap>{
|
||||||
QPixmap::fromImage(frame.image)),
|
QPixmap::fromImage(frame.image), frame.duration};
|
||||||
frame.duration};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// put into stack
|
// put into stack
|
||||||
static std::queue<std::pair<Assign, std::vector<Frame>>> queued;
|
static std::queue<std::pair<Assign, QVector<Frame<QPixmap>>>> queued;
|
||||||
static std::mutex mutex;
|
static std::mutex mutex;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
queued.emplace(assign, std::move(frames));
|
queued.emplace(assign, frames);
|
||||||
|
|
||||||
static std::atomic_bool loadedEventQueued{false};
|
static std::atomic_bool loadedEventQueued{false};
|
||||||
|
|
||||||
if (!loadedEventQueued) {
|
if (!loadedEventQueued) {
|
||||||
loadedEventQueued = true;
|
loadedEventQueued = true;
|
||||||
|
|
||||||
QTimer::singleShot(100,
|
QTimer::singleShot(
|
||||||
[=] { asd(queued, mutex, loadedEventQueued); });
|
100, [=] { assignDelayed(queued, mutex, loadedEventQueued); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -200,12 +175,7 @@ ImagePtr Image::fromUrl(const Url &url, qreal scale)
|
||||||
return shared;
|
return shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Image::fromOwningPixmap(std::unique_ptr<QPixmap> pixmap, qreal scale)
|
ImagePtr Image::fromPixmap(const QPixmap &pixmap, qreal scale)
|
||||||
{
|
|
||||||
return ImagePtr(new Image(std::move(pixmap), scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePtr Image::fromNonOwningPixmap(QPixmap *pixmap, qreal scale)
|
|
||||||
{
|
{
|
||||||
return ImagePtr(new Image(pixmap, scale));
|
return ImagePtr(new Image(pixmap, scale));
|
||||||
}
|
}
|
||||||
|
@ -228,20 +198,10 @@ Image::Image(const Url &url, qreal scale)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Image(std::unique_ptr<QPixmap> owning, qreal scale)
|
Image::Image(const QPixmap &pixmap, qreal scale)
|
||||||
: scale_(scale)
|
: scale_(scale)
|
||||||
|
, frames_(QVector<Frame<QPixmap>>{Frame<QPixmap>{pixmap}})
|
||||||
{
|
{
|
||||||
std::vector<Frame> vec;
|
|
||||||
vec.push_back(Frame{std::move(owning)});
|
|
||||||
this->frames_ = std::move(vec);
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::Image(QPixmap *nonOwning, qreal scale)
|
|
||||||
: scale_(scale)
|
|
||||||
{
|
|
||||||
std::vector<Frame> vec;
|
|
||||||
vec.push_back(Frame{nonOwning});
|
|
||||||
this->frames_ = std::move(vec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Url &Image::url() const
|
const Url &Image::url() const
|
||||||
|
@ -249,7 +209,7 @@ const Url &Image::url() const
|
||||||
return this->url_;
|
return this->url_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPixmap *Image::pixmap() const
|
boost::optional<QPixmap> Image::pixmap() const
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
|
|
||||||
|
@ -266,7 +226,7 @@ qreal Image::scale() const
|
||||||
return this->scale_;
|
return this->scale_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::empty() const
|
bool Image::isEmpty() const
|
||||||
{
|
{
|
||||||
return this->empty_;
|
return this->empty_;
|
||||||
}
|
}
|
||||||
|
@ -301,23 +261,14 @@ int Image::height() const
|
||||||
void Image::load()
|
void Image::load()
|
||||||
{
|
{
|
||||||
NetworkRequest req(this->url().string);
|
NetworkRequest req(this->url().string);
|
||||||
|
req.setExecuteConcurrently(true);
|
||||||
req.setCaller(&this->object_);
|
req.setCaller(&this->object_);
|
||||||
req.setUseQuickLoadCache(true);
|
req.setUseQuickLoadCache(true);
|
||||||
req.onSuccess([that = this, weak = weakOf(this)](auto result) -> Outcome {
|
req.onSuccess([that = this, weak = weakOf(this)](auto result) -> Outcome {
|
||||||
assertInGuiThread();
|
|
||||||
|
|
||||||
auto shared = weak.lock();
|
auto shared = weak.lock();
|
||||||
if (!shared) return Failure;
|
if (!shared) return Failure;
|
||||||
|
|
||||||
static auto parseThread = [] {
|
auto data = result.getData();
|
||||||
auto thread = std::make_unique<QThread>();
|
|
||||||
thread->start();
|
|
||||||
return thread;
|
|
||||||
}();
|
|
||||||
|
|
||||||
postToThread(
|
|
||||||
[data = result.getData(), weak, that] {
|
|
||||||
// BenchmarkGuard guard("parse image");
|
|
||||||
|
|
||||||
// const cast since we are only reading from it
|
// const cast since we are only reading from it
|
||||||
QBuffer buffer(const_cast<QByteArray *>(&data));
|
QBuffer buffer(const_cast<QByteArray *>(&data));
|
||||||
|
@ -325,13 +276,9 @@ void Image::load()
|
||||||
QImageReader reader(&buffer);
|
QImageReader reader(&buffer);
|
||||||
auto parsed = readFrames(reader, that->url());
|
auto parsed = readFrames(reader, that->url());
|
||||||
|
|
||||||
postToThread(
|
postToThread(makeConvertCallback(parsed, [weak](auto frames) {
|
||||||
makeConvertCallback(std::move(parsed), [weak](auto frames) {
|
if (auto shared = weak.lock()) shared->frames_ = frames;
|
||||||
if (auto shared = weak.lock())
|
|
||||||
shared->frames_ = std::move(frames);
|
|
||||||
}));
|
}));
|
||||||
},
|
|
||||||
parseThread.get());
|
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
});
|
});
|
||||||
|
@ -341,7 +288,7 @@ void Image::load()
|
||||||
|
|
||||||
bool Image::operator==(const Image &other) const
|
bool Image::operator==(const Image &other) const
|
||||||
{
|
{
|
||||||
if (this->empty() && other.empty()) return true;
|
if (this->isEmpty() && other.isEmpty()) return true;
|
||||||
if (!this->url_.string.isEmpty() && this->url_ == other.url_) return true;
|
if (!this->url_.string.isEmpty() && this->url_ == other.url_) return true;
|
||||||
if (this->frames_.first() == other.frames_.first()) return true;
|
if (this->frames_.first() == other.frames_.first()) return true;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QVector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
@ -15,31 +16,27 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace {
|
namespace {
|
||||||
using Pixmap = boost::variant<const QPixmap *, std::unique_ptr<QPixmap>>;
|
template <typename Image>
|
||||||
struct Frame {
|
struct Frame {
|
||||||
Pixmap pixmap;
|
Image image;
|
||||||
int duration;
|
|
||||||
};
|
|
||||||
struct ParseFrame {
|
|
||||||
QImage image;
|
|
||||||
int duration;
|
int duration;
|
||||||
};
|
};
|
||||||
class Frames
|
class Frames
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Frames();
|
Frames();
|
||||||
Frames(std::vector<Frame> &&frames);
|
Frames(const QVector<Frame<QPixmap>> &frames);
|
||||||
~Frames();
|
~Frames();
|
||||||
Frames(Frames &&other) = default;
|
Frames(Frames &&other) = default;
|
||||||
Frames &operator=(Frames &&other) = default;
|
Frames &operator=(Frames &&other) = default;
|
||||||
|
|
||||||
bool animated() const;
|
bool animated() const;
|
||||||
void advance();
|
void advance();
|
||||||
const QPixmap *current() const;
|
boost::optional<QPixmap> current() const;
|
||||||
const QPixmap *first() const;
|
boost::optional<QPixmap> first() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Frame> items_;
|
QVector<Frame<QPixmap>> items_;
|
||||||
int index_{0};
|
int index_{0};
|
||||||
int durationOffset_{0};
|
int durationOffset_{0};
|
||||||
};
|
};
|
||||||
|
@ -52,15 +49,13 @@ class Image : public std::enable_shared_from_this<Image>, boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static ImagePtr fromUrl(const Url &url, qreal scale = 1);
|
static ImagePtr fromUrl(const Url &url, qreal scale = 1);
|
||||||
static ImagePtr fromOwningPixmap(std::unique_ptr<QPixmap> pixmap,
|
static ImagePtr fromPixmap(const QPixmap &pixmap, qreal scale = 1);
|
||||||
qreal scale = 1);
|
|
||||||
static ImagePtr fromNonOwningPixmap(QPixmap *pixmap, qreal scale = 1);
|
|
||||||
static ImagePtr getEmpty();
|
static ImagePtr getEmpty();
|
||||||
|
|
||||||
const Url &url() const;
|
const Url &url() const;
|
||||||
const QPixmap *pixmap() const;
|
boost::optional<QPixmap> pixmap() const;
|
||||||
qreal scale() const;
|
qreal scale() const;
|
||||||
bool empty() const;
|
bool isEmpty() const;
|
||||||
int width() const;
|
int width() const;
|
||||||
int height() const;
|
int height() const;
|
||||||
bool animated() const;
|
bool animated() const;
|
||||||
|
@ -71,8 +66,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Image();
|
Image();
|
||||||
Image(const Url &url, qreal scale);
|
Image(const Url &url, qreal scale);
|
||||||
Image(std::unique_ptr<QPixmap> owning, qreal scale);
|
Image(const QPixmap &nonOwning, qreal scale);
|
||||||
Image(QPixmap *nonOwning, qreal scale);
|
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
|
|
|
@ -71,11 +71,11 @@ const ImagePtr &ImageSet::getImage(float scale) const
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->imageX3_->empty() && quality == 3) {
|
if (!this->imageX3_->isEmpty() && quality == 3) {
|
||||||
return this->imageX3_;
|
return this->imageX3_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->imageX2_->empty() && quality == 2) {
|
if (!this->imageX2_->isEmpty() && quality == 2) {
|
||||||
return this->imageX3_;
|
return this->imageX3_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,6 @@ public:
|
||||||
|
|
||||||
const ImagePtr &getImage(float scale) const;
|
const ImagePtr &getImage(float scale) const;
|
||||||
|
|
||||||
ImagePtr getImage(float scale);
|
|
||||||
|
|
||||||
bool operator==(const ImageSet &other) const;
|
bool operator==(const ImageSet &other) const;
|
||||||
bool operator!=(const ImageSet &other) const;
|
bool operator!=(const ImageSet &other) const;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "messages/MessageElement.hpp"
|
#include "messages/MessageElement.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
#include "common/Emotemap.hpp"
|
|
||||||
#include "controllers/moderationactions/ModerationActions.hpp"
|
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||||
#include "debug/Benchmark.hpp"
|
#include "debug/Benchmark.hpp"
|
||||||
#include "messages/layouts/MessageLayoutContainer.hpp"
|
#include "messages/layouts/MessageLayoutContainer.hpp"
|
||||||
|
@ -102,7 +101,7 @@ void EmoteElement::addToContainer(MessageLayoutContainer &container,
|
||||||
if (flags.hasAny(this->getFlags())) {
|
if (flags.hasAny(this->getFlags())) {
|
||||||
if (flags.has(MessageElementFlag::EmoteImages)) {
|
if (flags.has(MessageElementFlag::EmoteImages)) {
|
||||||
auto image = this->emote_->images.getImage(container.getScale());
|
auto image = this->emote_->images.getImage(container.getScale());
|
||||||
if (image->empty()) return;
|
if (image->isEmpty()) return;
|
||||||
|
|
||||||
auto size = QSize(int(container.getScale() * image->width()),
|
auto size = QSize(int(container.getScale() * image->width()),
|
||||||
int(container.getScale() * image->height()));
|
int(container.getScale() * image->height()));
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Emotemap.hpp"
|
|
||||||
#include "common/FlagsEnum.hpp"
|
#include "common/FlagsEnum.hpp"
|
||||||
#include "messages/Emote.hpp"
|
#include "messages/Emote.hpp"
|
||||||
#include "messages/Image.hpp"
|
#include "messages/Image.hpp"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Emotemap.hpp"
|
|
||||||
#include "common/SimpleSignalVector.hpp"
|
#include "common/SimpleSignalVector.hpp"
|
||||||
#include "messages/Emote.hpp"
|
#include "messages/Emote.hpp"
|
||||||
#include "util/ConcurrentMap.hpp"
|
#include "util/ConcurrentMap.hpp"
|
||||||
|
|
|
@ -22,6 +22,32 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
namespace {
|
||||||
|
auto parseRecentMessages(const QJsonObject &jsonRoot, TwitchChannel &channel)
|
||||||
|
{
|
||||||
|
QJsonArray jsonMessages = jsonRoot.value("messages").toArray();
|
||||||
|
std::vector<MessagePtr> messages;
|
||||||
|
|
||||||
|
if (jsonMessages.empty()) return messages;
|
||||||
|
|
||||||
|
for (const auto jsonMessage : jsonMessages) {
|
||||||
|
auto content = jsonMessage.toString().toUtf8();
|
||||||
|
// passing nullptr as the channel makes the message invalid but we don't
|
||||||
|
// check for that anyways
|
||||||
|
auto message = Communi::IrcMessage::fromData(content, nullptr);
|
||||||
|
auto privMsg = dynamic_cast<Communi::IrcPrivateMessage *>(message);
|
||||||
|
assert(privMsg);
|
||||||
|
|
||||||
|
MessageParseArgs args;
|
||||||
|
TwitchMessageBuilder builder(&channel, privMsg, args);
|
||||||
|
if (!builder.isIgnored()) {
|
||||||
|
messages.push_back(builder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
TwitchChannel::TwitchChannel(const QString &name)
|
TwitchChannel::TwitchChannel(const QString &name)
|
||||||
: Channel(name, Channel::Type::Twitch)
|
: Channel(name, Channel::Type::Twitch)
|
||||||
|
@ -436,45 +462,23 @@ void TwitchChannel::loadRecentMessages()
|
||||||
NetworkRequest request(genericURL.arg(this->getRoomId()));
|
NetworkRequest request(genericURL.arg(this->getRoomId()));
|
||||||
request.makeAuthorizedV5(getDefaultClientID());
|
request.makeAuthorizedV5(getDefaultClientID());
|
||||||
request.setCaller(QThread::currentThread());
|
request.setCaller(QThread::currentThread());
|
||||||
|
// can't be concurrent right now due to SignalVector
|
||||||
|
// request.setExecuteConcurrently(true);
|
||||||
|
|
||||||
request.onSuccess(
|
request.onSuccess([that = this](auto result) -> Outcome {
|
||||||
[this, weak = weakOf<Channel>(this)](auto result) -> Outcome {
|
auto messages = parseRecentMessages(result.parseJson(), *that);
|
||||||
ChannelPtr shared = weak.lock();
|
|
||||||
if (!shared) return Failure;
|
|
||||||
|
|
||||||
return this->parseRecentMessages(result.parseJson());
|
// postToThread([that, weak = weakOf<Channel>(that),
|
||||||
|
// messages = std::move(messages)]() mutable {
|
||||||
|
that->addMessagesAtStart(messages);
|
||||||
|
// });
|
||||||
|
|
||||||
|
return Success;
|
||||||
});
|
});
|
||||||
|
|
||||||
request.execute();
|
request.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
Outcome TwitchChannel::parseRecentMessages(const QJsonObject &jsonRoot)
|
|
||||||
{
|
|
||||||
QJsonArray jsonMessages = jsonRoot.value("messages").toArray();
|
|
||||||
if (jsonMessages.empty()) return Failure;
|
|
||||||
|
|
||||||
std::vector<MessagePtr> messages;
|
|
||||||
|
|
||||||
for (const auto jsonMessage : jsonMessages) {
|
|
||||||
auto content = jsonMessage.toString().toUtf8();
|
|
||||||
// passing nullptr as the channel makes the message invalid but we don't
|
|
||||||
// check for that anyways
|
|
||||||
auto message = Communi::IrcMessage::fromData(content, nullptr);
|
|
||||||
auto privMsg = dynamic_cast<Communi::IrcPrivateMessage *>(message);
|
|
||||||
assert(privMsg);
|
|
||||||
|
|
||||||
MessageParseArgs args;
|
|
||||||
TwitchMessageBuilder builder(this, privMsg, args);
|
|
||||||
if (!builder.isIgnored()) {
|
|
||||||
messages.push_back(builder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->addMessagesAtStart(messages);
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TwitchChannel::refreshPubsub()
|
void TwitchChannel::refreshPubsub()
|
||||||
{
|
{
|
||||||
// listen to moderation actions
|
// listen to moderation actions
|
||||||
|
@ -581,7 +585,7 @@ void TwitchChannel::loadBadges()
|
||||||
|
|
||||||
void TwitchChannel::loadCheerEmotes()
|
void TwitchChannel::loadCheerEmotes()
|
||||||
{
|
{
|
||||||
auto url = Url{"https://api.twitch.tv/kraken/bits/actions?channel_id=" +
|
/*auto url = Url{"https://api.twitch.tv/kraken/bits/actions?channel_id=" +
|
||||||
this->getRoomId()};
|
this->getRoomId()};
|
||||||
auto request = NetworkRequest::twitchRequest(url.string);
|
auto request = NetworkRequest::twitchRequest(url.string);
|
||||||
request.setCaller(QThread::currentThread());
|
request.setCaller(QThread::currentThread());
|
||||||
|
@ -589,6 +593,7 @@ void TwitchChannel::loadCheerEmotes()
|
||||||
request.onSuccess(
|
request.onSuccess(
|
||||||
[this, weak = weakOf<Channel>(this)](auto result) -> Outcome {
|
[this, weak = weakOf<Channel>(this)](auto result) -> Outcome {
|
||||||
auto cheerEmoteSets = ParseCheermoteSets(result.parseRapidJson());
|
auto cheerEmoteSets = ParseCheermoteSets(result.parseRapidJson());
|
||||||
|
std::vector<CheerEmoteSet> emoteSets;
|
||||||
|
|
||||||
for (auto &set : cheerEmoteSets) {
|
for (auto &set : cheerEmoteSets) {
|
||||||
auto cheerEmoteSet = CheerEmoteSet();
|
auto cheerEmoteSet = CheerEmoteSet();
|
||||||
|
@ -631,13 +636,15 @@ void TwitchChannel::loadCheerEmotes()
|
||||||
return lhs.minBits < rhs.minBits; //
|
return lhs.minBits < rhs.minBits; //
|
||||||
});
|
});
|
||||||
|
|
||||||
this->cheerEmoteSets_.emplace_back(cheerEmoteSet);
|
emoteSets.emplace_back(cheerEmoteSet);
|
||||||
}
|
}
|
||||||
|
*this->cheerEmoteSets_.access() = std::move(emoteSets);
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
});
|
});
|
||||||
|
|
||||||
request.execute();
|
request.execute();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<EmotePtr> TwitchChannel::getTwitchBadge(
|
boost::optional<EmotePtr> TwitchChannel::getTwitchBadge(
|
||||||
|
|
|
@ -116,7 +116,6 @@ private:
|
||||||
void refreshViewerList();
|
void refreshViewerList();
|
||||||
Outcome parseViewerList(const QJsonObject &jsonRoot);
|
Outcome parseViewerList(const QJsonObject &jsonRoot);
|
||||||
void loadRecentMessages();
|
void loadRecentMessages();
|
||||||
Outcome parseRecentMessages(const QJsonObject &jsonRoot);
|
|
||||||
|
|
||||||
void setLive(bool newLiveStatus);
|
void setLive(bool newLiveStatus);
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ private:
|
||||||
|
|
||||||
// "subscribers": { "0": ... "3": ... "6": ...
|
// "subscribers": { "0": ... "3": ... "6": ...
|
||||||
UniqueAccess<std::map<QString, std::map<QString, EmotePtr>>> badgeSets_;
|
UniqueAccess<std::map<QString, std::map<QString, EmotePtr>>> badgeSets_;
|
||||||
std::vector<CheerEmoteSet> cheerEmoteSets_;
|
UniqueAccess<std::vector<CheerEmoteSet>> cheerEmoteSets_;
|
||||||
|
|
||||||
// --
|
// --
|
||||||
QByteArray messageSuffix_;
|
QByteArray messageSuffix_;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/Emotemap.hpp"
|
|
||||||
#include "common/UniqueAccess.hpp"
|
#include "common/UniqueAccess.hpp"
|
||||||
#include "messages/Emote.hpp"
|
#include "messages/Emote.hpp"
|
||||||
#include "providers/twitch/EmoteValue.hpp"
|
#include "providers/twitch/EmoteValue.hpp"
|
||||||
|
|
|
@ -715,41 +715,38 @@ void TwitchMessageBuilder::appendTwitchBadges()
|
||||||
//}
|
//}
|
||||||
} else if (badge == "staff/1") {
|
} else if (badge == "staff/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(&app->resources->twitch.staff),
|
Image::fromPixmap(app->resources->twitch.staff),
|
||||||
MessageElementFlag::BadgeGlobalAuthority)
|
MessageElementFlag::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Staff");
|
->setTooltip("Twitch Staff");
|
||||||
} else if (badge == "admin/1") {
|
} else if (badge == "admin/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(&app->resources->twitch.admin),
|
Image::fromPixmap(app->resources->twitch.admin),
|
||||||
MessageElementFlag::BadgeGlobalAuthority)
|
MessageElementFlag::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Admin");
|
->setTooltip("Twitch Admin");
|
||||||
} else if (badge == "global_mod/1") {
|
} else if (badge == "global_mod/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(
|
Image::fromPixmap(app->resources->twitch.globalmod),
|
||||||
&app->resources->twitch.globalmod),
|
|
||||||
MessageElementFlag::BadgeGlobalAuthority)
|
MessageElementFlag::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Global Moderator");
|
->setTooltip("Twitch Global Moderator");
|
||||||
} else if (badge == "moderator/1") {
|
} else if (badge == "moderator/1") {
|
||||||
// TODO: Implement custom FFZ moderator badge
|
// TODO: Implement custom FFZ moderator badge
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(
|
Image::fromPixmap(app->resources->twitch.moderator),
|
||||||
&app->resources->twitch.moderator),
|
|
||||||
MessageElementFlag::BadgeChannelAuthority)
|
MessageElementFlag::BadgeChannelAuthority)
|
||||||
->setTooltip("Twitch Channel Moderator");
|
->setTooltip("Twitch Channel Moderator");
|
||||||
} else if (badge == "turbo/1") {
|
} else if (badge == "turbo/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(&app->resources->twitch.turbo),
|
Image::fromPixmap(app->resources->twitch.turbo),
|
||||||
MessageElementFlag::BadgeGlobalAuthority)
|
MessageElementFlag::BadgeGlobalAuthority)
|
||||||
->setTooltip("Twitch Turbo Subscriber");
|
->setTooltip("Twitch Turbo Subscriber");
|
||||||
} else if (badge == "broadcaster/1") {
|
} else if (badge == "broadcaster/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(
|
Image::fromPixmap(app->resources->twitch.broadcaster),
|
||||||
&app->resources->twitch.broadcaster),
|
|
||||||
MessageElementFlag::BadgeChannelAuthority)
|
MessageElementFlag::BadgeChannelAuthority)
|
||||||
->setTooltip("Twitch Broadcaster");
|
->setTooltip("Twitch Broadcaster");
|
||||||
} else if (badge == "premium/1") {
|
} else if (badge == "premium/1") {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(&app->resources->twitch.prime),
|
Image::fromPixmap(app->resources->twitch.prime),
|
||||||
MessageElementFlag::BadgeVanity)
|
MessageElementFlag::BadgeVanity)
|
||||||
->setTooltip("Twitch Prime Subscriber");
|
->setTooltip("Twitch Prime Subscriber");
|
||||||
} else if (badge.startsWith("partner/")) {
|
} else if (badge.startsWith("partner/")) {
|
||||||
|
@ -757,8 +754,8 @@ void TwitchMessageBuilder::appendTwitchBadges()
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 1: {
|
case 1: {
|
||||||
this->emplace<ImageElement>(
|
this->emplace<ImageElement>(
|
||||||
Image::fromNonOwningPixmap(
|
Image::fromPixmap(app->resources->twitch.verified,
|
||||||
&app->resources->twitch.verified, 0.25),
|
0.25),
|
||||||
MessageElementFlag::BadgeVanity)
|
MessageElementFlag::BadgeVanity)
|
||||||
->setTooltip("Twitch Verified");
|
->setTooltip("Twitch Verified");
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -52,7 +52,7 @@ void addEmoteContextMenuItems(const Emote &emote,
|
||||||
|
|
||||||
// Add copy and open links for 1x, 2x, 3x
|
// Add copy and open links for 1x, 2x, 3x
|
||||||
auto addImageLink = [&](const ImagePtr &image, char scale) {
|
auto addImageLink = [&](const ImagePtr &image, char scale) {
|
||||||
if (!image->empty()) {
|
if (!image->isEmpty()) {
|
||||||
copyMenu->addAction(
|
copyMenu->addAction(
|
||||||
QString(scale) + "x link", [url = image->url()] {
|
QString(scale) + "x link", [url = image->url()] {
|
||||||
QApplication::clipboard()->setText(url.string);
|
QApplication::clipboard()->setText(url.string);
|
||||||
|
|
|
@ -322,11 +322,11 @@ ChannelPtr LookPage::createPreviewChannel()
|
||||||
{
|
{
|
||||||
MessageBuilder builder;
|
MessageBuilder builder;
|
||||||
builder.emplace<TimestampElement>(QTime(8, 13, 42));
|
builder.emplace<TimestampElement>(QTime(8, 13, 42));
|
||||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.moderator), MessageElementFlag::BadgeChannelAuthority);
|
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.moderator), MessageElementFlag::BadgeChannelAuthority);
|
||||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.subscriber, 0.25), MessageElementFlag::BadgeSubscription);
|
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.subscriber, 0.25), MessageElementFlag::BadgeSubscription);
|
||||||
builder.emplace<TextElement>("username1:", MessageElementFlag::Username, QColor("#0094FF"), FontStyle::ChatMediumBold);
|
builder.emplace<TextElement>("username1:", MessageElementFlag::Username, QColor("#0094FF"), FontStyle::ChatMediumBold);
|
||||||
builder.emplace<TextElement>("This is a preview message", MessageElementFlag::Text);
|
builder.emplace<TextElement>("This is a preview message", MessageElementFlag::Text);
|
||||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->pajaDank, 0.25), MessageElementFlag::AlwaysShow);
|
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->pajaDank, 0.25), MessageElementFlag::AlwaysShow);
|
||||||
builder.emplace<TextElement>("@fourtf", MessageElementFlag::BoldUsername, MessageColor::Text, FontStyle::ChatMediumBold);
|
builder.emplace<TextElement>("@fourtf", MessageElementFlag::BoldUsername, MessageColor::Text, FontStyle::ChatMediumBold);
|
||||||
builder.emplace<TextElement>("@fourtf", MessageElementFlag::NonBoldUsername);
|
builder.emplace<TextElement>("@fourtf", MessageElementFlag::NonBoldUsername);
|
||||||
channel->addMessage(builder.release());
|
channel->addMessage(builder.release());
|
||||||
|
@ -334,7 +334,7 @@ ChannelPtr LookPage::createPreviewChannel()
|
||||||
{
|
{
|
||||||
MessageBuilder message;
|
MessageBuilder message;
|
||||||
message.emplace<TimestampElement>(QTime(8, 15, 21));
|
message.emplace<TimestampElement>(QTime(8, 15, 21));
|
||||||
message.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.broadcaster), MessageElementFlag::BadgeChannelAuthority);
|
message.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.broadcaster), MessageElementFlag::BadgeChannelAuthority);
|
||||||
message.emplace<TextElement>("username2:", MessageElementFlag::Username, QColor("#FF6A00"), FontStyle::ChatMediumBold);
|
message.emplace<TextElement>("username2:", MessageElementFlag::Username, QColor("#FF6A00"), FontStyle::ChatMediumBold);
|
||||||
message.emplace<TextElement>("This is another one", MessageElementFlag::Text);
|
message.emplace<TextElement>("This is another one", MessageElementFlag::Text);
|
||||||
// message.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->ppHop), MessageElementFlag::BttvEmote);
|
// message.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->ppHop), MessageElementFlag::BttvEmote);
|
||||||
|
|
Loading…
Reference in a new issue