Compare commits

..

7 commits

Author SHA1 Message Date
hemirt c9da994af9
Merge 1bdb118391 into 9e8281b75b 2024-10-23 01:29:48 +02:00
unknown 1bdb118391 cache channel view id 2024-10-23 01:29:37 +02:00
unknown 0e4897969b replace ChannelViewProxy with ChannelViewId 2024-10-23 00:57:57 +02:00
dependabot[bot] 9e8281b75b
chore(deps): bump lib/expected-lite from 88ee08e to 5b5caad (#5667) 2024-10-22 22:30:25 +00:00
unknown 374e0c5fa0 remove leftovers 2024-10-23 00:28:47 +02:00
dependabot[bot] b46a893127
chore(deps): bump lib/settings from c58874c to 4a0a1e5 (#5646) 2024-10-22 21:49:58 +00:00
nerix 55a12fa008
test: add snapshots for raids, timeouts, and notices (#5671) 2024-10-22 21:06:29 +00:00
13 changed files with 603 additions and 73 deletions

View file

@ -105,7 +105,7 @@
- Dev: Added more tests for input completion. (#5604)
- Dev: Refactored legacy Unicode zero-width-joiner replacement. (#5594)
- Dev: The JSON output when copying a message (<kbd>SHIFT</kbd> + right-click) is now more extensive. (#5600)
- Dev: Added more tests for message building. (#5598, #5654, #5656)
- Dev: Added more tests for message building. (#5598, #5654, #5656, #5671)
- Dev: Twitch messages are now sent using Twitch's Helix API instead of IRC by default. (#5607)
- Dev: `GIFTimer` is no longer initialized in tests. (#5608)
- Dev: Emojis now use flags instead of a set of strings for capabilities. (#5616)

@ -1 +1 @@
Subproject commit 88ee08eb3c3f3627ca54b90dafd1d63a6d4da96b
Subproject commit 5b5caad7cd57d5ba3ca796bf1521b131d73ca405

@ -1 +1 @@
Subproject commit c58874c1aa5d0619df2c975bcb87433941b46920
Subproject commit 4a0a1e599377cdcdc91b0fbbefc312936b48730c

View file

@ -2,7 +2,6 @@
#include "widgets/BaseWidget.hpp"
#include <ForwardDecl.hpp>
#include <pajlada/signals/signal.hpp>
#include <pajlada/signals/signalholder.hpp>
#include <QList>

View file

@ -1063,6 +1063,8 @@ void ChannelView::setChannel(const ChannelPtr &underlyingChannel)
this->underlyingChannel_ = underlyingChannel;
this->updateID();
this->performLayout();
this->queueUpdate();
@ -1081,6 +1083,8 @@ void ChannelView::setChannel(const ChannelPtr &underlyingChannel)
void ChannelView::setFilters(const QList<QUuid> &ids)
{
this->channelFilters_ = std::make_shared<FilterSet>(ids);
this->updateID();
}
QList<QUuid> ChannelView::getFilterIds() const
@ -3242,4 +3246,27 @@ void ChannelView::pendingLinkInfoStateChanged()
this->tooltipWidget_->applyLastBoundsCheck();
}
void ChannelView::updateID()
{
if (!this->underlyingChannel_)
{
// cannot update
return;
}
std::size_t seed = 0;
auto first = qHash(this->underlyingChannel_->getName());
auto second = qHash(this->getFilterIds());
boost::hash_combine(seed, first);
boost::hash_combine(seed, second);
this->id_ = seed;
}
ChannelView::ChannelViewID ChannelView::getID() const
{
return this->id_;
}
} // namespace chatterino

View file

@ -215,6 +215,9 @@ public:
Scrollbar *scrollbar();
using ChannelViewID = std::size_t;
ChannelViewID getID() const;
pajlada::Signals::Signal<QMouseEvent *> mouseDown;
pajlada::Signals::NoArgSignal selectionChanged;
pajlada::Signals::Signal<HighlightState, const MessagePtr &>
@ -318,6 +321,9 @@ private:
void showReplyThreadPopup(const MessagePtr &message);
bool canReplyToMessages() const;
void updateID();
ChannelViewID id_{};
bool layoutQueued_ = false;
bool bufferInvalidationQueued_ = false;

View file

@ -56,27 +56,6 @@ namespace {
}
} // namespace
std::size_t NotebookTab::HighlightSources::ChannelViewProxyHash::operator()(
const ChannelViewProxy &cp) const noexcept
{
std::size_t seed = 0;
auto first = qHash(cp.channelView->underlyingChannel()->getName());
auto second = qHash(cp.channelView->getFilterIds());
boost::hash_combine(seed, first);
boost::hash_combine(seed, second);
return seed;
}
bool NotebookTab::HighlightSources::ChannelViewProxyEqual::operator()(
const ChannelViewProxy &lp, const ChannelViewProxy &rp) const
{
return lp.channelView->underlyingChannel() ==
rp.channelView->underlyingChannel() &&
lp.channelView->getFilterIds() == rp.channelView->getFilterIds();
}
NotebookTab::NotebookTab(Notebook *notebook)
: Button(notebook)
, positionChangedAnimation_(this, "pos")
@ -327,13 +306,13 @@ bool NotebookTab::isSelected() const
}
void NotebookTab::removeNewMessageSource(
const HighlightSources::ChannelViewProxy &source)
const ChannelView::ChannelViewID &source)
{
this->highlightSources_.newMessageSource.erase(source);
}
void NotebookTab::removeHighlightedSource(
const HighlightSources::ChannelViewProxy &source)
const ChannelView::ChannelViewID &source)
{
this->highlightSources_.highlightedSource.erase(source);
}
@ -354,11 +333,9 @@ void NotebookTab::removeHighlightStateChangeSources(
void NotebookTab::newHighlightSourceAdded(const ChannelView &channelViewSource)
{
auto channelViewProxy =
HighlightSources::ChannelViewProxy{&channelViewSource};
auto sourceChannel = channelViewSource.underlyingChannel();
this->removeHighlightedSource(channelViewProxy);
this->removeNewMessageSource(channelViewProxy);
auto channelViewId = channelViewSource.getID();
this->removeHighlightedSource(channelViewId);
this->removeNewMessageSource(channelViewId);
this->updateHighlightStateDueSourcesChange();
auto *splitNotebook = dynamic_cast<SplitNotebook *>(this->notebook_);
@ -373,8 +350,8 @@ void NotebookTab::newHighlightSourceAdded(const ChannelView &channelViewSource)
auto *tab = splitContainer->getTab();
if (tab && tab != this)
{
tab->removeHighlightedSource(channelViewProxy);
tab->removeNewMessageSource(channelViewProxy);
tab->removeHighlightedSource(channelViewId);
tab->removeNewMessageSource(channelViewId);
tab->updateHighlightStateDueSourcesChange();
}
}
@ -576,32 +553,23 @@ void NotebookTab::updateHighlightState(HighlightState newHighlightStyle,
// message is highlighting unvisible tab
auto underlyingChannel = channelViewSource.underlyingChannel();
auto newFilters = channelViewSource.getFilterIds();
auto channelViewProxy =
HighlightSources::ChannelViewProxy{&channelViewSource};
// the unvisible tab should unhighlight other tabs iff
// the other tab's filters are more generic therefore
// the other tab's filter set is subset of the unvisible tab
auto channelViewId = channelViewSource.getID();
switch (newHighlightStyle)
{
case HighlightState::Highlighted: {
if (!this->highlightSources_.highlightedSource.contains(
channelViewProxy))
channelViewId))
{
this->highlightSources_.highlightedSource.insert(
channelViewProxy);
this->highlightSources_.highlightedSource.insert(channelViewId);
}
break;
}
case HighlightState::NewMessage: {
if (!this->highlightSources_.newMessageSource.contains(
channelViewProxy))
channelViewId))
{
this->highlightSources_.newMessageSource.insert(
channelViewProxy);
this->highlightSources_.newMessageSource.insert(channelViewId);
}
break;
}

View file

@ -126,40 +126,19 @@ private:
const MessagePtr &message) const;
struct HighlightSources {
struct ChannelViewProxy {
const ChannelView *channelView;
};
struct ChannelViewProxyHash {
using is_transparent = void;
std::size_t operator()(const ChannelViewProxy &cp) const noexcept;
};
struct ChannelViewProxyEqual {
bool operator()(const ChannelViewProxy &l,
const ChannelViewProxy &r) const;
};
std::unordered_set<ChannelViewProxy, ChannelViewProxyHash,
ChannelViewProxyEqual>
newMessageSource;
std::unordered_set<ChannelViewProxy, ChannelViewProxyHash,
ChannelViewProxyEqual>
highlightedSource;
std::unordered_set<ChannelView::ChannelViewID> newMessageSource;
std::unordered_set<ChannelView::ChannelViewID> highlightedSource;
void clear()
{
this->newMessageSource.clear();
this->highlightedSource.clear();
}
} highlightSources_;
void removeHighlightStateChangeSources(const HighlightSources &toRemove);
void removeNewMessageSource(
const HighlightSources::ChannelViewProxy &source);
void removeHighlightedSource(
const HighlightSources::ChannelViewProxy &source);
void removeNewMessageSource(const ChannelView::ChannelViewID &source);
void removeHighlightedSource(const ChannelView::ChannelViewID &source);
void updateHighlightStateDueSourcesChange();
QPropertyAnimation positionChangedAnimation_;

View file

@ -0,0 +1,157 @@
{
"input": "@room-id=11148817;rm-received-ts=1729627607652;tmi-sent-ts=1729627607545;historical=1 :tmi.twitch.tv CLEARCHAT #pajlada",
"output": [
{
"badgeInfos": {
},
"badges": [
],
"channelName": "",
"count": 1,
"displayName": "",
"elements": [
{
"element": {
"color": "System",
"flags": "Timestamp",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"20:06"
]
},
"flags": "Timestamp",
"format": "",
"link": {
"type": "None",
"value": ""
},
"time": "20:06:47",
"tooltip": "",
"trailingSpace": true,
"type": "TimestampElement"
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"Chat"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"has"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"been"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"cleared"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"by"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"a"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"moderator."
]
}
],
"flags": "System|DoNotTriggerNotification",
"id": "",
"localizedName": "",
"loginName": "",
"messageText": "Chat has been cleared by a moderator.",
"searchText": "Chat has been cleared by a moderator.",
"serverReceivedTime": "",
"timeoutUser": "",
"usernameColor": "#ff000000"
}
]
}

View file

@ -0,0 +1,157 @@
{
"input": "@historical=1;rm-received-ts=1729627965650;msg-id=emote_only_on :tmi.twitch.tv NOTICE #pajlada :This room is now in emote-only mode.",
"output": [
{
"badgeInfos": {
},
"badges": [
],
"channelName": "",
"count": 1,
"displayName": "",
"elements": [
{
"element": {
"color": "System",
"flags": "Timestamp",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"20:12"
]
},
"flags": "Timestamp",
"format": "",
"link": {
"type": "None",
"value": ""
},
"time": "20:12:45",
"tooltip": "",
"trailingSpace": true,
"type": "TimestampElement"
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"This"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"room"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"is"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"now"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"in"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"emote-only"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"mode."
]
}
],
"flags": "System|DoNotTriggerNotification",
"id": "",
"localizedName": "",
"loginName": "",
"messageText": "This room is now in emote-only mode.",
"searchText": "This room is now in emote-only mode.",
"serverReceivedTime": "",
"timeoutUser": "",
"usernameColor": "#ff000000"
}
]
}

View file

@ -0,0 +1,145 @@
{
"input": "@badges=subscriber/24;login=nerixyz;msg-param-displayName=nerixyz;user-type=;tmi-sent-ts=1729626466361;system-msg=2\\sraiders\\sfrom\\snerixyz\\shave\\sjoined!;room-id=11148817;user-id=129546453;display-name=nerixyz;subscriber=1;historical=1;rm-received-ts=1729626466492;msg-id=raid;vip=0;id=7299b7bc-61ce-423c-85ce-8d651b56cce4;msg-param-login=nerixyz;color=#FF0000;mod=0;msg-param-viewerCount=2;flags=;msg-param-profileImageURL=https://static-cdn.jtvnw.net/jtv_user_pictures/e065218b-49df-459d-afd3-c6557870f551-profile_image-%s.png;emotes=;badge-info=subscriber/28 :tmi.twitch.tv USERNOTICE #pajlada",
"output": [
{
"badgeInfos": {
},
"badges": [
],
"channelName": "",
"count": 1,
"displayName": "",
"elements": [
{
"element": {
"color": "System",
"flags": "Timestamp",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"19:47"
]
},
"flags": "Timestamp",
"format": "",
"link": {
"type": "None",
"value": ""
},
"time": "19:47:46",
"tooltip": "",
"trailingSpace": true,
"type": "TimestampElement"
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"2"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"raiders"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"from"
]
},
{
"color": "Text",
"fallbackColor": "System",
"flags": "Text|Mention",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "MentionElement",
"userColor": "#ffff0000",
"userLoginName": "nerixyz",
"words": [
"nerixyz"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"have"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"joined!"
]
}
],
"flags": "System|DoNotTriggerNotification|Subscription",
"id": "",
"localizedName": "",
"loginName": "",
"messageText": "2 raiders from nerixyz have joined!",
"searchText": "2 raiders from nerixyz have joined!",
"serverReceivedTime": "",
"timeoutUser": "",
"usernameColor": "#ff000000"
}
]
}

View file

@ -0,0 +1,5 @@
{
"input": "@color=#FF0000;emotes=;subscriber=0;msg-id=sharedchatnotice;historical=1;msg-param-profileImageURL=https://static-cdn.jtvnw.net/jtv_user_pictures/e065218b-49df-459d-afd3-c6557870f551-profile_image-%s.png;tmi-sent-ts=1729627237027;rm-received-ts=1729627237138;msg-param-displayName=nerixyz;id=c585cb3e-cb4f-4a48-a251-b568d217587e;display-name=nerixyz;badges=;user-id=129546453;source-id=d86cdfb2-e138-48e2-985f-5b8efb765ba4;source-room-id=955766119;room-id=11148817;user-type=;msg-param-login=nerixyz;flags=;source-badge-info=;mod=0;vip=0;system-msg=2\\sraiders\\sfrom\\snerixyz\\shave\\sjoined!;login=nerixyz;msg-param-viewerCount=2;source-badges=;source-msg-id=raid;badge-info= :tmi.twitch.tv USERNOTICE #pajlada",
"output": [
]
}

View file

@ -0,0 +1,87 @@
{
"input": "@tmi-sent-ts=1729628658012;rm-received-ts=1729628658106;historical=1;ban-duration=1;room-id=11148817;target-user-id=129546453 :tmi.twitch.tv CLEARCHAT #pajlada nerixyz",
"output": [
{
"badgeInfos": {
},
"badges": [
],
"channelName": "",
"count": 1,
"displayName": "",
"elements": [
{
"element": {
"color": "System",
"flags": "Timestamp",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"20:24"
]
},
"flags": "Timestamp",
"format": "",
"link": {
"type": "None",
"value": ""
},
"time": "20:24:18",
"tooltip": "",
"trailingSpace": true,
"type": "TimestampElement"
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "UserInfo",
"value": "nerixyz"
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"nerixyz"
]
},
{
"color": "System",
"flags": "Text",
"link": {
"type": "None",
"value": ""
},
"style": "ChatMedium",
"tooltip": "",
"trailingSpace": true,
"type": "TextElement",
"words": [
"has",
"been",
"timed",
"out",
"for",
"1s."
]
}
],
"flags": "System|Timeout|DoNotTriggerNotification",
"id": "",
"localizedName": "",
"loginName": "",
"messageText": "nerixyz has been timed out for 1s. ",
"searchText": "nerixyz has been timed out for 1s. ",
"serverReceivedTime": "",
"timeoutUser": "nerixyz",
"usernameColor": "#ff000000"
}
]
}