Compare commits

...

17 commits

Author SHA1 Message Date
hemirt 0103b7e055
Merge 2884c828b0 into 85d34c8ff0 2024-10-18 21:44:23 +02:00
pajlada 85d34c8ff0
test: use httpbox fork release (#5655) 2024-10-18 19:23:13 +00:00
unknown 2884c828b0 update highlights of other tabs when adding new channel or changing
channel
2024-10-18 09:24:34 +02:00
unknown e288742360 more asserts 2024-10-17 20:43:25 +02:00
unknown 1ca5d38ad5 add some asserts 2024-10-17 20:35:52 +02:00
unknown 39e0e00f2d add more highlight state functions 2024-10-17 20:05:05 +02:00
unknown 8745d0740f fix duplicating tabs 2024-10-17 19:24:53 +02:00
unknown 5f862c5e5e solve highlighted tabs 2024-10-17 18:56:14 +02:00
unknown a2af8e791b switch from QHash to std::unordered_map 2024-10-17 17:25:54 +02:00
unknown 13d7692a89 add older version code 2024-10-17 16:38:32 +02:00
unknown 806fa7790d missing include 2024-10-17 15:37:36 +02:00
unknown edaafac010 initial state of selecting to unhiglight 2024-10-17 13:16:37 +02:00
unknown 7728f01916 name fixes 2024-10-15 18:14:11 +02:00
hemirt 70f497d3bd
Update src/widgets/helper/NotebookTab.cpp
Co-authored-by: nerix <nero.9@hotmail.de>
2024-10-15 18:03:14 +02:00
unknown 3b64f142e6 commit suggestions 2024-10-15 02:46:19 +02:00
unknown e827097c1c fix suggestions 2024-10-15 01:10:24 +02:00
unknown f7dd6de872 highlight tabs only on unviewed messages 2024-10-15 01:10:24 +02:00
10 changed files with 322 additions and 36 deletions

View file

@ -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: |

View file

@ -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

View file

@ -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);
}

View file

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

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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_;

View file

@ -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();

View file

@ -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`