mirror of
https://github.com/Chatterino/chatterino2.git
synced 2026-08-24 02:24:18 -05:00
refactor(window-layout): Build descriptor for serializing (#7092)
It's useful for other components to get a split descriptor from a split (e.g. chatterino-embed). To avoid differences between the descriptor and the JSON output (e.g. adding a field to the split data), this makes the descriptor mandatory. Instead of going `SplitContainer* -> JSON`, we do `SplitContainer* -> NodeDescriptor -> JSON`. In a followup, I'm going to add `*Descriptor::toJSON`. Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "util/CombinePath.hpp"
|
||||
#include "util/FilesystemHelpers.hpp"
|
||||
#include "util/SignalListener.hpp"
|
||||
#include "util/Variant.hpp"
|
||||
#include "widgets/AccountSwitchPopup.hpp"
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/FramelessEmbedWindow.hpp"
|
||||
@@ -38,6 +39,8 @@
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
using namespace Qt::Literals;
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<bool> &shouldMoveOutOfBoundsWindow()
|
||||
@@ -676,92 +679,62 @@ void WindowManager::encodeTab(SplitContainer *tab, bool isSelected,
|
||||
// splits
|
||||
QJsonObject splits;
|
||||
|
||||
WindowManager::encodeNodeRecursively(tab->getBaseNode(), splits);
|
||||
WindowManager::encodeNodeRecursively(tab->buildDescriptor(), splits);
|
||||
|
||||
obj.insert("splits2", splits);
|
||||
}
|
||||
|
||||
void WindowManager::encodeNodeRecursively(SplitNode *node, QJsonObject &obj)
|
||||
void WindowManager::encodeNodeRecursively(const NodeDescriptor &descriptor,
|
||||
QJsonObject &obj)
|
||||
{
|
||||
switch (node->getType())
|
||||
{
|
||||
case SplitNode::Type::Split: {
|
||||
obj.insert("type", "split");
|
||||
obj.insert("moderationMode", node->getSplit()->getModerationMode());
|
||||
std::visit(variant::Overloaded{
|
||||
[&](const SplitNodeDescriptor &split) {
|
||||
obj.insert("type", "split");
|
||||
obj.insert("flexh", split.flexH_);
|
||||
obj.insert("flexv", split.flexV_);
|
||||
|
||||
QJsonObject split;
|
||||
WindowManager::encodeChannel(node->getSplit()->getIndirectChannel(),
|
||||
split);
|
||||
obj.insert("data", split);
|
||||
obj.insert("moderationMode", split.moderationMode_);
|
||||
|
||||
QJsonArray filters;
|
||||
WindowManager::encodeFilters(node->getSplit(), filters);
|
||||
obj.insert("filters", filters);
|
||||
QJsonObject data{{"type"_L1, split.type_}};
|
||||
if (!split.channelName_.isEmpty())
|
||||
{
|
||||
data.insert("name"_L1, split.channelName_);
|
||||
}
|
||||
obj.insert("data", data);
|
||||
|
||||
auto spellOverride = node->getSplit()->checkSpellingOverride();
|
||||
if (spellOverride)
|
||||
{
|
||||
obj["checkSpelling"] = *spellOverride;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SplitNode::Type::HorizontalContainer:
|
||||
case SplitNode::Type::VerticalContainer: {
|
||||
obj.insert("type",
|
||||
node->getType() == SplitNode::Type::HorizontalContainer
|
||||
? "horizontal"
|
||||
: "vertical");
|
||||
QJsonArray filters;
|
||||
WindowManager::encodeFilters(split.filters_, filters);
|
||||
obj.insert("filters", filters);
|
||||
|
||||
QJsonArray itemsArr;
|
||||
for (const auto &n : node->getChildren())
|
||||
{
|
||||
QJsonObject subObj;
|
||||
WindowManager::encodeNodeRecursively(n.get(), subObj);
|
||||
itemsArr.append(subObj);
|
||||
}
|
||||
obj.insert("items", itemsArr);
|
||||
}
|
||||
break;
|
||||
if (split.spellCheckOverride.has_value())
|
||||
{
|
||||
obj["checkSpelling"] = *split.spellCheckOverride;
|
||||
}
|
||||
},
|
||||
[&](const ContainerNodeDescriptor &container) {
|
||||
obj.insert("type", container.vertical_ ? "vertical"
|
||||
: "horizontal");
|
||||
obj.insert("flexh", container.flexH_);
|
||||
obj.insert("flexv", container.flexV_);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
obj.insert("flexh", node->getHorizontalFlex());
|
||||
obj.insert("flexv", node->getVerticalFlex());
|
||||
QJsonArray itemsArr;
|
||||
for (const auto &n : container.items_)
|
||||
{
|
||||
QJsonObject subObj;
|
||||
WindowManager::encodeNodeRecursively(n, subObj);
|
||||
itemsArr.append(subObj);
|
||||
}
|
||||
obj.insert("items", itemsArr);
|
||||
},
|
||||
},
|
||||
descriptor);
|
||||
}
|
||||
|
||||
void WindowManager::encodeChannel(IndirectChannel channel, QJsonObject &obj)
|
||||
void WindowManager::encodeFilters(std::span<const QUuid> filters,
|
||||
QJsonArray &arr)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
obj.insert("type", qmagicenum::enumNameString(channel.getType()));
|
||||
switch (channel.getType())
|
||||
{
|
||||
case Channel::Type::Twitch:
|
||||
case Channel::Type::Misc:
|
||||
obj.insert("name", channel.get()->getName());
|
||||
break;
|
||||
|
||||
case Channel::Type::TwitchWhispers:
|
||||
case Channel::Type::TwitchWatching:
|
||||
case Channel::Type::TwitchMentions:
|
||||
case Channel::Type::TwitchLive:
|
||||
case Channel::Type::TwitchAutomod:
|
||||
|
||||
// FIXME: Remove these (#5703)
|
||||
case Channel::Type::None:
|
||||
case Channel::Type::Direct:
|
||||
case Channel::Type::TwitchEnd:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::encodeFilters(Split *split, QJsonArray &arr)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
auto filters = split->getFilters();
|
||||
for (const auto &f : filters)
|
||||
{
|
||||
arr.append(f.toString(QUuid::WithoutBraces));
|
||||
|
||||
@@ -26,7 +26,13 @@ class Window;
|
||||
class ChannelView;
|
||||
class IndirectChannel;
|
||||
class Split;
|
||||
|
||||
struct SplitDescriptor;
|
||||
struct SplitNodeDescriptor;
|
||||
struct ContainerNodeDescriptor;
|
||||
using NodeDescriptor =
|
||||
std::variant<ContainerNodeDescriptor, SplitNodeDescriptor>;
|
||||
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
struct Message;
|
||||
@@ -63,8 +69,7 @@ public:
|
||||
|
||||
static void encodeTab(SplitContainer *tab, bool isSelected,
|
||||
QJsonObject &obj);
|
||||
static void encodeChannel(IndirectChannel channel, QJsonObject &obj);
|
||||
static void encodeFilters(Split *split, QJsonArray &arr);
|
||||
static void encodeFilters(std::span<const QUuid> filters, QJsonArray &arr);
|
||||
|
||||
void showSettingsDialog(
|
||||
QWidget *parent,
|
||||
@@ -162,7 +167,7 @@ public:
|
||||
pajlada::Signals::Signal<const MessagePtr &> scrollToMessageSignal;
|
||||
|
||||
private:
|
||||
static void encodeNodeRecursively(SplitContainer::Node *node,
|
||||
static void encodeNodeRecursively(const NodeDescriptor &descriptor,
|
||||
QJsonObject &obj);
|
||||
|
||||
// Load window layout from the window-layout.json file
|
||||
|
||||
@@ -1358,6 +1358,38 @@ void Split::setInputReply(const MessagePtr &reply)
|
||||
this->input_->setReply(reply);
|
||||
}
|
||||
|
||||
SplitDescriptor Split::buildDescriptor() const
|
||||
{
|
||||
SplitDescriptor descriptor;
|
||||
descriptor.moderationMode_ = this->getModerationMode();
|
||||
descriptor.filters_ = this->getFilters();
|
||||
descriptor.spellCheckOverride = this->checkSpellingOverride();
|
||||
|
||||
auto chan = this->getChannel();
|
||||
descriptor.type_ = qmagicenum::enumNameString(chan->getType());
|
||||
switch (chan->getType())
|
||||
{
|
||||
case Channel::Type::Twitch:
|
||||
case Channel::Type::Misc:
|
||||
descriptor.channelName_ = chan->getName();
|
||||
break;
|
||||
|
||||
case Channel::Type::TwitchWhispers:
|
||||
case Channel::Type::TwitchWatching:
|
||||
case Channel::Type::TwitchMentions:
|
||||
case Channel::Type::TwitchLive:
|
||||
case Channel::Type::TwitchAutomod:
|
||||
|
||||
// FIXME: Remove these (#5703)
|
||||
case Channel::Type::None:
|
||||
case Channel::Type::Direct:
|
||||
case Channel::Type::TwitchEnd:
|
||||
break;
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void Split::unpause()
|
||||
{
|
||||
this->view_->unpause(PauseReason::KeyboardModifier);
|
||||
|
||||
@@ -27,6 +27,8 @@ class PinnedMessageWidget;
|
||||
class SelectChannelDialog;
|
||||
class OverlayWindow;
|
||||
|
||||
struct SplitDescriptor;
|
||||
|
||||
// Each ChatWidget consists of three sub-elements that handle their own part of
|
||||
// the chat widget: ChatWidgetHeader
|
||||
// - Responsible for rendering which channel the ChatWidget is in, and the
|
||||
@@ -86,6 +88,8 @@ public:
|
||||
|
||||
void setInputReply(const MessagePtr &reply);
|
||||
|
||||
SplitDescriptor buildDescriptor() const;
|
||||
|
||||
// This is called on window focus lost
|
||||
void unpause();
|
||||
|
||||
|
||||
@@ -841,44 +841,14 @@ void SplitContainer::popup()
|
||||
window.show();
|
||||
}
|
||||
|
||||
QString channelTypeToString(Channel::Type value) noexcept
|
||||
{
|
||||
using Type = chatterino::Channel::Type;
|
||||
switch (value)
|
||||
{
|
||||
default:
|
||||
assert(false && "value cannot be serialized");
|
||||
return "never";
|
||||
|
||||
case Type::Twitch:
|
||||
return "twitch";
|
||||
case Type::TwitchWhispers:
|
||||
return "whispers";
|
||||
case Type::TwitchWatching:
|
||||
return "watching";
|
||||
case Type::TwitchMentions:
|
||||
return "mentions";
|
||||
case Type::TwitchLive:
|
||||
return "live";
|
||||
case Type::TwitchAutomod:
|
||||
return "automod";
|
||||
case Type::Misc:
|
||||
return "misc";
|
||||
}
|
||||
}
|
||||
|
||||
NodeDescriptor SplitContainer::buildDescriptorRecursively(
|
||||
const Node *currentNode) const
|
||||
{
|
||||
if (currentNode->children_.empty())
|
||||
if (currentNode->children_.empty() && currentNode->split_)
|
||||
{
|
||||
const auto channelType =
|
||||
currentNode->split_->getIndirectChannel().getType();
|
||||
|
||||
SplitNodeDescriptor result;
|
||||
result.type_ = channelTypeToString(channelType);
|
||||
result.channelName_ = currentNode->split_->getChannel()->getName();
|
||||
result.filters_ = currentNode->split_->getFilters();
|
||||
SplitNodeDescriptor result(currentNode->split_->buildDescriptor());
|
||||
result.flexH_ = currentNode->flexH_;
|
||||
result.flexV_ = currentNode->flexV_;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -890,6 +860,8 @@ NodeDescriptor SplitContainer::buildDescriptorRecursively(
|
||||
descriptor.items_.push_back(
|
||||
this->buildDescriptorRecursively(child.get()));
|
||||
}
|
||||
descriptor.flexH_ = currentNode->flexH_;
|
||||
descriptor.flexV_ = currentNode->flexV_;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user