Emotes and emojis in webview (cheers not yet), rewriting of some code

This commit is contained in:
Matija 2017-09-30 16:24:23 +02:00
parent bfaf08745e
commit b00f0fcfb7
14 changed files with 178 additions and 353 deletions

View file

@ -53,7 +53,6 @@ SOURCES += \
src/messages/link.cpp \
src/messages/message.cpp \
src/messages/word.cpp \
src/messages/wordpart.cpp \
src/resources.cpp \
src/widgets/chatwidget.cpp \
src/widgets/chatwidgetheader.cpp \
@ -69,7 +68,6 @@ SOURCES += \
src/widgets/settingsdialog.cpp \
src/widgets/settingsdialogtab.cpp \
src/widgets/textinputdialog.cpp \
src/messages/messageref.cpp \
src/logging/loggingmanager.cpp \
src/logging/loggingchannel.cpp \
src/windowmanager.cpp \
@ -109,7 +107,6 @@ HEADERS += \
src/messages/link.hpp \
src/messages/message.hpp \
src/messages/word.hpp \
src/messages/wordpart.hpp \
src/resources.hpp \
src/setting.hpp \
src/twitch/emotevalue.hpp \
@ -132,7 +129,6 @@ HEADERS += \
src/settingssnapshot.hpp \
src/messages/limitedqueue.hpp \
src/messages/limitedqueuesnapshot.hpp \
src/messages/messageref.hpp \
src/logging/loggingmanager.hpp \
src/logging/loggingchannel.hpp \
src/channelmanager.hpp \

View file

@ -46,11 +46,6 @@
</div>
</div>
<script type="text/html" id="messageTemplate">
<div class="chat-element chat-textual">
<span style="color: blue;" class="chat-username">{{username}}</span>:
</div>
</script>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script>
@ -62,14 +57,13 @@
})
};
function addMessage(username, color, ...parts) {
function addMessage(...parts) {
let main = $('<div>');
let tmpl = $('#messageTemplate').html();
main.html(tmpl);
for (let part of parts) {
if (part.type === 'text') {
let msg = $('<div class="chat-element chat-textual"></div>');
msg.css('color', part.color);
msg.html(part.data);
main.append(msg);
} else if (part.type === 'emote') {
@ -82,6 +76,10 @@
window.scrollTo(0, document.body.scrollHeight);
}
function clearMessages() {
$('#chat').empty();
}
function test() {
if (CHANNEL) CHANNEL.objects.test.testMethod();
}

View file

@ -19,7 +19,6 @@ using namespace chatterino::messages;
namespace chatterino {
Channel::Channel()
// , loggingChannel(logging::get(name))
{
}
@ -37,10 +36,6 @@ void Channel::addMessage(std::shared_ptr<Message> message)
{
std::shared_ptr<Message> deleted;
// if (_loggingChannel.get() != nullptr) {
// _loggingChannel->append(message);
// }
if (this->messages.appendItem(message, deleted)) {
messageRemovedFromStart(deleted);
}

View file

@ -14,7 +14,7 @@
#include <memory>
#define TWITCH_EMOTE_TEMPLATE "https://static-cdn.jtvnw.net/emoticons/v1/{id}/{scale}.0"
#define TWITCH_EMOTE_TEMPLATE "https://static-cdn.jtvnw.net/emoticons/v1/%1/%2.0"
using namespace chatterino::messages;
@ -67,13 +67,9 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, std::weak
QString link = linkTemplate;
link.detach();
link.replace("{{id}}", id).replace("{{image}}", "1x");
link = link.replace("{{id}}", id).replace("{{image}}", "1x");
auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] {
return EmoteData(new LazyLoadedImage(*this, this->windowManager, link, 1, code,
code + "\nChannel BTTV Emote"));
});
Emote emote(code, link, channelName);
this->bttvChannelEmotes.insert(code, emote);
map->insert(code, emote);
@ -115,11 +111,7 @@ void EmoteManager::reloadFFZChannelEmotes(const QString &channelName, std::weak_
QJsonObject urls = emoteObject.value("urls").toObject();
QString url1 = "http:" + urls.value("1").toString();
auto emote =
this->getFFZChannelEmoteFromCaches().getOrAdd(id, [this, &code, &url1] {
return EmoteData(new LazyLoadedImage(*this, this->windowManager, url1, 1,
code, code + "\nGlobal FFZ Emote"));
});
Emote emote(code, url1, channelName);
this->ffzChannelEmotes.insert(code, emote);
map->insert(code, emote);
@ -146,26 +138,11 @@ EmoteMap &EmoteManager::getChatterinoEmotes()
return _chatterinoEmotes;
}
EmoteMap &EmoteManager::getBTTVChannelEmoteFromCaches()
{
return _bttvChannelEmoteFromCaches;
}
EmoteMap &EmoteManager::getEmojis()
{
return this->emojis;
}
ConcurrentMap<int, EmoteData> &EmoteManager::getFFZChannelEmoteFromCaches()
{
return _ffzChannelEmoteFromCaches;
}
ConcurrentMap<long, EmoteData> &EmoteManager::getTwitchEmoteFromCache()
{
return _twitchEmoteFromCache;
}
void EmoteManager::loadEmojis()
{
QFile file(":/emojidata.txt");
@ -203,9 +180,9 @@ void EmoteManager::loadEmojis()
}
EmojiData emojiData{
QString::fromUcs4(unicodeBytes, numUnicodeBytes), //
code, //
shortCode, //
QString::fromUcs4(unicodeBytes, numUnicodeBytes),
code,
shortCode,
};
this->emojiShortCodeToEmoji.insert(shortCode, emojiData);
@ -217,16 +194,15 @@ void EmoteManager::loadEmojis()
"emojione/2.2.6/assets/png/" +
code + ".png";
this->emojis.insert(code,
EmoteData(new LazyLoadedImage(*this, this->windowManager, url, 0.35)));
this->emojis.insert(code, Emote(code, url));
// TODO(pajlada): The vectors in emojiFirstByte need to be sorted by
// emojiData.code.length()
}
}
void EmoteManager::parseEmojis(std::vector<std::tuple<EmoteData, QString>> &parsedWords,
const QString &text)
void EmoteManager::parseEmojis(
std::vector<std::tuple<std::unique_ptr<Emote>, QString>> &parsedWords, const QString &text)
{
int lastParsedEmojiEndIndex = 0;
@ -286,8 +262,9 @@ void EmoteManager::parseEmojis(std::vector<std::tuple<EmoteData, QString>> &pars
if (charactersFromLastParsedEmoji > 0) {
// Add characters inbetween emojis
parsedWords.push_back(std::tuple<messages::LazyLoadedImage *, QString>(
nullptr, text.mid(lastParsedEmojiEndIndex, charactersFromLastParsedEmoji)));
parsedWords.push_back(std::tuple<std::unique_ptr<Emote>, QString>(
std::unique_ptr<Emote>(nullptr),
text.mid(lastParsedEmojiEndIndex, charactersFromLastParsedEmoji)));
}
QString url = "https://cdnjs.cloudflare.com/ajax/libs/"
@ -295,12 +272,11 @@ void EmoteManager::parseEmojis(std::vector<std::tuple<EmoteData, QString>> &pars
matchedEmoji.code + ".png";
// Create or fetch cached emoji image
auto emojiImage = this->emojiCache.getOrAdd(url, [this, &url] {
return EmoteData(new LazyLoadedImage(*this, this->windowManager, url, 0.35)); //
});
Emote *emojiImage = new Emote(url, "");
// Push the emoji as a word to parsedWords
parsedWords.push_back(std::tuple<EmoteData, QString>(emojiImage, QString()));
parsedWords.push_back(std::tuple<std::unique_ptr<Emote>, QString>(
std::unique_ptr<Emote>(emojiImage), QString()));
lastParsedEmojiEndIndex = currentParsedEmojiEndIndex;
@ -309,8 +285,8 @@ void EmoteManager::parseEmojis(std::vector<std::tuple<EmoteData, QString>> &pars
if (lastParsedEmojiEndIndex < text.length()) {
// Add remaining characters
parsedWords.push_back(std::tuple<messages::LazyLoadedImage *, QString>(
nullptr, text.mid(lastParsedEmojiEndIndex)));
parsedWords.push_back(std::tuple<std::unique_ptr<Emote>, QString>(
std::unique_ptr<Emote>(nullptr), text.mid(lastParsedEmojiEndIndex)));
}
}
@ -420,15 +396,12 @@ void EmoteManager::loadBTTVEmotes()
for (const QJsonValue &emote : emotes) {
QString id = emote.toObject().value("id").toString();
QString code = emote.toObject().value("code").toString();
// emote.value("imageType").toString();
QString tmp = linkTemplate;
tmp.detach();
QString url = tmp.replace("{{id}}", id).replace("{{image}}", "1x");
QString url = linkTemplate;
url.detach();
url.replace("{{id}}", id).replace("{{image}}", "1x");
this->bttvGlobalEmotes.insert(
code, new LazyLoadedImage(*this, this->windowManager, url, 1, code,
code + "\nGlobal BTTV Emote"));
this->bttvGlobalEmotes.insert(code, Emote(code, url));
codes.push_back(code.toStdString());
}
@ -472,9 +445,7 @@ void EmoteManager::loadFFZEmotes()
QJsonObject urls = object.value("urls").toObject();
QString url1 = "http:" + urls.value("1").toString();
this->ffzGlobalEmotes.insert(
code, new LazyLoadedImage(*this, this->windowManager, url1, 1, code,
code + "\nGlobal FFZ Emote"));
this->ffzGlobalEmotes.insert(code, Emote(code, url1));
codes.push_back(code.toStdString());
}
@ -489,32 +460,34 @@ void EmoteManager::loadFFZEmotes()
// id is used for lookup
// emoteName is used for giving a name to the emote in case it doesn't exist
EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteName)
Emote EmoteManager::getTwitchEmoteById(long id, const QString &emoteName)
{
return _twitchEmoteFromCache.getOrAdd(id, [this, &emoteName, &id] {
qDebug() << "added twitch emote: " << id;
qreal scale;
QString url = getTwitchEmoteLink(id, scale);
return new LazyLoadedImage(*this, this->windowManager, url, scale, emoteName,
emoteName + "\nTwitch Emote");
});
qreal scale;
QString url = getTwitchEmoteLink(id, scale);
return Emote(emoteName, url);
}
QString EmoteManager::getTwitchEmoteLink(long id, qreal &scale)
{
scale = .5;
QString value = TWITCH_EMOTE_TEMPLATE;
QString value(TWITCH_EMOTE_TEMPLATE);
value.detach();
return value.replace("{id}", QString::number(id)).replace("{scale}", "2");
return value.arg(QString::number(id), "1");
}
EmoteData EmoteManager::getCheerImage(long long amount, bool animated)
Emote EmoteManager::getCheerImage(long long amount, bool animated)
{
// TODO: Implement cheers
}
Emote::Emote(const QString &emoteName, const QString &emoteUrl, const QString &emoteChannel,
const QString &emoteCreator)
: name(emoteName)
, url(emoteUrl)
, channel(emoteChannel)
, creator(emoteCreator)
{
// TODO: fix this xD
return EmoteData();
}
} // namespace chatterino

View file

@ -19,20 +19,26 @@ namespace chatterino {
class WindowManager;
struct EmoteData {
EmoteData()
{
}
class Emote
{
public:
Emote() = default;
EmoteData(messages::LazyLoadedImage *_image)
: image(_image)
{
}
/**
* @param emoteName name of the emote (what chatter writes in chat)
* @param emoteChannel name of the channel which possesses this emote
* @param emoteCreator name of the user (FFZ / BTTV) who made this emote
*/
Emote(const QString &emoteName, const QString &emoteUrl, const QString &emoteChannel = "",
const QString &emoteCreator = "");
messages::LazyLoadedImage *image = nullptr;
QString name;
QString url;
QString channel;
QString creator;
};
typedef ConcurrentMap<QString, EmoteData> EmoteMap;
typedef ConcurrentMap<QString, Emote> EmoteMap;
class EmoteManager
{
@ -49,14 +55,11 @@ public:
ConcurrentMap<QString, twitch::EmoteValue *> &getTwitchEmotes();
EmoteMap &getFFZEmotes();
EmoteMap &getChatterinoEmotes();
EmoteMap &getBTTVChannelEmoteFromCaches();
EmoteMap &getEmojis();
ConcurrentMap<int, EmoteData> &getFFZChannelEmoteFromCaches();
ConcurrentMap<long, EmoteData> &getTwitchEmoteFromCache();
EmoteData getCheerImage(long long int amount, bool animated);
Emote getCheerImage(long long int amount, bool animated);
EmoteData getTwitchEmoteById(long int id, const QString &emoteName);
Emote getTwitchEmoteById(long int id, const QString &emoteName);
int getGeneration()
{
@ -90,7 +93,8 @@ private:
void loadEmojis();
public:
void parseEmojis(std::vector<std::tuple<EmoteData, QString>> &parsedWords, const QString &text);
void parseEmojis(std::vector<std::tuple<std::unique_ptr<Emote>, QString>> &parsedWords,
const QString &text);
QString replaceShortCodes(const QString &text);
@ -119,9 +123,6 @@ private:
// emote code
ConcurrentMap<QString, twitch::EmoteValue *> _twitchEmotes;
// emote id
ConcurrentMap<long, EmoteData> _twitchEmoteFromCache;
/// BTTV emotes
EmoteMap bttvChannelEmotes;
@ -146,8 +147,6 @@ public:
std::map<std::string, SignalVector<std::string>> ffzChannelEmoteCodes;
private:
ConcurrentMap<int, EmoteData> _ffzChannelEmoteFromCaches;
void loadFFZEmotes();
/// Chatterino emotes

View file

@ -42,13 +42,13 @@ void MessageBuilder::appendTimestamp(time_t time)
strftime(timeStampBuffer, 69, "%H:%M", localtime(&time));
QString timestampNoSeconds(timeStampBuffer);
this->appendWord(Word(timestampNoSeconds, Word::TimestampNoSeconds,
MessageColor(MessageColor::System), QString(), QString()));
MessageColor(MessageColor::System), QString()));
// Add word for timestamp with seconds
strftime(timeStampBuffer, 69, "%H:%M:%S", localtime(&time));
QString timestampWithSeconds(timeStampBuffer);
this->appendWord(Word(timestampWithSeconds, Word::TimestampWithSeconds,
MessageColor(MessageColor::System), QString(), QString()));
MessageColor(MessageColor::System), QString()));
}
QString MessageBuilder::matchLink(const QString &string)

View file

@ -4,35 +4,30 @@ namespace chatterino {
namespace messages {
// Image word
Word::Word(LazyLoadedImage *image, Type type, const QString &copytext, const QString &tooltip,
const Link &link)
: image(image)
Word::Word(const QString &imageURL, Type type, const QString &tooltip, const Link &link)
: imageURL(imageURL)
, _isImage(true)
, type(type)
, copyText(copytext)
, tooltip(tooltip)
, link(link)
{
image->getWidth(); // professional segfault test
}
// Text word
Word::Word(const QString &text, Type type, const MessageColor &color, const QString &copytext,
const QString &tooltip, const Link &link)
: image(nullptr)
, text(text)
Word::Word(const QString &text, Type type, const MessageColor &color, const QString &tooltip,
const Link &link)
: text(text)
, color(color)
, _isImage(false)
, type(type)
, copyText(copytext)
, tooltip(tooltip)
, link(link)
{
}
LazyLoadedImage &Word::getImage() const
const QString &Word::getImageURL() const
{
return *this->image;
return this->imageURL;
}
const QString &Word::getText() const
@ -40,22 +35,6 @@ const QString &Word::getText() const
return this->text;
}
int Word::getWidth() const
{
return this->width;
}
int Word::getHeight() const
{
return this->height;
}
void Word::setSize(int width, int height)
{
this->width = width;
this->height = height;
}
bool Word::isImage() const
{
return this->_isImage;
@ -71,21 +50,6 @@ const QString &Word::getCopyText() const
return this->copyText;
}
bool Word::hasTrailingSpace() const
{
return this->_hasTrailingSpace;
}
QFont &Word::getFont() const
{
return FontManager::getInstance().getFont(this->font);
}
QFontMetrics &Word::getFontMetrics() const
{
return FontManager::getInstance().getFontMetrics(this->font);
}
Word::Type Word::getType() const
{
return this->type;
@ -106,46 +70,5 @@ const Link &Word::getLink() const
return this->link;
}
int Word::getXOffset() const
{
return this->xOffset;
}
int Word::getYOffset() const
{
return this->yOffset;
}
void Word::setOffset(int xOffset, int yOffset)
{
this->xOffset = std::max(0, xOffset);
this->yOffset = std::max(0, yOffset);
}
int Word::getCharacterLength() const
{
return this->isImage() ? 2 : this->getText().length() + 1;
}
const QString &Word::getEmoteURL() const
{
return emoteURL;
}
std::vector<short> &Word::getCharacterWidthCache() const
{
// lock not required because there is only one gui thread
// std::lock_guard<std::mutex> lock(this->charWidthCacheMutex);
if (this->charWidthCache.size() == 0 && this->isText()) {
for (int i = 0; i < this->getText().length(); i++) {
this->charWidthCache.push_back(this->getFontMetrics().charWidth(this->getText(), i));
}
}
// TODO: on font change
return this->charWidthCache;
}
} // namespace messages
} // namespace chatterino

View file

@ -89,56 +89,32 @@ public:
{
}
explicit Word(LazyLoadedImage *_image, Type getType, const QString &copytext,
const QString &getTooltip, const Link &getLink = Link());
explicit Word(const QString &imageURL, Type getType, const QString &getTooltip,
const Link &getLink = Link());
explicit Word(const QString &_text, Type getType, const MessageColor &getColor,
const QString &copytext, const QString &getTooltip, const Link &getLink = Link());
const QString &getTooltip, const Link &getLink = Link());
LazyLoadedImage &getImage() const;
const QString &getImageURL() const;
const QString &getText() const;
int getWidth() const;
int getHeight() const;
void setSize(int _width, int _height);
bool isImage() const;
bool isText() const;
const QString &getCopyText() const;
bool hasTrailingSpace() const;
QFont &getFont() const;
QFontMetrics &getFontMetrics() const;
Type getType() const;
const QString &getTooltip() const;
const MessageColor &getColor() const;
const Link &getLink() const;
int getXOffset() const;
int getYOffset() const;
void setOffset(int _xOffset, int _yOffset);
int getCharacterLength() const;
const QString &getEmoteURL() const;
std::vector<short> &getCharacterWidthCache() const;
private:
LazyLoadedImage *image;
QString imageURL;
QString text;
MessageColor color;
bool _isImage;
QString emoteURL;
Type type;
QString copyText;
QString tooltip;
int width = 16;
int height = 16;
int xOffset = 0;
int yOffset = 0;
bool _hasTrailingSpace = true;
FontManager::Type font = FontManager::Medium;
Link link;
mutable std::vector<short> charWidthCache;
};
} // namespace messages

View file

@ -1,4 +1,4 @@
#include "twitch/twitchmessagebuilder.hpp"
#include "twitch/twitchmessagebuilder.hpp"
#include "colorscheme.hpp"
#include "debug/log.hpp"
#include "emotemanager.hpp"
@ -52,9 +52,11 @@ SharedMessage TwitchMessageBuilder::parse()
this->appendModerationButtons();
/*
this->parseTwitchBadges();
this->parseChatterinoBadges();
*/
if (this->args.includeChannelName) {
this->parseChannelName();
@ -76,7 +78,7 @@ SharedMessage TwitchMessageBuilder::parse()
}
// twitch emotes
std::vector<std::pair<long, EmoteData>> twitchEmotes;
std::vector<std::pair<long, Emote>> twitchEmotes;
iterator = this->tags.find("emotes");
if (iterator != this->tags.end()) {
@ -87,8 +89,7 @@ SharedMessage TwitchMessageBuilder::parse()
}
struct {
bool operator()(const std::pair<long, EmoteData> &lhs,
const std::pair<long, EmoteData> &rhs)
bool operator()(const std::pair<long, Emote> &lhs, const std::pair<long, Emote> &rhs)
{
return lhs.first < rhs.first;
}
@ -111,14 +112,10 @@ SharedMessage TwitchMessageBuilder::parse()
// twitch emote
if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) {
this->appendWord(
Word(currentTwitchEmote->second.image, Word::TwitchEmoteImage,
currentTwitchEmote->second.image->getName(),
currentTwitchEmote->second.image->getName() + QString("\nTwitch Emote")));
this->appendWord(
Word(currentTwitchEmote->second.image->getName(), Word::TwitchEmoteText, textColor,
currentTwitchEmote->second.image->getName(),
currentTwitchEmote->second.image->getName() + QString("\nTwitch Emote")));
this->appendWord(Word(currentTwitchEmote->second.url, Word::TwitchEmoteImage,
currentTwitchEmote->second.name));
/*this->appendWord(Word(currentTwitchEmote->second.url, Word::TwitchEmoteText,
textColor, currentTwitchEmote->second.name));*/
i += split.length() + 1;
currentTwitchEmote = std::next(currentTwitchEmote);
@ -127,15 +124,15 @@ SharedMessage TwitchMessageBuilder::parse()
}
// split words
std::vector<std::tuple<EmoteData, QString>> parsed;
std::vector<std::tuple<std::unique_ptr<Emote>, QString>> parsed;
// Parse emojis and take all non-emojis and put them in parsed as full text-words
emoteManager.parseEmojis(parsed, split);
for (const auto &tuple : parsed) {
const EmoteData &emoteData = std::get<0>(tuple);
for (const std::tuple<std::unique_ptr<Emote>, QString> &tuple : parsed) {
Emote *emote = std::get<0>(tuple).get();
if (emoteData.image == nullptr) { // is text
if (emote == nullptr) { // is text
QString string = std::get<1>(tuple);
static QRegularExpression cheerRegex("cheer[1-9][0-9]*");
@ -170,31 +167,20 @@ SharedMessage TwitchMessageBuilder::parse()
QString bitsLink =
QString("http://static-cdn.jtvnw.net/bits/dark/static/" + color + "/1");
LazyLoadedImage *imageAnimated = emoteManager.miscImageCache.getOrAdd(
bitsLinkAnimated, [this, &bitsLinkAnimated] {
return new LazyLoadedImage(this->emoteManager, this->windowManager,
bitsLinkAnimated);
});
LazyLoadedImage *image =
emoteManager.miscImageCache.getOrAdd(bitsLink, [this, &bitsLink] {
return new LazyLoadedImage(this->emoteManager, this->windowManager,
bitsLink);
});
this->appendWord(Word(imageAnimated, Word::BitsAnimated, QString("cheer"),
this->appendWord(Word(bitsLinkAnimated, Word::BitsAnimated,
QString("Twitch Cheer"),
Link(Link::Url, QString("https://blog.twitch.tv/"
"introducing-cheering-celebrate-"
"together-da62af41fac6"))));
this->appendWord(Word(
image, Word::BitsStatic, QString("cheer"), QString("Twitch Cheer"),
bitsLink, Word::BitsStatic, QString("Twitch Cheer"),
Link(Link::Url,
QString("https://blog.twitch.tv/"
"introducing-cheering-celebrate-together-da62af41fac6"))));
this->appendWord(Word(
QString("x" + string.mid(5)), Word::BitsAmount, MessageColor(bitsColor),
QString(string.mid(5)), QString("Twitch Cheer"),
QString("Twitch Cheer"),
Link(Link::Url,
QString("https://blog.twitch.tv/"
"introducing-cheering-celebrate-together-da62af41fac6"))));
@ -224,14 +210,13 @@ SharedMessage TwitchMessageBuilder::parse()
textColor = MessageColor(MessageColor::Link);
}
this->appendWord(Word(string, Word::Text, textColor, string, QString(), link));
this->appendWord(Word(string, Word::Text, textColor, string, link));
} else { // is emoji
static QString emojiTooltip("Emoji");
this->appendWord(Word(emoteData.image, Word::EmojiImage, emoteData.image->getName(),
emojiTooltip));
Word(emoteData.image->getName(), Word::EmojiText, textColor,
emoteData.image->getName(), emojiTooltip);
this->appendWord(Word(emote->url, Word::EmojiImage, emojiTooltip));
/*Word(emoteData.image->getName(), Word::EmojiText, textColor,
emoteData.image->getName(), emojiTooltip);*/
}
}
@ -275,7 +260,7 @@ void TwitchMessageBuilder::parseChannelName()
{
QString channelName("#" + this->channel->name);
this->appendWord(Word(channelName, Word::Misc, MessageColor(MessageColor::System),
QString(channelName), QString(),
QString(channelName),
Link(Link::Url, this->channel->name + "\n" + this->messageID)));
}
@ -356,7 +341,7 @@ void TwitchMessageBuilder::appendUsername()
}
this->appendWord(Word(usernameString, Word::Username, MessageColor(this->usernameColor),
usernameString, QString(), Link(Link::UserInfo, this->userName)));
usernameString, Link(Link::UserInfo, this->userName)));
}
void TwitchMessageBuilder::parseHighlights()
@ -450,18 +435,22 @@ void TwitchMessageBuilder::parseHighlights()
void TwitchMessageBuilder::appendModerationButtons()
{
// mod buttons
static QString buttonBanTooltip("Ban user");
static QString buttonTimeoutTooltip("Timeout user");
this->appendWord(Word(this->resources.buttonBan, Word::ButtonBan, QString(), buttonBanTooltip,
Link(Link::UserBan, ircMessage->account())));
this->appendWord(Word(this->resources.buttonTimeout, Word::ButtonTimeout, QString(),
buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account())));
// TODO: Implement ban buttons
/*
this->appendWord(Word(this->resources.buttonBan->getUrl(), Word::ButtonBan, QString(),
buttonBanTooltip, Link(Link::UserBan, ircMessage->account())));
this->appendWord(Word(this->resources.buttonTimeout->getUrl(), Word::ButtonTimeout,
QString(), buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account())));
*/
}
void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage,
const QString &emote,
std::vector<std::pair<long int, EmoteData>> &vec,
std::vector<std::pair<long, Emote>> &vec,
EmoteManager &emoteManager)
{
if (!emote.contains(':')) {
@ -494,45 +483,43 @@ void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcPrivateMessage *i
QString name = ircMessage->content().mid(start, end - start + 1);
vec.push_back(
std::pair<long int, EmoteData>(start, emoteManager.getTwitchEmoteById(id, name)));
vec.push_back(std::pair<long, Emote>(start, emoteManager.getTwitchEmoteById(id, name)));
}
}
bool TwitchMessageBuilder::tryAppendEmote(QString &emoteString)
{
EmoteData emoteData;
Emote emote;
if (emoteManager.bttvGlobalEmotes.tryGet(emoteString, emoteData)) {
if (emoteManager.bttvGlobalEmotes.tryGet(emoteString, emote)) {
// BTTV Global Emote
return this->appendEmote(emoteData);
} else if (this->twitchChannel->bttvChannelEmotes->tryGet(emoteString, emoteData)) {
return this->appendEmote(emote);
} else if (this->twitchChannel->bttvChannelEmotes->tryGet(emoteString, emote)) {
// BTTV Channel Emote
return this->appendEmote(emoteData);
} else if (emoteManager.ffzGlobalEmotes.tryGet(emoteString, emoteData)) {
return this->appendEmote(emote);
} else if (emoteManager.ffzGlobalEmotes.tryGet(emoteString, emote)) {
// FFZ Global Emote
return this->appendEmote(emoteData);
} else if (this->twitchChannel->ffzChannelEmotes->tryGet(emoteString, emoteData)) {
return this->appendEmote(emote);
} else if (this->twitchChannel->ffzChannelEmotes->tryGet(emoteString, emote)) {
// FFZ Channel Emote
return this->appendEmote(emoteData);
} else if (emoteManager.getChatterinoEmotes().tryGet(emoteString, emoteData)) {
return this->appendEmote(emote);
} else if (emoteManager.getChatterinoEmotes().tryGet(emoteString, emote)) {
// Chatterino Emote
return this->appendEmote(emoteData);
return this->appendEmote(emote);
}
return false;
}
bool TwitchMessageBuilder::appendEmote(EmoteData &emoteData)
bool TwitchMessageBuilder::appendEmote(Emote &emote)
{
this->appendWord(Word(emoteData.image, Word::BttvEmoteImage, emoteData.image->getName(),
emoteData.image->getTooltip(),
Link(Link::Url, emoteData.image->getUrl())));
this->appendWord(Word(emote.url, Word::EmoteImages, emote.name, Link(Link::Url, emote.url)));
// Perhaps check for ignored emotes here?
return true;
}
/*
void TwitchMessageBuilder::parseTwitchBadges()
{
const auto &channelResources = this->resources.channels[this->roomID];
@ -567,7 +554,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
auto &badgeVersion = badgeSet.versions.at(versionKey);
appendWord(
Word(badgeVersion.badgeImage1x, Word::BadgeVanity, QString(),
Word(badgeVersion.badgeImage1x, Word::BadgeVanity,
QString("Twitch " + QString::fromStdString(badgeVersion.title))));
} catch (const std::exception &e) {
debug::Log("Exception caught: {} when trying to fetch badge version {}",
@ -577,34 +564,34 @@ void TwitchMessageBuilder::parseTwitchBadges()
debug::Log("No badge set with key bits. Exception: {}", e.what());
}
} else if (badge == "staff/1") {
appendWord(Word(this->resources.badgeStaff, Word::BadgeGlobalAuthority, QString(),
appendWord(Word(this->resources.badgeStaff, Word::BadgeGlobalAuthority,
QString("Twitch Staff")));
} else if (badge == "admin/1") {
appendWord(Word(this->resources.badgeAdmin, Word::BadgeGlobalAuthority, QString(),
appendWord(Word(this->resources.badgeAdmin, Word::BadgeGlobalAuthority,
QString("Twitch Admin")));
} else if (badge == "global_mod/1") {
appendWord(Word(this->resources.badgeGlobalModerator, Word::BadgeGlobalAuthority,
QString(), QString("Global Moderator")));
QString("Global Moderator")));
} else if (badge == "moderator/1") {
// TODO: Implement custom FFZ moderator badge
appendWord(Word(this->resources.badgeModerator, Word::BadgeChannelAuthority, QString(),
appendWord(Word(this->resources.badgeModerator, Word::BadgeChannelAuthority,
QString("Channel Moderator"))); // custom badge
} else if (badge == "turbo/1") {
appendWord(Word(this->resources.badgeTurbo, Word::BadgeVanity, QString(),
QString("Turbo Subscriber")));
appendWord(
Word(this->resources.badgeTurbo, Word::BadgeVanity, QString("Turbo Subscriber")));
} else if (badge == "broadcaster/1") {
appendWord(Word(this->resources.badgeBroadcaster, Word::BadgeChannelAuthority,
QString(), QString("Channel Broadcaster")));
QString("Channel Broadcaster")));
} else if (badge == "premium/1") {
appendWord(Word(this->resources.badgePremium, Word::BadgeVanity, QString(),
appendWord(Word(this->resources.badgePremium, Word::BadgeVanity),
QString("Twitch Prime")));
} else if (badge.startsWith("partner/")) {
int index = badge.midRef(8).toInt();
switch (index) {
case 1: {
appendWord(Word(this->resources.badgeVerified, Word::BadgeVanity, QString(),
"Twitch Verified"));
appendWord(
Word(this->resources.badgeVerified, Word::BadgeVanity, "Twitch Verified"));
} break;
default: {
printf("[TwitchMessageBuilder] Unhandled partner badge index: %d\n", index);
@ -625,7 +612,7 @@ void TwitchMessageBuilder::parseTwitchBadges()
auto &badgeVersion = badgeSet.versions.at(versionKey);
appendWord(
Word(badgeVersion.badgeImage1x, Word::Type::BadgeSubscription, QString(),
Word(badgeVersion.badgeImage1x, Word::Type::BadgeSubscription,
QString("Twitch " + QString::fromStdString(badgeVersion.title))));
} catch (const std::exception &e) {
qDebug() << "Exception caught:" << e.what()
@ -673,7 +660,9 @@ void TwitchMessageBuilder::parseTwitchBadges()
}
}
}
*/
/*
void TwitchMessageBuilder::parseChatterinoBadges()
{
auto &badges = this->resources.chatterinoBadges;
@ -687,6 +676,7 @@ void TwitchMessageBuilder::parseChatterinoBadges()
this->appendWord(Word(badge->image, Word::BadgeChatterino, QString(), badge->tooltip.c_str()));
}
*/
// bool
// sortTwitchEmotes(const std::pair<long int, LazyLoadedImage *> &a,

View file

@ -66,13 +66,14 @@ private:
void appendModerationButtons();
void appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, const QString &emote,
std::vector<std::pair<long, EmoteData>> &vec,
EmoteManager &emoteManager);
std::vector<std::pair<long, Emote>> &vec, EmoteManager &emoteManager);
bool tryAppendEmote(QString &emoteString);
bool appendEmote(EmoteData &emoteData);
bool appendEmote(Emote &emote);
/* TODO: Implement badges
void parseTwitchBadges();
void parseChatterinoBadges();
*/
};
} // namespace twitch

View file

@ -3,13 +3,13 @@
#include "colorscheme.hpp"
#include "messages/limitedqueuesnapshot.hpp"
#include "messages/message.hpp"
#include "messages/messageref.hpp"
#include "settingsmanager.hpp"
#include "ui_accountpopupform.h"
#include "util/distancebetweenpoints.hpp"
#include "widgets/chatwidget.hpp"
#include "windowmanager.hpp"
#include <QColor>
#include <QDebug>
#include <QDesktopServices>
#include <QGraphicsBlurEffect>
@ -45,12 +45,32 @@ ChannelView::~ChannelView()
void ChannelView::clearMessages()
{
this->messages.clear();
web.page()->runJavaScript("clearMessages()");
}
messages::LimitedQueueSnapshot<SharedMessageRef> ChannelView::getMessagesSnapshot()
void ChannelView::addMessage(SharedMessage &message)
{
return this->messages.getSnapshot();
auto command = QString("addMessage(");
for (int i = 0; i < message->getWords().size(); i++) {
auto word = message->getWords()[i];
if (word.isText()) {
if (i != 0)
command += ",";
command += QString("{type:'text', data:'%1', color: '%2'}")
.arg(word.getText(), word.getColor().getColor(this->colorScheme).name());
} else {
if (word.getType() == messages::Word::Type::Badges) {
// command += "{type:'emote', data:'" + word.+ "'}";
} else if (word.getType() | messages::Word::Type::EmoteImages) {
if (i != 0)
command += ",";
command += "{type:'emote', data:'" + word.getImageURL() + "'}";
}
}
}
command += ");";
qDebug() << command;
web.page()->runJavaScript(command);
}
void ChannelView::setChannel(std::shared_ptr<Channel> channel)
@ -58,49 +78,11 @@ void ChannelView::setChannel(std::shared_ptr<Channel> channel)
if (this->channel) {
this->detachChannel();
}
this->messages.clear();
this->clearMessages();
// on new message
this->messageAppendedConnection =
channel->messageAppended.connect([this](SharedMessage &message) {
// SharedMessageRef deleted;
auto command = QString("addMessage('%1','%2'").arg("", "");
for (const auto &word : message->getWords()) {
command += ",";
if (word.isText()) {
command += "{type:'text', data:'" + word.getText() + "'}";
} else {
command += "{type:'emote', data:'" + word.getEmoteURL() + "'}";
}
}
command += ");";
qDebug() << command;
web.page()->runJavaScript(command);
/*if (this->messages.appendItem(SharedMessageRef(messageRef), deleted)) {
qreal value = std::max(0.0, this->getScrollBar().getDesiredValue() - 1);
this->getScrollBar().setDesiredValue(value, false);
}*/
// layoutMessages();
// update();
});
// on message removed
this->messageRemovedConnection =
channel->messageRemovedFromStart.connect([](SharedMessage &) {});
auto snapshot = channel->getMessageSnapshot();
for (size_t i = 0; i < snapshot.getLength(); i++) {
SharedMessageRef deleted;
auto messageRef = new MessageRef(snapshot[i]);
this->messages.appendItem(SharedMessageRef(messageRef), deleted);
}
this->messageAppendedConnection = channel->messageAppended.connect(boost::bind(
&ChannelView::addMessage, this, _1)); // Has to use boost::bind for some reason.
this->channel = channel;
@ -111,9 +93,6 @@ void ChannelView::detachChannel()
{
// on message added
this->messageAppendedConnection.disconnect();
// on message removed
this->messageRemovedConnection.disconnect();
}
} // namespace widgets

View file

@ -3,7 +3,6 @@
#include "channel.hpp"
#include "messages/lazyloadedimage.hpp"
#include "messages/limitedqueuesnapshot.hpp"
#include "messages/messageref.hpp"
#include "messages/word.hpp"
#include "widgets/accountpopup.hpp"
#include "widgets/basewidget.hpp"
@ -30,7 +29,7 @@ public:
~ChannelView();
void setChannel(std::shared_ptr<Channel> channel);
messages::LimitedQueueSnapshot<messages::SharedMessageRef> getMessagesSnapshot();
void addMessage(messages::SharedMessage &message);
void clearMessages();
@ -50,10 +49,7 @@ private:
AccountPopupWidget userPopupWidget;
messages::LimitedQueue<messages::SharedMessageRef> messages;
boost::signals2::connection messageAppendedConnection;
boost::signals2::connection messageRemovedConnection;
QWebEngineView web;
QVBoxLayout vbox;
};

View file

@ -2,9 +2,7 @@
#include "channel.hpp"
#include "messages/limitedqueuesnapshot.hpp"
#include "messages/messageref.hpp"
#include "messages/word.hpp"
#include "messages/wordpart.hpp"
#include "widgets/basewidget.hpp"
#include "widgets/channelview.hpp"
#include "widgets/chatwidgetheader.hpp"

View file

@ -41,7 +41,7 @@ void EmotePopup::loadChannel(std::shared_ptr<Channel> _channel)
messages::MessageBuilder builder1;
builder1.appendWord(
Word(title, Word::Type::Text, MessageColor(MessageColor::Text), QString(), QString()));
Word(title, Word::Type::Text, MessageColor(MessageColor::Text), QString()));
builder1.getMessage()->centered = true;
emoteChannel->addMessage(builder1.getMessage());
@ -50,11 +50,12 @@ void EmotePopup::loadChannel(std::shared_ptr<Channel> _channel)
messages::MessageBuilder builder2;
builder2.getMessage()->centered = true;
map.each([&](const QString &key, const EmoteData &value) {
builder2.appendWord(Word(value.image, Word::Type::AlwaysShow, key, emoteDesc,
/*
map.each([&](const QString &key, const QString &value) {
builder2.appendWord(Word(value, Word::Type::AlwaysShow, key, emoteDesc,
Link(Link::Type::InsertText, key)));
});
*/
emoteChannel->addMessage(builder2.getMessage());
};