Merge branch 'master' into logging
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
#include "singletons/accountmanager.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
void AccountManager::load()
|
||||
{
|
||||
this->Twitch.load();
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "providers/twitch/twitchaccountmanager.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
class AccountManager
|
||||
{
|
||||
public:
|
||||
AccountManager() = default;
|
||||
|
||||
~AccountManager() = delete;
|
||||
|
||||
void load();
|
||||
|
||||
providers::twitch::TwitchAccountManager Twitch;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
@@ -86,8 +86,8 @@ EmoteManager::EmoteManager()
|
||||
|
||||
void EmoteManager::initialize()
|
||||
{
|
||||
getApp()->accounts->Twitch.currentUserChanged.connect([this] {
|
||||
auto currentUser = getApp()->accounts->Twitch.getCurrent();
|
||||
getApp()->accounts->twitch.currentUserChanged.connect([this] {
|
||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||
assert(currentUser);
|
||||
this->refreshTwitchEmotes(currentUser);
|
||||
});
|
||||
@@ -130,13 +130,23 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName,
|
||||
QString code = emoteObject.value("code").toString();
|
||||
// emoteObject.value("imageType").toString();
|
||||
|
||||
QString link = linkTemplate;
|
||||
link.detach();
|
||||
auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [&] {
|
||||
util::EmoteData emoteData;
|
||||
QString link = linkTemplate;
|
||||
link.detach();
|
||||
emoteData.image1x = new Image(link.replace("{{id}}", id).replace("{{image}}", "1x"),
|
||||
1, code, code + "<br />Channel BTTV Emote");
|
||||
link = linkTemplate;
|
||||
link.detach();
|
||||
emoteData.image2x = new Image(link.replace("{{id}}", id).replace("{{image}}", "2x"),
|
||||
0.5, code, code + "<br />Channel BTTV Emote");
|
||||
link = linkTemplate;
|
||||
link.detach();
|
||||
emoteData.image3x = new Image(link.replace("{{id}}", id).replace("{{image}}", "3x"),
|
||||
0.25, code, code + "<br />Channel BTTV Emote");
|
||||
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
||||
|
||||
link = link.replace("{{id}}", id).replace("{{image}}", "1x");
|
||||
|
||||
auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [&code, &link] {
|
||||
return util::EmoteData(new Image(link, 1, code, code + "<br/>Channel BTTV Emote"));
|
||||
return emoteData;
|
||||
});
|
||||
|
||||
this->bttvChannelEmotes.insert(code, emote);
|
||||
@@ -182,9 +192,11 @@ void EmoteManager::reloadFFZChannelEmotes(const QString &channelName,
|
||||
|
||||
QJsonObject urls = emoteObject.value("urls").toObject();
|
||||
|
||||
auto emote = this->getFFZChannelEmoteFromCaches().getOrAdd(id, [&code, &urls] {
|
||||
auto emote = this->getFFZChannelEmoteFromCaches().getOrAdd(id, [id, &code, &urls] {
|
||||
util::EmoteData emoteData;
|
||||
FillInFFZEmoteData(urls, code, code + "<br/>Channel FFZ Emote", emoteData);
|
||||
emoteData.pageLink =
|
||||
QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code);
|
||||
|
||||
return emoteData;
|
||||
});
|
||||
@@ -436,6 +448,7 @@ void EmoteManager::refreshTwitchEmotes(const std::shared_ptr<TwitchAccount> &use
|
||||
[=, &emoteData](const QJsonObject &root) {
|
||||
emoteData.emoteSets.clear();
|
||||
emoteData.emoteCodes.clear();
|
||||
|
||||
auto emoticonSets = root.value("emoticon_sets").toObject();
|
||||
for (QJsonObject::iterator it = emoticonSets.begin(); it != emoticonSets.end(); ++it) {
|
||||
std::string emoteSetString = it.key().toStdString();
|
||||
@@ -443,7 +456,7 @@ void EmoteManager::refreshTwitchEmotes(const std::shared_ptr<TwitchAccount> &use
|
||||
|
||||
for (QJsonValue emoteValue : emoteSetList) {
|
||||
QJsonObject emoticon = emoteValue.toObject();
|
||||
std::string id = emoticon["id"].toString().toStdString();
|
||||
std::string id = QString::number(emoticon["id"].toInt()).toStdString();
|
||||
std::string code = emoticon["code"].toString().toStdString();
|
||||
emoteData.emoteSets[emoteSetString].push_back({id, code});
|
||||
emoteData.emoteCodes.push_back(code);
|
||||
@@ -483,6 +496,7 @@ void EmoteManager::loadBTTVEmotes()
|
||||
code + "<br />Global BTTV Emote");
|
||||
emoteData.image3x = new Image(GetBTTVEmoteLink(urlTemplate, id, "3x"), 0.25, code,
|
||||
code + "<br />Global BTTV Emote");
|
||||
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
||||
|
||||
this->bttvGlobalEmotes.insert(code, emoteData);
|
||||
codes.push_back(code.toStdString());
|
||||
@@ -510,10 +524,13 @@ void EmoteManager::loadFFZEmotes()
|
||||
QJsonObject object = emote.toObject();
|
||||
|
||||
QString code = object.value("name").toString();
|
||||
int id = object.value("id").toInt();
|
||||
QJsonObject urls = object.value("urls").toObject();
|
||||
|
||||
util::EmoteData emoteData;
|
||||
FillInFFZEmoteData(urls, code, code + "<br/>Global FFZ Emote", emoteData);
|
||||
emoteData.pageLink =
|
||||
QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code);
|
||||
|
||||
this->ffzGlobalEmotes.insert(code, emoteData);
|
||||
codes.push_back(code.toStdString());
|
||||
@@ -530,6 +547,20 @@ util::EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteNa
|
||||
{
|
||||
QString _emoteName = emoteName;
|
||||
_emoteName.replace("<", "<");
|
||||
_emoteName.replace(">", ">");
|
||||
|
||||
static QMap<QString, QString> emoteNameReplacements{
|
||||
{"[oO](_|\\.)[oO]", "O_o"}, {"\\>\\;\\(", ">("}, {"\\<\\;3", "<3"},
|
||||
{"\\:-?(o|O)", ":O"}, {"\\:-?(p|P)", ":P"}, {"\\:-?[\\\\/]", ":/"},
|
||||
{"\\:-?[z|Z|\\|]", ":Z"}, {"\\:-?\\(", ":("}, {"\\:-?\\)", ":)"},
|
||||
{"\\:-?D", ":D"}, {"\\;-?(p|P)", ";P"}, {"\\;-?\\)", ";)"},
|
||||
{"R-?\\)", "R)"}, {"B-?\\)", "B)"},
|
||||
};
|
||||
|
||||
auto it = emoteNameReplacements.find(_emoteName);
|
||||
if (it != emoteNameReplacements.end()) {
|
||||
_emoteName = it.value();
|
||||
}
|
||||
|
||||
return _twitchEmoteFromCache.getOrAdd(id, [&emoteName, &_emoteName, &id] {
|
||||
util::EmoteData newEmoteData;
|
||||
|
||||
@@ -46,16 +46,6 @@ public:
|
||||
|
||||
util::EmoteData getTwitchEmoteById(long int id, const QString &emoteName);
|
||||
|
||||
int getGeneration()
|
||||
{
|
||||
return _generation;
|
||||
}
|
||||
|
||||
void incGeneration()
|
||||
{
|
||||
_generation++;
|
||||
}
|
||||
|
||||
pajlada::Signals::NoArgSignal &getGifUpdateSignal();
|
||||
|
||||
// Bit badge/emotes?
|
||||
@@ -145,8 +135,6 @@ private:
|
||||
pajlada::Signals::NoArgSignal gifUpdateTimerSignal;
|
||||
QTimer gifUpdateTimer;
|
||||
bool gifUpdateTimerInitiated = false;
|
||||
|
||||
int _generation = 0;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
+103
-74
@@ -3,6 +3,10 @@
|
||||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "util/assertinguithread.hpp"
|
||||
#include "windowmanager.hpp"
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#define DEFAULT_FONT_FAMILY "Segoe UI"
|
||||
#define DEFAULT_FONT_SIZE 10
|
||||
@@ -20,86 +24,111 @@ namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
FontManager::FontManager()
|
||||
: currentFontFamily("/appearance/currentFontFamily", DEFAULT_FONT_FAMILY)
|
||||
, currentFontSize("/appearance/currentFontSize", DEFAULT_FONT_SIZE)
|
||||
// , currentFont(this->currentFontFamily.getValue().c_str(), currentFontSize.getValue())
|
||||
: chatFontFamily("/appearance/currentFontFamily", DEFAULT_FONT_FAMILY)
|
||||
, chatFontSize("/appearance/currentFontSize", DEFAULT_FONT_SIZE)
|
||||
{
|
||||
qDebug() << "init FontManager";
|
||||
|
||||
this->currentFontFamily.connect([this](const std::string &newValue, auto) {
|
||||
this->incGeneration();
|
||||
// this->currentFont.setFamily(newValue.c_str());
|
||||
this->currentFontByScale.clear();
|
||||
this->fontChanged.invoke();
|
||||
});
|
||||
this->chatFontFamily.connect([this](const std::string &, auto) {
|
||||
util::assertInGuiThread();
|
||||
|
||||
this->currentFontSize.connect([this](const int &newValue, auto) {
|
||||
this->incGeneration();
|
||||
// this->currentFont.setSize(newValue);
|
||||
this->currentFontByScale.clear();
|
||||
this->fontChanged.invoke();
|
||||
});
|
||||
}
|
||||
|
||||
QFont &FontManager::getFont(FontManager::Type type, float scale)
|
||||
{
|
||||
// return this->currentFont.getFont(type);
|
||||
return this->getCurrentFont(scale).getFont(type);
|
||||
}
|
||||
|
||||
QFontMetrics &FontManager::getFontMetrics(FontManager::Type type, float scale)
|
||||
{
|
||||
// return this->currentFont.getFontMetrics(type);
|
||||
return this->getCurrentFont(scale).getFontMetrics(type);
|
||||
}
|
||||
|
||||
FontManager::FontData &FontManager::Font::getFontData(FontManager::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Tiny:
|
||||
return this->tiny;
|
||||
case Small:
|
||||
return this->small;
|
||||
case MediumSmall:
|
||||
return this->mediumSmall;
|
||||
case Medium:
|
||||
return this->medium;
|
||||
case MediumBold:
|
||||
return this->mediumBold;
|
||||
case MediumItalic:
|
||||
return this->mediumItalic;
|
||||
case Large:
|
||||
return this->large;
|
||||
case VeryLarge:
|
||||
return this->veryLarge;
|
||||
default:
|
||||
qDebug() << "Unknown font type:" << type << ", defaulting to medium";
|
||||
return this->medium;
|
||||
}
|
||||
}
|
||||
|
||||
QFont &FontManager::Font::getFont(Type type)
|
||||
{
|
||||
return this->getFontData(type).font;
|
||||
}
|
||||
|
||||
QFontMetrics &FontManager::Font::getFontMetrics(Type type)
|
||||
{
|
||||
return this->getFontData(type).metrics;
|
||||
}
|
||||
|
||||
FontManager::Font &FontManager::getCurrentFont(float scale)
|
||||
{
|
||||
for (auto it = this->currentFontByScale.begin(); it != this->currentFontByScale.end(); it++) {
|
||||
if (it->first == scale) {
|
||||
return it->second;
|
||||
if (getApp()->windows) {
|
||||
getApp()->windows->incGeneration();
|
||||
}
|
||||
}
|
||||
this->currentFontByScale.push_back(
|
||||
std::make_pair(scale, Font(this->currentFontFamily.getValue().c_str(),
|
||||
this->currentFontSize.getValue() * scale)));
|
||||
|
||||
return this->currentFontByScale.back().second;
|
||||
for (auto &map : this->fontsByType) {
|
||||
map.clear();
|
||||
}
|
||||
this->fontChanged.invoke();
|
||||
});
|
||||
|
||||
this->chatFontSize.connect([this](const int &, auto) {
|
||||
util::assertInGuiThread();
|
||||
|
||||
if (getApp()->windows) {
|
||||
getApp()->windows->incGeneration();
|
||||
}
|
||||
|
||||
for (auto &map : this->fontsByType) {
|
||||
map.clear();
|
||||
}
|
||||
this->fontChanged.invoke();
|
||||
});
|
||||
|
||||
this->fontsByType.resize(size_t(EndType));
|
||||
}
|
||||
|
||||
QFont FontManager::getFont(FontManager::Type type, float scale)
|
||||
{
|
||||
return this->getOrCreateFontData(type, scale).font;
|
||||
}
|
||||
|
||||
QFontMetrics FontManager::getFontMetrics(FontManager::Type type, float scale)
|
||||
{
|
||||
return this->getOrCreateFontData(type, scale).metrics;
|
||||
}
|
||||
|
||||
FontManager::FontData &FontManager::getOrCreateFontData(Type type, float scale)
|
||||
{
|
||||
util::assertInGuiThread();
|
||||
|
||||
assert(type >= 0 && type < EndType);
|
||||
|
||||
auto &map = this->fontsByType[size_t(type)];
|
||||
|
||||
// find element
|
||||
auto it = map.find(scale);
|
||||
if (it != map.end()) {
|
||||
// return if found
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// emplace new element
|
||||
auto result = map.emplace(scale, this->createFontData(type, scale));
|
||||
assert(result.second);
|
||||
|
||||
return result.first->second;
|
||||
}
|
||||
|
||||
FontManager::FontData FontManager::createFontData(Type type, float scale)
|
||||
{
|
||||
// check if it's a chat (scale the setting)
|
||||
if (type >= ChatStart && type <= ChatEnd) {
|
||||
static std::unordered_map<Type, ChatFontData> sizeScale{
|
||||
{ChatSmall, {0.6f, false, QFont::Normal}},
|
||||
{ChatMediumSmall, {0.8f, false, QFont::Normal}},
|
||||
{ChatMedium, {1, false, QFont::Normal}},
|
||||
{ChatMediumBold, {1, false, QFont::Medium}},
|
||||
{ChatMediumItalic, {1, true, QFont::Normal}},
|
||||
{ChatLarge, {1.2f, false, QFont::Normal}},
|
||||
{ChatVeryLarge, {1.4f, false, QFont::Normal}},
|
||||
};
|
||||
|
||||
auto data = sizeScale[type];
|
||||
return FontData(QFont(QString::fromStdString(this->chatFontFamily.getValue()),
|
||||
int(this->chatFontSize.getValue() * data.scale * scale), data.weight,
|
||||
data.italic));
|
||||
}
|
||||
|
||||
// normal Ui font (use pt size)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
constexpr float multiplier = 0.8f;
|
||||
#else
|
||||
constexpr float multiplier = 1.f;
|
||||
#endif
|
||||
|
||||
static std::unordered_map<Type, UiFontData> defaultSize{
|
||||
{Tiny, {8, "Monospace", false, QFont::Normal}},
|
||||
{UiMedium, {int(12 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
|
||||
{UiTabs, {int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
|
||||
};
|
||||
|
||||
UiFontData &data = defaultSize[type];
|
||||
QFont font(data.name, int(data.size * scale), data.weight, data.italic);
|
||||
return FontData(font);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
+43
-102
@@ -3,138 +3,79 @@
|
||||
#include <QFont>
|
||||
#include <QFontDatabase>
|
||||
#include <QFontMetrics>
|
||||
#include <array>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <pajlada/settings/setting.hpp>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
class FontManager
|
||||
class FontManager : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
FontManager();
|
||||
|
||||
FontManager(const FontManager &) = delete;
|
||||
FontManager(FontManager &&) = delete;
|
||||
~FontManager() = delete;
|
||||
|
||||
// font data gets set in createFontData(...)
|
||||
enum Type : uint8_t {
|
||||
Tiny,
|
||||
Small,
|
||||
MediumSmall,
|
||||
Medium,
|
||||
MediumBold,
|
||||
MediumItalic,
|
||||
Large,
|
||||
VeryLarge,
|
||||
ChatSmall,
|
||||
ChatMediumSmall,
|
||||
ChatMedium,
|
||||
ChatMediumBold,
|
||||
ChatMediumItalic,
|
||||
ChatLarge,
|
||||
ChatVeryLarge,
|
||||
|
||||
UiMedium,
|
||||
UiTabs,
|
||||
|
||||
// don't remove this value
|
||||
EndType,
|
||||
|
||||
// make sure to update these values accordingly!
|
||||
ChatStart = ChatSmall,
|
||||
ChatEnd = ChatVeryLarge,
|
||||
};
|
||||
|
||||
QFont &getFont(Type type, float scale);
|
||||
QFontMetrics &getFontMetrics(Type type, float scale);
|
||||
QFont getFont(Type type, float scale);
|
||||
QFontMetrics getFontMetrics(Type type, float scale);
|
||||
|
||||
int getGeneration() const
|
||||
{
|
||||
return this->generation;
|
||||
}
|
||||
|
||||
void incGeneration()
|
||||
{
|
||||
this->generation++;
|
||||
}
|
||||
|
||||
pajlada::Settings::Setting<std::string> currentFontFamily;
|
||||
pajlada::Settings::Setting<int> currentFontSize;
|
||||
pajlada::Settings::Setting<std::string> chatFontFamily;
|
||||
pajlada::Settings::Setting<int> chatFontSize;
|
||||
|
||||
pajlada::Signals::NoArgSignal fontChanged;
|
||||
|
||||
private:
|
||||
struct FontData {
|
||||
FontData(QFont &&_font)
|
||||
FontData(const QFont &_font)
|
||||
: font(_font)
|
||||
, metrics(this->font)
|
||||
, metrics(_font)
|
||||
{
|
||||
}
|
||||
|
||||
QFont font;
|
||||
QFontMetrics metrics;
|
||||
const QFont font;
|
||||
const QFontMetrics metrics;
|
||||
};
|
||||
|
||||
struct Font {
|
||||
Font() = delete;
|
||||
|
||||
Font(const char *fontFamilyName, int mediumSize)
|
||||
: tiny(QFont("Monospace", 8))
|
||||
, small(QFont(fontFamilyName, mediumSize - 4))
|
||||
, mediumSmall(QFont(fontFamilyName, mediumSize - 2))
|
||||
, medium(QFont(fontFamilyName, mediumSize))
|
||||
, mediumBold(QFont(fontFamilyName, mediumSize, QFont::DemiBold))
|
||||
, mediumItalic(QFont(fontFamilyName, mediumSize, -1, true))
|
||||
, large(QFont(fontFamilyName, mediumSize))
|
||||
, veryLarge(QFont(fontFamilyName, mediumSize))
|
||||
{
|
||||
tiny.font.setStyleHint(QFont::TypeWriter);
|
||||
}
|
||||
|
||||
void setFamily(const char *newFamily)
|
||||
{
|
||||
this->small.font.setFamily(newFamily);
|
||||
this->mediumSmall.font.setFamily(newFamily);
|
||||
this->medium.font.setFamily(newFamily);
|
||||
this->mediumBold.font.setFamily(newFamily);
|
||||
this->mediumItalic.font.setFamily(newFamily);
|
||||
this->large.font.setFamily(newFamily);
|
||||
this->veryLarge.font.setFamily(newFamily);
|
||||
|
||||
this->updateMetrics();
|
||||
}
|
||||
|
||||
void setSize(int newMediumSize)
|
||||
{
|
||||
this->small.font.setPointSize(newMediumSize - 4);
|
||||
this->mediumSmall.font.setPointSize(newMediumSize - 2);
|
||||
this->medium.font.setPointSize(newMediumSize);
|
||||
this->mediumBold.font.setPointSize(newMediumSize);
|
||||
this->mediumItalic.font.setPointSize(newMediumSize);
|
||||
this->large.font.setPointSize(newMediumSize + 2);
|
||||
this->veryLarge.font.setPointSize(newMediumSize + 4);
|
||||
|
||||
this->updateMetrics();
|
||||
}
|
||||
|
||||
void updateMetrics()
|
||||
{
|
||||
this->small.metrics = QFontMetrics(this->small.font);
|
||||
this->mediumSmall.metrics = QFontMetrics(this->mediumSmall.font);
|
||||
this->medium.metrics = QFontMetrics(this->medium.font);
|
||||
this->mediumBold.metrics = QFontMetrics(this->mediumBold.font);
|
||||
this->mediumItalic.metrics = QFontMetrics(this->mediumItalic.font);
|
||||
this->large.metrics = QFontMetrics(this->large.font);
|
||||
this->veryLarge.metrics = QFontMetrics(this->veryLarge.font);
|
||||
}
|
||||
|
||||
FontData &getFontData(Type type);
|
||||
|
||||
QFont &getFont(Type type);
|
||||
QFontMetrics &getFontMetrics(Type type);
|
||||
|
||||
FontData tiny;
|
||||
FontData small;
|
||||
FontData mediumSmall;
|
||||
FontData medium;
|
||||
FontData mediumBold;
|
||||
FontData mediumItalic;
|
||||
FontData large;
|
||||
FontData veryLarge;
|
||||
struct ChatFontData {
|
||||
float scale;
|
||||
bool italic;
|
||||
QFont::Weight weight;
|
||||
};
|
||||
|
||||
Font &getCurrentFont(float scale);
|
||||
struct UiFontData {
|
||||
float size;
|
||||
const char *name;
|
||||
bool italic;
|
||||
QFont::Weight weight;
|
||||
};
|
||||
|
||||
// Future plans:
|
||||
// Could have multiple fonts in here, such as "Menu font", "Application font", "Chat font"
|
||||
FontData &getOrCreateFontData(Type type, float scale);
|
||||
FontData createFontData(Type type, float scale);
|
||||
|
||||
std::list<std::pair<float, Font>> currentFontByScale;
|
||||
|
||||
int generation = 0;
|
||||
std::vector<std::unordered_map<float, FontData>> fontsByType;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace ipc = boost::interprocess;
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
// fourtf: don't add this class to the application class
|
||||
NativeMessagingManager::NativeMessagingManager()
|
||||
{
|
||||
qDebug() << "init NativeMessagingManager";
|
||||
@@ -50,6 +51,10 @@ void NativeMessagingManager::registerHost()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
if (app->paths->isPortable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create manifest
|
||||
QJsonDocument document;
|
||||
QJsonObject root_obj;
|
||||
@@ -113,13 +118,14 @@ void NativeMessagingManager::ReceiverThread::run()
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
char *buf = (char *)malloc(MESSAGE_SIZE);
|
||||
std::unique_ptr<char> buf(static_cast<char *>(malloc(MESSAGE_SIZE)));
|
||||
ipc::message_queue::size_type retSize;
|
||||
unsigned int priority;
|
||||
|
||||
messageQueue.receive(buf, MESSAGE_SIZE, retSize, priority);
|
||||
messageQueue.receive(buf.get(), MESSAGE_SIZE, retSize, priority);
|
||||
|
||||
QJsonDocument document = QJsonDocument::fromJson(QByteArray(buf, retSize));
|
||||
QJsonDocument document =
|
||||
QJsonDocument::fromJson(QByteArray::fromRawData(buf.get(), retSize));
|
||||
|
||||
this->handleMessage(document.object());
|
||||
} catch (ipc::interprocess_exception &ex) {
|
||||
@@ -143,26 +149,37 @@ void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &ro
|
||||
QString _type = root.value("type").toString();
|
||||
bool attach = root.value("attach").toBool();
|
||||
QString name = root.value("name").toString();
|
||||
QString winId = root.value("winId").toString();
|
||||
int yOffset = root.value("yOffset").toInt(-1);
|
||||
|
||||
if (_type.isNull() || name.isNull() || winId.isNull()) {
|
||||
#ifdef USEWINSDK
|
||||
widgets::AttachedWindow::GetArgs args;
|
||||
args.winId = root.value("winId").toString();
|
||||
args.yOffset = root.value("yOffset").toInt(-1);
|
||||
args.width = root.value("size").toObject().value("width").toInt(-1);
|
||||
args.height = root.value("size").toObject().value("height").toInt(-1);
|
||||
|
||||
if (_type.isNull() || args.winId.isNull()) {
|
||||
qDebug() << "NM type, name or winId missing";
|
||||
attach = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_type == "twitch") {
|
||||
util::postToThread([name, attach, winId, yOffset, app] {
|
||||
app->twitch.server->watchingChannel.update(
|
||||
app->twitch.server->getOrAddChannel(name));
|
||||
util::postToThread([=] {
|
||||
if (!name.isEmpty()) {
|
||||
app->twitch.server->watchingChannel.update(
|
||||
app->twitch.server->getOrAddChannel(name));
|
||||
}
|
||||
|
||||
if (attach) {
|
||||
#ifdef USEWINSDK
|
||||
auto *window =
|
||||
widgets::AttachedWindow::get(::GetForegroundWindow(), winId, yOffset);
|
||||
window->setChannel(app->twitch.server->getOrAddChannel(name));
|
||||
window->show();
|
||||
if (args.height != -1) {
|
||||
auto *window = widgets::AttachedWindow::get(::GetForegroundWindow(), args);
|
||||
if (!name.isEmpty()) {
|
||||
window->setChannel(app->twitch.server->getOrAddChannel(name));
|
||||
}
|
||||
}
|
||||
// window->show();
|
||||
#endif
|
||||
}
|
||||
});
|
||||
@@ -179,12 +196,15 @@ void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &ro
|
||||
}
|
||||
|
||||
#ifdef USEWINSDK
|
||||
util::postToThread([winId] { widgets::AttachedWindow::detach(winId); });
|
||||
util::postToThread([winId] {
|
||||
qDebug() << "NW detach";
|
||||
widgets::AttachedWindow::detach(winId);
|
||||
});
|
||||
#endif
|
||||
} else {
|
||||
qDebug() << "NM unknown action " + action;
|
||||
}
|
||||
}
|
||||
} // namespace singletons
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace singletons {
|
||||
class NativeMessagingManager
|
||||
{
|
||||
public:
|
||||
// fourtf: don't add this class to the application class
|
||||
NativeMessagingManager();
|
||||
|
||||
~NativeMessagingManager() = delete;
|
||||
|
||||
@@ -19,21 +19,21 @@ PathManager::PathManager(int argc, char **argv)
|
||||
.replace("/", "x");
|
||||
|
||||
// Options
|
||||
bool portable = false;
|
||||
this->portable = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "portable") == 0) {
|
||||
portable = true;
|
||||
this->portable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/portable")) {
|
||||
portable = true;
|
||||
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/this->portable")) {
|
||||
this->portable = true;
|
||||
}
|
||||
|
||||
// Root path = %APPDATA%/Chatterino or the folder that the executable resides in
|
||||
QString rootPath;
|
||||
if (portable) {
|
||||
if (this->portable) {
|
||||
rootPath.append(QCoreApplication::applicationDirPath());
|
||||
} else {
|
||||
// Get settings path
|
||||
@@ -91,5 +91,10 @@ bool PathManager::createFolder(const QString &folderPath)
|
||||
return QDir().mkpath(folderPath);
|
||||
}
|
||||
|
||||
bool PathManager::isPortable()
|
||||
{
|
||||
return this->portable;
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -28,6 +28,10 @@ public:
|
||||
QString appPathHash;
|
||||
|
||||
bool createFolder(const QString &folderPath);
|
||||
bool isPortable();
|
||||
|
||||
private:
|
||||
bool portable;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "util/emotemap.hpp"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -39,8 +39,18 @@ void SettingManager::initialize()
|
||||
|
||||
this->timestampFormat.connect([](auto, auto) {
|
||||
auto app = getApp();
|
||||
app->windows->layoutVisibleChatWidgets();
|
||||
app->windows->layoutChannelViews();
|
||||
});
|
||||
|
||||
this->emoteScale.connect([](auto, auto) { getApp()->windows->forceLayoutChannelViews(); });
|
||||
|
||||
this->timestampFormat.connect([](auto, auto) { getApp()->windows->forceLayoutChannelViews(); });
|
||||
this->alternateMessageBackground.connect(
|
||||
[](auto, auto) { getApp()->windows->forceLayoutChannelViews(); });
|
||||
this->seperateMessages.connect(
|
||||
[](auto, auto) { getApp()->windows->forceLayoutChannelViews(); });
|
||||
this->collpseMessagesMinLines.connect(
|
||||
[](auto, auto) { getApp()->windows->forceLayoutChannelViews(); });
|
||||
}
|
||||
|
||||
MessageElement::Flags SettingManager::getWordFlags()
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
BoolSetting hideEmptyInput = {"/appearance/hideEmptyInputBox", false};
|
||||
BoolSetting showMessageLength = {"/appearance/messages/showMessageLength", false};
|
||||
BoolSetting seperateMessages = {"/appearance/messages/separateMessages", false};
|
||||
// BoolSetting collapseLongMessages = {"/appearance/messages/collapseLongMessages", false};
|
||||
IntSetting collpseMessagesMinLines = {"/appearance/messages/collapseMessagesMinLines", 0};
|
||||
BoolSetting alternateMessageBackground = {"/appearance/messages/alternateMessageBackground",
|
||||
false};
|
||||
BoolSetting windowTopMost = {"/appearance/windowAlwaysOnTop", false};
|
||||
@@ -54,6 +56,8 @@ public:
|
||||
/// Behaviour
|
||||
BoolSetting allowDuplicateMessages = {"/behaviour/allowDuplicateMessages", true};
|
||||
BoolSetting mentionUsersWithAt = {"/behaviour/mentionUsersWithAt", false};
|
||||
BoolSetting showJoins = {"/behaviour/showJoins", false};
|
||||
BoolSetting showParts = {"/behaviour/showParts", false};
|
||||
FloatSetting mouseScrollMultiplier = {"/behaviour/mouseScrollMultiplier", 1.0};
|
||||
|
||||
// Auto-completion
|
||||
@@ -75,10 +79,10 @@ public:
|
||||
BoolSetting enableGifAnimations = {"/emotes/enableGifAnimations", true};
|
||||
FloatSetting emoteScale = {"/emotes/scale", 1.f};
|
||||
|
||||
// 0 = Smallest size
|
||||
// 1 = One size above 0 (usually size of 0 * 2)
|
||||
// 2 = One size above 1 (usually size of 1 * 2)
|
||||
// etc...
|
||||
// 0 = No preference
|
||||
// 1 = 1x
|
||||
// 2 = 2x
|
||||
// 3 = 3x
|
||||
IntSetting preferredEmoteQuality = {"/emotes/preferredEmoteQuality", 0};
|
||||
|
||||
/// Links
|
||||
|
||||
@@ -52,7 +52,6 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
isLight = multiplier > 0;
|
||||
bool lightWin = isLight;
|
||||
|
||||
QColor none(0, 0, 0, 0);
|
||||
QColor themeColor = QColor::fromHslF(hue, 0.43, 0.5);
|
||||
QColor themeColorNoSat = QColor::fromHslF(hue, 0, 0.5);
|
||||
|
||||
@@ -69,7 +68,7 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
#ifdef Q_OS_LINUX
|
||||
this->window.background = lightWin ? "#fff" : QColor(61, 60, 56);
|
||||
#else
|
||||
this->window.background = lightWin ? "#fff" : "#444";
|
||||
this->window.background = lightWin ? "#fff" : "#111";
|
||||
#endif
|
||||
|
||||
QColor fg = this->window.text = lightWin ? "#000" : "#eee";
|
||||
@@ -89,27 +88,52 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
|
||||
/// TABS
|
||||
if (lightWin) {
|
||||
this->tabs.regular = {fg, {bg, QColor("#ccc"), bg}};
|
||||
this->tabs.regular = {QColor("#444"),
|
||||
{QColor("#fff"), QColor("#fff"), QColor("#fff")},
|
||||
{QColor("#fff"), QColor("#fff"), QColor("#fff")}};
|
||||
this->tabs.newMessage = {
|
||||
fg,
|
||||
{QBrush(blendColors(themeColor, "#ccc", 0.9), Qt::FDiagPattern),
|
||||
QBrush(blendColors(themeColor, "#ccc", 0.9), Qt::FDiagPattern),
|
||||
QBrush(blendColors(themeColorNoSat, "#ccc", 0.9), Qt::FDiagPattern)}};
|
||||
this->tabs.highlighted = {fg, {QColor("#ccc"), QColor("#ccc"), QColor("#bbb")}};
|
||||
this->tabs.selected = {QColor("#fff"),
|
||||
{QColor("#777"), QColor("#777"), QColor("#888")}};
|
||||
} else {
|
||||
this->tabs.regular = {fg, {bg, QColor("#555"), bg}};
|
||||
this->tabs.newMessage = {
|
||||
fg,
|
||||
{QBrush(blendColors(themeColor, "#666", 0.7), Qt::FDiagPattern),
|
||||
QBrush(blendColors(themeColor, "#666", 0.5), Qt::FDiagPattern),
|
||||
QBrush(blendColors(themeColorNoSat, "#666", 0.7), Qt::FDiagPattern)}};
|
||||
this->tabs.highlighted = {fg, {QColor("#777"), QColor("#777"), QColor("#666")}};
|
||||
fg, {bg, QColor("#ccc"), bg}, {QColor("#aaa"), QColor("#aaa"), QColor("#aaa")}};
|
||||
this->tabs.highlighted = {fg,
|
||||
{bg, QColor("#ccc"), bg},
|
||||
{QColor("#b60505"), QColor("#b60505"), QColor("#b60505")}};
|
||||
this->tabs.selected = {QColor("#000"),
|
||||
{QColor("#999"), QColor("#999"), QColor("#888")}};
|
||||
{QColor("#b4d7ff"), QColor("#b4d7ff"), QColor("#b4d7ff")},
|
||||
{QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}};
|
||||
} else {
|
||||
this->tabs.regular = {QColor("#aaa"),
|
||||
{QColor("#252525"), QColor("#252525"), QColor("#252525")},
|
||||
{QColor("#444"), QColor("#444"), QColor("#444")}};
|
||||
this->tabs.newMessage = {fg,
|
||||
{QColor("#252525"), QColor("#252525"), QColor("#252525")},
|
||||
{QColor("#888"), QColor("#888"), QColor("#888")}};
|
||||
this->tabs.highlighted = {fg,
|
||||
{QColor("#252525"), QColor("#252525"), QColor("#252525")},
|
||||
{QColor("#ee6166"), QColor("#ee6166"), QColor("#ee6166")}};
|
||||
|
||||
this->tabs.selected = {QColor("#fff"),
|
||||
{QColor("#555555"), QColor("#555555"), QColor("#555555")},
|
||||
{QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}};
|
||||
}
|
||||
|
||||
// scrollbar
|
||||
this->scrollbars.highlights.highlight = QColor("#ee6166");
|
||||
this->scrollbars.highlights.subscription = QColor("#C466FF");
|
||||
|
||||
// this->tabs.newMessage = {
|
||||
// fg,
|
||||
// {QBrush(blendColors(themeColor, "#ccc", 0.9), Qt::FDiagPattern),
|
||||
// QBrush(blendColors(themeColor, "#ccc", 0.9), Qt::FDiagPattern),
|
||||
// QBrush(blendColors(themeColorNoSat, "#ccc", 0.9), Qt::FDiagPattern)}};
|
||||
|
||||
// this->tabs.newMessage = {
|
||||
// fg,
|
||||
// {QBrush(blendColors(themeColor, "#666", 0.7), Qt::FDiagPattern),
|
||||
// QBrush(blendColors(themeColor, "#666", 0.5), Qt::FDiagPattern),
|
||||
// QBrush(blendColors(themeColorNoSat, "#666", 0.7),
|
||||
// Qt::FDiagPattern)}};
|
||||
// this->tabs.highlighted = {fg, {QColor("#777"), QColor("#777"),
|
||||
// QColor("#666")}};
|
||||
|
||||
this->tabs.bottomLine = this->tabs.selected.backgrounds.regular.color();
|
||||
}
|
||||
|
||||
@@ -119,7 +143,12 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
this->splits.messageSeperator = isLight ? QColor(127, 127, 127) : QColor(60, 60, 60);
|
||||
this->splits.background = getColor(0, sat, 1);
|
||||
this->splits.dropPreview = QColor(0, 148, 255, 0x30);
|
||||
this->splits.dropPreviewBorder = QColor(0, 148, 255, 0x70);
|
||||
this->splits.dropPreviewBorder = QColor(0, 148, 255, 0xff);
|
||||
this->splits.dropTargetRect = QColor(0, 148, 255, 0x00);
|
||||
this->splits.dropTargetRectBorder = QColor(0, 148, 255, 0x00);
|
||||
this->splits.resizeHandle = QColor(0, 148, 255, 0x70);
|
||||
this->splits.resizeHandleBackground = QColor(0, 148, 255, 0x20);
|
||||
|
||||
// this->splits.border
|
||||
// this->splits.borderFocused
|
||||
|
||||
@@ -143,7 +172,10 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
this->messages.backgrounds.regular = splits.background;
|
||||
this->messages.backgrounds.alternate = getColor(0, sat, 0.93);
|
||||
this->messages.backgrounds.highlighted =
|
||||
blendColors(themeColor, this->messages.backgrounds.regular, 0.8);
|
||||
blendColors(themeColor, this->messages.backgrounds.regular, 0.6);
|
||||
this->messages.backgrounds.subscription =
|
||||
blendColors(QColor("#C466FF"), this->messages.backgrounds.regular, 0.7);
|
||||
|
||||
// this->messages.backgrounds.resub
|
||||
// this->messages.backgrounds.whisper
|
||||
this->messages.disabled = getColor(0, sat, 1, 0.6);
|
||||
@@ -151,7 +183,9 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
// this->messages.seperatorInner =
|
||||
|
||||
// Scrollbar
|
||||
this->scrollbars.background = getColor(0, sat, 0.94);
|
||||
this->scrollbars.background = QColor(0, 0, 0, 0);
|
||||
// this->scrollbars.background = splits.background;
|
||||
// this->scrollbars.background.setAlphaF(qreal(0.2));
|
||||
this->scrollbars.thumb = getColor(0, sat, 0.80);
|
||||
this->scrollbars.thumbSelected = getColor(0, sat, 0.7);
|
||||
|
||||
@@ -163,13 +197,13 @@ void ThemeManager::actuallyUpdate(double hue, double multiplier)
|
||||
this->messages.selection = isLightTheme() ? QColor(0, 0, 0, 64) : QColor(255, 255, 255, 64);
|
||||
|
||||
this->updated.invoke();
|
||||
}
|
||||
} // namespace singletons
|
||||
|
||||
QColor ThemeManager::blendColors(const QColor &color1, const QColor &color2, qreal ratio)
|
||||
{
|
||||
int r = color1.red() * (1 - ratio) + color2.red() * ratio;
|
||||
int g = color1.green() * (1 - ratio) + color2.green() * ratio;
|
||||
int b = color1.blue() * (1 - ratio) + color2.blue() * ratio;
|
||||
int r = int(color1.red() * (1 - ratio) + color2.red() * ratio);
|
||||
int g = int(color1.green() * (1 - ratio) + color2.green() * ratio);
|
||||
int b = int(color1.blue() * (1 - ratio) + color2.blue() * ratio);
|
||||
|
||||
return QColor(r, g, b, 255);
|
||||
}
|
||||
@@ -177,22 +211,22 @@ QColor ThemeManager::blendColors(const QColor &color1, const QColor &color2, qre
|
||||
void ThemeManager::normalizeColor(QColor &color)
|
||||
{
|
||||
if (this->isLight) {
|
||||
if (color.lightnessF() > 0.5f) {
|
||||
color.setHslF(color.hueF(), color.saturationF(), 0.5f);
|
||||
if (color.lightnessF() > 0.5) {
|
||||
color.setHslF(color.hueF(), color.saturationF(), 0.5);
|
||||
}
|
||||
|
||||
if (color.lightnessF() > 0.4f && color.hueF() > 0.1 && color.hueF() < 0.33333) {
|
||||
if (color.lightnessF() > 0.4 && color.hueF() > 0.1 && color.hueF() < 0.33333) {
|
||||
color.setHslF(
|
||||
color.hueF(), color.saturationF(),
|
||||
color.lightnessF() - sin((color.hueF() - 0.1) / (0.3333 - 0.1) * 3.14159) *
|
||||
color.saturationF() * 0.2);
|
||||
}
|
||||
} else {
|
||||
if (color.lightnessF() < 0.5f) {
|
||||
color.setHslF(color.hueF(), color.saturationF(), 0.5f);
|
||||
if (color.lightnessF() < 0.5) {
|
||||
color.setHslF(color.hueF(), color.saturationF(), 0.5);
|
||||
}
|
||||
|
||||
if (color.lightnessF() < 0.6f && color.hueF() > 0.54444 && color.hueF() < 0.83333) {
|
||||
if (color.lightnessF() < 0.6 && color.hueF() > 0.54444 && color.hueF() < 0.83333) {
|
||||
color.setHslF(
|
||||
color.hueF(), color.saturationF(),
|
||||
color.lightnessF() + sin((color.hueF() - 0.54444) / (0.8333 - 0.54444) * 3.14159) *
|
||||
|
||||
@@ -25,11 +25,16 @@ public:
|
||||
|
||||
struct TabColors {
|
||||
QColor text;
|
||||
struct Backgrounds {
|
||||
struct {
|
||||
QBrush regular;
|
||||
QBrush hover;
|
||||
QBrush unfocused;
|
||||
} backgrounds;
|
||||
struct {
|
||||
QColor regular;
|
||||
QColor hover;
|
||||
QColor unfocused;
|
||||
} line;
|
||||
};
|
||||
|
||||
/// WINDOW
|
||||
@@ -43,9 +48,9 @@ public:
|
||||
/// TABS
|
||||
struct {
|
||||
TabColors regular;
|
||||
TabColors selected;
|
||||
TabColors highlighted;
|
||||
TabColors newMessage;
|
||||
TabColors highlighted;
|
||||
TabColors selected;
|
||||
QColor border;
|
||||
QColor bottomLine;
|
||||
} tabs;
|
||||
@@ -58,6 +63,10 @@ public:
|
||||
QColor borderFocused;
|
||||
QColor dropPreview;
|
||||
QColor dropPreviewBorder;
|
||||
QColor dropTargetRect;
|
||||
QColor dropTargetRectBorder;
|
||||
QColor resizeHandle;
|
||||
QColor resizeHandleBackground;
|
||||
|
||||
struct {
|
||||
QColor border;
|
||||
@@ -89,7 +98,7 @@ public:
|
||||
QColor regular;
|
||||
QColor alternate;
|
||||
QColor highlighted;
|
||||
// QColor resub;
|
||||
QColor subscription;
|
||||
// QColor whisper;
|
||||
} backgrounds;
|
||||
|
||||
@@ -104,8 +113,10 @@ public:
|
||||
QColor background;
|
||||
QColor thumb;
|
||||
QColor thumbSelected;
|
||||
// const int highlightsCount = 3;
|
||||
// QColor highlights[3];
|
||||
struct {
|
||||
QColor highlight;
|
||||
QColor subscription;
|
||||
} highlights;
|
||||
} scrollbars;
|
||||
|
||||
/// TOOLTIP
|
||||
|
||||
@@ -7,25 +7,31 @@ namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
UpdateManager::UpdateManager()
|
||||
: currentVersion(CHATTERINO_VERSION)
|
||||
: currentVersion_(CHATTERINO_VERSION)
|
||||
{
|
||||
qDebug() << "init UpdateManager";
|
||||
}
|
||||
|
||||
UpdateManager &UpdateManager::getInstance()
|
||||
{
|
||||
// fourtf: don't add this class to the application class
|
||||
static UpdateManager instance;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
const QString &UpdateManager::getCurrentVersion() const
|
||||
{
|
||||
return this->getCurrentVersion();
|
||||
return currentVersion_;
|
||||
}
|
||||
|
||||
const QString &UpdateManager::getOnlineVersion() const
|
||||
{
|
||||
return this->getOnlineVersion();
|
||||
return onlineVersion_;
|
||||
}
|
||||
|
||||
void UpdateManager::installUpdates()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateManager::checkForUpdates()
|
||||
@@ -33,17 +39,38 @@ void UpdateManager::checkForUpdates()
|
||||
QString url = "https://notitia.chatterino.com/version/chatterino/" CHATTERINO_OS "/stable";
|
||||
|
||||
util::NetworkRequest req(url);
|
||||
req.setTimeout(20000);
|
||||
req.setTimeout(30000);
|
||||
req.getJSON([this](QJsonObject &object) {
|
||||
QJsonValue version_val = object.value("version");
|
||||
if (!version_val.isString()) {
|
||||
this->setStatus_(Error);
|
||||
qDebug() << "error updating";
|
||||
return;
|
||||
}
|
||||
|
||||
this->onlineVersion = version_val.toString();
|
||||
this->onlineVersionUpdated.invoke();
|
||||
this->onlineVersion_ = version_val.toString();
|
||||
|
||||
if (this->currentVersion_ != this->onlineVersion_) {
|
||||
this->setStatus_(UpdateAvailable);
|
||||
} else {
|
||||
this->setStatus_(NoUpdateAvailable);
|
||||
}
|
||||
});
|
||||
this->setStatus_(Searching);
|
||||
req.execute();
|
||||
}
|
||||
|
||||
UpdateManager::UpdateStatus UpdateManager::getStatus() const
|
||||
{
|
||||
return this->status_;
|
||||
}
|
||||
|
||||
void UpdateManager::setStatus_(UpdateStatus status)
|
||||
{
|
||||
if (this->status_ != status) {
|
||||
this->status_ = status;
|
||||
this->statusUpdated.invoke(status);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
@@ -11,17 +11,25 @@ class UpdateManager
|
||||
UpdateManager();
|
||||
|
||||
public:
|
||||
enum UpdateStatus { None, Searching, UpdateAvailable, NoUpdateAvailable, Error };
|
||||
|
||||
// fourtf: don't add this class to the application class
|
||||
static UpdateManager &getInstance();
|
||||
|
||||
void checkForUpdates();
|
||||
const QString &getCurrentVersion() const;
|
||||
const QString &getOnlineVersion() const;
|
||||
void installUpdates();
|
||||
UpdateStatus getStatus() const;
|
||||
|
||||
pajlada::Signals::NoArgSignal onlineVersionUpdated;
|
||||
pajlada::Signals::Signal<UpdateStatus> statusUpdated;
|
||||
|
||||
private:
|
||||
QString currentVersion;
|
||||
QString onlineVersion;
|
||||
QString currentVersion_;
|
||||
QString onlineVersion_;
|
||||
UpdateStatus status_ = None;
|
||||
|
||||
void setStatus_(UpdateStatus status);
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "widgets/accountswitchpopupwidget.hpp"
|
||||
#include "widgets/settingsdialog.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
@@ -20,6 +21,9 @@
|
||||
namespace chatterino {
|
||||
namespace singletons {
|
||||
|
||||
using SplitNode = widgets::SplitContainer::Node;
|
||||
using SplitDirection = widgets::SplitContainer::Direction;
|
||||
|
||||
void WindowManager::showSettingsDialog()
|
||||
{
|
||||
QTimer::singleShot(80, [] { widgets::SettingsDialog::showDialog(); });
|
||||
@@ -54,11 +58,17 @@ WindowManager::WindowManager()
|
||||
qDebug() << "init WindowManager";
|
||||
}
|
||||
|
||||
void WindowManager::layoutVisibleChatWidgets(Channel *channel)
|
||||
void WindowManager::layoutChannelViews(Channel *channel)
|
||||
{
|
||||
this->layout.invoke(channel);
|
||||
}
|
||||
|
||||
void WindowManager::forceLayoutChannelViews()
|
||||
{
|
||||
this->incGeneration();
|
||||
this->layoutChannelViews(nullptr);
|
||||
}
|
||||
|
||||
void WindowManager::repaintVisibleChatWidgets(Channel *channel)
|
||||
{
|
||||
if (this->mainWindow != nullptr) {
|
||||
@@ -184,32 +194,40 @@ void WindowManager::initialize()
|
||||
// load tabs
|
||||
QJsonArray tabs = window_obj.value("tabs").toArray();
|
||||
for (QJsonValue tab_val : tabs) {
|
||||
widgets::SplitContainer *tab = window.getNotebook().addNewPage();
|
||||
widgets::SplitContainer *page = window.getNotebook().addPage(false);
|
||||
|
||||
QJsonObject tab_obj = tab_val.toObject();
|
||||
|
||||
// set custom title
|
||||
QJsonValue title_val = tab_obj.value("title");
|
||||
if (title_val.isString()) {
|
||||
tab->getTab()->setTitle(title_val.toString());
|
||||
tab->getTab()->useDefaultTitle = false;
|
||||
page->getTab()->setCustomTitle(title_val.toString());
|
||||
}
|
||||
|
||||
// selected
|
||||
if (tab_obj.value("selected").toBool(false)) {
|
||||
window.getNotebook().select(tab);
|
||||
window.getNotebook().select(page);
|
||||
}
|
||||
|
||||
// load splits
|
||||
QJsonObject splitRoot = tab_obj.value("splits2").toObject();
|
||||
|
||||
if (!splitRoot.isEmpty()) {
|
||||
page->decodeFromJson(splitRoot);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// fallback load splits (old)
|
||||
int colNr = 0;
|
||||
for (QJsonValue column_val : tab_obj.value("splits").toArray()) {
|
||||
for (QJsonValue split_val : column_val.toArray()) {
|
||||
widgets::Split *split = new widgets::Split(tab);
|
||||
widgets::Split *split = new widgets::Split(page);
|
||||
|
||||
QJsonObject split_obj = split_val.toObject();
|
||||
split->setChannel(this->decodeChannel(split_obj));
|
||||
split->setChannel(decodeChannel(split_obj));
|
||||
|
||||
tab->addToLayout(split, std::make_pair(colNr, 10000000));
|
||||
page->appendSplit(split);
|
||||
}
|
||||
colNr++;
|
||||
}
|
||||
@@ -218,7 +236,7 @@ void WindowManager::initialize()
|
||||
|
||||
if (mainWindow == nullptr) {
|
||||
mainWindow = &createWindow(widgets::Window::Main);
|
||||
mainWindow->getNotebook().addNewPage(true);
|
||||
mainWindow->getNotebook().addPage(true);
|
||||
}
|
||||
|
||||
this->initialized = true;
|
||||
@@ -255,13 +273,15 @@ void WindowManager::save()
|
||||
// window tabs
|
||||
QJsonArray tabs_arr;
|
||||
|
||||
for (int tab_i = 0; tab_i < window->getNotebook().tabCount(); tab_i++) {
|
||||
for (int tab_i = 0; tab_i < window->getNotebook().getPageCount(); tab_i++) {
|
||||
QJsonObject tab_obj;
|
||||
widgets::SplitContainer *tab = window->getNotebook().tabAt(tab_i);
|
||||
widgets::SplitContainer *tab =
|
||||
dynamic_cast<widgets::SplitContainer *>(window->getNotebook().getPageAt(tab_i));
|
||||
assert(tab != nullptr);
|
||||
|
||||
// custom tab title
|
||||
if (!tab->getTab()->useDefaultTitle) {
|
||||
tab_obj.insert("title", tab->getTab()->getTitle());
|
||||
if (tab->getTab()->hasCustomTitle()) {
|
||||
tab_obj.insert("title", tab->getTab()->getCustomTitle());
|
||||
}
|
||||
|
||||
// selected
|
||||
@@ -270,23 +290,11 @@ void WindowManager::save()
|
||||
}
|
||||
|
||||
// splits
|
||||
QJsonArray columns_arr;
|
||||
std::vector<std::vector<widgets::Split *>> columns = tab->getColumns();
|
||||
QJsonObject splits;
|
||||
|
||||
for (std::vector<widgets::Split *> &cells : columns) {
|
||||
QJsonArray cells_arr;
|
||||
this->encodeNodeRecusively(tab->getBaseNode(), splits);
|
||||
|
||||
for (widgets::Split *cell : cells) {
|
||||
QJsonObject cell_obj;
|
||||
|
||||
this->encodeChannel(cell->getIndirectChannel(), cell_obj);
|
||||
|
||||
cells_arr.append(cell_obj);
|
||||
}
|
||||
columns_arr.append(cells_arr);
|
||||
}
|
||||
|
||||
tab_obj.insert("splits", columns_arr);
|
||||
tab_obj.insert("splits2", splits);
|
||||
tabs_arr.append(tab_obj);
|
||||
}
|
||||
|
||||
@@ -302,10 +310,46 @@ void WindowManager::save()
|
||||
QString settingsPath = app->paths->settingsFolderPath + SETTINGS_FILENAME;
|
||||
QFile file(settingsPath);
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
file.write(document.toJson());
|
||||
|
||||
QJsonDocument::JsonFormat format =
|
||||
#ifdef _DEBUG
|
||||
QJsonDocument::JsonFormat::Compact
|
||||
#else
|
||||
(QJsonDocument::JsonFormat)0
|
||||
#endif
|
||||
;
|
||||
|
||||
file.write(document.toJson(format));
|
||||
file.flush();
|
||||
}
|
||||
|
||||
void WindowManager::encodeNodeRecusively(SplitNode *node, QJsonObject &obj)
|
||||
{
|
||||
switch (node->getType()) {
|
||||
case SplitNode::_Split: {
|
||||
obj.insert("type", "split");
|
||||
QJsonObject split;
|
||||
encodeChannel(node->getSplit()->getIndirectChannel(), split);
|
||||
obj.insert("data", split);
|
||||
obj.insert("flexh", node->getHorizontalFlex());
|
||||
obj.insert("flexv", node->getVerticalFlex());
|
||||
} break;
|
||||
case SplitNode::HorizontalContainer:
|
||||
case SplitNode::VerticalContainer: {
|
||||
obj.insert("type", node->getType() == SplitNode::HorizontalContainer ? "horizontal"
|
||||
: "vertical");
|
||||
|
||||
QJsonArray items_arr;
|
||||
for (const std::unique_ptr<SplitNode> &n : node->getChildren()) {
|
||||
QJsonObject subObj;
|
||||
this->encodeNodeRecusively(n.get(), subObj);
|
||||
items_arr.append(subObj);
|
||||
}
|
||||
obj.insert("items", items_arr);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::encodeChannel(IndirectChannel channel, QJsonObject &obj)
|
||||
{
|
||||
util::assertInGuiThread();
|
||||
@@ -356,5 +400,15 @@ void WindowManager::closeAll()
|
||||
}
|
||||
}
|
||||
|
||||
int WindowManager::getGeneration() const
|
||||
{
|
||||
return this->generation;
|
||||
}
|
||||
|
||||
void WindowManager::incGeneration()
|
||||
{
|
||||
this->generation++;
|
||||
}
|
||||
|
||||
} // namespace singletons
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/splitcontainer.hpp"
|
||||
#include "widgets/window.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
// namespace widgets {
|
||||
// struct SplitContainer::Node;
|
||||
//}
|
||||
namespace singletons {
|
||||
|
||||
class WindowManager
|
||||
@@ -15,7 +19,8 @@ public:
|
||||
void showSettingsDialog();
|
||||
void showAccountSelectPopup(QPoint point);
|
||||
|
||||
void layoutVisibleChatWidgets(Channel *channel = nullptr);
|
||||
void layoutChannelViews(Channel *channel = nullptr);
|
||||
void forceLayoutChannelViews();
|
||||
void repaintVisibleChatWidgets(Channel *channel = nullptr);
|
||||
void repaintGifEmotes();
|
||||
// void updateAll();
|
||||
@@ -31,19 +36,27 @@ public:
|
||||
void initialize();
|
||||
void closeAll();
|
||||
|
||||
int getGeneration() const;
|
||||
void incGeneration();
|
||||
|
||||
pajlada::Signals::NoArgSignal repaintGifs;
|
||||
pajlada::Signals::Signal<Channel *> layout;
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
|
||||
std::atomic<int> generation{0};
|
||||
|
||||
std::vector<widgets::Window *> windows;
|
||||
|
||||
widgets::Window *mainWindow = nullptr;
|
||||
widgets::Window *selectedWindow = nullptr;
|
||||
|
||||
void encodeChannel(IndirectChannel channel, QJsonObject &obj);
|
||||
IndirectChannel decodeChannel(const QJsonObject &obj);
|
||||
void encodeNodeRecusively(widgets::SplitContainer::Node *node, QJsonObject &obj);
|
||||
|
||||
public:
|
||||
static void encodeChannel(IndirectChannel channel, QJsonObject &obj);
|
||||
static IndirectChannel decodeChannel(const QJsonObject &obj);
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
||||
Reference in New Issue
Block a user