mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Compare commits
17 commits
14f882aadc
...
0103b7e055
Author | SHA1 | Date | |
---|---|---|---|
0103b7e055 | |||
85d34c8ff0 | |||
2884c828b0 | |||
e288742360 | |||
1ca5d38ad5 | |||
39e0e00f2d | |||
8745d0740f | |||
5f862c5e5e | |||
a2af8e791b | |||
13d7692a89 | |||
806fa7790d | |||
edaafac010 | |||
7728f01916 | |||
70f497d3bd | |||
3b64f142e6 | |||
e827097c1c | |||
f7dd6de872 |
12
.github/workflows/test-macos.yml
vendored
12
.github/workflows/test-macos.yml
vendored
|
@ -8,6 +8,7 @@ on:
|
|||
|
||||
env:
|
||||
TWITCH_PUBSUB_SERVER_TAG: v1.0.7
|
||||
HTTPBOX_TAG: v0.2.1
|
||||
QT_QPA_PLATFORM: minimal
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||
|
@ -58,6 +59,13 @@ jobs:
|
|||
run: |
|
||||
brew install boost openssl rapidjson p7zip create-dmg cmake
|
||||
|
||||
- name: Install httpbox
|
||||
run: |
|
||||
curl -L -o httpbox.tar.xz "https://github.com/Chatterino/httpbox/releases/download/${{ env.HTTPBOX_TAG }}/httpbox-x86_64-apple-darwin.tar.xz"
|
||||
tar -xJf httpbox.tar.xz
|
||||
mv ./httpbox-x86_64-apple-darwin/httpbox /usr/local/bin
|
||||
working-directory: /tmp
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build-test
|
||||
|
@ -83,10 +91,6 @@ jobs:
|
|||
curl -L -o server.key "https://github.com/Chatterino/twitch-pubsub-server-test/raw/${{ env.TWITCH_PUBSUB_SERVER_TAG }}/cmd/server/server.key"
|
||||
cd ..
|
||||
|
||||
- name: Cargo Install httpbox
|
||||
run: |
|
||||
cargo install --git https://github.com/kevinastone/httpbox --rev 89b971f
|
||||
|
||||
- name: Test
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
|
|
14
.github/workflows/test-windows.yml
vendored
14
.github/workflows/test-windows.yml
vendored
|
@ -8,6 +8,7 @@ on:
|
|||
|
||||
env:
|
||||
TWITCH_PUBSUB_SERVER_TAG: v1.0.7
|
||||
HTTPBOX_TAG: v0.2.1
|
||||
QT_QPA_PLATFORM: minimal
|
||||
# Last known good conan version
|
||||
# 2.0.3 has a bug on Windows (conan-io/conan#13606)
|
||||
|
@ -111,6 +112,13 @@ jobs:
|
|||
mkdir -Force build-test/bin
|
||||
cp "$((ls $Env:VCToolsRedistDir/onecore/x64 -Filter '*.CRT')[0].FullName)/*" build-test/bin
|
||||
|
||||
- name: Install httpbox
|
||||
run: |
|
||||
mkdir httpbox
|
||||
Invoke-WebRequest -Uri "https://github.com/Chatterino/httpbox/releases/download/${{ env.HTTPBOX_TAG }}/httpbox-x86_64-pc-windows-msvc.zip" -outfile "httpbox.zip"
|
||||
Expand-Archive httpbox.zip -DestinationPath httpbox
|
||||
rm httpbox.zip
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake `
|
||||
|
@ -139,14 +147,10 @@ jobs:
|
|||
Invoke-WebRequest -Uri "https://github.com/Chatterino/twitch-pubsub-server-test/raw/${{ env.TWITCH_PUBSUB_SERVER_TAG }}/cmd/server/server.key" -outfile "server.key"
|
||||
cd ..
|
||||
|
||||
- name: Cargo Install httpbox
|
||||
run: |
|
||||
cargo install --git https://github.com/kevinastone/httpbox --rev 89b971f
|
||||
|
||||
- name: Test
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
httpbox --port 9051 &
|
||||
..\httpbox\httpbox.exe --port 9051 &
|
||||
cd ..\pubsub-server-test
|
||||
.\server.exe 127.0.0.1:9050 &
|
||||
cd ..\build-test
|
||||
|
|
|
@ -204,7 +204,7 @@ void Notebook::duplicatePage(QWidget *page)
|
|||
{
|
||||
newTabPosition = tabPosition + 1;
|
||||
}
|
||||
auto newTabHighlightState = item->tab->highlightState();
|
||||
|
||||
QString newTabTitle = "";
|
||||
if (item->tab->hasCustomTitle())
|
||||
{
|
||||
|
@ -213,7 +213,7 @@ void Notebook::duplicatePage(QWidget *page)
|
|||
|
||||
auto *tab =
|
||||
this->addPageAt(newContainer, newTabPosition, newTabTitle, false);
|
||||
tab->setHighlightState(newTabHighlightState);
|
||||
tab->copyHighlightStateAndSourcesFrom(item->tab);
|
||||
|
||||
newContainer->setTab(tab);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <ForwardDecl.hpp>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
#include <QList>
|
||||
|
|
|
@ -1190,11 +1190,13 @@ void ChannelView::messageAppended(MessagePtr &message,
|
|||
(this->channel_->getType() == Channel::Type::TwitchAutomod &&
|
||||
getSettings()->enableAutomodHighlight))
|
||||
{
|
||||
this->tabHighlightRequested.invoke(HighlightState::Highlighted);
|
||||
this->tabHighlightRequested.invoke(HighlightState::Highlighted,
|
||||
message);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->tabHighlightRequested.invoke(HighlightState::NewMessage);
|
||||
this->tabHighlightRequested.invoke(HighlightState::NewMessage,
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,6 +179,9 @@ public:
|
|||
|
||||
LimitedQueueSnapshot<MessageLayoutPtr> &getMessagesSnapshot();
|
||||
|
||||
// Returns true if message should be included
|
||||
bool shouldIncludeMessage(const MessagePtr &m) const;
|
||||
|
||||
void queueLayout();
|
||||
void invalidateBuffers();
|
||||
|
||||
|
@ -214,7 +217,8 @@ public:
|
|||
|
||||
pajlada::Signals::Signal<QMouseEvent *> mouseDown;
|
||||
pajlada::Signals::NoArgSignal selectionChanged;
|
||||
pajlada::Signals::Signal<HighlightState> tabHighlightRequested;
|
||||
pajlada::Signals::Signal<HighlightState, const MessagePtr &>
|
||||
tabHighlightRequested;
|
||||
pajlada::Signals::NoArgSignal liveStatusChanged;
|
||||
pajlada::Signals::Signal<const Link &> linkClicked;
|
||||
pajlada::Signals::Signal<QString, FromTwitchLinkOpenChannelIn>
|
||||
|
@ -374,9 +378,6 @@ private:
|
|||
|
||||
FilterSetPtr channelFilters_;
|
||||
|
||||
// Returns true if message should be included
|
||||
bool shouldIncludeMessage(const MessagePtr &m) const;
|
||||
|
||||
// Returns whether the scrollbar should have highlights
|
||||
bool showScrollbarHighlights() const;
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/splits/DraggedSplit.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <boost/bind/bind.hpp>
|
||||
|
@ -302,10 +304,141 @@ bool NotebookTab::isSelected() const
|
|||
return this->selected_;
|
||||
}
|
||||
|
||||
void NotebookTab::removeNewMessageSource(const ChannelPtr &source)
|
||||
{
|
||||
this->highlightSources_.newMessageSource.erase(source);
|
||||
}
|
||||
|
||||
void NotebookTab::removeHighlightedSource(const ChannelPtr &source)
|
||||
{
|
||||
this->highlightSources_.highlightedSource.erase(source);
|
||||
}
|
||||
|
||||
void NotebookTab::removeHighlightStateChangeSources(
|
||||
const HighlightSources &toRemove)
|
||||
{
|
||||
for (const auto &source : toRemove.newMessageSource)
|
||||
{
|
||||
this->removeNewMessageSource(source);
|
||||
}
|
||||
|
||||
for (const auto &source : toRemove.highlightedSource)
|
||||
{
|
||||
this->removeHighlightedSource(source);
|
||||
}
|
||||
}
|
||||
|
||||
void NotebookTab::newHighlightSourceAdded(const ChannelPtr &source)
|
||||
{
|
||||
this->removeHighlightedSource(source);
|
||||
this->removeNewMessageSource(source);
|
||||
this->updateHighlightStateDueSourcesChange();
|
||||
|
||||
auto *splitNotebook = dynamic_cast<SplitNotebook *>(this->notebook_);
|
||||
if (splitNotebook)
|
||||
{
|
||||
for (int i = 0; i < splitNotebook->getPageCount(); ++i)
|
||||
{
|
||||
auto *splitContainer =
|
||||
dynamic_cast<SplitContainer *>(splitNotebook->getPageAt(i));
|
||||
if (splitContainer)
|
||||
{
|
||||
auto *tab = splitContainer->getTab();
|
||||
if (tab && tab != this)
|
||||
{
|
||||
tab->removeHighlightedSource(source);
|
||||
tab->removeNewMessageSource(source);
|
||||
tab->updateHighlightStateDueSourcesChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NotebookTab::updateHighlightStateDueSourcesChange()
|
||||
{
|
||||
if (!this->highlightSources_.highlightedSource.empty())
|
||||
{
|
||||
assert(this->highlightState_ == HighlightState::Highlighted);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->highlightSources_.newMessageSource.empty())
|
||||
{
|
||||
if (this->highlightState_ != HighlightState::NewMessage)
|
||||
{
|
||||
this->highlightState_ = HighlightState::NewMessage;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->highlightState_ != HighlightState::None)
|
||||
{
|
||||
this->highlightState_ = HighlightState::None;
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
assert(this->highlightState_ != HighlightState::Highlighted);
|
||||
}
|
||||
|
||||
void NotebookTab::copyHighlightStateAndSourcesFrom(const NotebookTab *sourceTab)
|
||||
{
|
||||
if (this->isSelected())
|
||||
{
|
||||
assert(this->highlightSources_.highlightedSource.empty());
|
||||
assert(this->highlightSources_.newMessageSource.empty());
|
||||
assert(this->highlightState_ == HighlightState::None);
|
||||
return;
|
||||
}
|
||||
|
||||
this->highlightSources_ = sourceTab->highlightSources_;
|
||||
|
||||
if (!this->highlightEnabled_ &&
|
||||
sourceTab->highlightState_ == HighlightState::NewMessage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->highlightState_ == sourceTab->highlightState_ ||
|
||||
this->highlightState_ == HighlightState::Highlighted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->highlightState_ = sourceTab->highlightState_;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void NotebookTab::setSelected(bool value)
|
||||
{
|
||||
this->selected_ = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
auto *splitNotebook = dynamic_cast<SplitNotebook *>(this->notebook_);
|
||||
if (splitNotebook)
|
||||
{
|
||||
for (int i = 0; i < splitNotebook->getPageCount(); ++i)
|
||||
{
|
||||
auto *splitContainer =
|
||||
dynamic_cast<SplitContainer *>(splitNotebook->getPageAt(i));
|
||||
if (splitContainer)
|
||||
{
|
||||
auto *tab = splitContainer->getTab();
|
||||
if (tab && tab != this)
|
||||
{
|
||||
tab->removeHighlightStateChangeSources(
|
||||
this->highlightSources_);
|
||||
tab->updateHighlightStateDueSourcesChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->highlightSources_.clear();
|
||||
this->highlightState_ = HighlightState::None;
|
||||
|
||||
this->update();
|
||||
|
@ -358,13 +491,82 @@ bool NotebookTab::isLive() const
|
|||
return this->isLive_;
|
||||
}
|
||||
|
||||
HighlightState NotebookTab::highlightState() const
|
||||
{
|
||||
return this->highlightState_;
|
||||
}
|
||||
|
||||
void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
|
||||
{
|
||||
if (this->isSelected())
|
||||
{
|
||||
assert(this->highlightSources_.highlightedSource.empty());
|
||||
assert(this->highlightSources_.newMessageSource.empty());
|
||||
assert(this->highlightState_ == HighlightState::None);
|
||||
return;
|
||||
}
|
||||
|
||||
this->highlightSources_.clear();
|
||||
|
||||
if (!this->highlightEnabled_ &&
|
||||
newHighlightStyle == HighlightState::NewMessage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->highlightState_ == newHighlightStyle ||
|
||||
this->highlightState_ == HighlightState::Highlighted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->highlightState_ = newHighlightStyle;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void NotebookTab::updateHighlightState(HighlightState newHighlightStyle,
|
||||
const ChannelView &channelViewSource,
|
||||
const MessagePtr &message)
|
||||
{
|
||||
if (this->isSelected())
|
||||
{
|
||||
assert(this->highlightSources_.highlightedSource.empty());
|
||||
assert(this->highlightSources_.newMessageSource.empty());
|
||||
assert(this->highlightState_ == HighlightState::None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->shouldMessageHighlight(channelViewSource, message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto underlyingChannel = channelViewSource.underlyingChannel();
|
||||
|
||||
switch (newHighlightStyle)
|
||||
{
|
||||
case HighlightState::Highlighted: {
|
||||
if (!this->highlightSources_.highlightedSource.contains(
|
||||
underlyingChannel))
|
||||
{
|
||||
this->highlightSources_.highlightedSource.insert(
|
||||
underlyingChannel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HighlightState::NewMessage: {
|
||||
if (!this->highlightSources_.newMessageSource.contains(
|
||||
underlyingChannel))
|
||||
{
|
||||
this->highlightSources_.newMessageSource.insert(
|
||||
underlyingChannel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HighlightState::None:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this->highlightEnabled_ &&
|
||||
newHighlightStyle == HighlightState::NewMessage)
|
||||
{
|
||||
|
@ -381,9 +583,37 @@ void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
|
|||
this->update();
|
||||
}
|
||||
|
||||
HighlightState NotebookTab::highlightState() const
|
||||
bool NotebookTab::shouldMessageHighlight(const ChannelView &channelViewSource,
|
||||
const MessagePtr &message) const
|
||||
{
|
||||
return this->highlightState_;
|
||||
auto *visibleSplitContainer =
|
||||
dynamic_cast<SplitContainer *>(this->notebook_->getSelectedPage());
|
||||
if (visibleSplitContainer != nullptr)
|
||||
{
|
||||
const auto &visibleSplits = visibleSplitContainer->getSplits();
|
||||
for (const auto &visibleSplit : visibleSplits)
|
||||
{
|
||||
auto filterIdsSource = channelViewSource.getFilterIds();
|
||||
auto filterIdsSplit = visibleSplit->getChannelView().getFilterIds();
|
||||
|
||||
auto isSubset = []<typename T>(const QList<T> &sub,
|
||||
const QList<T> &super) {
|
||||
return std::ranges::all_of(sub, [&super](const auto &subItem) {
|
||||
return super.contains(subItem);
|
||||
});
|
||||
};
|
||||
|
||||
if (channelViewSource.underlyingChannel() ==
|
||||
visibleSplit->getChannel() &&
|
||||
visibleSplit->getChannelView().shouldIncludeMessage(message) &&
|
||||
isSubset(filterIdsSource, filterIdsSplit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NotebookTab::setHighlightsEnabled(const bool &newVal)
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace chatterino {
|
|||
inline constexpr int NOTEBOOK_TAB_HEIGHT = 28;
|
||||
|
||||
class SplitContainer;
|
||||
class ChannelView;
|
||||
|
||||
class NotebookTab : public Button
|
||||
{
|
||||
|
@ -59,11 +60,25 @@ public:
|
|||
**/
|
||||
bool isLive() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the highlight state of this tab clearing highlight sources
|
||||
*
|
||||
* Obeys the HighlightsEnabled setting and highlight states hierarchy
|
||||
*/
|
||||
void setHighlightState(HighlightState style);
|
||||
HighlightState highlightState() const;
|
||||
|
||||
/**
|
||||
* @brief Updates the highlight state and highlight sources of this tab
|
||||
*
|
||||
* Obeys the HighlightsEnabled setting and the highlight state hierarchy and tracks the highlight state update sources
|
||||
*/
|
||||
void updateHighlightState(HighlightState style,
|
||||
const ChannelView &channelViewSource,
|
||||
const MessagePtr &message);
|
||||
void copyHighlightStateAndSourcesFrom(const NotebookTab *sourceTab);
|
||||
void setHighlightsEnabled(const bool &newVal);
|
||||
void newHighlightSourceAdded(const ChannelPtr &source);
|
||||
bool hasHighlightsEnabled() const;
|
||||
HighlightState highlightState() const;
|
||||
|
||||
void moveAnimated(QPoint targetPos, bool animated = true);
|
||||
|
||||
|
@ -107,6 +122,26 @@ private:
|
|||
|
||||
int normalTabWidthForHeight(int height) const;
|
||||
|
||||
bool shouldMessageHighlight(const ChannelView &channelViewSource,
|
||||
const MessagePtr &message) const;
|
||||
|
||||
struct HighlightSources {
|
||||
std::unordered_set<ChannelPtr> newMessageSource;
|
||||
std::unordered_set<ChannelPtr> highlightedSource;
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->newMessageSource.clear();
|
||||
this->highlightedSource.clear();
|
||||
}
|
||||
|
||||
} highlightSources_;
|
||||
|
||||
void removeHighlightStateChangeSources(const HighlightSources &toRemove);
|
||||
void removeNewMessageSource(const ChannelPtr &source);
|
||||
void removeHighlightedSource(const ChannelPtr &source);
|
||||
void updateHighlightStateDueSourcesChange();
|
||||
|
||||
QPropertyAnimation positionChangedAnimation_;
|
||||
QPoint positionAnimationDesiredPoint_;
|
||||
|
||||
|
|
|
@ -213,13 +213,25 @@ void SplitContainer::addSplit(Split *split)
|
|||
|
||||
auto &&conns = this->connectionsPerSplit_[split];
|
||||
|
||||
conns.managedConnect(split->getChannelView().tabHighlightRequested,
|
||||
[this](HighlightState state) {
|
||||
if (this->tab_ != nullptr)
|
||||
{
|
||||
this->tab_->setHighlightState(state);
|
||||
}
|
||||
});
|
||||
conns.managedConnect(
|
||||
split->getChannelView().tabHighlightRequested,
|
||||
[this, split](HighlightState state, const MessagePtr &message) {
|
||||
if (this->tab_ != nullptr)
|
||||
{
|
||||
this->tab_->updateHighlightState(state, split->getChannelView(),
|
||||
message);
|
||||
}
|
||||
});
|
||||
|
||||
conns.managedConnect(split->channelChanged, [this, split] {
|
||||
qDebug() << "Changing Channel"
|
||||
<< split->getChannelView().underlyingChannel()->getName();
|
||||
if (this->tab_ != nullptr)
|
||||
{
|
||||
this->tab_->newHighlightSourceAdded(
|
||||
split->getChannelView().underlyingChannel());
|
||||
}
|
||||
});
|
||||
|
||||
conns.managedConnect(split->getChannelView().liveStatusChanged, [this]() {
|
||||
this->refreshTabLiveStatus();
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
To run all tests you will need to run the `kennethreitz/httpbin` and `ghcr.io/chatterino/twitch-pubsub-server-test:latest` docker images.
|
||||
# Pre-requisites to running tests
|
||||
|
||||
For example:
|
||||
- Download & run [httpbox](https://github.com/Chatterino/httpbox/releases/latest)
|
||||
`httpbox --port 9051`
|
||||
|
||||
```bash
|
||||
docker run --network=host --detach ghcr.io/chatterino/twitch-pubsub-server-test:latest
|
||||
docker run -p 9051:80 --detach kennethreitz/httpbin
|
||||
```
|
||||
|
||||
If you're unable to use docker, you can use [httpbox](https://github.com/kevinastone/httpbox) (`httpbox --port 9051`) and [Chatterino/twitch-pubsub-server-test](https://github.com/Chatterino/twitch-pubsub-server-test/releases/latest) manually.
|
||||
- Download & run [twitch-pubsub-server-test](https://github.com/Chatterino/twitch-pubsub-server-test/releases/latest)
|
||||
`twitch-pubsub-server-test`
|
||||
|
|
Loading…
Reference in a new issue